Nan in calculating Distance using Latitude and Longitude - android

I am calculating the Distance between two Latitudes and Longitudes. I get the results for some distances but sometimes,I get the results as NAN.
This is the Latitude and Longitude which I have got for 2 places.
For eg:
38.655553,-121.091611
38.654875,-121.091324
I am using the below code to calculate the distance with reference to the below link
Calculating distance between two geographic locations
public static double distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2)
{
float pk = (float) (180/3.14169);
double a1 = currentLat2 / pk;
double a2 = currentLong2 / pk;
double b1 = mallLat2 / pk;
double b2 = mallLong2 / pk;
double t1 = FloatMath.cos((float) a1)*FloatMath.cos((float) a2)*FloatMath.cos((float) b1)*FloatMath.cos((float) b2);
double t2 = FloatMath.cos((float) a1)*FloatMath.sin((float) a2)*FloatMath.cos((float) b1)*FloatMath.sin((float) b2);
double t3 = FloatMath.sin((float) a1)*FloatMath.sin((float) b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000*tt;
}
Any Help?
Thanks.

MathFloat together with float casts is the cause of your problem.
I rewrote, now it works, it gives 79.34m
But the main problem is that you use the wrong formula for this task, you use here the greater circle distance formula with law of cosines, which is well know to be "ill conditioned" for floating point arithmetic. Then to make it even worse, you use that with single precision only, instead of double.
The more robust formula is the haversine formula.
It was designed to overcome the disadvantage of the greater circle formula.
Here your original code fixed, (but i still recommend use the haversine formula instead)
public void test1() {
// 79.34253285803419
double lat1 = 38.655553;
double lon1 = -121.091611;
double lat2 = 38.654875;
double lon2 = -121.091324;
System.out.println(distanceBetween(lat1, lon1, lat2, lon2));
}
public static double distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2)
{
double pk = 180 / Math.PI;
double a1 = currentLat2 / pk;
double a2 = currentLong2 / pk;
double b1 = mallLat2 / pk;
double b2 = mallLong2 / pk;
double t1 = Math.cos( a1) * Math.cos(a2) * Math.cos(b1) * Math.cos(b2);
double t2 = Math.cos( a1) * Math.sin(a2) * Math.cos(b1) * Math.sin(b2);
double t3 = Math.sin( a1) * Math.sin(b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000*tt;
}

the doc for Location.distanceTo(LOcation) says:
Returns the approximate distance in meters between this location and
the given location. Distance is defined using the WGS84 ellipsoid.
So you can try this way:
public static float distanceBetween (double currentLat2, double currentLong2, double mallLat2, double mallLong2) {
Location loc1 = new Location("");
loc1.setLatitude(currentLat2);
loc1.setLongitude(currentLong2);
Location loc2 = new Location("");
loc2.setLatitude(mallLat2);
loc2.setLongitude(mallLong2);
return loc1.distanceTo(loc2);
}

Can you log the outputs for t1, t2, t3? I have a feeling that the argument for Math.acos() is out of range. Also not sure why you're needlessly casting to float and back to double when you can just use Math.sin and Math.cos.
Edit
Use Math.PI instead of 3.14169. This approximation is causing your error.

Related

Using Google maps api how to cmpare GPS coordinates(latti , longi) of two locations

In an Android application I am struck in a problem any one have information about GPS coordinates from map , please help.
The problem is if I have coordinates(latitude and longitude) of two different points on Map and
I want to check that the points are on the same location on map
Secondly are the two points are nearer to each other according to any criteria
For example .. if the point is in the 100m radius of the other point it seems to be nearer.
You can use haversine formula to calculate two points,
public static void main(String[] args) {
// TODO Auto-generated method stub
final int R = 6371; // Radious of the earth
Double lat1 = Double.parseDouble(args[0]);
Double lon1 = Double.parseDouble(args[1]);
Double lat2 = Double.parseDouble(args[2]);
Double lon2 = Double.parseDouble(args[3]);
Double latDistance = toRad(lat2-lat1);
Double lonDistance = toRad(lon2-lon1);
Double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
Double distance = R * c;
System.out.println("The distance between two lat and long is::" + distance);
}
You can compare this distance.This will do your job.

android - how can I get the bearing degree between two locations?

As title said, I have current location, and want to know the bearing in degree from my current location to other location. I have read this post, is the value return by location.getBearing() my answer?
Let say it simply: from the picture, I expect the value of 45 degree.
I was having trouble doing this and managed to figure it out converting the C? approach to working out the bearing degree.
I worked this out using 4 coordinate points
Start Latitude
Start Longitude
End Latitude
End Longitude
Here's the code:
protected double bearing(double startLat, double startLng, double endLat, double endLng){
double latitude1 = Math.toRadians(startLat);
double latitude2 = Math.toRadians(endLat);
double longDiff= Math.toRadians(endLng - startLng);
double y= Math.sin(longDiff)*Math.cos(latitude2);
double x=Math.cos(latitude1)*Math.sin(latitude2)-Math.sin(latitude1)*Math.cos(latitude2)*Math.cos(longDiff);
return (Math.toDegrees(Math.atan2(y, x))+360)%360;
}
Just change the variable names were needed.
Output bearing to a TextView
Hope it helped!
Location have method bearingTo:
float bearingTo(Location dest)
Location from = new Location(LocationManager.GPS_PROVIDER);
Location to = new Location(LocationManager.GPS_PROVIDER);
from.setLatitude(0);
from.setLongitude(0);
to.setLongitude(10);
to.setLatitude(10);
float bearingTo = from.bearingTo(to);
Here is the code for calculating bearing angle between two points(startPoint, endPoint):
public float CalculateBearingAngle(double startLatitude,double startLongitude, double endLatitude, double endLongitude){
double Phi1 = Math.toRadians(startLatitude);
double Phi2 = Math.toRadians(endLatitude);
double DeltaLambda = Math.toRadians(endLongitude - startLongitude);
double Theta = atan2((sin(DeltaLambda)*cos(Phi2)) , (cos(Phi1)*sin(Phi2) - sin(Phi1)*cos(Phi2)*cos(DeltaLambda)));
return (float)Math.toDegrees(Theta);
}
Call for function:
float angle = CalculateBearingAngle(startLatitude, startLongitude, endLatitude, endLongitude);
I found best method for calculating "Bearing between two point " from this answer and convert it to java from python. And this method work like charm for me!
here is the code:
public static double getBearing(double startLat, double startLng, double endLat, double endLng) {
double latitude1 = Math.toRadians(startLat);
double longitude1 = Math.toRadians(-startLng);
double latitude2 = Math.toRadians(endLat);
double longitude2 = Math.toRadians(-endLng);
double dLong = longitude2 - longitude1;
double dPhi = Math.log(Math.tan(latitude2 / 2.0 + Math.PI / 4.0) / Math.tan(latitude1 / 2.0 + Math.PI / 4.0));
if (abs(dLong) > Math.PI)
if (dLong > 0.0)
dLong = -(2.0 * Math.PI - dLong);
else
dLong = (2.0 * Math.PI + dLong);
return (Math.toDegrees(Math.atan2(dLong, dPhi)) + 360.0) % 360.0;
}

Find geopoints in a radius near me

I have a DB with Geopoints.
I need to do a query to get all geopoints in the radius of X meters of me.
How can i do this?
I think the best way is get the minimal lat/long possible point, and the max lat/long point and get all of them for which: geopoint > minPoint AND geopoint < MaxPoint
Other ideas?
You can use this class to get de distance between to points:
How to use:
double distInKm = GeoMath.getDistance(12.345, -8.788, 12.33, -8.77);
Or, if point1 and point2 are GeoPoint:
double distInKm = GeoMath.getDistance(point1, point2);
You can also calculate a Geopoint that is a distance of you and along a bearing.
This computes a point that is 5 km northward from point1:
GeoPoint northPointAt5 = GeoMath.getGeoPointAlongBearing(point1, 0, 5);
You can calculate the other points at 90 degrees, 180 degrees and 270 degrees to calculate minPoint AND MaxPoint.
GeoMath class:
public class GeoMath {
public static final int EARTH_MEAN_RADIUS = 6371; // earth's mean radius in Km
public static double getDistance(double startLatitude, double startLongitude,
double endLatitude, double endLongitude){
return distHaversine(startLatitude,startLongitude,endLatitude,endLongitude);
}
public static double getDistance(GeoPoint point1, GeoPoint point2){
return distHaversine(point1.getLatitudeE6()/1E6, point1.getLongitudeE6()/1E6,
point2.getLatitudeE6()/1E6, point2.getLongitudeE6()/1E6);
}
private static double getSpanInRadians(double max, double min){
return Math.toRadians(max - min);
}
//Distance in Km between point1 (lat1,lon1) and point2 (lat2,lon2) Haversine formula
private static double distHaversine(double lat1, double lon1, double lat2, double lon2) {
double dLat = getSpanInRadians(lat2,lat1);
double dLon = getSpanInRadians(lon2,lon1);
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = EARTH_MEAN_RADIUS * c;
return Math.round(dist * 1000)/1000; //3 decimal places
}
// Get GeoPoint at distance along a bearing
// bearing in degrees
// distance in Km
public static GeoPoint getGeoPointAlongBearing(GeoPoint location, double bearing, double distance){
double PI = Math.PI;
double NM = 1.852; //1 nm = 1.852 Km -> nm = Km/NM
GeoPoint geoPointAlongBearing;
double locationLatRad = Math.toRadians(location.getLatitudeE6()/1E6);
double locationLongRad = Math.toRadians(location.getLongitudeE6()/1E6)*(-1.0d);
double distanceRad = distance/NM * PI/(180*60);
double bearingRad = Math.toRadians(bearing);
double latAlongBearingRad = Math.asin(Math.sin(locationLatRad) *
Math.cos(distanceRad) +
Math.cos(locationLatRad) *
Math.sin(distanceRad) *
Math.cos(bearingRad));
double lonAlongBearingRad = mod(locationLongRad -
Math.asin(Math.sin(bearingRad) *
Math.sin(distanceRad) /
Math.cos(latAlongBearingRad)) + PI, 2 * PI) - PI;
double latAlongBearing = rad2lat(latAlongBearingRad);
double lonAlongBearing = rad2lng(lonAlongBearingRad) * (-1);
geoPointAlongBearing = new GeoPoint((int)(latAlongBearing*1E6),(int)(lonAlongBearing*1E6));
return geoPointAlongBearing;
}
private static double mod(double y, double x) {
return y - x * Math.floor(y/x);
}
}
With your query I think that you will find all points inside a square centered at your location and with a side length X.
After that, yuo can get all the points that are inside a circle centered at your location with radius X.
What about this pseudo code:
//create your location
Location yourLocation=new Location("myLoc");
double latitude = geoPointYourLocation.getLatitudeE6() / 1E6;
double longitude = geoPointYourLocation.getLongitudeE6() / 1E6;
yourLocation.setLatitude(latitude);
yourLocation.setLongitude(longitude);
//Browse geopoints from DB, convert to GeoPoint and check if it is at a distance less than X
for (geoPointTemp in in query geopoint of your DDBB inside square) {
//create the location of the geopoint
Location locTemp=new Location("locTemp");
double latitude = geoPointTemp.getLatitudeE6() / 1E6;
double longitude = geoPointTemp.getLongitudeE6() / 1E6;
locTemp.setLatitude(latitude);
locTemp.setLongitude(longitude);
//calculate the distance between you and de temporary location
double distance=yourLocation.distanceTo(locTemp);
if(distance<X){
//do something
}
With Mysql, you can use built-in spacial functions such as GLength, linestring ....

Calculating distance between two geographic locations

please shed some light on this situation
Right now i have two array having latitude and longitude of nearby places and also have the user location latiude and longiude now i want to calculate the distance between user location and nearby places and want to show them in listview.
I know that there is a method for calculating distance as
public static void distanceBetween (double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results);
Now what is the problem is how to pass these two array having nearby latitude and longitue in this method and get the array of distances.
http://developer.android.com/reference/android/location/Location.html
Look into distanceTo
Returns the approximate distance in meters between this location and
the given location. Distance is defined using the WGS84 ellipsoid.
or distanceBetween
Computes the approximate distance in meters between two locations, and
optionally the initial and final bearings of the shortest path between
them. Distance and bearing are defined using the WGS84 ellipsoid.
You can create a Location object from a latitude and longitude:
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
locationB.setLongitude(lngB);
float distance = locationA.distanceTo(locationB);
or
private double meterDistanceBetweenPoints(float lat_a, float lng_a, float lat_b, float lng_b) {
float pk = (float) (180.f/Math.PI);
float a1 = lat_a / pk;
float a2 = lng_a / pk;
float b1 = lat_b / pk;
float b2 = lng_b / pk;
double t1 = Math.cos(a1) * Math.cos(a2) * Math.cos(b1) * Math.cos(b2);
double t2 = Math.cos(a1) * Math.sin(a2) * Math.cos(b1) * Math.sin(b2);
double t3 = Math.sin(a1) * Math.sin(b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000 * tt;
}
Try This Code. here we have two longitude and latitude values and selected_location.distanceTo(near_locations) function returns the distance between those places in meters.
Location selected_location = new Location("locationA");
selected_location.setLatitude(17.372102);
selected_location.setLongitude(78.484196);
Location near_locations = new Location("locationB");
near_locations.setLatitude(17.375775);
near_locations.setLongitude(78.469218);
double distance = selected_location.distanceTo(near_locations);
here "distance" is distance between locationA & locationB (in Meters)
There is only one user Location, so you can iterate List of nearby places can call the distanceTo() function to get the distance, you can store in an array if you like.
From what I understand, distanceBetween() is for far away places, it's output is a WGS84 ellipsoid.
private static Double _MilesToKilometers = 1.609344;
private static Double _MilesToNautical = 0.8684;
/// <summary>
/// Calculates the distance between two points of latitude and longitude.
/// Great Link - http://www.movable-type.co.uk/scripts/latlong.html
/// </summary>
/// <param name="coordinate1">First coordinate.</param>
/// <param name="coordinate2">Second coordinate.</param>
/// <param name="unitsOfLength">Sets the return value unit of length.</param>
public static Double Distance(Coordinate coordinate1, Coordinate coordinate2, UnitsOfLength unitsOfLength)
{
double theta = coordinate1.getLongitude() - coordinate2.getLongitude();
double distance = Math.sin(ToRadian(coordinate1.getLatitude())) * Math.sin(ToRadian(coordinate2.getLatitude())) +
Math.cos(ToRadian(coordinate1.getLatitude())) * Math.cos(ToRadian(coordinate2.getLatitude())) *
Math.cos(ToRadian(theta));
distance = Math.acos(distance);
distance = ToDegree(distance);
distance = distance * 60 * 1.1515;
if (unitsOfLength == UnitsOfLength.Kilometer)
distance = distance * _MilesToKilometers;
else if (unitsOfLength == UnitsOfLength.NauticalMiles)
distance = distance * _MilesToNautical;
return (distance);
}
distanceTo will give you the distance in meters between the two given location ej target.distanceTo(destination).
distanceBetween give you the distance also but it will store the distance in a array of float( results[0]). the doc says If results has length 2 or greater, the initial bearing is stored in results[1]. If results has length 3 or greater, the final bearing is stored in results[2]
hope that this helps
i've used distanceTo to get the distance from point A to B i think that is the way to go.
public double distance(Double latitude, Double longitude, double e, double f) {
double d2r = Math.PI / 180;
double dlong = (longitude - f) * d2r;
double dlat = (latitude - e) * d2r;
double a = Math.pow(Math.sin(dlat / 2.0), 2) + Math.cos(e * d2r)
* Math.cos(latitude * d2r) * Math.pow(Math.sin(dlong / 2.0), 2)
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = 6367 * c;
return d;
}
I wanted to implement myself this, i ended up reading the Wikipedia page on Great-circle distance formula, because no code was readable enough for me to use as basis.
C# example
/// <summary>
/// Calculates the distance between two locations using the Great Circle Distance algorithm
/// <see cref="https://en.wikipedia.org/wiki/Great-circle_distance"/>
/// </summary>
/// <param name="first"></param>
/// <param name="second"></param>
/// <returns></returns>
private static double DistanceBetween(GeoLocation first, GeoLocation second)
{
double longitudeDifferenceInRadians = Math.Abs(ToRadians(first.Longitude) - ToRadians(second.Longitude));
double centralAngleBetweenLocationsInRadians = Math.Acos(
Math.Sin(ToRadians(first.Latitude)) * Math.Sin(ToRadians(second.Latitude)) +
Math.Cos(ToRadians(first.Latitude)) * Math.Cos(ToRadians(second.Latitude)) *
Math.Cos(longitudeDifferenceInRadians));
const double earthRadiusInMeters = 6357 * 1000;
return earthRadiusInMeters * centralAngleBetweenLocationsInRadians;
}
private static double ToRadians(double degrees)
{
return degrees * Math.PI / 180;
}

Sort list of lon\lat points, start with nearest

I have location from GPS (lon_base, lat_base).
I have a list of locations (lon1, lat1|lon2, lat2|lon3, lat3...)
This list is very long and is around the world.
My questions are:
1. How do I get from that list only the lon\lat that are 1 mile from my lon_base\lat_base?
2. How do I sort them from closest to farthest?
Thanks in advance!
public static List<Location> sortLocations(List<Location> locations, final double myLatitude,final double myLongitude) {
Comparator comp = new Comparator<Location>() {
#Override
public int compare(Location o, Location o2) {
float[] result1 = new float[3];
android.location.Location.distanceBetween(myLatitude, myLongitude, o.Lat, o.Long, result1);
Float distance1 = result1[0];
float[] result2 = new float[3];
android.location.Location.distanceBetween(myLatitude, myLongitude, o2.Lat, o2.Long, result2);
Float distance2 = result2[0];
return distance1.compareTo(distance2);
}
};
Collections.sort(locations, comp);
return locations;
}
Where the List of Locations is a list containing your own Location class, not the android.location.Location.
You may use the great circle distance to calculate the distance between two points whose you know the latitude-longitude coordinates. The formulae are quite easy to code:
static double distance(double fromLat, double fromLon, double toLat, double toLon) {
double radius = 6378137; // approximate Earth radius, *in meters*
double deltaLat = toLat - fromLat;
double deltaLon = toLon - fromLon;
double angle = 2 * Math.asin( Math.sqrt(
Math.pow(Math.sin(deltaLat/2), 2) +
Math.cos(fromLat) * Math.cos(toLat) *
Math.pow(Math.sin(deltaLon/2), 2) ) );
return radius * angle;
}
You want to define your own Comparator that, in general, looks something like this:
LonLat myHouse = /* whatever */ ;
Comparable comp = new Comparable () {
LonLat a;
int compareTo (Object b) {
int aDist = calcDistance(a, myHouse) ;
int bDist = calcDistance(b, myHouse) ;
return aDist - bDist;
}
};
myLonLatList.sort(lonLatList, comp);
where calcDistance() simply calculates the distance between the two points. If you're on Android, I think Google Maps has a function somewhere in their API that will do this for you.
EDIT : You'll want your calcDistance() function to look like ChrisJ's distance function.
-tjw
You can use followig approximation (since 1 mile is much smaller than the radius of the earth) to calculate the distances from your base:
dx = cos(phi_base) * (theta - theta_base)
dy = phi - phi_base
dist = sqrt(dx*dx+dy*dy)
with: phi = latitude and theta = longitude
The result is in units of 60 nautical miles if theta and phi are given in degrees.
The results will be quite wrong for points that have a latitude that is much different from your base latitude, but this doesn't matter if you just want to know wich points are about 1 mile from your base.
For most programming languages you have to convert phi_base to radians (multiply by pi/180) in order to use it for cos().
(Attention: You have to take special care if your base longitude is very close to 180° or -180°, but probably that is not the case :-)
Use the calculated distances as sorting key to sort your points.
If you have to be more exact (e.g. if you want to know all points that are about 2000 miles from your home), than you must use the formula for Great Circle Distance to calculate the exact distance of two points on a sphere.
According to this link
i made working method. The answer above was wrong, because it doesn't convert lat/lng degrees to radians.
private double getDistance(double fromLat, double fromLon, double toLat, double toLon){
double radius = 6371; // Earth radius in km
double deltaLat = Math.toRadians(toLat - fromLat);
double deltaLon = Math.toRadians(toLon - fromLon);
double lat1 = Math.toRadians(fromLat);
double lat2 = Math.toRadians(toLat);
double aVal = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
Math.sin(deltaLon/2) * Math.sin(deltaLon/2) * Math.cos(lat1) * Math.cos(lat2);
double cVal = 2*Math.atan2(Math.sqrt(aVal), Math.sqrt(1-aVal));
double distance = radius*cVal;
Log.d("distance","radius * angle = " +distance);
return distance;
}

Categories

Resources