Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions library/src/main/java/com/google/maps/android/PolyUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -466,16 +482,18 @@ 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);
final double s1lng = toRadians(start.longitude);
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);
Expand Down
53 changes: 51 additions & 2 deletions library/src/test/java/com/google/maps/android/PolyUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -469,14 +472,60 @@ 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 <a href="https://www.qgis.org/">QGIS</a>.
*
* @see <a href="https://www.qgis.org/">QGIS</a>
*/
@Test
public void testDistanceToLine() {
LatLng startLine = new LatLng(28.05359, -82.41632);
LatLng endLine = new LatLng(28.05310, -82.41634);
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
Expand Down