package de.westnordost.streetcomplete.util; import junit.framework.TestCase; import de.westnordost.osmapi.map.data.BoundingBox; import de.westnordost.osmapi.map.data.LatLon; import de.westnordost.osmapi.map.data.OsmLatLon; public class SphericalEarthMathTest extends TestCase { private static LatLon HH = new OsmLatLon(53.5,10.0); public void testToBerlin() { checkHamburgTo(52.4, 13.4, 259, 117, 110); } public void testToLübeck() { checkHamburgTo(53.85, 10.68, 59, 49, 61); } public void testToLosAngeles() { checkHamburgTo(34, -118, 9075, 319, 206); } public void testToReykjavik() { checkHamburgTo(64.11, -21.98, 2152, 316, 280); } public void testToPortElizabeth() { checkHamburgTo(-33.9, -25.6, 10307, 209, 231); } public void testToPoles() { checkHamburgTo(90.0, 123.0, 4059, 0, null); checkHamburgTo(-90.0, 0.0, 15956, 180, null); } public void testToOtherSideOfEarth() { checkHamburgTo(-53.5, -170.0, (int) (Math.PI*6371), 270, 180); } public void testShortDistance() { LatLon one = new OsmLatLon(53.5712482, 9.9782365); LatLon two = new OsmLatLon(53.5712528, 9.9782517); assertEquals(1, (int) SphericalEarthMath.distance(one, two)); } public void testEnclosingBoundingBox() { LatLon pos = new OsmLatLon(0, 0); BoundingBox bbox = SphericalEarthMath.enclosingBoundingBox(pos, 5000); int dist = (int) (Math.sqrt(2) * 5000); // all four corners of the bbox should be 'radius' away assertEquals(dist, Math.round(SphericalEarthMath.distance(pos, bbox.getMin()))); assertEquals(dist, Math.round(SphericalEarthMath.distance(pos, bbox.getMax()))); assertEquals(dist, Math.round(SphericalEarthMath.distance(pos, new OsmLatLon(bbox.getMinLatitude(), bbox.getMaxLongitude())))); assertEquals(dist, Math.round(SphericalEarthMath.distance(pos, new OsmLatLon(bbox.getMaxLatitude(), bbox.getMinLongitude())))); assertEquals(225, Math.round(SphericalEarthMath.bearing(pos, bbox.getMin()))); assertEquals(45, Math.round(SphericalEarthMath.bearing(pos, bbox.getMax()))); } public void testTranslateLatitudeNorth() { checkTranslate(1000, 0); } public void testTranslateLatitudeSouth() { checkTranslate(1000, 180); } public void testTranslateLatitudeWest() { checkTranslate(1000, 270); } public void testTranslateLatitudeEast() { checkTranslate(1000, 90); } public void testTranslateLatitudeNorthEast() { checkTranslate(1000, 45); } public void testTranslateLatitudeSouthEast() { checkTranslate(1000, 135); } public void testTranslateLatitudeSouthWest() { checkTranslate(1000, 225); } public void testTranslateLatitudeNorthWest() { checkTranslate(1000, 315); } public void testTranslateOverBoundaries() { // cross 180th meridian both ways checkTranslate(new OsmLatLon(0,179.9999999), 1000, 90); checkTranslate(new OsmLatLon(0,-179.9999999), 1000, 270); // cross north pole and come out on the other side // should come out at 45,-90 int quarterOfEarth = (int) (Math.PI/2 * SphericalEarthMath.EARTH_RADIUS); checkTranslate(new OsmLatLon(+45, 90), quarterOfEarth, 0); // should come out at -45,-90 checkTranslate(new OsmLatLon(-45, 90), quarterOfEarth, 180); } private void checkTranslate(LatLon one, int distance, int angle) { LatLon two = SphericalEarthMath.translate(one, distance, angle); assertEquals(distance, Math.round(SphericalEarthMath.distance(one, two))); assertEquals(angle, Math.round(SphericalEarthMath.bearing(one, two))); } private void checkTranslate(int distance, int angle) { LatLon one = new OsmLatLon(53.5712482, 9.9782365); checkTranslate(one, distance, angle); } private void checkHamburgTo(double lat, double lon, int dist, int angle, Integer angle2) { LatLon t = new OsmLatLon(lat, lon); assertEquals(dist, Math.round(SphericalEarthMath.distance(HH, t) / 1000)); assertEquals(dist, Math.round(SphericalEarthMath.distance(t, HH) / 1000)); assertEquals(angle, Math.round(SphericalEarthMath.bearing(HH, t))); if(angle2 != null) assertEquals((int) angle2, Math.round(SphericalEarthMath.finalBearing(HH, t))); } }