Skip to content

Commit ac7706e

Browse files
committed
BoundingBox improvements, closes #200
1 parent 4994d61 commit ac7706e

File tree

2 files changed

+167
-32
lines changed

2 files changed

+167
-32
lines changed

docs/Applications.md

-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@
55
| [Cachebox 3.0](https://github.com/Longri/cachebox3.0) | Android / Desktop / iOS geocaching application | GPL/Free | Open |
66
| [Cruiser](http://wiki.openstreetmap.org/wiki/Cruiser) | Android / Desktop map and navigation application | Proprietary/Free | Closed |
77

8-
98
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).

vtm/src/org/oscim/core/BoundingBox.java

+167-31
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,40 @@ public BoundingBox(int minLatitudeE6, int minLongitudeE6, int maxLatitudeE6, int
6767
this.maxLongitudeE6 = maxLongitudeE6;
6868
}
6969

70-
public BoundingBox(double minLatitude, double minLongitude, double maxLatitude,
71-
double maxLongitude) {
70+
/**
71+
* @param minLatitude the minimum latitude coordinate in degrees.
72+
* @param minLongitude the minimum longitude coordinate in degrees.
73+
* @param maxLatitude the maximum latitude coordinate in degrees.
74+
* @param maxLongitude the maximum longitude coordinate in degrees.
75+
*/
76+
public BoundingBox(double minLatitude, double minLongitude, double maxLatitude, double maxLongitude) {
7277
this.minLatitudeE6 = (int) (minLatitude * 1E6);
7378
this.minLongitudeE6 = (int) (minLongitude * 1E6);
7479
this.maxLatitudeE6 = (int) (maxLatitude * 1E6);
7580
this.maxLongitudeE6 = (int) (maxLongitude * 1E6);
7681
}
7782

83+
/**
84+
* @param geoPoints the coordinates list.
85+
*/
86+
public BoundingBox(List<GeoPoint> geoPoints) {
87+
int minLat = Integer.MAX_VALUE;
88+
int minLon = Integer.MAX_VALUE;
89+
int maxLat = Integer.MIN_VALUE;
90+
int maxLon = Integer.MIN_VALUE;
91+
for (GeoPoint geoPoint : geoPoints) {
92+
minLat = Math.min(minLat, geoPoint.latitudeE6);
93+
minLon = Math.min(minLon, geoPoint.longitudeE6);
94+
maxLat = Math.max(maxLat, geoPoint.latitudeE6);
95+
maxLon = Math.max(maxLon, geoPoint.longitudeE6);
96+
}
97+
98+
this.minLatitudeE6 = minLat;
99+
this.minLongitudeE6 = minLon;
100+
this.maxLatitudeE6 = maxLat;
101+
this.maxLongitudeE6 = maxLon;
102+
}
103+
78104
/**
79105
* @param geoPoint the point whose coordinates should be checked.
80106
* @return true if this BoundingBox contains the given GeoPoint, false
@@ -107,6 +133,118 @@ public boolean equals(Object obj) {
107133
return true;
108134
}
109135

136+
/**
137+
* @param boundingBox the BoundingBox which this BoundingBox should be extended if it is larger
138+
* @return a BoundingBox that covers this BoundingBox and the given BoundingBox.
139+
*/
140+
public BoundingBox extendBoundingBox(BoundingBox boundingBox) {
141+
return new BoundingBox(Math.min(this.minLatitudeE6, boundingBox.minLatitudeE6),
142+
Math.min(this.minLongitudeE6, boundingBox.minLongitudeE6),
143+
Math.max(this.maxLatitudeE6, boundingBox.maxLatitudeE6),
144+
Math.max(this.maxLongitudeE6, boundingBox.maxLongitudeE6));
145+
}
146+
147+
/**
148+
* Creates a BoundingBox extended up to <code>GeoPoint</code> (but does not cross date line/poles).
149+
*
150+
* @param geoPoint coordinates up to the extension
151+
* @return an extended BoundingBox or this (if contains coordinates)
152+
*/
153+
public BoundingBox extendCoordinates(GeoPoint geoPoint) {
154+
if (contains(geoPoint)) {
155+
return this;
156+
}
157+
158+
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, Math.min(getMinLatitude(), geoPoint.getLatitude()));
159+
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, Math.min(getMinLongitude(), geoPoint.getLongitude()));
160+
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, Math.max(getMaxLatitude(), geoPoint.getLatitude()));
161+
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, Math.max(getMaxLongitude(), geoPoint.getLongitude()));
162+
163+
return new BoundingBox(minLat, minLon, maxLat, maxLon);
164+
}
165+
166+
/**
167+
* Creates a BoundingBox that is a fixed degree amount larger on all sides (but does not cross date line/poles).
168+
*
169+
* @param verticalExpansion degree extension (must be >= 0)
170+
* @param horizontalExpansion degree extension (must be >= 0)
171+
* @return an extended BoundingBox or this (if degrees == 0)
172+
*/
173+
public BoundingBox extendDegrees(double verticalExpansion, double horizontalExpansion) {
174+
if (verticalExpansion == 0 && horizontalExpansion == 0) {
175+
return this;
176+
} else if (verticalExpansion < 0 || horizontalExpansion < 0) {
177+
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative values");
178+
}
179+
180+
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
181+
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
182+
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
183+
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
184+
185+
return new BoundingBox(minLat, minLon, maxLat, maxLon);
186+
}
187+
188+
/**
189+
* Creates a BoundingBox that is a fixed margin factor larger on all sides (but does not cross date line/poles).
190+
*
191+
* @param margin extension (must be > 0)
192+
* @return an extended BoundingBox or this (if margin == 1)
193+
*/
194+
public BoundingBox extendMargin(float margin) {
195+
if (margin == 1) {
196+
return this;
197+
} else if (margin <= 0) {
198+
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative or zero values");
199+
}
200+
201+
double verticalExpansion = (getLatitudeSpan() * margin - getLatitudeSpan()) * 0.5;
202+
double horizontalExpansion = (getLongitudeSpan() * margin - getLongitudeSpan()) * 0.5;
203+
204+
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
205+
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
206+
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
207+
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
208+
209+
return new BoundingBox(minLat, minLon, maxLat, maxLon);
210+
}
211+
212+
/**
213+
* Creates a BoundingBox that is a fixed meter amount larger on all sides (but does not cross date line/poles).
214+
*
215+
* @param meters extension (must be >= 0)
216+
* @return an extended BoundingBox or this (if meters == 0)
217+
*/
218+
public BoundingBox extendMeters(int meters) {
219+
if (meters == 0) {
220+
return this;
221+
} else if (meters < 0) {
222+
throw new IllegalArgumentException("BoundingBox extend operation does not accept negative values");
223+
}
224+
225+
double verticalExpansion = GeoPoint.latitudeDistance(meters);
226+
double horizontalExpansion = GeoPoint.longitudeDistance(meters, Math.max(Math.abs(getMinLatitude()), Math.abs(getMaxLatitude())));
227+
228+
double minLat = Math.max(MercatorProjection.LATITUDE_MIN, getMinLatitude() - verticalExpansion);
229+
double minLon = Math.max(MercatorProjection.LONGITUDE_MIN, getMinLongitude() - horizontalExpansion);
230+
double maxLat = Math.min(MercatorProjection.LATITUDE_MAX, getMaxLatitude() + verticalExpansion);
231+
double maxLon = Math.min(MercatorProjection.LONGITUDE_MAX, getMaxLongitude() + horizontalExpansion);
232+
233+
return new BoundingBox(minLat, minLon, maxLat, maxLon);
234+
}
235+
236+
public String format() {
237+
return new StringBuilder()
238+
.append(minLatitudeE6 / CONVERSION_FACTOR)
239+
.append(',')
240+
.append(minLongitudeE6 / CONVERSION_FACTOR)
241+
.append(',')
242+
.append(maxLatitudeE6 / CONVERSION_FACTOR)
243+
.append(',')
244+
.append(maxLongitudeE6 / CONVERSION_FACTOR)
245+
.toString();
246+
}
247+
110248
/**
111249
* @return the GeoPoint at the horizontal and vertical center of this
112250
* BoundingBox.
@@ -118,6 +256,20 @@ public GeoPoint getCenterPoint() {
118256
+ longitudeOffset);
119257
}
120258

259+
/**
260+
* @return the latitude span of this BoundingBox in degrees.
261+
*/
262+
public double getLatitudeSpan() {
263+
return getMaxLatitude() - getMinLatitude();
264+
}
265+
266+
/**
267+
* @return the longitude span of this BoundingBox in degrees.
268+
*/
269+
public double getLongitudeSpan() {
270+
return getMaxLongitude() - getMinLatitude();
271+
}
272+
121273
/**
122274
* @return the maximum latitude value of this BoundingBox in degrees.
123275
*/
@@ -156,6 +308,19 @@ public int hashCode() {
156308
return result;
157309
}
158310

