BoundingBox improvements, closes #200

This commit is contained in:
Emux 2016-10-08 15:48:00 +03:00
parent 4994d611fe
commit ac7706eb7a
2 changed files with 167 additions and 32 deletions

View File

@ -5,5 +5,4 @@
| [Cachebox 3.0](https://github.com/Longri/cachebox3.0) | Android / Desktop / iOS geocaching application | GPL/Free | Open |
| [Cruiser](http://wiki.openstreetmap.org/wiki/Cruiser) | Android / Desktop map and navigation application | Proprietary/Free | Closed |
You know an application that is missing here? Please inform us by sending a message via our public [mailing list](https://groups.google.com/group/mapsforge-dev).

View File

@ -67,14 +67,40 @@ public class BoundingBox {
this.maxLongitudeE6 = maxLongitudeE6;
}
public BoundingBox(double minLatitude, double minLongitude, double maxLatitude,
double maxLongitude) {
/**
* @param minLatitude the minimum latitude coordinate in degrees.
* @param minLongitude the minimum longitude coordinate in degrees.
* @param maxLatitude the maximum latitude coordinate in degrees.
* @param maxLongitude the maximum longitude coordinate in degrees.
*/
public BoundingBox(double minLatitude, double minLongitude, double maxLatitude, double maxLongitude) {
this.minLatitudeE6 = (int) (minLatitude * 1E6);
this.minLongitudeE6 = (int) (minLongitude * 1E6);
this.maxLatitudeE6 = (int) (maxLatitude * 1E6);
this.maxLongitudeE6 = (int) (maxLongitude * 1E6);
}
/**
* @param geoPoints the coordinates list.
*/
public BoundingBox(List<GeoPoint> geoPoints) {
int minLat = Integer.MAX_VALUE;
int minLon = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int maxLon = Integer.MIN_VALUE;
for (GeoPoint geoPoint : geoPoints) {
minLat = Math.min(minLat, geoPoint.latitudeE6);
minLon = Math.min(minLon, geoPoint.longitudeE6);
maxLat = Math.max(maxLat, geoPoint.latitudeE6);
maxLon = Math.max(maxLon, geoPoint.longitudeE6);
}
this.minLatitudeE6 = minLat;
this.minLongitudeE6 = minLon;
this.maxLatitudeE6 = maxLat;
this.maxLongitudeE6 = maxLon;
}
/**
* @param geoPoint the point whose coordinates should be checked.
* @return true if this BoundingBox contains the given GeoPoint, false
@ -107,6 +133,118 @@ public class BoundingBox {
return true;
}
/**
* @param boundingBox the BoundingBox which this BoundingBox should be extended if it is larger
* @return a BoundingBox that covers this BoundingBox and the given BoundingBox.
*/
public BoundingBox extendBoundingBox(BoundingBox boundingBox) {
return new BoundingBox(Math.min(this.minLatitudeE6, boundingBox.minLatitudeE6),
Math.min(this.minLongitudeE6, boundingBox.minLongitudeE6),
Math.max(this.maxLatitudeE6, boundingBox.maxLatitudeE6),
Math.max(this.maxLongitudeE6, boundingBox.maxLongitudeE6));
}
/**
* Creates a BoundingBox extended up to <code>GeoPoint</code> (but does not cross date line/poles).
*
* @param geoPoint coordinates up to the extension
* @return an extended BoundingBox or this (if contains coordinates)
*/
public BoundingBox extendCoordinates(GeoPoint geoPoint) {
if (contains(geoPoint)) {
return this;
}
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, Math.min(getMinLatitude(), geoPoint.getLatitude()));
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, Math.min(getMinLongitude(), geoPoint.getLongitude()));
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, Math.max(getMaxLatitude(), geoPoint.getLatitude()));
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, Math.max(getMaxLongitude(), geoPoint.getLongitude()));
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
/**
* Creates a BoundingBox that is a fixed degree amount larger on all sides (but does not cross date line/poles).
*
* @param verticalExpansion degree extension (must be >= 0)
* @param horizontalExpansion degree extension (must be >= 0)
* @return an extended BoundingBox or this (if degrees == 0)
*/
public BoundingBox extendDegrees(double verticalExpansion, double horizontalExpansion) {
if (verticalExpansion == 0 && horizontalExpansion == 0) {
return this;
} else if (verticalExpansion < 0 || horizontalExpansion < 0) {
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative values");
}
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
/**
* Creates a BoundingBox that is a fixed margin factor larger on all sides (but does not cross date line/poles).
*
* @param margin extension (must be > 0)
* @return an extended BoundingBox or this (if margin == 1)
*/
public BoundingBox extendMargin(float margin) {
if (margin == 1) {
return this;
} else if (margin <= 0) {
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative or zero values");
}
double verticalExpansion = (getLatitudeSpan() * margin - getLatitudeSpan()) * 0.5;
double horizontalExpansion = (getLongitudeSpan() * margin - getLongitudeSpan()) * 0.5;
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
/**
* Creates a BoundingBox that is a fixed meter amount larger on all sides (but does not cross date line/poles).
*
* @param meters extension (must be >= 0)
* @return an extended BoundingBox or this (if meters == 0)
*/
public BoundingBox extendMeters(int meters) {
if (meters == 0) {
return this;
} else if (meters < 0) {
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative values");
}
double verticalExpansion = GeoPoint.latitudeDistance(meters);
double horizontalExpansion = GeoPoint.longitudeDistance(meters, Math.max(Math.abs(getMinLatitude()), Math.abs(getMaxLatitude())));
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
public String format() {
return new StringBuilder()
.append(minLatitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(minLongitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(maxLatitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(maxLongitudeE6 / CONVERSION_FACTOR)
.toString();
}
/**
* @return the GeoPoint at the horizontal and vertical center of this
* BoundingBox.
@ -118,6 +256,20 @@ public class BoundingBox {
+ longitudeOffset);
}
/**
* @return the latitude span of this BoundingBox in degrees.
*/
public double getLatitudeSpan() {
return getMaxLatitude() - getMinLatitude();
}
/**
* @return the longitude span of this BoundingBox in degrees.
*/
public double getLongitudeSpan() {
return getMaxLongitude() - getMinLatitude();
}
/**
* @return the maximum latitude value of this BoundingBox in degrees.
*/
@ -156,6 +308,19 @@ public class BoundingBox {
return result;
}
/**
* @param boundingBox the BoundingBox which should be checked for intersection with this BoundingBox.
* @return true if this BoundingBox intersects with the given BoundingBox, false otherwise.
*/
public boolean intersects(BoundingBox boundingBox) {
if (this == boundingBox) {
return true;
}
return getMaxLatitude() >= boundingBox.getMinLatitude() && getMaxLongitude() >= boundingBox.getMinLongitude()
&& getMinLatitude() <= boundingBox.getMaxLatitude() && getMinLongitude() <= boundingBox.getMaxLongitude();
}
@Override
public String toString() {
return new StringBuilder()
@ -170,33 +335,4 @@ public class BoundingBox {
.append("]")
.toString();
}
public String format() {
return new StringBuilder()
.append(minLatitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(minLongitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(maxLatitudeE6 / CONVERSION_FACTOR)
.append(',')
.append(maxLongitudeE6 / CONVERSION_FACTOR)
.toString();
}
/* code below is from osdmroid, @author Nicolas Gramlich */
public static BoundingBox fromGeoPoints(final List<? extends GeoPoint> partialPolyLine) {
int minLat = Integer.MAX_VALUE;
int minLon = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int maxLon = Integer.MIN_VALUE;
for (final GeoPoint gp : partialPolyLine) {
minLat = Math.min(minLat, gp.latitudeE6);
minLon = Math.min(minLon, gp.longitudeE6);
maxLat = Math.max(maxLat, gp.latitudeE6);
maxLon = Math.max(maxLon, gp.longitudeE6);
}
return new BoundingBox(minLat, minLon, maxLat, maxLon);
}
}