[android] - unwrap LatLngBounds for the shortest path when passing to core (#11759)
This commit is contained in:
@@ -28,7 +28,7 @@ public class LatLngBounds implements Parcelable {
|
|||||||
/**
|
/**
|
||||||
* Construct a new LatLngBounds based on its corners, given in NESW
|
* Construct a new LatLngBounds based on its corners, given in NESW
|
||||||
* order.
|
* order.
|
||||||
*
|
* <p>
|
||||||
* If eastern longitude is smaller than the western one, bounds will include antimeridian.
|
* 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
|
* 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.
|
* and cross the antimeridian.
|
||||||
@@ -46,6 +46,11 @@ public class LatLngBounds implements Parcelable {
|
|||||||
this.longitudeWest = westLongitude;
|
this.longitudeWest = westLongitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LatLngBounds(LatLngBounds latLngBounds) {
|
||||||
|
this(latLngBounds.latitudeNorth, latLngBounds.longitudeEast,
|
||||||
|
latLngBounds.latitudeSouth, latLngBounds.longitudeWest);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the world bounds.
|
* Returns the world bounds.
|
||||||
*
|
*
|
||||||
@@ -75,7 +80,6 @@ public class LatLngBounds implements Parcelable {
|
|||||||
if (longCenter >= GeometryConstants.MAX_LONGITUDE) {
|
if (longCenter >= GeometryConstants.MAX_LONGITUDE) {
|
||||||
longCenter = this.longitudeEast - halfSpan;
|
longCenter = this.longitudeEast - halfSpan;
|
||||||
}
|
}
|
||||||
return new LatLng(latCenter, longCenter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LatLng(latCenter, longCenter);
|
return new LatLng(latCenter, longCenter);
|
||||||
@@ -188,7 +192,6 @@ public class LatLngBounds implements Parcelable {
|
|||||||
return GeometryConstants.LONGITUDE_SPAN - longSpan;
|
return GeometryConstants.LONGITUDE_SPAN - longSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static double getLongitudeSpan(final double longEast, final double longWest) {
|
static double getLongitudeSpan(final double longEast, final double longWest) {
|
||||||
double longSpan = Math.abs(longEast - longWest);
|
double longSpan = Math.abs(longEast - longWest);
|
||||||
if (longEast >= longWest) {
|
if (longEast >= longWest) {
|
||||||
@@ -199,6 +202,25 @@ public class LatLngBounds implements Parcelable {
|
|||||||
return GeometryConstants.LONGITUDE_SPAN - longSpan;
|
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
|
* Validate if LatLngBounds is empty, determined if absolute distance is
|
||||||
*
|
*
|
||||||
@@ -279,12 +301,11 @@ public class LatLngBounds implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a LatLngBounds from doubles representing a LatLng pair.
|
* Constructs a LatLngBounds from doubles representing a LatLng pair.
|
||||||
*
|
* <p>
|
||||||
* This values of latNorth and latSouth should be in the range of [-90, 90],
|
* This values of latNorth and latSouth should be in the range of [-90, 90],
|
||||||
* see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
|
* see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
|
||||||
* otherwise IllegalArgumentException will be thrown.
|
* otherwise IllegalArgumentException will be thrown.
|
||||||
* latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown.
|
* latNorth should be greater or equal latSouth, otherwise IllegalArgumentException will be thrown.
|
||||||
*
|
|
||||||
* <p>
|
* <p>
|
||||||
* This method doesn't recalculate most east or most west boundaries.
|
* 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],
|
* Note that lonEast and lonWest will be wrapped to be in the range of [-180, 180],
|
||||||
@@ -318,12 +339,20 @@ public class LatLngBounds implements Parcelable {
|
|||||||
throw new IllegalArgumentException("LatSouth cannot be less than latNorth");
|
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);
|
lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||||
lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||||
|
|
||||||
return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
|
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) {
|
private static double lat_(int z, int y) {
|
||||||
double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z);
|
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))));
|
return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
|
||||||
@@ -335,14 +364,14 @@ public class LatLngBounds implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a LatLngBounds from a Tile identifier.
|
* Constructs a LatLngBounds from a Tile identifier.
|
||||||
*
|
* <p>
|
||||||
* Returned bounds will have latitude in the range of Mercator projection.
|
* 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 z Tile zoom level.
|
||||||
* @param x Tile X coordinate.
|
* @param x Tile X coordinate.
|
||||||
* @param y Tile Y 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) {
|
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));
|
return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x));
|
||||||
|
|||||||
@@ -1540,7 +1540,12 @@ public final class MapboxMap {
|
|||||||
* @param latLngBounds the bounds to constrain the map with
|
* @param latLngBounds the bounds to constrain the map with
|
||||||
*/
|
*/
|
||||||
public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) {
|
public void setLatLngBoundsForCameraTarget(@Nullable LatLngBounds latLngBounds) {
|
||||||
nativeMapView.setLatLngBounds(latLngBounds);
|
if (latLngBounds == null) {
|
||||||
|
nativeMapView.setLatLngBounds(latLngBounds);
|
||||||
|
} else {
|
||||||
|
//unwrapping the bounds to generate the right convex hull in core
|
||||||
|
nativeMapView.setLatLngBounds(latLngBounds.unwrapBounds());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1550,9 +1555,9 @@ public final class MapboxMap {
|
|||||||
* @param padding the padding to apply to the bounds
|
* @param padding the padding to apply to the bounds
|
||||||
* @return the camera position that fits the bounds and padding
|
* @return the camera position that fits the bounds and padding
|
||||||
*/
|
*/
|
||||||
public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) {
|
public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) {
|
||||||
// get padded camera position from LatLngBounds
|
// get padded camera position from LatLngBounds, unwrapping the bounds to generate the right convex hull in core
|
||||||
return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding);
|
return nativeMapView.getCameraForLatLngBounds(latLngBounds.unwrapBounds(), padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -524,7 +524,6 @@ public class LatLngBoundsTest {
|
|||||||
LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20);
|
LatLngBounds.from(0, Double.POSITIVE_INFINITY, -20, -20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConstructorChecksSouthLatitudeNaN() {
|
public void testConstructorChecksSouthLatitudeNaN() {
|
||||||
exception.expect(IllegalArgumentException.class);
|
exception.expect(IllegalArgumentException.class);
|
||||||
@@ -543,7 +542,7 @@ public class LatLngBoundsTest {
|
|||||||
public void testConstructorChecksSouthLatitudeGreaterThan90() {
|
public void testConstructorChecksSouthLatitudeGreaterThan90() {
|
||||||
exception.expect(IllegalArgumentException.class);
|
exception.expect(IllegalArgumentException.class);
|
||||||
exception.expectMessage("latitude must be between -90 and 90");
|
exception.expectMessage("latitude must be between -90 and 90");
|
||||||
LatLngBounds.from(20, 20,95, 0);
|
LatLngBounds.from(20, 20, 95, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -566,4 +565,23 @@ public class LatLngBoundsTest {
|
|||||||
exception.expectMessage("LatSouth cannot be less than latNorth");
|
exception.expectMessage("LatSouth cannot be less than latNorth");
|
||||||
LatLngBounds.from(0, 20, 20, 0);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user