311+
/**
312+
* @param boundingBox the BoundingBox which should be checked for intersection with this BoundingBox.
313+
* @return true if this BoundingBox intersects with the given BoundingBox, false otherwise.
314+
*/
315+
public boolean intersects(BoundingBox boundingBox) {
316+
if (this == boundingBox) {
317+
return true;
318+
}
319+
320+
return getMaxLatitude() >= boundingBox.getMinLatitude() && getMaxLongitude() >= boundingBox.getMinLongitude()
321+
&& getMinLatitude() <= boundingBox.getMaxLatitude() && getMinLongitude() <= boundingBox.getMaxLongitude();
322+
}
323+
159324
@Override
160325
public String toString() {
161326
return new StringBuilder()
@@ -170,33 +335,4 @@ public String toString() {
170335
.append("]")
171336
.toString();
172337
}
173-
174-
public String format() {
175-
return new StringBuilder()
176-
.append(minLatitudeE6 / CONVERSION_FACTOR)
177-
.append(',')
178-
.append(minLongitudeE6 / CONVERSION_FACTOR)
179-
.append(',')
180-
.append(maxLatitudeE6 / CONVERSION_FACTOR)
181-
.append(',')
182-
.append(maxLongitudeE6 / CONVERSION_FACTOR)
183-
.toString();
184-
}
185-
186-
/* code below is from osdmroid, @author Nicolas Gramlich */
187-
public static BoundingBox fromGeoPoints(final List<? extends GeoPoint> partialPolyLine) {
188-
int minLat = Integer.MAX_VALUE;
189-
int minLon = Integer.MAX_VALUE;
190-
int maxLat = Integer.MIN_VALUE;
191-
int maxLon = Integer.MIN_VALUE;
192-
for (final GeoPoint gp : partialPolyLine) {
193-
194-
minLat = Math.min(minLat, gp.latitudeE6);
195-
minLon = Math.min(minLon, gp.longitudeE6);
196-
maxLat = Math.max(maxLat, gp.latitudeE6);
197-
maxLon = Math.max(maxLon, gp.longitudeE6);
198-
}
199-
200-
return new BoundingBox(minLat, minLon, maxLat, maxLon);
201-
}
202338
}

0 commit comments

Comments
 (0)