Found a plenty of answers to question how to calculate distance by lat/lon and nothing for a "reverse" problem.
I have a displacment in X and Y and a GPS point (lat/lon), yet need to calc coordinates for a new point.
Using formula:
double deltaLat = dy / EARTH_RADIUS;
double deltaLon = dx / EARTH_RADIUS;
double lat = locLat + Math.signum(dy) * Math.toDegrees(deltaLat); // formula correct
double lon = locLon + Math.signum(dx) * Math.toDegrees(deltaLon);
It's accurate for calculating latitude, but for longitude I get about 10–15% error.
Does anyone have the same issue? Any possible formulas to calculate longitude by displacement?
The reason you're getting 10-15% error in longitude is because for longitude you cannot use the earth's radius to compute your displacement. Instead, you need to use the radius of the "circle" at the corresponding latitude. Therefore using your formula your longitude calculations should be more like
double deltaLon = dx / (EARTH_RADIUS * cos(locLat))
However this may give you undesired results around the poles, as cos(locLat) will get close to 0, so you may want to have some special cases for the poles (or even around them). Logically, if you think about, if you're at the pole, moving any distance along the x axis will not get your anywhere anyway.
Simplest but not the best solution is:
double deltaLat = dy / EARTH_RADIUS; // up-down
double deltaLon = dx / EARTH_RADIUS ; // left-right
double lat = locLat + Math.signum(dy) * Math.toDegrees(deltaLat); // formula correct
double lon = locLon + Math.signum(dx) * Math.toDegrees(deltaLon * 1.195);
Related
I have a Geopoint that is the current position of the user. I know its latitude and longitude. I would like to get a square perimeter 50km around the user position so I need to know what are the min & max latitude and the min&max longitude around that given poin, in java.
May someone helps me out with that ?
Thanks in advance ?
Just found out the solution. If you have a given point P(lat, long).
If you need to get 50 km around square perimeter for example, you need to take in consideration earth radius. Below how to do it:
double R = 6371; // earth radius in km
double radius = 50; // km
double latMin = lon - Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));
double latMax = lon + Math.toDegrees(radius/R/Math.cos(Math.toRadians(lat)));
double longMax = lat + Math.toDegrees(radius/R);
double longMin = lat - Math.toDegrees(radius/R);
The real answer is here: credit to the real answerer
I have a little project I've been playing with (Android, GPS, mapping APIs), and I need to figure how to find a longitude/latitude/GeoPoint from a given longitude/latitude/GeoPoint with only knowing the meters/km longitude and latitude. e.g. I want to figure out where a point is from me, that I know is +1000 meters along the longitude and +1000 along the latitude.
It's a little different than the usual GeoPoint/distance questions you'll see, and it's not quite geo fencing radius related as the distance is X,Y meters/kms, and I don't have a bearing. (I could work out a bearing, but I don't have a suitable direct distance)
Basically, if I could reverse GeoPoint.distanceTo() it would do the job for me.
Update
Just a little more background. I'm basically applying a node triangulation idea I had, but the algorithm requires that my inputs be in a map normalized form that's not the same as longitude and latitude. I create a map/grid where 0,0 (the bottom/left) is the left/west and bottom/south most longitude/latitude values from the nodes I'm working with. All the other node X/Y on the map are determined by finding their meters from the 0,0 node's longitude/latitude using GeoPoint.distanceTo(). (note that I find their X/Y by performing distanceTo twice for each node so I have the X and Y meters from 0,0, not a direct line to the node) That distance in meters is fed into the algorithm and new X/Y map points are produced.
And so I need to figure out how to convert distance from a longitude/latitude into another, previously unknown, longitude/latitude.
double startPointLongitude = 23.459821;
double startPointLatitude = 76.998200;
double distanceLongitude = 100; // 100 meters along the longitude
double distanceLatitude = 75; // 75 meters along the latitude
Basically i took the Answer from AlexWien, corrected two things and made it into a java method
private static final double WGS84_RADIUS = 6370997.0;
private static double EarthCircumFence = 2* WGS84_RADIUS * Math.PI;
private static Position getPosition(Position sourcePosition, double mEastWest, double mNorthSouth){
double degreesPerMeterForLat = EarthCircumFence/360.0;
double shrinkFactor = Math.cos((sourcePosition.getLat()*Math.PI/180));
double degreesPerMeterForLon = degreesPerMeterForLat * shrinkFactor;
double newLat = sourcePosition.getLat() + mNorthSouth * (1/degreesPerMeterForLat);
double newLng = sourcePosition.getLng() + mEastWest * (1/degreesPerMeterForLon);
return new Position(newLat, newLng);
}
The distance between two degrees of latitude never change, it is always aprox. 111 km
(The exact value you should caculate by using the WGS84 Earth radius:
EarthCircumFence = 2* WGS84_RADIUS * Math.Pi;
metersPerDegree = (Earth Cirumfence / 360)
With this info you easily can calculate the latitude offset,
just reverse the factor and have:
degreesPerMeterForLat = EarthCircumfenceMeter / 360.0
with longitude its a bit different, the distance between two degrees of longitude shrink
the more you move away from aequator.
shrinkFactor = cos(toRadians(locationLatitude));
compensate now:
degreesPerMeterForLon = degreesPerMeterForLat / shrinkFactor;
Finally
newLatPos = latOld + numMeters * degreesPerMeterForLat;
newLonPos = lonOld + numMeters * degreesPerMeterForLon;
This works for distance offset < 10 - 50 km
Sigh, I posted this like 6 hours ago but it does not appear to have gone through.
Ok, worked it out in spite of most geographical formulas and facts occasionally going over my head. Working with geography is like working with the Gregorian calendar, it makes sense if you program for it all the time, but otherwise it's easy to get confused by an incorrect assumption.
The following except from my app will take a starting GeoPoint's long/lat
/**
* the length of one degree of latitude (and one degree of longitude at equator) in meters.
*/
private static final double DEGREE_DISTANCE_AT_EQUATOR = 111329;
/**
* calculates the x,y in meters from a given starting point's long0, lat0 to a target destination point's long1, lat1.
* #param long0 start point longitude
* #param lat0 start point latitude
* #param long1 end point longitude
* #param lat1 end point latitude
* #return
*/
public static Pair<Double, Double> xyFromLongLat(int long0, int lat0, int long1, int lat1) {
double x = (long1 / 1E6 - long0 / 1E6) * longitudeDistanceAtLatitude(lat0 / 1E6);
double y = (lat1 / 1E6 - lat0 / 1E6) * DEGREE_DISTANCE_AT_EQUATOR;
return new Pair<Double, Double>(x, y);
}
/**
* calculates longitude and latitude from a given starting point, with only the X/Y meters
* #param long0
* #param lat0
* #param x
* #param y
* #return
*/
public static Pair<Double, Double> longLatFromXY(int long0, int lat0, double x, double y) {
double lat1 = (y / DEGREE_DISTANCE_AT_EQUATOR) + (lat0 / 1E6);
double long1 = x / longitudeDistanceAtLatitude(lat0) + (long0 / 1E6);
return new Pair<Double, Double>(lat1, long1);
}
I am getting two GEO locations in my application and I have to calculate distance between them and after distance calculation I have to compare that result with the a defined threshold which is in my case 50 meters, how would I define that threshold in float. Also, Currently I my android fone is at the same location, but I always get the calculated distance between my 2 two geolocations determined after an interval to be more than 50 meters. How is it possible? I am taking threshold of 50 meters as:
private static final float DISTANCE_CHANGE_METERS = 50.0f; //50 meters
and I am calculating distance through following formula I found on StackOverflow:
public static float distFrom(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double dist = earthRadius * c;
int meterConversion = 1609;
return new Float(dist * meterConversion).floatValue();
}
Kindly help me out in this regard. Thanks!
Currently my android phone is at the same location, but I always get the calculated distance between my 2 two geolocations determined after an interval to be more than 50 meters. How is that possible?
It actually depends on how you are passing the latitude and longitude to the distFrom function. Just to remind you that there is a simpler way to calculate the distance.
You can use just distanceTo() function in android API using Location to calculate the distance between two places like this:
Location locationA = new Location("point A");
locationA.setLatitude(latA); // co-ordinates in double
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
locationB.setLongitude(lngB);
float distance = locationA.distanceTo(locationB);
If after using this also you are getting a distance greater than 50 meters then your co-ordinates that you are providing are not that accurate. Its perfectly fine because its tough to get accuracy with less that 50 meter precision. It would be most accurate if you are using internet along with GPS. If you see here, even if you use ACCURACY_HIGH as a criteria to choose a Location Provider, it provides accuracy of less than 100 meters. It can be accurate upto 100, 70 or even 50 meters. So even the most accurate option is not guaranteed to give extreme accuracy. If you are using GPS/Network provider for getting Location, then it your situation is very much possible. Getting location using `Network Provider1 is also not that accurate as it can catch signals of 2 network towers on different occasions, which can be well apart physically.
Hope it helps and clears the point to some extent. Its the problem to accuracy of your Location Provider.
Could you just do:
if (distFrom(lat1,lng1,lat2,lng2) > DISTANCE_CHANGE_METERS)
{
//greater than threshhold
}
Basically the title says it all. Rather than plotting every single entry in my database on a map as I do at the moment, I want to query the database and only plot the entries whose co-ordinates fall within the circle drawn around the users current location, however I can't quite figure out how to do it. At the moment, I have written code that plots the users current location on the map along with the locations of all the entries stored on my database and also the circle around the current location (See picture below). Based on my picture below, I only want the three markers within the circle to be plotted.
Does anyone know if there are any ways of checking if the latlng co-ordinates stored in my database fall within the area of the circle? Or if not, could anyone suggest any alternatives that use a similar idea.
An alternative I was thinking of was using a square / rectangle rather than a circle so that I could simply compare the co-ordinates of my entries with bounds of the square / rectangle, however I don't really know how feasible that is seen as those shapes aren't supported by the Google Maps API. I also came across the LatLngBounds class which could be useful but I can't find any sample code using it. How I might do this either?
I believe the circle has a fixed Radius and a center point.
So, go with this method to get the distance between the center and some LatLng and set a condition
distance <= radius
public static String getDistance(LatLng ll_source, LatLng ll_destination,
int unit) {
int Radius = 6371;// radius of earth in Km
double lat1 = ll_source.latitude;
double lat2 = ll_destination.latitude;
double lon1 = ll_source.longitude;
double lon2 = ll_destination.longitude;
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
* Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
double valueResult = Radius * c;
double km = valueResult / 1;
DecimalFormat newFormat = new DecimalFormat("####");
Integer kmInDec = Integer.valueOf(newFormat.format(km));
double meter = valueResult % 1000;
Integer meterInDec = Integer.valueOf(newFormat.format(meter));
DecimalFormat df = new DecimalFormat("#.#");
return df.format(valueResult);
}
Ok, I've figured out a solution using the LatLngBounds class I referred to in my question. What it does is:
Creates a new rectangular perimeter around the user's current latitude and longitude co-ordinates (this example is roughly one square kilometer).
It then checks if the perimeter contains the co-ordinates stored in the database.
If it does, the marker is plotted on the map.
public void getNearbyMarkers(){
LatLngBounds perimeter = new LatLngBounds(new LatLng(currentLat - 0.004,
currentLon - 0.004), new LatLng(currentLat + 0.004, currentLon + 0.004));
if (perimeter.contains(LatlongFromDatabase)) {
//Plot Marker on Map
} else {
Toast.makeText(getApplicationContext(), "Co-ordinates not in perimeter!", 8).show();
}
}
I got the below code from #DanS at this link how-to-display-a-map-still-image-file-with-a-moving-current-location
onCurrentPosition(Location current){
double hypotenuse = upperLeft.distanceTo(current);
double bearing = upperLeft.bearingTo(current);
double currentDistanceX = Math.cos(bearing) * hypotenuse;
// "percentage to mark the position"
double currentPixelX = (currentDistanceX / upperLeft.distanceTo(lowerRight) * Math.cos(upperLeft.bearingTo(lowerRight))) * mapWidth;
moveIndicatorX(currentPixelX);
}
Here are the values:
current: 41.850033,-87.65005229999997
upperLeft: 41.866514127810355,-87.6720142364502
lowerRight: 41.83397145565242,-87.62824058532715
mapWidth: 512 x 512 px
Here are the calculator online for Location, hypotenuse(Distance), bearing(Azimuths)
convert LatLng to Location format(e.g. 41° 51′ 59.45″ N 87° 40′ 19.25″ W)
compute distance & azimuths from the given Location
I got the results of:
hypotenuse = 2581
bearing = 135.21
currentDistanceX = -2562
currentPixelX = 311.9
Would like to ask you guys to:
to confirm if my computed results are correct.
on how to compute the currentPixelY (the another one point)?
By the way, I am planning to use that to compute the location of a given real life LatLng(current) against with my still image map which bonded the upperLeft and lowerRight corners of the still image into real life LatLng.
If you want to see the actual & expected output and want to easily understand the whole picture. Please refer to this link -> How to mark the current location into a still image map
This is the actual code I'm using, not pseudo code posted previously:
Location upperLeft = new Location("");
upperLeft.setLatitude(41.866514127810355);
upperLeft.setLongitude(-87.6720142364502);
Location lowerRight = new Location("");
lowerRight.setLatitude(41.83397145565242);
lowerRight.setLongitude(-87.62824058532715);
Location current = new Location("");
current.setLatitude(41.850033);
current.setLongitude(-87.65005229999997);
double hypotenuse = upperLeft.distanceTo(current);
double bearing = upperLeft.bearingTo(current);
double currentDistanceX = Math.cos(bearing * Math.PI / 180.0) * hypotenuse;
// "percentage to mark the position"
double totalHypotenuse = upperLeft.distanceTo(lowerRight);
double totalDistanceX = totalHypotenuse * Math.cos(upperLeft.bearingTo(lowerRight) * Math.PI / 180.0);
double currentPixelX = currentDistanceX / totalDistanceX * 512;
System.out.println(currentPixelX); // 259.3345493341548
Your calculated answer looks a bit off.
To calculate Y change copy all the X marked calculations and variables to use Math.sin() instead of Math.cos().