source: josm/trunk/src/org/openstreetmap/josm/data/Bounds.java@ 4541

Last change on this file since 4541 was 4522, checked in by Don-vip, 13 years ago

see #6960 - Code simplification

  • Property svn:eol-style set to native
File size: 10.4 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.geom.Rectangle2D;
7import java.text.DecimalFormat;
8import java.text.MessageFormat;
9
10import org.openstreetmap.josm.data.coor.LatLon;
11import org.openstreetmap.josm.tools.CheckParameterUtil;
12
13/**
14 * This is a simple data class for "rectangular" areas of the world, given in
15 * lat/lon min/max values. The values are rounded to LatLon.OSM_SERVER_PRECISION
16 *
17 * @author imi
18 */
19public class Bounds {
20 /**
21 * The minimum and maximum coordinates.
22 */
23 private double minLat, minLon, maxLat, maxLon;
24
25 public LatLon getMin() {
26 return new LatLon(minLat, minLon);
27 }
28
29 public LatLon getMax() {
30 return new LatLon(maxLat, maxLon);
31 }
32
33 public enum ParseMethod {
34 MINLAT_MINLON_MAXLAT_MAXLON,
35 LEFT_BOTTOM_RIGHT_TOP
36 }
37
38 /**
39 * Construct bounds out of two points
40 */
41 public Bounds(LatLon min, LatLon max) {
42 this(min.lat(), min.lon(), max.lat(), max.lon());
43 }
44
45 public Bounds(LatLon b) {
46 this(b, b);
47 }
48
49 public Bounds(double minlat, double minlon, double maxlat, double maxlon) {
50 this.minLat = LatLon.roundToOsmPrecision(minlat);
51 this.minLon = LatLon.roundToOsmPrecision(minlon);
52 this.maxLat = LatLon.roundToOsmPrecision(maxlat);
53 this.maxLon = LatLon.roundToOsmPrecision(maxlon);
54 }
55
56 public Bounds(double [] coords) {
57 CheckParameterUtil.ensureParameterNotNull(coords, "coords");
58 if (coords.length != 4)
59 throw new IllegalArgumentException(MessageFormat.format("Expected array of length 4, got {0}", coords.length));
60 this.minLat = LatLon.roundToOsmPrecision(coords[0]);
61 this.minLon = LatLon.roundToOsmPrecision(coords[1]);
62 this.maxLat = LatLon.roundToOsmPrecision(coords[2]);
63 this.maxLon = LatLon.roundToOsmPrecision(coords[3]);
64 }
65
66 public Bounds(String asString, String separator) throws IllegalArgumentException {
67 this(asString, separator, ParseMethod.MINLAT_MINLON_MAXLAT_MAXLON);
68 }
69
70 public Bounds(String asString, String separator, ParseMethod parseMethod) throws IllegalArgumentException {
71 CheckParameterUtil.ensureParameterNotNull(asString, "asString");
72 String[] components = asString.split(separator);
73 if (components.length != 4)
74 throw new IllegalArgumentException(MessageFormat.format("Exactly four doubles expected in string, got {0}: {1}", components.length, asString));
75 double[] values = new double[4];
76 for (int i=0; i<4; i++) {
77 try {
78 values[i] = Double.parseDouble(components[i]);
79 } catch(NumberFormatException e) {
80 throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", components[i]));
81 }
82 }
83
84 switch (parseMethod) {
85 case LEFT_BOTTOM_RIGHT_TOP:
86 this.minLat = initLat(values[1]);
87 this.minLon = initLon(values[0]);
88 this.maxLat = initLat(values[3]);
89 this.maxLon = initLon(values[2]);
90 break;
91 case MINLAT_MINLON_MAXLAT_MAXLON:
92 default:
93 this.minLat = initLat(values[0]);
94 this.minLon = initLon(values[1]);
95 this.maxLat = initLat(values[2]);
96 this.maxLon = initLon(values[3]);
97 }
98 }
99
100 protected static double initLat(double value) {
101 if (!LatLon.isValidLat(value))
102 throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", value));
103 return LatLon.roundToOsmPrecision(value);
104 }
105
106 protected static double initLon(double value) {
107 if (!LatLon.isValidLon(value))
108 throw new IllegalArgumentException(tr("Illegal longitude value ''{0}''", value));
109 return LatLon.roundToOsmPrecision(value);
110 }
111
112 public Bounds(Bounds other) {
113 this(other.getMin(), other.getMax());
114 }
115
116 public Bounds(Rectangle2D rect) {
117 this(rect.getMinY(), rect.getMinX(), rect.getMaxY(), rect.getMaxX());
118 }
119
120 /**
121 * Creates new bounds around a coordinate pair <code>center</code>. The
122 * new bounds shall have an extension in latitude direction of <code>latExtent</code>,
123 * and in longitude direction of <code>lonExtent</code>.
124 *
125 * @param center the center coordinate pair. Must not be null.
126 * @param latExtent the latitude extent. > 0 required.
127 * @param lonExtent the longitude extent. > 0 required.
128 * @throws IllegalArgumentException thrown if center is null
129 * @throws IllegalArgumentException thrown if latExtent <= 0
130 * @throws IllegalArgumentException thrown if lonExtent <= 0
131 */
132 public Bounds(LatLon center, double latExtent, double lonExtent) {
133 CheckParameterUtil.ensureParameterNotNull(center, "center");
134 if (latExtent <= 0.0)
135 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "latExtent", latExtent));
136 if (lonExtent <= 0.0)
137 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "lonExtent", lonExtent));
138
139 this.minLat = LatLon.roundToOsmPrecision(center.lat() - latExtent / 2);
140 this.minLon = LatLon.roundToOsmPrecision(center.lon() - lonExtent / 2);
141 this.maxLat = LatLon.roundToOsmPrecision(center.lat() + latExtent / 2);
142 this.maxLon = LatLon.roundToOsmPrecision(center.lon() + lonExtent / 2);
143 }
144
145 @Override public String toString() {
146 return "Bounds["+minLat+","+minLon+","+maxLat+","+maxLon+"]";
147 }
148
149 public String toShortString(DecimalFormat format) {
150 return
151 format.format(minLat) + " "
152 + format.format(minLon) + " / "
153 + format.format(maxLat) + " "
154 + format.format(maxLon);
155 }
156
157 /**
158 * @return Center of the bounding box.
159 */
160 public LatLon getCenter()
161 {
162 return getMin().getCenter(getMax());
163 }
164
165 /**
166 * Extend the bounds if necessary to include the given point.
167 */
168 public void extend(LatLon ll) {
169 if (ll.lat() < minLat) {
170 minLat = LatLon.roundToOsmPrecision(ll.lat());
171 }
172 if (ll.lon() < minLon) {
173 minLon = LatLon.roundToOsmPrecision(ll.lon());
174 }
175 if (ll.lat() > maxLat) {
176 maxLat = LatLon.roundToOsmPrecision(ll.lat());
177 }
178 if (ll.lon() > maxLon) {
179 maxLon = LatLon.roundToOsmPrecision(ll.lon());
180 }
181 }
182
183 public void extend(Bounds b) {
184 extend(b.getMin());
185 extend(b.getMax());
186 }
187 /**
188 * Is the given point within this bounds?
189 */
190 public boolean contains(LatLon ll) {
191 if (ll.lat() < minLat || ll.lon() < minLon)
192 return false;
193 if (ll.lat() > maxLat || ll.lon() > maxLon)
194 return false;
195 return true;
196 }
197
198 /**
199 * The two bounds intersect? Compared to java Shape.intersects, if does not use
200 * the interior but the closure. (">=" instead of ">")
201 */
202 public boolean intersects(Bounds b) {
203 return b.maxLat >= minLat &&
204 b.maxLon >= minLon &&
205 b.minLat <= maxLat &&
206 b.minLon <= maxLon;
207 }
208
209
210 /**
211 * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
212 * @return the bounding box to Rectangle2D.Double
213 */
214 public Rectangle2D.Double asRect() {
215 return new Rectangle2D.Double(minLon, minLat, maxLon-minLon, maxLat-minLat);
216 }
217
218 public double getArea() {
219 return (maxLon - minLon) * (maxLat - minLat);
220 }
221
222 public String encodeAsString(String separator) {
223 StringBuffer sb = new StringBuffer();
224 sb.append(minLat).append(separator).append(minLon)
225 .append(separator).append(maxLat).append(separator)
226 .append(maxLon);
227 return sb.toString();
228 }
229
230 /**
231 * <p>Replies true, if this bounds are <em>collapsed</em>, i.e. if the min
232 * and the max corner are equal.</p>
233 *
234 * @return true, if this bounds are <em>collapsed</em>
235 */
236 public boolean isCollapsed() {
237 return getMin().equals(getMax());
238 }
239
240 public boolean isOutOfTheWorld() {
241 return
242 minLat < -90 || minLat > 90 ||
243 maxLat < -90 || maxLat > 90 ||
244 minLon < -180 || minLon > 180 ||
245 maxLon < -180 || maxLon > 180;
246 }
247
248 private double toIntervalLat(double value, double min, double max) {
249 if (value < min)
250 return min;
251 if (value > max)
252 return max;
253 return value;
254 }
255
256 private double toIntervalLon(double value) {
257 if (value < -180 || value > 180) {
258 value = (value + 180) % 360;
259 if (value < 0) {
260 value += 360;
261 }
262 return value - 180;
263 } else
264 return value;
265 }
266
267 public void normalize() {
268 minLat = toIntervalLat(minLat, -90, 90);
269 maxLat = toIntervalLat(maxLat, -90, 90);
270 minLon = toIntervalLon(minLon);
271 maxLon = toIntervalLon(maxLon);
272 }
273
274 @Override
275 public int hashCode() {
276 final int prime = 31;
277 int result = 1;
278 long temp;
279 temp = Double.doubleToLongBits(maxLat);
280 result = prime * result + (int) (temp ^ (temp >>> 32));
281 temp = Double.doubleToLongBits(maxLon);
282 result = prime * result + (int) (temp ^ (temp >>> 32));
283 temp = Double.doubleToLongBits(minLat);
284 result = prime * result + (int) (temp ^ (temp >>> 32));
285 temp = Double.doubleToLongBits(minLon);
286 result = prime * result + (int) (temp ^ (temp >>> 32));
287 return result;
288 }
289
290 @Override
291 public boolean equals(Object obj) {
292 if (this == obj)
293 return true;
294 if (obj == null)
295 return false;
296 if (getClass() != obj.getClass())
297 return false;
298 Bounds other = (Bounds) obj;
299 if (Double.doubleToLongBits(maxLat) != Double.doubleToLongBits(other.maxLat))
300 return false;
301 if (Double.doubleToLongBits(maxLon) != Double.doubleToLongBits(other.maxLon))
302 return false;
303 if (Double.doubleToLongBits(minLat) != Double.doubleToLongBits(other.minLat))
304 return false;
305 if (Double.doubleToLongBits(minLon) != Double.doubleToLongBits(other.minLon))
306 return false;
307 return true;
308 }
309}
Note: See TracBrowser for help on using the repository browser.