Monday, April 21, 2014

Haversine Algorithm Implementation in Java

This is to calculate from two sets of points (Latitude, and Longitude) and distance based on the Earth's diameter/radius.

Here is the Haversine Formula followed by the java code. I've added Miles, KM, Meters, CM, Feet and Yards methods as well.

Haversine
formula:
a = sin²(Δφ/2) + cos(φ1).cos(φ2).sin²(Δλ/2)
c = 2.atan2(√a, √(1−a))
d = R.c
whereφ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km)
 note that angles need to be in radians to pass to trig functions!

/**
 * This is the implementation Haversine Distance Algorithm between two places
 * @author amitapollo
 *  R = earth’s radius (mean radius = 6372.8km)
    Δlat = lat2 − lat1
    Δlong = long2 − long1
    a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
    c = 2.atan2(√a, √(1−a))
    d = R.c * (distance converstion factor*)
 * 
 * * - km, mi, m, yds
 */

import java.lang.Math.*;

public class Haversine {
    /**
     * @param args
     * arg 1- latitude 1
     * arg 2 - longitude 1
     * arg 3 - latitude 2
     * arg 4 - longitude 2
     */

    public static final double RKilometers = 6372.8; // In kilometers
    public static final double RMiles = 10256.0; // In miles

    //returns kilometers between two sets of points (lat, lon)
    public static double haversineKilometers(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RKilometers * c;
    }

//returns meters between two sets of points (lat, lon)
    public static double haversineMeters(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RKilometers * c * 1000;
    }

    //returns centimeters between two sets of points (lat, lon)
    public static double haversineCentimeters(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RKilometers * c * 1000 * 100;
    }

    //returns miles between two sets of points (lat, lon)
    public static double haversineMiles(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RMiles * c;
    }

    //returns feet between two sets of points (lat, lon)
    public static double haversineFeet(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RMiles * c * 5280;
    }

    //returns inches between two sets of points (lat, lon)
    public static double haversineInches(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RMiles * c * 5280 * 12;
    }

    //returns yards between two sets of points (lat, lon)
    public static double haversineYards(double lat1, double lon1, double lat2, double lon2) {
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
 
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        double c = 2 * Math.asin(Math.sqrt(a));
        return RMiles * c * 1760;
    }

    //CONVERTS value to Radians
    private static Double toRad(Double value) {
        return value * Math.PI / 180;
    }
}

1 comment:

  1. Your RMiles constant is wrong. You inadvertently divided KM by .62 instead of multiplying by .62. Miles will ALWAYS be less than KM for the same distance, since a mile is larger.

    ReplyDelete