Improve `arc` geo-distance accuracy.

Close #5192
This commit is contained in:
Adrien Grand 2014-02-20 11:15:20 +01:00
parent 9160516b28
commit e1634f66bb
3 changed files with 15 additions and 10 deletions

View File

@ -81,10 +81,12 @@ public enum GeoDistance {
public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnit unit) {
double x1 = sourceLatitude * Math.PI / 180D;
double x2 = targetLatitude * Math.PI / 180D;
double h1 = (1D - Math.cos(x1 - x2)) / 2D;
double h2 = (1D - Math.cos((sourceLongitude - targetLongitude) * Math.PI / 180D)) / 2D;
double h = h1 + Math.cos(x1) * Math.cos(x2) * h2;
return unit.fromMeters(GeoUtils.EARTH_MEAN_RADIUS * 2D * Math.asin(Math.min(1, Math.sqrt(h))));
double h1 = 1D - Math.cos(x1 - x2);
double h2 = 1D - Math.cos((sourceLongitude - targetLongitude) * Math.PI / 180D);
double h = (h1 + Math.cos(x1) * Math.cos(x2) * h2) / 2;
double averageLatitude = (x1 + x2) / 2;
double diameter = GeoUtils.earthDiameter(averageLatitude);
return unit.fromMeters(diameter * Math.asin(Math.min(1, Math.sqrt(h))));
}
@Override

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.geo;
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
import org.apache.lucene.util.SloppyMath;
import org.elasticsearch.common.unit.DistanceUnit;
/**
@ -45,6 +46,14 @@ public class GeoUtils {
/** Earth ellipsoid polar distance in meters */
public static final double EARTH_POLAR_DISTANCE = Math.PI * EARTH_SEMI_MINOR_AXIS;
/**
* Return an approximate value of the diameter of the earth (in meters) at the given latitude (in radians).
*/
public static double earthDiameter(double latitude) {
// SloppyMath impl returns a result in kilometers
return SloppyMath.earthDiameter(latitude) * 1000;
}
/**
* Calculate the width (in meters) of geohash cells at a specific level
* @param level geohash level must be greater or equal to zero

View File

@ -44,12 +44,6 @@ public class SloppyMathTests extends ElasticsearchTestCase {
@Test
public void testSloppyMath() {
assertThat(GeoDistance.SLOPPY_ARC.calculate(-46.645, -171.057, -46.644, -171.058, DistanceUnit.METERS), closeTo(134.87709, maxError(134.87709)));
assertThat(GeoDistance.SLOPPY_ARC.calculate(-77.912, -81.173, -77.912, -81.171, DistanceUnit.METERS), closeTo(46.57161, maxError(46.57161)));
assertThat(GeoDistance.SLOPPY_ARC.calculate(65.75, -20.708, 65.75, -20.709, DistanceUnit.METERS), closeTo(45.66996, maxError(45.66996)));
assertThat(GeoDistance.SLOPPY_ARC.calculate(-86.9, 53.738, -86.9, 53.741, DistanceUnit.METERS), closeTo(18.03998, maxError(18.03998)));
assertThat(GeoDistance.SLOPPY_ARC.calculate(89.041, 115.93, 89.04, 115.946, DistanceUnit.METERS), closeTo(115.11711, maxError(115.11711)));
testSloppyMath(DistanceUnit.METERS, 0.01, 5, 45, 90);
testSloppyMath(DistanceUnit.KILOMETERS, 0.01, 5, 45, 90);
testSloppyMath(DistanceUnit.INCH, 0.01, 5, 45, 90);