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

Last change on this file since 3775 was 2943, checked in by mjulius, 14 years ago

generally round Bounds to LatLon.MAX_SERVER_PRECISION

  • Property svn:eol-style set to native
File size: 8.8 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 /**
34 * Construct bounds out of two points
35 */
36 public Bounds(LatLon min, LatLon max) {
37 this(min.lat(), min.lon(), max.lat(), max.lon());
38 }
39
40 public Bounds(LatLon b) {
41 this(b, b);
42 }
43
44 public Bounds(double minlat, double minlon, double maxlat, double maxlon) {
45 this.minLat = roundToOsmPrecision(minlat);
46 this.minLon = roundToOsmPrecision(minlon);
47 this.maxLat = roundToOsmPrecision(maxlat);
48 this.maxLon = roundToOsmPrecision(maxlon);
49 }
50
51 public Bounds(double [] coords) {
52 CheckParameterUtil.ensureParameterNotNull(coords, "coords");
53 if (coords.length != 4)
54 throw new IllegalArgumentException(MessageFormat.format("Expected array of length 4, got {0}", coords.length));
55 this.minLat = roundToOsmPrecision(coords[0]);
56 this.minLon = roundToOsmPrecision(coords[1]);
57 this.maxLat = roundToOsmPrecision(coords[2]);
58 this.maxLon = roundToOsmPrecision(coords[3]);
59 }
60
61 public Bounds(String asString, String separator) throws IllegalArgumentException {
62 CheckParameterUtil.ensureParameterNotNull(asString, "asString");
63 String[] components = asString.split(separator);
64 if (components.length != 4)
65 throw new IllegalArgumentException(MessageFormat.format("Exactly four doubles excpected in string, got {0}", components.length));
66 double[] values = new double[4];
67 for (int i=0; i<4; i++) {
68 try {
69 values[i] = Double.parseDouble(components[i]);
70 } catch(NumberFormatException e) {
71 throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", components[i]));
72 }
73 }
74 if (!LatLon.isValidLat(values[0]))
75 throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", values[0]));
76 if (!LatLon.isValidLon(values[1]))
77 throw new IllegalArgumentException(tr("Illegal longitude value ''{0}''", values[1]));
78 if (!LatLon.isValidLat(values[2]))
79 throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", values[2]));
80 if (!LatLon.isValidLon(values[3]))
81 throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", values[3]));
82
83 this.minLat = roundToOsmPrecision(values[0]);
84 this.minLon = roundToOsmPrecision(values[1]);
85 this.maxLat = roundToOsmPrecision(values[2]);
86 this.maxLon = roundToOsmPrecision(values[3]);
87 }
88
89 public Bounds(Bounds other) {
90 this(other.getMin(), other.getMax());
91 }
92
93 public Bounds(Rectangle2D rect) {
94 this(rect.getMinY(), rect.getMinX(), rect.getMaxY(), rect.getMaxX());
95 }
96
97 /**
98 * Creates new bounds around a coordinate pair <code>center</code>. The
99 * new bounds shall have an extension in latitude direction of <code>latExtent</code>,
100 * and in longitude direction of <code>lonExtent</code>.
101 *
102 * @param center the center coordinate pair. Must not be null.
103 * @param latExtent the latitude extent. > 0 required.
104 * @param lonExtent the longitude extent. > 0 required.
105 * @throws IllegalArgumentException thrown if center is null
106 * @throws IllegalArgumentException thrown if latExtent <= 0
107 * @throws IllegalArgumentException thrown if lonExtent <= 0
108 */
109 public Bounds(LatLon center, double latExtent, double lonExtent) {
110 CheckParameterUtil.ensureParameterNotNull(center, "center");
111 if (latExtent <= 0.0)
112 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "latExtent", latExtent));
113 if (lonExtent <= 0.0)
114 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 exptected, got {1}", "lonExtent", lonExtent));
115
116 this.minLat = roundToOsmPrecision(center.lat() - latExtent / 2);
117 this.minLon = roundToOsmPrecision(center.lon() - lonExtent / 2);
118 this.maxLat = roundToOsmPrecision(center.lat() + latExtent / 2);
119 this.maxLon = roundToOsmPrecision(center.lon() + lonExtent / 2);
120 }
121
122 @Override public String toString() {
123 return "Bounds["+minLat+","+minLon+","+maxLat+","+maxLon+"]";
124 }
125
126 public String toShortString(DecimalFormat format) {
127 return
128 format.format(minLat) + " "
129 + format.format(minLon) + " / "
130 + format.format(maxLat) + " "
131 + format.format(maxLon);
132 }
133
134 /**
135 * @return Center of the bounding box.
136 */
137 public LatLon getCenter()
138 {
139 return getMin().getCenter(getMax());
140 }
141
142 /**
143 * Extend the bounds if necessary to include the given point.
144 */
145 public void extend(LatLon ll) {
146 if (ll.lat() < minLat) {
147 minLat = roundToOsmPrecision(ll.lat());
148 }
149 if (ll.lon() < minLon) {
150 minLon = roundToOsmPrecision(ll.lon());
151 }
152 if (ll.lat() > maxLat) {
153 maxLat = roundToOsmPrecision(ll.lat());
154 }
155 if (ll.lon() > maxLon) {
156 maxLon = roundToOsmPrecision(ll.lon());
157 }
158 }
159
160 public void extend(Bounds b) {
161 extend(b.getMin());
162 extend(b.getMax());
163 }
164 /**
165 * Is the given point within this bounds?
166 */
167 public boolean contains(LatLon ll) {
168 if (ll.lat() < minLat || ll.lon() < minLon)
169 return false;
170 if (ll.lat() > maxLat || ll.lon() > maxLon)
171 return false;
172 return true;
173 }
174
175 /**
176 * The two bounds intersect? Compared to java Shape.intersects, if does not use
177 * the interior but the closure. (">=" instead of ">")
178 */
179 public boolean intersects(Bounds b) {
180 return b.getMax().lat() >= minLat &&
181 b.getMax().lon() >= minLon &&
182 b.getMin().lat() <= maxLat &&
183 b.getMin().lon() <= maxLon;
184 }
185
186
187 /**
188 * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
189 * @return the bounding box to Rectangle2D.Double
190 */
191 public Rectangle2D.Double asRect() {
192 return new Rectangle2D.Double(minLon, minLat, maxLon-minLon, maxLat-minLat);
193 }
194
195 public double getArea() {
196 return (maxLon - minLon) * (maxLat - minLat);
197 }
198
199 public String encodeAsString(String separator) {
200 StringBuffer sb = new StringBuffer();
201 sb.append(minLat).append(separator).append(minLon)
202 .append(separator).append(maxLat).append(separator)
203 .append(maxLon);
204 return sb.toString();
205 }
206
207 @Override
208 public int hashCode() {
209 final int prime = 31;
210 int result = 1;
211 long temp;
212 temp = Double.doubleToLongBits(maxLat);
213 result = prime * result + (int) (temp ^ (temp >>> 32));
214 temp = Double.doubleToLongBits(maxLon);
215 result = prime * result + (int) (temp ^ (temp >>> 32));
216 temp = Double.doubleToLongBits(minLat);
217 result = prime * result + (int) (temp ^ (temp >>> 32));
218 temp = Double.doubleToLongBits(minLon);
219 result = prime * result + (int) (temp ^ (temp >>> 32));
220 return result;
221 }
222
223 @Override
224 public boolean equals(Object obj) {
225 if (this == obj)
226 return true;
227 if (obj == null)
228 return false;
229 if (getClass() != obj.getClass())
230 return false;
231 Bounds other = (Bounds) obj;
232 if (Double.doubleToLongBits(maxLat) != Double.doubleToLongBits(other.maxLat))
233 return false;
234 if (Double.doubleToLongBits(maxLon) != Double.doubleToLongBits(other.maxLon))
235 return false;
236 if (Double.doubleToLongBits(minLat) != Double.doubleToLongBits(other.minLat))
237 return false;
238 if (Double.doubleToLongBits(minLon) != Double.doubleToLongBits(other.minLon))
239 return false;
240 return true;
241 }
242
243 /**
244 * Returns the value rounded to OSM precisions, i.e. to
245 * LatLon.MAX_SERVER_PRECISION
246 *
247 * @return rounded value
248 */
249 private double roundToOsmPrecision(double value) {
250 return Math.round(value / LatLon.MAX_SERVER_PRECISION) * LatLon.MAX_SERVER_PRECISION;
251 }
252}
Note: See TracBrowser for help on using the repository browser.