76

I am wanting to find the distance between two different points. This I know can be accomplished with the great circle distance. http://www.meridianworlddata.com/Distance-calculation.asp

Once done, with a point and distance I would like to find the point that distance north, and that distance east in order to create a box around the point.

Shog9
  • 156,901
  • 35
  • 231
  • 235
will
  • 1,175
  • 4
  • 17
  • 20

12 Answers12

155

Here is a Java implementation of Haversine formula. I use this in a project to calculate distance in miles between lat/longs.

public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
    double earthRadius = 3958.75; // miles (or 6371.0 kilometers)
    double dLat = Math.toRadians(lat2-lat1);
    double dLng = Math.toRadians(lng2-lng1);
    double sindLat = Math.sin(dLat / 2);
    double sindLng = Math.sin(dLng / 2);
    double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
            * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double dist = earthRadius * c;

    return dist;
    }
Ryan R
  • 8,342
  • 15
  • 84
  • 111
Sean
  • 7,562
  • 10
  • 27
  • 29
  • 23
    Just a note on this, it will return the distance in miles (because of the earthRadius setting). For other units change the earthRadius (see http://en.wikipedia.org/wiki/Earth_radius for more) – John Meagher Sep 24 '08 at 21:23
  • Is there a reason you're using floats instead of doubles? If I understand properly you can increase the accuracy of your results by simply changing your input parameter types – Hamy Mar 31 '11 at 19:05
  • There is also no need to calculate the sine of half the deltas twice. Calculate it once and multiply it with itself. It is definitely worth in in a tight loop. – Glenn Bech Jan 02 '12 at 20:47
  • 1
    The derivation for this can be found at http://mathforum.org/library/drmath/view/51879.html – Anand Sunderraman Apr 20 '12 at 09:24
  • This was rendered incorrect somewhere along the edits. I hope someone will fix it, because I don't see where it got messed up. The original code is correct. (tested on lat/lng 42,-82 and 42,-83) – you786 Aug 17 '12 at 05:23
  • Earth is not a perfect sphere – Steve Kuo Nov 02 '13 at 21:18
  • 7
    Use earthRadius as **6371** to get result in **kilometers**. – stevo.mit Nov 12 '13 at 15:46
  • Kotlin version of formula here https://stackoverflow.com/a/57346001/5788341 – Binakot Aug 04 '19 at 11:02
45

Or you could use SimpleLatLng. Apache 2.0 licensed and used in one production system that I know of: mine.

Short story:

I was searching for a simple geo library and couldn't find one to fit my needs. And who wants to write and test and debug these little geo tools over and over again in every application? There's got to be a better way!

So SimpleLatLng was born as a way to store latitude-longitude data, do distance calculations, and create shaped boundaries.

I know I'm two years too late to help the original poster, but my aim is to help the people like me who find this question in a search. I would love to have some people use it and contribute to the testing and vision of this little lightweight utility.

JavadocMD
  • 4,397
  • 2
  • 25
  • 23
  • this might help me! did you create it? Do you use the Haversine formula for distance calculations?? I'll try to jump in if I find the time! – Marsellus Wallace Mar 30 '12 at 19:13
  • Correct, it uses Haversine for distance calculations with an emphasis on (although admittedly not an obsession with) speed and a low memory profile. I think it has some other nice number-handling properties as well, like considering coordinates that are "really close" to be equal. – JavadocMD Apr 06 '12 at 00:31
21

We've had some success using OpenMap to plot a lot of positional data. There's a LatLonPoint class that has some basic functionality, including distance.

Rüdiger Schulz
  • 2,588
  • 3
  • 27
  • 43
Brendan Cashman
  • 4,878
  • 2
  • 23
  • 20
  • 5
    Warning to possible adopters: I just ran into a BIG problem with OpenMap; they use floats internally for decimal lat/lon, which limits the accuracy depending how close to the equator you are. They plan to support the option for doubles with their OMGraphic classes starting in version 4.7, but current stable is only 4.6.5 (as of March 2010). Source: http://openmap.bbn.com/mailArchives/openmap-users/2006-01/4522.html – Marc Mar 30 '10 at 18:13
  • Also note that the current OpenMap Software License Agreement http://openmap.bbn.com/license.html has been deemed non-free. http://web.archiveorange.com/archive/v/XyE55YoXwS3lME936I0U Some discussions with BBN has occurred to change licenses but nothing has happened yet. – Leif Gruenwoldt Apr 07 '11 at 13:51
  • 3
    This answer is now outdated since both links are offline. – xivo Feb 26 '18 at 04:46
  • I just fixed the links to the new domain at http://openmap-java.org. License is now here: http://openmap-java.org/License.html (no idea if it was changed since the comment from @LeifGruenwoldt – Rüdiger Schulz Dec 03 '18 at 10:44
11

For a more accurate distance (0.5mm) you can also use the Vincenty approximation:

/**
 * Calculates geodetic distance between two points specified by latitude/longitude using Vincenty inverse formula
 * for ellipsoids
 * 
 * @param lat1
 *            first point latitude in decimal degrees
 * @param lon1
 *            first point longitude in decimal degrees
 * @param lat2
 *            second point latitude in decimal degrees
 * @param lon2
 *            second point longitude in decimal degrees
 * @returns distance in meters between points with 5.10<sup>-4</sup> precision
 * @see <a href="http://www.movable-type.co.uk/scripts/latlong-vincenty.html">Originally posted here</a>
 */
public static double distVincenty(double lat1, double lon1, double lat2, double lon2) {
    double a = 6378137, b = 6356752.314245, f = 1 / 298.257223563; // WGS-84 ellipsoid params
    double L = Math.toRadians(lon2 - lon1);
    double U1 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat1)));
    double U2 = Math.atan((1 - f) * Math.tan(Math.toRadians(lat2)));
    double sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
    double sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);

    double sinLambda, cosLambda, sinSigma, cosSigma, sigma, sinAlpha, cosSqAlpha, cos2SigmaM;
    double lambda = L, lambdaP, iterLimit = 100;
    do {
        sinLambda = Math.sin(lambda);
        cosLambda = Math.cos(lambda);
        sinSigma = Math.sqrt((cosU2 * sinLambda) * (cosU2 * sinLambda)
                + (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda) * (cosU1 * sinU2 - sinU1 * cosU2 * cosLambda));
        if (sinSigma == 0)
            return 0; // co-incident points
        cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
        sigma = Math.atan2(sinSigma, cosSigma);
        sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
        cosSqAlpha = 1 - sinAlpha * sinAlpha;
        cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
        if (Double.isNaN(cos2SigmaM))
            cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6)
        double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
        lambdaP = lambda;
        lambda = L + (1 - C) * f * sinAlpha
                * (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
    } while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0);

    if (iterLimit == 0)
        return Double.NaN; // formula failed to converge

    double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
    double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
    double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
    double deltaSigma = B
            * sinSigma
            * (cos2SigmaM + B
                    / 4
                    * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6 * cos2SigmaM
                            * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
    double dist = b * A * (sigma - deltaSigma);

    return dist;
}

