[android] added more tests for LatLngBounds.union(), LatLngBounds.intersect() (#11777)
fixed going over antimeridian for both
This commit is contained in:
@@ -294,6 +294,20 @@ public class LatLngBounds implements Parcelable {
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
|
||||
double lonWest) {
|
||||
|
||||
checkParams(latNorth, lonEast, latSouth, 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);
|
||||
}
|
||||
|
||||
private static void checkParams(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latNorth,
|
||||
double lonEast,
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
|
||||
double lonWest) {
|
||||
|
||||
if (Double.isNaN(latNorth) || Double.isNaN(latSouth)) {
|
||||
throw new IllegalArgumentException("latitude must not be NaN");
|
||||
}
|
||||
@@ -314,11 +328,6 @@ public class LatLngBounds implements Parcelable {
|
||||
if (latNorth < latSouth) {
|
||||
throw new IllegalArgumentException("LatSouth cannot be less than latNorth");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private static double lat_(int z, int y) {
|
||||
@@ -395,7 +404,7 @@ public class LatLngBounds implements Parcelable {
|
||||
return (longitude <= eastLon)
|
||||
&& (longitude >= westLon);
|
||||
}
|
||||
return (longitude < eastLon) || (longitude > westLon);
|
||||
return (longitude <= eastLon) || (longitude >= westLon);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,36 +435,94 @@ public class LatLngBounds implements Parcelable {
|
||||
* @param bounds LatLngBounds to add
|
||||
* @return LatLngBounds
|
||||
*/
|
||||
public LatLngBounds union(LatLngBounds bounds) {
|
||||
return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
|
||||
public @NonNull LatLngBounds union(@NonNull LatLngBounds bounds) {
|
||||
return unionNoParamCheck(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new LatLngBounds that stretches to include another LatLngBounds,
|
||||
* given by corner points.
|
||||
* <p>
|
||||
* This values of northLat and southLat should be in the range of [-90, 90],
|
||||
* see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
|
||||
* otherwise IllegalArgumentException will be thrown.
|
||||
* northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
|
||||
* <p>
|
||||
* This method doesn't recalculate most east or most west boundaries.
|
||||
* Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
|
||||
* see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
|
||||
*
|
||||
* @param latNorth Northern Latitude
|
||||
* @param lonEast Eastern Longitude
|
||||
* @param latSouth Southern Latitude
|
||||
* @param lonWest Western Longitude
|
||||
* @return BoundingBox
|
||||
* @param northLat Northern Latitude corner point
|
||||
* @param eastLon Eastern Longitude corner point
|
||||
* @param southLat Southern Latitude corner point
|
||||
* @param westLon Western Longitude corner point
|
||||
* @return LatLngBounds
|
||||
*/
|
||||
public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) {
|
||||
double north = (this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth;
|
||||
double south = (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth;
|
||||
public @NonNull LatLngBounds union(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
|
||||
double eastLon,
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
|
||||
double westLon) {
|
||||
|
||||
if (LatLngSpan.getLongitudeSpan(lonEast, this.longitudeWest)
|
||||
< LatLngSpan.getLongitudeSpan(this.longitudeEast, lonWest)) {
|
||||
return new LatLngBounds(north,
|
||||
lonEast,
|
||||
south,
|
||||
checkParams(northLat, eastLon, southLat, westLon);
|
||||
|
||||
return unionNoParamCheck(northLat, eastLon, southLat, westLon);
|
||||
}
|
||||
|
||||
private @NonNull LatLngBounds unionNoParamCheck(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
|
||||
double eastLon,
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
|
||||
double westLon) {
|
||||
|
||||
northLat = (this.latitudeNorth < northLat) ? northLat : this.latitudeNorth;
|
||||
southLat = (this.latitudeSouth > southLat) ? southLat : this.latitudeSouth;
|
||||
|
||||
eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||
westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||
|
||||
// longitudes match
|
||||
if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
|
||||
return new LatLngBounds(northLat, eastLon, southLat, westLon);
|
||||
}
|
||||
|
||||
boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
|
||||
boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
|
||||
boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
|
||||
boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
|
||||
|
||||
// two intersections on each end - covers entire longitude
|
||||
if (eastInThis && westInThis && thisEastInside && thisWestInside) {
|
||||
return new LatLngBounds(northLat, GeometryConstants.MAX_LONGITUDE, southLat, GeometryConstants.MIN_LONGITUDE);
|
||||
}
|
||||
|
||||
if (eastInThis) {
|
||||
if (westInThis) {
|
||||
return new LatLngBounds(northLat, this.longitudeEast, southLat, this.longitudeWest);
|
||||
}
|
||||
return new LatLngBounds(northLat, this.longitudeEast, southLat, westLon);
|
||||
}
|
||||
|
||||
if (thisEastInside) {
|
||||
if (thisWestInside) {
|
||||
return new LatLngBounds(northLat, eastLon, southLat, westLon);
|
||||
}
|
||||
return new LatLngBounds(northLat, eastLon, southLat, this.longitudeWest);
|
||||
}
|
||||
|
||||
// bounds do not intersect, find where they will form shortest union
|
||||
if (LatLngSpan.getLongitudeSpan(eastLon, this.longitudeWest)
|
||||
< LatLngSpan.getLongitudeSpan(this.longitudeEast, westLon)) {
|
||||
return new LatLngBounds(northLat,
|
||||
eastLon,
|
||||
southLat,
|
||||
this.longitudeWest);
|
||||
}
|
||||
|
||||
return new LatLngBounds(north,
|
||||
return new LatLngBounds(northLat,
|
||||
this.longitudeEast,
|
||||
south,
|
||||
lonWest);
|
||||
southLat,
|
||||
westLon);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,32 +531,89 @@ public class LatLngBounds implements Parcelable {
|
||||
* @param box LatLngBounds to intersect with
|
||||
* @return LatLngBounds
|
||||
*/
|
||||
@Nullable
|
||||
public LatLngBounds intersect(LatLngBounds box) {
|
||||
double minLonWest = Math.max(getLonWest(), box.getLonWest());
|
||||
double maxLonEast = Math.min(getLonEast(), box.getLonEast());
|
||||
if (maxLonEast > minLonWest) {
|
||||
double minLatSouth = Math.max(getLatSouth(), box.getLatSouth());
|
||||
double maxLatNorth = Math.min(getLatNorth(), box.getLatNorth());
|
||||
if (maxLatNorth > minLatSouth) {
|
||||
return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public @Nullable LatLngBounds intersect(@NonNull LatLngBounds box) {
|
||||
return intersectNoParamCheck(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new LatLngBounds that is the intersection of this with another LatLngBounds
|
||||
* <p>
|
||||
* This values of northLat and southLat should be in the range of [-90, 90],
|
||||
* see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
|
||||
* otherwise IllegalArgumentException will be thrown.
|
||||
* northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
|
||||
* <p>
|
||||
* This method doesn't recalculate most east or most west boundaries.
|
||||
* Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
|
||||
* see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
|
||||
*
|
||||
* @param northLatitude Northern Longitude
|
||||
* @param eastLongitude Eastern Latitude
|
||||
* @param southLatitude Southern Longitude
|
||||
* @param westLongitude Western Latitude
|
||||
* @param northLat Northern Latitude corner point
|
||||
* @param eastLon Eastern Longitude corner point
|
||||
* @param southLat Southern Latitude corner point
|
||||
* @param westLon Western Longitude corner point
|
||||
* @return LatLngBounds
|
||||
*/
|
||||
public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude,
|
||||
double westLongitude) {
|
||||
return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude));
|
||||
public @Nullable LatLngBounds intersect(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
|
||||
double eastLon,
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
|
||||
double westLon) {
|
||||
|
||||
checkParams(northLat, eastLon, southLat, westLon);
|
||||
|
||||
return intersectNoParamCheck(northLat, eastLon, southLat, westLon);
|
||||
}
|
||||
|
||||
private @Nullable LatLngBounds intersectNoParamCheck(
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
|
||||
double eastLon,
|
||||
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
|
||||
double westLon) {
|
||||
|
||||
double maxsouthLat = Math.max(getLatSouth(), Math.min(GeometryConstants.MAX_LATITUDE, southLat));
|
||||
double minnorthLat = Math.min(getLatNorth(), Math.max(GeometryConstants.MIN_LATITUDE, northLat));
|
||||
if (minnorthLat < maxsouthLat) {
|
||||
return null;
|
||||
}
|
||||
|
||||
eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||
westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
|
||||
|
||||
// longitudes match
|
||||
if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
|
||||
return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
|
||||
}
|
||||
|
||||
boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
|
||||
boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
|
||||
boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
|
||||
boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
|
||||
|
||||
// two intersections : find the one that has longest span
|
||||
if (eastInThis && westInThis && thisEastInside && thisWestInside) {
|
||||
|
||||
if (getLongitudeSpan(eastLon, this.longitudeWest) > getLongitudeSpan(this.longitudeEast, westLon)) {
|
||||
return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
|
||||
}
|
||||
|
||||
return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
|
||||
}
|
||||
|
||||
if (eastInThis) {
|
||||
if (westInThis) {
|
||||
return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
|
||||
}
|
||||
return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
|
||||
}
|
||||
|
||||
if (thisEastInside) {
|
||||
if (thisWestInside) {
|
||||
return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, this.longitudeWest);
|
||||
}
|
||||
return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,7 +642,7 @@ public class LatLngBounds implements Parcelable {
|
||||
return (int) ((latitudeNorth + 90)
|
||||
+ ((latitudeSouth + 90) * 1000)
|
||||
+ ((longitudeEast + 180) * 1000000)
|
||||
+ ((longitudeEast + 180) * 1000000000));
|
||||
+ ((longitudeWest + 180) * 1000000000));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -546,11 +670,11 @@ public class LatLngBounds implements Parcelable {
|
||||
}
|
||||
|
||||
private static LatLngBounds readFromParcel(final Parcel in) {
|
||||
final double lonNorth = in.readDouble();
|
||||
final double latEast = in.readDouble();
|
||||
final double lonSouth = in.readDouble();
|
||||
final double latWest = in.readDouble();
|
||||
return new LatLngBounds(lonNorth, latEast, lonSouth, latWest);
|
||||
final double northLat = in.readDouble();
|
||||
final double eastLon = in.readDouble();
|
||||
final double southLat = in.readDouble();
|
||||
final double westLon = in.readDouble();
|
||||
return new LatLngBounds(northLat, eastLon, southLat, westLon);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user