Skip to content

Commit 59a48d3

Browse files
barbeaukikoso
andauthored
fix: Apply correction to distanceToLine() measurements (#767)
* Testing new distance to line formula * Add links to theory for initial implementation * Add lonCorrection From #720 (comment) * chore: addded tests for different latitudes and magnitude * chore: added javadoc Co-authored-by: Enrique López Mañas <eenriquelopez@gmail.com>
1 parent fc2b964 commit 59a48d3

File tree

2 files changed

+74
-7
lines changed

2 files changed

+74
-7
lines changed

library/src/main/java/com/google/maps/android/PolyUtil.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,25 @@
2222
import java.util.List;
2323
import java.util.Stack;
2424

25-
import static com.google.maps.android.SphericalUtil.*;
26-
import static java.lang.Math.*;
27-
import static com.google.maps.android.MathUtil.*;
25+
import static com.google.maps.android.MathUtil.EARTH_RADIUS;
26+
import static com.google.maps.android.MathUtil.clamp;
27+
import static com.google.maps.android.MathUtil.hav;
28+
import static com.google.maps.android.MathUtil.havDistance;
29+
import static com.google.maps.android.MathUtil.havFromSin;
30+
import static com.google.maps.android.MathUtil.inverseMercator;
31+
import static com.google.maps.android.MathUtil.mercator;
32+
import static com.google.maps.android.MathUtil.sinFromHav;
33+
import static com.google.maps.android.MathUtil.sinSumFromHav;
34+
import static com.google.maps.android.MathUtil.wrap;
35+
import static com.google.maps.android.SphericalUtil.computeDistanceBetween;
36+
import static java.lang.Math.PI;
37+
import static java.lang.Math.cos;
38+
import static java.lang.Math.max;
39+
import static java.lang.Math.min;
40+
import static java.lang.Math.sin;
41+
import static java.lang.Math.sqrt;
42+
import static java.lang.Math.tan;
43+
import static java.lang.Math.toRadians;
2844

2945
public class PolyUtil {
3046

@@ -466,16 +482,18 @@ public static double distanceToLine(final LatLng p, final LatLng start, final La
466482
return computeDistanceBetween(end, p);
467483
}
468484

485+
// Implementation of http://paulbourke.net/geometry/pointlineplane/ or http://geomalgorithms.com/a02-_lines.html
469486
final double s0lat = toRadians(p.latitude);
470487
final double s0lng = toRadians(p.longitude);
471488
final double s1lat = toRadians(start.latitude);
472489
final double s1lng = toRadians(start.longitude);
473490
final double s2lat = toRadians(end.latitude);
474491
final double s2lng = toRadians(end.longitude);
475492

493+
double lonCorrection = Math.cos(s1lat);
476494
double s2s1lat = s2lat - s1lat;
477-
double s2s1lng = s2lng - s1lng;
478-
final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * s2s1lng)
495+
double s2s1lng = (s2lng - s1lng) * lonCorrection;
496+
final double u = ((s0lat - s1lat) * s2s1lat + (s0lng - s1lng) * lonCorrection * s2s1lng)
479497
/ (s2s1lat * s2s1lat + s2s1lng * s2s1lng);
480498
if (u <= 0) {
481499
return computeDistanceBetween(p, start);

library/src/test/java/com/google/maps/android/PolyUtilTest.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
import java.util.ArrayList;
2424
import java.util.List;
2525

26-
import static org.junit.Assert.*;
26+
import static org.junit.Assert.assertEquals;
27+
import static org.junit.Assert.assertFalse;
28+
import static org.junit.Assert.assertSame;
29+
import static org.junit.Assert.assertTrue;
2730

2831
public class PolyUtilTest {
2932
private static final String TEST_LINE =
@@ -469,14 +472,60 @@ public void testIsClosedPolygon() {
469472
assertTrue(PolyUtil.isClosedPolygon(poly));
470473
}
471474

475+
/**
476+
* The following method checks whether {@link PolyUtil#distanceToLine(LatLng, LatLng, LatLng) distanceToLine()} }
477+
* is determining the distance between a point and a segment accurately.
478+
*
479+
* Currently there are tests for different orders of magnitude (i.e., 1X, 10X, 100X, 1000X), as well as a test
480+
* where the segment and the point lie in different hemispheres.
481+
*
482+
* If further tests need to be added here, make sure that the distance has been verified with <a href="https://www.qgis.org/">QGIS</a>.
483+
*
484+
* @see <a href="https://www.qgis.org/">QGIS</a>
485+
*/
472486
@Test
473487
public void testDistanceToLine() {
474488
LatLng startLine = new LatLng(28.05359, -82.41632);
475489
LatLng endLine = new LatLng(28.05310, -82.41634);
476490
LatLng p = new LatLng(28.05342, -82.41594);
477491

478492
double distance = PolyUtil.distanceToLine(p, startLine, endLine);
479-
assertEquals(37.947946, distance, 1e-6);
493+
assertEquals(37.94596795917082, distance, 1e-6);
494+
495+
startLine = new LatLng(49.321045, 12.097749);
496+
endLine = new LatLng(49.321016, 12.097795);
497+
p = new LatLng(49.3210674, 12.0978238);
498+
499+
distance = PolyUtil.distanceToLine(p, startLine, endLine);
500+
assertEquals(5.559443879999753, distance, 1e-6);
501+
502+
startLine = new LatLng(48.125961, 11.548998);
503+
endLine = new LatLng(48.125918, 11.549005);
504+
p = new LatLng(48.125941, 11.549028);
505+
506+
distance = PolyUtil.distanceToLine(p, startLine, endLine);
507+
assertEquals(1.9733966358947437, distance, 1e-6);
508+
509+
startLine = new LatLng(78.924669, 11.925521);
510+
endLine = new LatLng(78.924707, 11.929060);
511+
p = new LatLng(78.923164, 11.924029);
512+
513+
distance = PolyUtil.distanceToLine(p, startLine, endLine);
514+
assertEquals(170.35662670453187, distance, 1e-6);
515+
516+
startLine = new LatLng(69.664036, 18.957124);
517+
endLine = new LatLng(69.664029, 18.957109);
518+
p = new LatLng(69.672901, 18.967911);
519+
520+
distance = PolyUtil.distanceToLine(p, startLine, endLine);
521+
assertEquals(1070.222749990837, distance, 1e-6);
522+
523+
startLine = new LatLng(-0.018200, 109.343282);
524+
endLine = new LatLng(-0.017877, 109.343537);
525+
p = new LatLng(0.058299, 109.408054);
526+
527+
distance = PolyUtil.distanceToLine(p, startLine, endLine);
528+
assertEquals(11100.157563150981, distance, 1e-6);
480529
}
481530

482531
@Test

0 commit comments

Comments
 (0)