This code was freely adapted from http://www.movable-type.co.uk/scripts/latlong-vincenty.html

Victor P.
  • 630
  • 1
  • 6
  • 14
6

Corrected Haversine Distance formula....

public static double HaverSineDistance(double lat1, double lng1, double lat2, double lng2) 
{
    // mHager 08-12-2012
    // http://en.wikipedia.org/wiki/Haversine_formula
    // Implementation

    // convert to radians
    lat1 = Math.toRadians(lat1);
    lng1 = Math.toRadians(lng1);
    lat2 = Math.toRadians(lat2);
    lng2 = Math.toRadians(lng2);

    double dlon = lng2 - lng1;
    double dlat = lat2 - lat1;

    double a = Math.pow((Math.sin(dlat/2)),2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2),2);

    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    return EARTH_RADIUS * c;
}   
Matthew Hager
  • 81
  • 1
  • 2
  • Earth is not a perfect sphere – Steve Kuo Nov 02 '13 at 21:19
  • Correct, sometimes **close** is good enough. IE: Why Mr. Inman created it. I'd tell him he is wrong, but he is dead. :o( If you need to calculate for the oblong shape of the world, there are better formulas for that. There are also some great apache libraries that you can use as well. If you just need something simple, this is a good quick example. :) – Matthew Hager Feb 24 '14 at 22:50
  • 1
    Ya, Haversine formula is built on the 'close is good enough' principal. At the time we were measuring distances that were < 50 miles to determine proximity from one location to another as a 'heuristic'. – Matthew Hager Jul 09 '15 at 17:25
2

http://www.movable-type.co.uk/scripts/latlong.html

public static Double distanceBetweenTwoLocationsInKm(Double latitudeOne, Double longitudeOne, Double latitudeTwo, Double longitudeTwo) {
        if (latitudeOne == null || latitudeTwo == null || longitudeOne == null || longitudeTwo == null) {
            return null;
        }

        Double earthRadius = 6371.0;
        Double diffBetweenLatitudeRadians = Math.toRadians(latitudeTwo - latitudeOne);
        Double diffBetweenLongitudeRadians = Math.toRadians(longitudeTwo - longitudeOne);
        Double latitudeOneInRadians = Math.toRadians(latitudeOne);
        Double latitudeTwoInRadians = Math.toRadians(latitudeTwo);
        Double a = Math.sin(diffBetweenLatitudeRadians / 2) * Math.sin(diffBetweenLatitudeRadians / 2) + Math.cos(latitudeOneInRadians) * Math.cos(latitudeTwoInRadians) * Math.sin(diffBetweenLongitudeRadians / 2)
                * Math.sin(diffBetweenLongitudeRadians / 2);
        Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return (earthRadius * c);
    }
