[android] added more tests for LatLngBounds.union(), LatLngBounds.intersect() (#11777)

fixed going over antimeridian for both
This commit is contained in:
Osana Babayan
2018-05-11 16:00:45 -04:00
committed by GitHub
parent b6f56db4fe
commit 36d30f13fc
2 changed files with 389 additions and 51 deletions

View File

@@ -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);
}
/**