From 85a8cf731df7dc85ce9da5067f0854e373bdbb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 23 Apr 2018 13:23:19 +0200 Subject: [android] - unwrap LatLngBounds for the shortest path when passing to core --- .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 46 ++++++++++++++++++---- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 5 ++- .../mapboxsdk/geometry/LatLngBoundsTest.java | 22 ++++++++++- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 55494b72d8..626d7176e8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable { /** * Construct a new LatLngBounds based on its corners, given in NESW * order. - * + *

* If eastern longitude is smaller than the western one, bounds will include antimeridian. * For example, if the NE point is (10, -170) and the SW point is (-10, 170), then bounds will span over 20 degrees * and cross the antimeridian. @@ -46,6 +46,11 @@ public class LatLngBounds implements Parcelable { this.longitudeWest = westLongitude; } + LatLngBounds(LatLngBounds latLngBounds) { + this(latLngBounds.latitudeNorth, latLngBounds.longitudeEast, + latLngBounds.latitudeSouth, latLngBounds.longitudeWest); + } + /** * Returns the world bounds. * @@ -75,7 +80,6 @@ public class LatLngBounds implements Parcelable { if (longCenter >= GeometryConstants.MAX_LONGITUDE) { longCenter = this.longitudeEast - halfSpan; } - return new LatLng(latCenter, longCenter); } return new LatLng(latCenter, longCenter); @@ -188,7 +192,6 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } - static double getLongitudeSpan(final double longEast, final double longWest) { double longSpan = Math.abs(longEast - longWest); if (longEast >= longWest) { @@ -199,6 +202,25 @@ public class LatLngBounds implements Parcelable { return GeometryConstants.LONGITUDE_SPAN - longSpan; } + /** + * If bounds cross the antimeridian, unwrap west longitude for the shortest path. + * + * @return unwrapped bounds + */ + public LatLngBounds unwrapBounds() { + double unwrapedLonWest = longitudeWest; + if (longitudeEast < longitudeWest) { + if (longitudeWest > 0 && longitudeEast < 0) { + unwrapedLonWest -= GeometryConstants.LONGITUDE_SPAN; + } else if (longitudeWest < 0 && longitudeEast > 0) { + unwrapedLonWest += GeometryConstants.LONGITUDE_SPAN; + } + return unwrapped(latitudeNorth, longitudeEast, latitudeSouth, unwrapedLonWest); + } else { + return new LatLngBounds(this); + } + } + /** * Validate if LatLngBounds is empty, determined if absolute distance is * @@ -278,12 +300,12 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from doubles representing a LatLng pair. - * + *

* This values of latNorth and latSouth should be in the range of [-90, 90], * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE}, * otherwise IllegalArgumentException will be thrown. * latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown. - * + *

*

* This method doesn't recalculate most east or most west boundaries. * Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180], @@ -317,12 +339,20 @@ public class LatLngBounds implements Parcelable { throw new IllegalArgumentException("LatSouth cannot be less than latNorth"); } + return wrapped(latNorth, lonEast, latSouth, lonWest); + } + + static LatLngBounds wrapped(double latNorth, double lonEast, double latSouth, double lonWest) { lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE); return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); } + static LatLngBounds unwrapped(double latNorth, double lonEast, double latSouth, double lonWest) { + return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); + } + private static double lat_(int z, int y) { double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z); return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))); @@ -334,14 +364,14 @@ public class LatLngBounds implements Parcelable { /** * Constructs a LatLngBounds from a Tile identifier. - * + *

* Returned bounds will have latitude in the range of Mercator projection. - * @see GeometryConstants#MIN_MERCATOR_LATITUDE - * @see GeometryConstants#MAX_MERCATOR_LATITUDE * * @param z Tile zoom level. * @param x Tile X coordinate. * @param y Tile Y coordinate. + * @see GeometryConstants#MIN_MERCATOR_LATITUDE + * @see GeometryConstants#MAX_MERCATOR_LATITUDE */ public static LatLngBounds from(int z, int x, int y) { return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 976277dcac..7f48fbf87c 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -176,7 +176,8 @@ final class NativeMapView { if (isDestroyedOn("setLatLngBounds")) { return; } - nativeSetLatLngBounds(latLngBounds); + //unwrapping the bounds to generate the right convex hull in core + nativeSetLatLngBounds(latLngBounds.unwrapBounds()); } public void cancelTransitions() { @@ -234,7 +235,7 @@ final class NativeMapView { return null; } return nativeGetCameraForLatLngBounds( - latLngBounds, + latLngBounds.unwrapBounds(), //unwrapping the bounds to generate the right convex hull in core padding[1] / pixelRatio, padding[0] / pixelRatio, padding[3] / pixelRatio, diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index e072f07fb9..c1e497af32 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -524,7 +524,6 @@ public class LatLngBoundsTest { LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20); } - @Test public void testConstructorChecksSouthLatitudeNaN() { exception.expect(IllegalArgumentException.class); @@ -543,7 +542,7 @@ public class LatLngBoundsTest { public void testConstructorChecksSouthLatitudeGreaterThan90() { exception.expect(IllegalArgumentException.class); exception.expectMessage("latitude must be between -90 and 90"); - LatLngBounds.from(20, 20,95, 0); + LatLngBounds.from(20, 20, 95, 0); } @Test @@ -566,4 +565,23 @@ public class LatLngBoundsTest { exception.expectMessage("LatSouth cannot be less than latNorth"); LatLngBounds.from(0, 20, 20, 0); } + + @Test + public void testCopyConstructor() { + LatLngBounds bounds = LatLngBounds.from(50, 10, -20, -30); + LatLngBounds copyBounds = new LatLngBounds(bounds); + assertEquals(bounds, copyBounds); + } + + @Test + public void testUnwrapBounds() { + LatLngBounds bounds = LatLngBounds.from(16.5, -172.8, -35.127709, 172.6); + LatLngBounds unwrappedBounds = bounds.unwrapBounds(); + assertEquals(bounds.getCenter().wrap(), unwrappedBounds.getCenter().wrap()); + assertEquals(bounds.getSpan(), unwrappedBounds.getSpan()); + assertTrue(unwrappedBounds.getLonEast() < 0 && unwrappedBounds.getLonWest() < 0); + + LatLngBounds bounds2 = LatLngBounds.from(16.5, -162.8, -35.127709, -177.4); + assertEquals(bounds2, bounds2.unwrapBounds()); + } } -- cgit v1.2.1