Divers
  • 9,531
  • 7
  • 45
  • 88
1

I know that there are many answers, but in doing some research on this topic, I found that most answers here use the Haversine formula, but the Vincenty formula is actually more accurate. There was one post that adapted the calculation from a Javascript version, but it's very unwieldy. I found a version that is superior because:

  1. It also has an open license.
  2. It uses OOP principles.
  3. It has greater flexibility to choose the ellipsoid you want to use.
  4. It has more methods to allow for different calculations in the future.
  5. It is well documented.

VincentyDistanceCalculator

mikeho
  • 6,790
  • 3
  • 34
  • 46
  • And it's gone. Might be this one: https://github.com/manuelhartl/opensaft/blob/fb44617d6166f293ad32d5244c7abb4c9c0e4e2e/opensaft-input/src/main/java/de/hartlit/opensaft/common/geodetic/VincentyDistanceCalculator.java – debuglevel Nov 14 '21 at 14:31
  • Good catch! I did some digging and the Apache Lucene tools would probably be more reliable. I'll update the answer. – mikeho Nov 15 '21 at 15:09
1

This method would help you find the distance between to geographic location in km.

private double getDist(double lat1, double lon1, double lat2, double lon2)
{
    int R = 6373; // radius of the earth in kilometres
    double lat1rad = Math.toRadians(lat1);
    double lat2rad = Math.toRadians(lat2);
    double deltaLat = Math.toRadians(lat2-lat1);
    double deltaLon = Math.toRadians(lon2-lon1);

    double a = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) +
            Math.cos(lat1rad) * Math.cos(lat2rad) *
            Math.sin(deltaLon/2) * Math.sin(deltaLon/2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

    double d = R * c;
    return d;
}
Ad Infinitum
  • 3,560
  • 27
  • 33
1

Kotlin version of Haversine formula. Returned result in meters. Tested on https://www.vcalc.com/wiki/vCalc/Haversine+-+Distance

const val EARTH_RADIUS_IN_METERS = 6371007.177356707

fun distance(lat1: Double, lng1: Double, lat2: Double, lng2: Double): Double {
    val latDiff = Math.toRadians(abs(lat2 - lat1))
    val lngDiff = Math.toRadians(abs(lng2 - lng1))
    val a = sin(latDiff / 2) * sin(latDiff / 2) +
        cos(Math.toRadians(lat1)) * cos(Math.toRadians(lat2)) *
        sin(lngDiff / 2) * sin(lngDiff / 2)
    val c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return EARTH_RADIUS_IN_METERS * c
}
Binakot
  • 298
  • 5
  • 15
  • hey so I can use this as a geofence right???? The geofence code on android is not working for me for some unknown reason and I was thinking to use this as an alternative – Pemba Tamang Aug 29 '19 at 13:24
1

You can use the Java Geodesy Library for GPS, it uses the Vincenty's formulae which takes account of the earths surface curvature.

Implementation goes like this:

import org.gavaghan.geodesy.*;
...
GeodeticCalculator geoCalc = new GeodeticCalculator();
Ellipsoid reference = Ellipsoid.WGS84;
GlobalPosition pointA = new GlobalPosition(latitude, longitude, 0.0);
GlobalPosition userPos = new GlobalPosition(userLat, userLon, 0.0);
double distance = geoCalc.calculateGeodeticCurve(reference, userPos, pointA).getEllipsoidalDistance();

The resulting distance is in meters.

jpsecher
  • 4,461
  • 2
  • 33
  • 42
Oscar Salguero
  • 10,275
  • 5
  • 49
  • 48
0

I typically use MATLAB with the Mapping Toolbox, and then use the code in my Java using MATLAB Builder JA. It makes my life a lot simpler. Given most schools have it for free student access, you can try it out (or get the trial version to get over your work).

0

For Android, there is a simple approach.

 public static float getDistanceInMeter(LatLng start, LatLng end) { 
    float[] results = new float[1];
    Location.distanceBetween(start.latitude, start.longitude, end.latitude, end.longitude, results);
    return results[0];

}

;

https://developer.android.com/reference/android/location/Location#distanceBetween(lat1,lng1,lat2,lng2,output[])

makata
  • 2,188
  • 2
  • 28
  • 23