I have a small algorithmic problem.
I am developing an Android application. I get GPS coordinates. For example: latitude: 23.23907, longitude: 50.45786.
So I get a point. I want to compute bounds details on this point plus or minus 5 meters. I.e.:
[23.23907 - 5 meters ; 23.23907 + 5 meters]
[50.45786 - 5 meters ; 50.45786 + 5 meters]
How to make this calculation?
Thank you very much!
The haversine formula can be simplified a great deal when you work in north-south and east-west directions only.
If Earth's circumference is C, the point at d kilometers to south of a given point is 360*d/C degrees to the south. The point at d kilometers to east is 360*d/(C*cos(latitude)) degrees to the east. The cosine in the denominator comes from the fact that the length of the longitude at a given latitude shorter than the equator by that much.
So if the Earth's circumference is 40075.04 km, to move 5 m to the north/south you would add/subtract 0.0000449 from the latitude and use the same longitude. To move 5 m to the west/east you would use the same latitude and add/subtract 0.0000449/cos(latitude) to the longitude. Don't forget about the edge cases though: near poles you have to clamp latitude to 90°, and near longitude 180° you'll have too add or subtract 360° to keep the longitude in the correct range.
With your numbers the range turns out to be approximately:
latitude: [23.23903 ; 23.23911]
longitude: [50.45781 ; 50.45791]
Update: Note that this still assumes that the Earth is a perfect sphere, which it's not. The GPS system for example models the Earth as an ellipsoid where the equator is at 6378.137km and the poles are at 6356.7523142km from the center of the Earth. The difference is about 1/300th and matters a great deal for many applications, but in this case it's within the margin of error.
Correcting the formula for the longitude should be simple since the parallels are still circles: you would just have to swap cos(latitude) for the correct coefficient. Calculating the correct latitude is harder because the meridians are not circles but ellipses, and the arc length of an ellipse cannot be calculated using elementary functions, so you must use approximations.
I would like to add a very important comment:
The cosine is to be calculated on the latitude in radians and not in degrees.
conversion: radians = PI / 180 * degrees
Related
Suppose if a marker's longitude is 124.4567. How can I calculate the longitude which is 1 centimetre away to the left side of the screen? It will vary depending on the screen density and zoom level. Is there any inbuilt method to calculate that longitude?
PS: I am sorry, it was "longitude". I always am confused by the two. I have edited the question.
I am not trying to calculate geological distances between two markers. Basically, I want to know how much longitude is 1 centimetre on the screen (not 1 centimetre of actual land) of the device. I mean, 1cm on the screen could be 30 degree longitude difference if I have zoom it out on my phone, but 1cm on the screen could be 1 degree longitude on your phone if you have zoomed it in.
You got distance calculation between 2 coordinator from here:
Distance betwee
n coordinator
And you have destination long, source long, source lat, and distance just find out destination lat.
And about zoom level, you have scale ratio of google map here:
Google map scale ratio
"To the left side" means western direction. Actually, latitude varies from -90 to 90 degrees, so there is no latitude 124.
If you have any point LatLng, you can find point 1 meter to the left via simple math.
Radius of a parallel ring is r = R * cos(latitude_in_radians), so 1 meter takes 360 / r of longitude.
Therefore you can calculate your point as follows without any library.
var EarthR = 6378137;
var point = {lat: 45, lng: 124};
var point2 = {lat: point.lat, lng: point.lng - 360 / ( EarthR * Math.cos(point.lat * Math.PI / 180))};
console.log(point2);
After a lot of Google search, I have found this How to access Google Maps API v3 marker's DIV and its pixel position?. The answer showed how to convert screen locations to lat/lng coordinates. So I modified it a little to get the position 1 centimetre on the left, no matter what the zoom level is.
I put a marker on the left for visual debugging, when a marker is clicked. Here is the code. I am hoping it could be helpful to future people.
var dpi = resources.displayMetrics.densityDpi;
var pixelsInCm = (dpi/2.54).toInt();
var existingPoint = mMap!!.projection.toScreenLocation(marker.position);
var leftPoint = Point(existingPoint.x - pixelsInCm, existingPoint.y);
var leftLatLng = mMap!!.projection.fromScreenLocation(leftPoint);
//The code below is only for visual test. Not necessary.
var leftMarker = MarkerOptions()
leftMarker.position(leftLatLng);
leftMarker.title("1cm to the left");
mMap!!.addMarker(leftMarker);
I'm trying to make an app that points you toward a position. You press a button and it stores the gps coordinates, then calculates things like distance and the angle you need to face. Then it leads you back to that remembered position by "pointing" toward it using an onscreen compass graphic.
At least, it's supposed to. After messing with the code for hours, I've come to the conclusion that there's just a logic error somewhere due to my lack of trig practice over the past few years.
The compass and GPS position are updated fairly frequently. This is the code in my main update call for the user interface that rotates the compass and displays the distance.
public void updateUI(){
double deltaX = targetLongitude - currentLongitude;
double deltaY = targetLatitude - currentLatitude;
double distance = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
double rotation = Math.toDegrees(Math.atan2(deltaX,deltaY));
distanceTextView.setText(Double.toString(distance));
rotateCompass(rotation - degreesClockwiseFromNorth);
}
and the code for rotateCompass:
public void rotateCompass(double degrees){
degrees -= currentRotation; //calculates necessary rotation across updates
currentRotation += degrees;
matrix.postRotate(
(float) degrees,
compass.getDrawable().getBounds().width() / 2,
compass.getDrawable().getBounds().height() / 2);
compass.setImageMatrix(matrix);
}
I'm almost certain my rotation code works because when I replace
rotateCompass(rotation - degreesClockwiseFromNorth);
with
rotateCompass(0 - degreesClockwiseFromNorth);
it points north right alongside a real compass regardless of the direction I'm facing. But when I use the former, it points towards a consistent point, but that point seems to be nowhere near the target point.
So I've come to the conclusion my error is either in calculating the correct angle, or expecting the gps to be too precise. I haven't tested it for distances further than what I can in my backyard, but I assume that if it was a gps accuracy issue I'd see my compass jumping all over the place rather than adamantly pointing in a wrong direction.
Thanks for reading, any suggestions or corrections are appreciated.
Your math is all screwed up because the distance between 2 degrees of longitude is not the same as 2 degrees of latitude. In fact, it isn't even a constant length for longitude- its shorted by the poles and longest at the equator. Use the Location.distanceTo functions instead.
At the moment , I have two point(LatLng) A and B on the google map.
I present my problem as image follows:
When rotate device in vertical axis,I want to get angle # between point A and B
I want to get angle between AB and north-axis (y-axis)
How must I do.
I created a function to get angle but it return null :(
public double getAngleTwoPoint(LatLng point1,LatLng point2){
double lat1=point1.latitude;
double lat2=point2.latitude;
double long1=point1.longitude;
double long2=point2.longitude;
double deltaLong=long2-long1;
double angle = Math.atan2(Math.sin(deltaLong)*Math.cos(lat2), Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(deltaLong));
return Math.toDegrees(angle);
}
you can use this formula to get angle between to lat longs have a look.
θ = atan2(sin(Δlong)*cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong))
Note that the angle(θ) should be converted to radians before using this formula and Δlong = long2 - long1.
atan2 is a common function found in almost all programming languages (mostly in the Math package). Usually there is also functions for conversion between degrees and radians(also in the Math package).
Remember that atan2 returns values in the range of -π ... +π, to convert the result to a compass bearing, you need to multiply θ by 180/π then use (θ+360) % 360, where % is modulus division operation returning the remainder of the division.
The following link is a good resource for formulas involving latitudes and longitudes. They also provide Javascript implementation of their formulas. In fact the answer is based on the information from this page:
http://www.yourhomenow.com/house/haversine.html
If you have triangle
CB
A
then the angle between AB and y-axis is equal to CAB angle. tg(CAB) = BC/AC, you need the angle, so actually what you are loking for is arctg(BC/AC).
First read Question carefully ...
I need straight distance, not by walking,car,or etc.
Take a look to this image which given below,
Google provide us distance by car and driving.
But I don't want it, I want straight distance between two location (latitude - longitude).
Which is displayed as as RED LINE.
NOTE : I don't want to put red line on Google map, just want the Distance in Units(mile,km,etc.)
ANDROID
double distance
Location locationA = new Location(“point A”)
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location(“point B”);
locationB.setLatitude(latB);
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB);
MATHEMATICALY
a = distance in degrees //meterConversion = 1609;
b = 90 - latitude of point 1
c = 90 - latitude of point 2
l = longitude of point 1 - longitude of point 2
Cos(a) = Cos(b)Cos(c) + Sin(b)Sin(c)Sin(l)
d = circumference of Earth * a / 360 // circumference of Earth = 3958.7558657440545D km
The Haversine function is used to find the distance between two points on a sphere.
It's fairly straightforward to extend this to finding the straight line distance between two points on the Earth. The Earth is not a perfect sphere, but this is still a good approximation using a standard measurement (called WGS84) for the radius at the equator.
As CommonsWare has said, you can do this very simply by using distanceBetween(), which uses the Haversine function and the WGS84 radius.
For better understanding of implementation/math, take a look at this sample code in Python.
Distance you find with following code.
You just need to get two geoPoint's latitude and longitude.
and use that in following calculation to get distance.
R = 6371; // km
d = Math.acos(Math.sin(lat1)*Math.sin(lat2) +
Math.cos(lat1)*Math.cos(lat2) *
Math.cos(lon2-lon1)) * R;
That will be return distance after all calculation.
R is the radius of surface in KM, need to use in calculation and you try this. I hope it is useful for you.
I have an application of augmented reality in which I have stored information such us metro, gas stations, places of interest, etc. with the corresponding latitude and longitude.
Now, according to the orientation of the device, I would show a marker for each site in the camera view of the device. Similar to Layar and Wikitude.
It takes three days searching without stopping and have not found anyone to explain how to solve this problem.
Since information on this topic is very sparse, and I recently solved this problem on the iPhone, I thought I would share my method for anyone that can make it work with Android (there's nothing really specific to iPhone in this answer except for the Math functions sin, cos, and fmod, which can be found in java.lang.Math). These are the steps I took:
Obtain your own lat/lon and your current compass heading (lat1, lon1 and heading). On the iPhone, CLLocation returns these in degrees, but for these calculations they MUST be in radians (i.e. multiply by PI/180)
Obtain lat/lon of Points of Interest (POI) in radians (lat2 and lon2).
Calculate the distance between lat1/lon1 and lat2/lon2 using formula found here: http://www.movable-type.co.uk/scripts/latlong.html
Calculate angle to lat2/lon2 in relation to north. This is also described in the link above but I had a little bit of trouble getting this to work, here is C code for this:
double latDelta = (lat2 - lat1);
double lonDelta = (lon2 - lon1);
double y = sin(lonDelta) * cos(lat2);
double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2)* cos(lonDelta);
double angle = atan2(y, x); //not finished here yet
double headingDeg = compass.currentHeading;
double angleDeg = angle * 180/PI;
double heading = headingDeg*PI/180;
angle = fmod(angleDeg + 360, 360) * PI/180; //normalize to 0 to 360 (instead of -180 to 180), then convert back to radians
angleDeg = angle * 180/PI;
Using standard trigonometry, I calculate x and y. Remember, these coordinates are in 3D space, so we are not finished here yet because you still have to map them to 2D:
x = sin(angle-heading) * distance;
z = cos(angle-heading) * distance; //typically, z faces into the screen, but in our 2D map, it is a y-coordinate, as if you are looking from the bottom down on the world, like Google Maps
Finally, using the projection formula, you can calculate screen x ( I didn't do y because it was not necessary for my project, but you would need to get accelerator data and figure out if the device is perpendicular to the ground). The projection formula is found here (scroll to the very bottom): http://membres.multimania.fr/amycoders/tutorials/3dbasics.html
double screenX = (x * 256) / z
Now you can use this x coordinate to move an image or a marker on your screen. Remember a few points:
Everything must be in radians
The angle from you to the POI relative to North is angleBeteweenPoints - currentHeading
(For some reason I can't properly format the code on this computer, so if anyone wants to edit this answer, feel free).