diff --git a/library/src/main/java/com/google/maps/android/PolyUtil.java b/library/src/main/java/com/google/maps/android/PolyUtil.java
index 2f8413bc7..1c32d5a38 100644
--- a/library/src/main/java/com/google/maps/android/PolyUtil.java
+++ b/library/src/main/java/com/google/maps/android/PolyUtil.java
@@ -22,9 +22,25 @@
import java.util.List;
import java.util.Stack;
-import static com.google.maps.android.SphericalUtil.*;
-import static java.lang.Math.*;
-import static com.google.maps.android.MathUtil.*;
+import static com.google.maps.android.MathUtil.EARTH_RADIUS;
+import static com.google.maps.android.MathUtil.clamp;
+import static com.google.maps.android.MathUtil.hav;
+import static com.google.maps.android.MathUtil.havDistance;
+import static com.google.maps.android.MathUtil.havFromSin;
+import static com.google.maps.android.MathUtil.inverseMercator;
+import static com.google.maps.android.MathUtil.mercator;
+import static com.google.maps.android.MathUtil.sinFromHav;
+import static com.google.maps.android.MathUtil.sinSumFromHav;
+import static com.google.maps.android.MathUtil.wrap;
+import static com.google.maps.android.SphericalUtil.computeDistanceBetween;
+import static java.lang.Math.PI;
+import static java.lang.Math.cos;
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+import static java.lang.Math.sin;
+import static java.lang.Math.sqrt;
+import static java.lang.Math.tan;
+import static java.lang.Math.toRadians;
public class PolyUtil {
@@ -466,6 +482,7 @@ public static double distanceToLine(final LatLng p, final LatLng start, final La
return computeDistanceBetween(end, p);
}
+ // Implementation of http://paulbourke.net/geometry/pointlineplane/ or http://geomalgorithms.com/a02-_lines.html
final double s0lat = toRadians(p.latitude);
final double s0lng = toRadians(p.longitude);
final double s1lat = toRadians(start.latitude);
@@ -473,9 +490,10 @@ public static double distanceToLine(final LatLng p, final LatLng start, final La
final double s2lat = toRadians(end.latitude);
final double s2lng = toRadians(end.longitude);
+ double lonCorrection = Math.cos(s1lat);
double s2s1lat = s2lat - s1lat;
- double s2s1lng = s2lng - s1lng;
- final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * s2s1lng)
+ double s2s1lng = (s2lng - s1lng) * lonCorrection;
+ final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * lonCorrection * s2s1lng)
/ (s2s1lat * s2s1lat + s2s1lng * s2s1lng);
if (u <= 0) {
return computeDistanceBetween(p, start);
diff --git a/library/src/test/java/com/google/maps/android/PolyUtilTest.java b/library/src/test/java/com/google/maps/android/PolyUtilTest.java
index c278887d6..cff8c538e 100644
--- a/library/src/test/java/com/google/maps/android/PolyUtilTest.java
+++ b/library/src/test/java/com/google/maps/android/PolyUtilTest.java
@@ -23,7 +23,10 @@
import java.util.ArrayList;
import java.util.List;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
public class PolyUtilTest {
private static final String TEST_LINE =
@@ -469,6 +472,17 @@ public void testIsClosedPolygon() {
assertTrue(PolyUtil.isClosedPolygon(poly));
}
+ /**
+ * The following method checks whether {@link PolyUtil#distanceToLine(LatLng, LatLng, LatLng) distanceToLine()} }
+ * is determining the distance between a point and a segment accurately.
+ *
+ * Currently there are tests for different orders of magnitude (i.e., 1X, 10X, 100X, 1000X), as well as a test
+ * where the segment and the point lie in different hemispheres.
+ *
+ * If further tests need to be added here, make sure that the distance has been verified with QGIS.
+ *
+ * @see QGIS
+ */
@Test
public void testDistanceToLine() {
LatLng startLine = new LatLng(28.05359, -82.41632);
@@ -476,7 +490,42 @@ public void testDistanceToLine() {
LatLng p = new LatLng(28.05342, -82.41594);
double distance = PolyUtil.distanceToLine(p, startLine, endLine);
- assertEquals(37.947946, distance, 1e-6);
+ assertEquals(37.94596795917082, distance, 1e-6);
+
+ startLine = new LatLng(49.321045, 12.097749);
+ endLine = new LatLng(49.321016, 12.097795);
+ p = new LatLng(49.3210674, 12.0978238);
+
+ distance = PolyUtil.distanceToLine(p, startLine, endLine);
+ assertEquals(5.559443879999753, distance, 1e-6);
+
+ startLine = new LatLng(48.125961, 11.548998);
+ endLine = new LatLng(48.125918, 11.549005);
+ p = new LatLng(48.125941, 11.549028);
+
+ distance = PolyUtil.distanceToLine(p, startLine, endLine);
+ assertEquals(1.9733966358947437, distance, 1e-6);
+
+ startLine = new LatLng(78.924669, 11.925521);
+ endLine = new LatLng(78.924707, 11.929060);
+ p = new LatLng(78.923164, 11.924029);
+
+ distance = PolyUtil.distanceToLine(p, startLine, endLine);
+ assertEquals(170.35662670453187, distance, 1e-6);
+
+ startLine = new LatLng(69.664036, 18.957124);
+ endLine = new LatLng(69.664029, 18.957109);
+ p = new LatLng(69.672901, 18.967911);
+
+ distance = PolyUtil.distanceToLine(p, startLine, endLine);
+ assertEquals(1070.222749990837, distance, 1e-6);
+
+ startLine = new LatLng(-0.018200, 109.343282);
+ endLine = new LatLng(-0.017877, 109.343537);
+ p = new LatLng(0.058299, 109.408054);
+
+ distance = PolyUtil.distanceToLine(p, startLine, endLine);
+ assertEquals(11100.157563150981, distance, 1e-6);
}
@Test