The following is code that I've carefully ripped off from the Interweb and 
messed with.  You should be able to understand /extract the bit you need.  It's 
a scary amount of trig. and I have absolutely no idea how it works, but seems 
to be some sort of iterative process.  If you feel guilty using it for free in 
your project - donate some money to charity   ;-)

I think that it works, but I do not have the resources to check it on a larger 
scale than the Scottish tests (about 20 km distance).  Perhaps others in this 
list can help verify the code.  I would appreciate that a lot...



=======================================================
package com.klickngo.geometry;


import org.apache.commons.lang.builder.*;


public class LatLongCoordinate {
    
    
    /* These are directly accessible */
    public double altitude;
    public double latitudeY;
    public double longitudeX;
    
    
    
    private LatLongCoordinate() {
        this(0.0, 0.0, 0.0);
    }
    
    
    public LatLongCoordinate(double longitudeX, double latitudeY) {
        this(longitudeX, latitudeY, 0.0);
    }
    
    
    public LatLongCoordinate(double longitudeX, double latitudeY, double 
altitude)
    throws IllegalArgumentException {
        if (longitudeX > 180.0 | longitudeX < -180.0) throw new 
IllegalArgumentException("Longitude out of +/- 180 bounds");
        if (latitudeY > 90.0 | latitudeY < -90.0) throw new 
IllegalArgumentException("Latitude out of +/- 90 bounds");
        if (altitude < 0.0) throw new IllegalArgumentException("Altitude below 
sea level");
        
        
        this.longitudeX = longitudeX;
        this.latitudeY = latitudeY;
        this.altitude = altitude;
    }
    
    
    public LatLongCoordinate(LatLongCoordinate coordinate) {
        this(coordinate.longitudeX, coordinate.latitudeY, coordinate.altitude);
    }
    
    
    public void setCoordinate(LatLongCoordinate otherCoord) {
        this.longitudeX = otherCoord.longitudeX;
        this.latitudeY = otherCoord.latitudeY;
        this.altitude = otherCoord.altitude;
    }
    
    
    
    /**********************************************************
     *
     *  Did some testing in Scotland (via Memory Map).
     *  Two points 18 by 9 km grid squares apart, results were:
     *  VD = 20.125 km, Pythagarus = 20.116 km, MM = 20 km
     *
     *  Two points 1 by 1 km grid square:-
     *  VD = 1.413 km, Pythagarus = 1.414 km, MM = 1.41 km
     *
     **********************************************************/
    
    public double getVincentyDistance(LatLongCoordinate otherCoord) {
        double retVal = 0.0D;
        
        double a      = 6378137, b = 6356752.3142,  f = 1 / 298.257223563;
        double l      = Math.toRadians(otherCoord.longitudeX) -  
Math.toRadians(this.longitudeX);
        double u1     = Math.atan((1 - f) * 
Math.tan(Math.toRadians(this.latitudeY)));
        double u2     = Math.atan((1 - f) * 
Math.tan(Math.toRadians(otherCoord.latitudeY)));
        double sinU1  = Math.sin(u1), cosU1 = Math.cos(u1);
        double sinU2  = Math.sin(u2), cosU2 = Math.cos(u2);
        double lambda = l, lambdaP = 2 * Math.PI;
        int    iterLimit = 20;
        
        double sinLambda, cosLambda;
        double sinSigma = 0.0D;
        double cosSigma = 0.0D;
        double sigma = 0.0D;
        double alpha;
        double cosSqAlpha  = 0.0D;
        double cosToSigmaM = 0.0D;
        double c;
        
        while (Math.abs(lambda - lambdaP) > 1e-12 && --iterLimit > 0) {
            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));
            cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
            sigma = Math.atan2(sinSigma, cosSigma);
            alpha = Math.asin(cosU1 * cosU2 * sinLambda / sinSigma);
            cosSqAlpha  = Math.cos(alpha) * Math.cos(alpha);
            cosToSigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
            c = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
            
            lambdaP = lambda;
            lambda = l + (1 - c) * f *
                    Math.sin(alpha) *
                    (sigma + c * sinSigma *
                    (cosToSigmaM + c * cosSigma * (- 1 + 2 *
                    cosToSigmaM * cosToSigmaM)));
        }
        
        
        // IF no convergence
        if (iterLimit == 0) {
            retVal = Double.NaN;
        } else {
            double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
            double a2   = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq *
                    (320 - 175 * uSq)));
            double b2   = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 -
                    47 * uSq)));
            double deltaSigma = b2 * sinSigma *
                    (cosToSigmaM +
                    b2 / 4 * (cosSigma * (-1 + 2 * cosToSigmaM *
                    cosToSigmaM) -
                    b2 / 6 * cosToSigmaM *
                    (-3 + 4 * sinSigma * sinSigma) *
                    (-3 + 4 * cosToSigmaM * cosToSigmaM)));
            retVal = b * a2 * (sigma - deltaSigma);
        }
        
        return retVal;
    }
    
    
    public String toString() {
        return new ToStringBuilder(this).
                append("Long.", this.longitudeX).
                append("Lat.", this.latitudeY).
                append("Alt.", this.altitude).
                toString();
    }
    
    
    public boolean equals(Object obj) {
        if (obj == null) { return false; }
        if (obj == this) { return true; }
        if (obj.getClass() != getClass()) {
            return false;
        }
        
        
        LatLongCoordinate rhs = (LatLongCoordinate) obj;
        return new EqualsBuilder()
        .append(this.altitude, rhs.altitude)
        .append(this.longitudeX, rhs.longitudeX)
        .append(this.latitudeY, rhs.latitudeY)
        .isEquals();
    }
    
    
    public int hashCode() {
        // you pick a hard-coded, randomly chosen, non-zero, odd number
        // ideally different for each class
        return new HashCodeBuilder(307, 31).
                append(this.altitude).
                append(this.longitudeX).
                append(this.latitudeY).
                toHashCode();
    }
    
    
    /* These private accessors are only for Hibernate to use  */
    private double getAltitude() {
        return altitude;
    }
    
    
    private void setAltitude(double altitude) {
        this.altitude = altitude;
    }
    
    
    private double getLongitudeX() {
        return longitudeX;
    }
    
    
    private void setLongitudeX(double longitudeX) {
        this.longitudeX = longitudeX;
    }
    
    
    private double getLatitudeY() {
        return latitudeY;
    }
    
    
    private void setLatitudeY(double latitudeY) {
        this.latitudeY = latitudeY;
    }
}
============================================
_______________________________________________
jts-devel mailing list
[email protected]
http://lists.refractions.net/mailman/listinfo/jts-devel

Reply via email to