Android Maps v2 API...How to calculate distance between two locations (Lat, long)
Asked Answered
W

5

6

In my "native" Android app I'm trying to calculate the distance in feet and/or meters (as the crow flies) between two locations on a map. Ideally there would be a method that would take two LatLng values (as that is what I have readily available) as input and return the distance in meters and/or yards. As noted above I'm using Android Maps v2 API.

I've looked at MANY postings (20-30) regarding calculating distances and haven't found any that have helped me resolve my issue. Again this is a native Android application and I'm using Maps v2 API.

Not sure if this is the best approach but I'm currently trying to use the Location method:

distanceBetween(double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results)

But unfortunately the app crashes every time because I get a null value for results. I have verified via the debugger that the latitude and longitude dummy values that I'm passing in are valid and that the value of results is null (hence the problem). Here is the LogCat:

04-04 23:48:04.770: D/onMapClick(17970): lat/lng: (32.90843038503306,-117.22537234425546)
04-04 23:48:08.710: D/dalvikvm(17970): threadid=1: still suspended after undo (sc=1 dc=1 s=Y)
04-04 23:48:08.710: D/dalvikvm(17970): GC_FOR_MALLOC freed 7010 objects / 641712 bytes in 121ms
04-04 23:48:24.980: D/AndroidRuntime(17970): Shutting down VM
04-04 23:48:24.980: W/dalvikvm(17970): threadid=1: thread exiting with uncaught exception (group=0x40020950)
04-04 23:48:25.100: E/AndroidRuntime(17970): FATAL EXCEPTION: main
04-04 23:48:25.100: E/AndroidRuntime(17970): java.lang.IllegalArgumentException: results is null or has length < 1
04-04 23:48:25.100: E/AndroidRuntime(17970):    at android.location.Location.distanceBetween(Location.java:394)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.example.googleplacesandmaps.PlacesMapActivity$1.onMapClick(PlacesMapActivity.java:259)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.google.android.gms.maps.GoogleMap$6.onMapClick(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.google.android.gms.internal.t$a.onTransact(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at android.os.Binder.transact(Binder.java:249)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.google.android.gms.maps.internal.IOnMapClickListener$Stub$Proxy.onMapClick(IOnMapClickListener.java:93)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at maps.i.s.b(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at maps.y.v.c(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at maps.y.bf.onSingleTapConfirmed(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at maps.d.v.onSingleTapConfirmed(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at maps.d.j.handleMessage(Unknown Source)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at android.os.Handler.dispatchMessage(Handler.java:99)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at android.os.Looper.loop(Looper.java:123)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at android.app.ActivityThread.main(ActivityThread.java:4627)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at java.lang.reflect.Method.invokeNative(Native Method)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at java.lang.reflect.Method.invoke(Method.java:521)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:893)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:651)
04-04 23:48:25.100: E/AndroidRuntime(17970):    at dalvik.system.NativeStart.main(Native Method)

Here is the method I'm currently using to try and calculate the distance:

            Location.distanceBetween(Double.parseDouble(user_latitude), Double.parseDouble(user_longitude),
                fxdLatitude, fxdLongitude, results);

The results was defined as a Class variable: private float[] results = null;

Not sure what i'm doing wrong here.

Again I'd rather have a method that would take two LatLng's as input parameters because they are both readily available...but perhaps more importantly I only have one of the locations available as separate Longitude, Latitude values...the second location is only available as a LatLng value because I get it via onMapClick (when user taps screen). So to use the method distanceBetween I'd need someway to convert this LatLng value into a Latitude/Longitude pair to be able to use it. Anybody know how to do that?

Hopefully there is a simple way of calculating the distances and a simple way to "extract" the latitude/longitude from a LatLng value.

Waltman answered 5/4, 2013 at 7:35 Comment(0)
D
14

What about making Location object from the two ?

private float distanceBetween(LatLng latLng1, LatLng latLng2) {

        Location loc1 = new Location(LocationManager.GPS_PROVIDER);
        Location loc2 = new Location(LocationManager.GPS_PROVIDER);

        loc1.setLatitude(latLng1.latitude);
        loc1.setLongitude(latLng1.longitude);

        loc2.setLatitude(latLng2.latitude);
        loc2.setLongitude(latLng2.longitude);


        return loc1.distanceTo(loc2);
    }
Denver answered 14/11, 2014 at 8:19 Comment(3)
Don't you need to convert the latitude and longitude since they are in micro degrees?Benbow
if they are not in float format (like 27.132235 ), they have to be converted.Denver
You may consider voting the answer up if you think it's useful :).Denver
I
3

You can use following function that accepts two LatLng for calculating distance between them. But before you use this make sure your LatLng variables are not null.

public static double distance(LatLng StartP, LatLng EndP) {
    double lat1 = StartP.latitude;
    double lat2 = EndP.latitude;
    double lon1 = StartP.longitude;
    double lon2 = EndP.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));
    return 6366000 * c;
}
Ivey answered 15/4, 2013 at 1:16 Comment(1)
@KetanMehta If you mean radius of the visible area, you can get the viewport via LatLngBounds bbox = GoogleMap.getProjection().getVisibleRegion().latLngBounds. Afterwards just use Sharj distance calc method to get the distance between bbox.southwest and bbox.northeast (what would be the diameter of the viewport).Ellington
M
1

private float[] results = null; is wrong.

You need to use private float[] results = new float[1]; and read the distance with results[0].

Manos answered 14/4, 2013 at 14:37 Comment(0)
G
1

In Kotlin, you can:

Define a method to convert LatLng to Location:

fun LatLng.toLocation() = Location(LocationManager.GPS_PROVIDER).also {
    it.latitude = latitude
    it.longitude = longitude
}

Call it on each LatLng and use Location#distanceTo(...) method:

val distance = coords1.toLocation().distanceTo(coords2.toLocation())

Define an extension method for LatLngBounds:

fun LatLngBounds.computeDistance(): Float {
    return northeast.toLocation().distanceTo(southwest.toLocation())
}
Guideboard answered 30/6, 2017 at 8:1 Comment(0)
J
0

Yes, I think MaciejGórski is right.

The computed distance is stored in results[0]. 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].

Jacquez answered 11/12, 2013 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.