[6380] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
[71] | 2 | package org.openstreetmap.josm.data;
|
---|
| 3 |
|
---|
[2456] | 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
[746] | 6 | import java.awt.geom.Rectangle2D;
|
---|
[2717] | 7 | import java.text.DecimalFormat;
|
---|
[2845] | 8 | import java.text.MessageFormat;
|
---|
[746] | 9 |
|
---|
[71] | 10 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
[6203] | 11 | import org.openstreetmap.josm.data.osm.BBox;
|
---|
[2845] | 12 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
---|
[71] | 13 |
|
---|
| 14 | /**
|
---|
[1169] | 15 | * This is a simple data class for "rectangular" areas of the world, given in
|
---|
[2943] | 16 | * lat/lon min/max values. The values are rounded to LatLon.OSM_SERVER_PRECISION
|
---|
[1169] | 17 | *
|
---|
[71] | 18 | * @author imi
|
---|
| 19 | */
|
---|
| 20 | public class Bounds {
|
---|
[1169] | 21 | /**
|
---|
| 22 | * The minimum and maximum coordinates.
|
---|
| 23 | */
|
---|
[2805] | 24 | private double minLat, minLon, maxLat, maxLon;
|
---|
[2456] | 25 |
|
---|
[2327] | 26 | public LatLon getMin() {
|
---|
[2805] | 27 | return new LatLon(minLat, minLon);
|
---|
[2327] | 28 | }
|
---|
[71] | 29 |
|
---|
[6203] | 30 | /**
|
---|
| 31 | * Returns min latitude of bounds. Efficient shortcut for {@code getMin().lat()}.
|
---|
[6830] | 32 | *
|
---|
[6203] | 33 | * @return min latitude of bounds.
|
---|
| 34 | * @since 6203
|
---|
| 35 | */
|
---|
| 36 | public double getMinLat() {
|
---|
| 37 | return minLat;
|
---|
| 38 | }
|
---|
| 39 |
|
---|
| 40 | /**
|
---|
| 41 | * Returns min longitude of bounds. Efficient shortcut for {@code getMin().lon()}.
|
---|
[6830] | 42 | *
|
---|
[6203] | 43 | * @return min longitude of bounds.
|
---|
| 44 | * @since 6203
|
---|
| 45 | */
|
---|
| 46 | public double getMinLon() {
|
---|
| 47 | return minLon;
|
---|
| 48 | }
|
---|
| 49 |
|
---|
[2327] | 50 | public LatLon getMax() {
|
---|
[2805] | 51 | return new LatLon(maxLat, maxLon);
|
---|
[2327] | 52 | }
|
---|
[6069] | 53 |
|
---|
[6203] | 54 | /**
|
---|
| 55 | * Returns max latitude of bounds. Efficient shortcut for {@code getMax().lat()}.
|
---|
[6830] | 56 | *
|
---|
[6203] | 57 | * @return max latitude of bounds.
|
---|
| 58 | * @since 6203
|
---|
| 59 | */
|
---|
| 60 | public double getMaxLat() {
|
---|
| 61 | return maxLat;
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 | /**
|
---|
| 65 | * Returns max longitude of bounds. Efficient shortcut for {@code getMax().lon()}.
|
---|
[6830] | 66 | *
|
---|
[6203] | 67 | * @return max longitude of bounds.
|
---|
| 68 | * @since 6203
|
---|
| 69 | */
|
---|
| 70 | public double getMaxLon() {
|
---|
| 71 | return maxLon;
|
---|
| 72 | }
|
---|
| 73 |
|
---|
[4521] | 74 | public enum ParseMethod {
|
---|
| 75 | MINLAT_MINLON_MAXLAT_MAXLON,
|
---|
| 76 | LEFT_BOTTOM_RIGHT_TOP
|
---|
| 77 | }
|
---|
[6069] | 78 |
|
---|
[1169] | 79 | /**
|
---|
[6203] | 80 | * Construct bounds out of two points. Coords will be rounded.
|
---|
[1169] | 81 | */
|
---|
| 82 | public Bounds(LatLon min, LatLon max) {
|
---|
[2805] | 83 | this(min.lat(), min.lon(), max.lat(), max.lon());
|
---|
[1169] | 84 | }
|
---|
[71] | 85 |
|
---|
[5235] | 86 | public Bounds(LatLon min, LatLon max, boolean roundToOsmPrecision) {
|
---|
| 87 | this(min.lat(), min.lon(), max.lat(), max.lon(), roundToOsmPrecision);
|
---|
| 88 | }
|
---|
| 89 |
|
---|
[1724] | 90 | public Bounds(LatLon b) {
|
---|
[5235] | 91 | this(b, true);
|
---|
| 92 | }
|
---|
[6069] | 93 |
|
---|
[6203] | 94 | /**
|
---|
| 95 | * Single point Bounds defined by lat/lon {@code b}.
|
---|
| 96 | * Coordinates will be rounded to osm precision if {@code roundToOsmPrecision} is true.
|
---|
[6830] | 97 | *
|
---|
[6203] | 98 | * @param b lat/lon of given point.
|
---|
| 99 | * @param roundToOsmPrecision defines if lat/lon will be rounded.
|
---|
| 100 | */
|
---|
[5235] | 101 | public Bounds(LatLon b, boolean roundToOsmPrecision) {
|
---|
[6203] | 102 | this(b.lat(), b.lon(), roundToOsmPrecision);
|
---|
| 103 | }
|
---|
[6830] | 104 |
|
---|
[6203] | 105 | /**
|
---|
| 106 | * Single point Bounds defined by point [lat,lon].
|
---|
| 107 | * Coordinates will be rounded to osm precision if {@code roundToOsmPrecision} is true.
|
---|
[6830] | 108 | *
|
---|
[6203] | 109 | * @param lat latitude of given point.
|
---|
| 110 | * @param lon longitude of given point.
|
---|
| 111 | * @param roundToOsmPrecision defines if lat/lon will be rounded.
|
---|
| 112 | * @since 6203
|
---|
| 113 | */
|
---|
| 114 | public Bounds(double lat, double lon, boolean roundToOsmPrecision) {
|
---|
[4573] | 115 | // Do not call this(b, b) to avoid GPX performance issue (see #7028) until roundToOsmPrecision() is improved
|
---|
[5235] | 116 | if (roundToOsmPrecision) {
|
---|
[6203] | 117 | this.minLat = LatLon.roundToOsmPrecision(lat);
|
---|
| 118 | this.minLon = LatLon.roundToOsmPrecision(lon);
|
---|
[5235] | 119 | } else {
|
---|
[6203] | 120 | this.minLat = lat;
|
---|
| 121 | this.minLon = lon;
|
---|
[5235] | 122 | }
|
---|
[4573] | 123 | this.maxLat = this.minLat;
|
---|
| 124 | this.maxLon = this.minLon;
|
---|
[1724] | 125 | }
|
---|
[2456] | 126 |
|
---|
[2327] | 127 | public Bounds(double minlat, double minlon, double maxlat, double maxlon) {
|
---|
[5235] | 128 | this(minlat, minlon, maxlat, maxlon, true);
|
---|
[2327] | 129 | }
|
---|
[2456] | 130 |
|
---|
[5235] | 131 | public Bounds(double minlat, double minlon, double maxlat, double maxlon, boolean roundToOsmPrecision) {
|
---|
| 132 | if (roundToOsmPrecision) {
|
---|
| 133 | this.minLat = LatLon.roundToOsmPrecision(minlat);
|
---|
| 134 | this.minLon = LatLon.roundToOsmPrecision(minlon);
|
---|
| 135 | this.maxLat = LatLon.roundToOsmPrecision(maxlat);
|
---|
| 136 | this.maxLon = LatLon.roundToOsmPrecision(maxlon);
|
---|
| 137 | } else {
|
---|
| 138 | this.minLat = minlat;
|
---|
| 139 | this.minLon = minlon;
|
---|
| 140 | this.maxLat = maxlat;
|
---|
| 141 | this.maxLon = maxlon;
|
---|
| 142 | }
|
---|
| 143 | }
|
---|
| 144 |
|
---|
[8443] | 145 | public Bounds(double[] coords) {
|
---|
[5235] | 146 | this(coords, true);
|
---|
| 147 | }
|
---|
| 148 |
|
---|
[8443] | 149 | public Bounds(double[] coords, boolean roundToOsmPrecision) {
|
---|
[2845] | 150 | CheckParameterUtil.ensureParameterNotNull(coords, "coords");
|
---|
[2327] | 151 | if (coords.length != 4)
|
---|
[2845] | 152 | throw new IllegalArgumentException(MessageFormat.format("Expected array of length 4, got {0}", coords.length));
|
---|
[5235] | 153 | if (roundToOsmPrecision) {
|
---|
| 154 | this.minLat = LatLon.roundToOsmPrecision(coords[0]);
|
---|
| 155 | this.minLon = LatLon.roundToOsmPrecision(coords[1]);
|
---|
| 156 | this.maxLat = LatLon.roundToOsmPrecision(coords[2]);
|
---|
| 157 | this.maxLon = LatLon.roundToOsmPrecision(coords[3]);
|
---|
| 158 | } else {
|
---|
| 159 | this.minLat = coords[0];
|
---|
| 160 | this.minLon = coords[1];
|
---|
| 161 | this.maxLat = coords[2];
|
---|
| 162 | this.maxLon = coords[3];
|
---|
| 163 | }
|
---|
[2327] | 164 | }
|
---|
[2456] | 165 |
|
---|
[8291] | 166 | public Bounds(String asString, String separator) {
|
---|
[4521] | 167 | this(asString, separator, ParseMethod.MINLAT_MINLON_MAXLAT_MAXLON);
|
---|
| 168 | }
|
---|
| 169 |
|
---|
[8291] | 170 | public Bounds(String asString, String separator, ParseMethod parseMethod) {
|
---|
[5235] | 171 | this(asString, separator, parseMethod, true);
|
---|
| 172 | }
|
---|
| 173 |
|
---|
[8291] | 174 | public Bounds(String asString, String separator, ParseMethod parseMethod, boolean roundToOsmPrecision) {
|
---|
[2845] | 175 | CheckParameterUtil.ensureParameterNotNull(asString, "asString");
|
---|
[2327] | 176 | String[] components = asString.split(separator);
|
---|
[2456] | 177 | if (components.length != 4)
|
---|
[8509] | 178 | throw new IllegalArgumentException(
|
---|
| 179 | MessageFormat.format("Exactly four doubles expected in string, got {0}: {1}", components.length, asString));
|
---|
[2327] | 180 | double[] values = new double[4];
|
---|
[8510] | 181 | for (int i = 0; i < 4; i++) {
|
---|
[2327] | 182 | try {
|
---|
| 183 | values[i] = Double.parseDouble(components[i]);
|
---|
[8510] | 184 | } catch (NumberFormatException e) {
|
---|
[6798] | 185 | throw new IllegalArgumentException(MessageFormat.format("Illegal double value ''{0}''", components[i]), e);
|
---|
[2327] | 186 | }
|
---|
| 187 | }
|
---|
[6069] | 188 |
|
---|
[4521] | 189 | switch (parseMethod) {
|
---|
| 190 | case LEFT_BOTTOM_RIGHT_TOP:
|
---|
[5235] | 191 | this.minLat = initLat(values[1], roundToOsmPrecision);
|
---|
| 192 | this.minLon = initLon(values[0], roundToOsmPrecision);
|
---|
| 193 | this.maxLat = initLat(values[3], roundToOsmPrecision);
|
---|
| 194 | this.maxLon = initLon(values[2], roundToOsmPrecision);
|
---|
[4521] | 195 | break;
|
---|
| 196 | case MINLAT_MINLON_MAXLAT_MAXLON:
|
---|
| 197 | default:
|
---|
[5235] | 198 | this.minLat = initLat(values[0], roundToOsmPrecision);
|
---|
| 199 | this.minLon = initLon(values[1], roundToOsmPrecision);
|
---|
| 200 | this.maxLat = initLat(values[2], roundToOsmPrecision);
|
---|
| 201 | this.maxLon = initLon(values[3], roundToOsmPrecision);
|
---|
[4521] | 202 | }
|
---|
[4522] | 203 | }
|
---|
[6069] | 204 |
|
---|
[5235] | 205 | protected static double initLat(double value, boolean roundToOsmPrecision) {
|
---|
[4522] | 206 | if (!LatLon.isValidLat(value))
|
---|
| 207 | throw new IllegalArgumentException(tr("Illegal latitude value ''{0}''", value));
|
---|
[5235] | 208 | return roundToOsmPrecision ? LatLon.roundToOsmPrecision(value) : value;
|
---|
[4522] | 209 | }
|
---|
[2686] | 210 |
|
---|
[5235] | 211 | protected static double initLon(double value, boolean roundToOsmPrecision) {
|
---|
[4522] | 212 | if (!LatLon.isValidLon(value))
|
---|
| 213 | throw new IllegalArgumentException(tr("Illegal longitude value ''{0}''", value));
|
---|
[5235] | 214 | return roundToOsmPrecision ? LatLon.roundToOsmPrecision(value) : value;
|
---|
[2327] | 215 | }
|
---|
[2456] | 216 |
|
---|
[6203] | 217 | /**
|
---|
| 218 | * Creates new {@code Bounds} from an existing one.
|
---|
| 219 | * @param other The bounds to copy
|
---|
| 220 | */
|
---|
| 221 | public Bounds(final Bounds other) {
|
---|
| 222 | this(other.minLat, other.minLon, other.maxLat, other.maxLon);
|
---|
[2327] | 223 | }
|
---|
[1724] | 224 |
|
---|
[2327] | 225 | public Bounds(Rectangle2D rect) {
|
---|
[2805] | 226 | this(rect.getMinY(), rect.getMinX(), rect.getMaxY(), rect.getMaxX());
|
---|
[2327] | 227 | }
|
---|
[2456] | 228 |
|
---|
| 229 | /**
|
---|
| 230 | * Creates new bounds around a coordinate pair <code>center</code>. The
|
---|
| 231 | * new bounds shall have an extension in latitude direction of <code>latExtent</code>,
|
---|
| 232 | * and in longitude direction of <code>lonExtent</code>.
|
---|
[2512] | 233 | *
|
---|
[2456] | 234 | * @param center the center coordinate pair. Must not be null.
|
---|
[6830] | 235 | * @param latExtent the latitude extent. > 0 required.
|
---|
| 236 | * @param lonExtent the longitude extent. > 0 required.
|
---|
[8291] | 237 | * @throws IllegalArgumentException if center is null
|
---|
| 238 | * @throws IllegalArgumentException if latExtent <= 0
|
---|
| 239 | * @throws IllegalArgumentException if lonExtent <= 0
|
---|
[2456] | 240 | */
|
---|
| 241 | public Bounds(LatLon center, double latExtent, double lonExtent) {
|
---|
[2845] | 242 | CheckParameterUtil.ensureParameterNotNull(center, "center");
|
---|
[2456] | 243 | if (latExtent <= 0.0)
|
---|
[6830] | 244 | throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 expected, got {1}", "latExtent", latExtent));
|
---|
[2456] | 245 | if (lonExtent <= 0.0)
|
---|
[6830] | 246 | throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' > 0.0 expected, got {1}", "lonExtent", lonExtent));
|
---|
[2456] | 247 |
|
---|
[4580] | 248 | this.minLat = LatLon.roundToOsmPrecision(LatLon.toIntervalLat(center.lat() - latExtent / 2));
|
---|
| 249 | this.minLon = LatLon.roundToOsmPrecision(LatLon.toIntervalLon(center.lon() - lonExtent / 2));
|
---|
| 250 | this.maxLat = LatLon.roundToOsmPrecision(LatLon.toIntervalLat(center.lat() + latExtent / 2));
|
---|
| 251 | this.maxLon = LatLon.roundToOsmPrecision(LatLon.toIntervalLon(center.lon() + lonExtent / 2));
|
---|
[2456] | 252 | }
|
---|
| 253 |
|
---|
[6203] | 254 | /**
|
---|
| 255 | * Creates BBox with same coordinates.
|
---|
[6830] | 256 | *
|
---|
[6203] | 257 | * @return BBox with same coordinates.
|
---|
| 258 | * @since 6203
|
---|
| 259 | */
|
---|
| 260 | public BBox toBBox() {
|
---|
| 261 | return new BBox(minLon, minLat, maxLon, maxLat);
|
---|
| 262 | }
|
---|
[6830] | 263 |
|
---|
[8846] | 264 | @Override
|
---|
| 265 | public String toString() {
|
---|
| 266 | return "Bounds["+minLat+','+minLon+','+maxLat+','+maxLon+']';
|
---|
[1169] | 267 | }
|
---|
[746] | 268 |
|
---|
[2717] | 269 | public String toShortString(DecimalFormat format) {
|
---|
[8846] | 270 | return format.format(minLat) + ' '
|
---|
[2805] | 271 | + format.format(minLon) + " / "
|
---|
[8846] | 272 | + format.format(maxLat) + ' '
|
---|
[2805] | 273 | + format.format(maxLon);
|
---|
[2717] | 274 | }
|
---|
| 275 |
|
---|
[1169] | 276 | /**
|
---|
| 277 | * @return Center of the bounding box.
|
---|
| 278 | */
|
---|
[6509] | 279 | public LatLon getCenter() {
|
---|
[6830] | 280 | if (crosses180thMeridian()) {
|
---|
[6203] | 281 | double lat = (minLat + maxLat) / 2;
|
---|
| 282 | double lon = (minLon + maxLon - 360.0) / 2;
|
---|
[8510] | 283 | if (lon < -180.0) {
|
---|
[6203] | 284 | lon += 360.0;
|
---|
[4580] | 285 | }
|
---|
[6203] | 286 | return new LatLon(lat, lon);
|
---|
[4580] | 287 | } else {
|
---|
[6203] | 288 | return new LatLon((minLat + maxLat) / 2, (minLon + maxLon) / 2);
|
---|
[4580] | 289 | }
|
---|
[1169] | 290 | }
|
---|
| 291 |
|
---|
| 292 | /**
|
---|
| 293 | * Extend the bounds if necessary to include the given point.
|
---|
[6203] | 294 | * @param ll The point to include into these bounds
|
---|
[1169] | 295 | */
|
---|
| 296 | public void extend(LatLon ll) {
|
---|
[6203] | 297 | extend(ll.lat(), ll.lon());
|
---|
| 298 | }
|
---|
[6830] | 299 |
|
---|
[6203] | 300 | /**
|
---|
| 301 | * Extend the bounds if necessary to include the given point [lat,lon].
|
---|
| 302 | * Good to use if you know coordinates to avoid creation of LatLon object.
|
---|
| 303 | * @param lat Latitude of point to include into these bounds
|
---|
| 304 | * @param lon Longitude of point to include into these bounds
|
---|
| 305 | * @since 6203
|
---|
| 306 | */
|
---|
| 307 | public void extend(final double lat, final double lon) {
|
---|
| 308 | if (lat < minLat) {
|
---|
| 309 | minLat = LatLon.roundToOsmPrecision(lat);
|
---|
[2456] | 310 | }
|
---|
[6203] | 311 | if (lat > maxLat) {
|
---|
| 312 | maxLat = LatLon.roundToOsmPrecision(lat);
|
---|
[2805] | 313 | }
|
---|
[4580] | 314 | if (crosses180thMeridian()) {
|
---|
[6203] | 315 | if (lon > maxLon && lon < minLon) {
|
---|
| 316 | if (Math.abs(lon - minLon) <= Math.abs(lon - maxLon)) {
|
---|
| 317 | minLon = LatLon.roundToOsmPrecision(lon);
|
---|
[4580] | 318 | } else {
|
---|
[6203] | 319 | maxLon = LatLon.roundToOsmPrecision(lon);
|
---|
[4580] | 320 | }
|
---|
| 321 | }
|
---|
| 322 | } else {
|
---|
[6203] | 323 | if (lon < minLon) {
|
---|
| 324 | minLon = LatLon.roundToOsmPrecision(lon);
|
---|
[4580] | 325 | }
|
---|
[6203] | 326 | if (lon > maxLon) {
|
---|
| 327 | maxLon = LatLon.roundToOsmPrecision(lon);
|
---|
[4580] | 328 | }
|
---|
[2805] | 329 | }
|
---|
[1169] | 330 | }
|
---|
[2805] | 331 |
|
---|
| 332 | public void extend(Bounds b) {
|
---|
[6203] | 333 | extend(b.minLat, b.minLon);
|
---|
| 334 | extend(b.maxLat, b.maxLon);
|
---|
[2805] | 335 | }
|
---|
[6069] | 336 |
|
---|
[1169] | 337 | /**
|
---|
[6203] | 338 | * Determines if the given point {@code ll} is within these bounds.
|
---|
| 339 | * @param ll The lat/lon to check
|
---|
| 340 | * @return {@code true} if {@code ll} is within these bounds, {@code false} otherwise
|
---|
[1169] | 341 | */
|
---|
| 342 | public boolean contains(LatLon ll) {
|
---|
[4580] | 343 | if (ll.lat() < minLat || ll.lat() > maxLat)
|
---|
[1169] | 344 | return false;
|
---|
[4580] | 345 | if (crosses180thMeridian()) {
|
---|
| 346 | if (ll.lon() > maxLon && ll.lon() < minLon)
|
---|
| 347 | return false;
|
---|
| 348 | } else {
|
---|
| 349 | if (ll.lon() < minLon || ll.lon() > maxLon)
|
---|
| 350 | return false;
|
---|
| 351 | }
|
---|
[1169] | 352 | return true;
|
---|
| 353 | }
|
---|
[2943] | 354 |
|
---|
[4580] | 355 | private static boolean intersectsLonCrossing(Bounds crossing, Bounds notCrossing) {
|
---|
| 356 | return notCrossing.minLon <= crossing.maxLon || notCrossing.maxLon >= crossing.minLon;
|
---|
| 357 | }
|
---|
[6069] | 358 |
|
---|
[2941] | 359 | /**
|
---|
| 360 | * The two bounds intersect? Compared to java Shape.intersects, if does not use
|
---|
[6830] | 361 | * the interior but the closure. (">=" instead of ">")
|
---|
[2941] | 362 | */
|
---|
| 363 | public boolean intersects(Bounds b) {
|
---|
[4580] | 364 | if (b.maxLat < minLat || b.minLat > maxLat)
|
---|
| 365 | return false;
|
---|
[6069] | 366 |
|
---|
[4580] | 367 | if (crosses180thMeridian() && !b.crosses180thMeridian()) {
|
---|
| 368 | return intersectsLonCrossing(this, b);
|
---|
| 369 | } else if (!crosses180thMeridian() && b.crosses180thMeridian()) {
|
---|
| 370 | return intersectsLonCrossing(b, this);
|
---|
| 371 | } else if (crosses180thMeridian() && b.crosses180thMeridian()) {
|
---|
| 372 | return true;
|
---|
| 373 | } else {
|
---|
| 374 | return b.maxLon >= minLon && b.minLon <= maxLon;
|
---|
| 375 | }
|
---|
[2941] | 376 | }
|
---|
[1169] | 377 |
|
---|
| 378 | /**
|
---|
[4580] | 379 | * Determines if this Bounds object crosses the 180th Meridian.
|
---|
| 380 | * See http://wiki.openstreetmap.org/wiki/180th_meridian
|
---|
| 381 | * @return true if this Bounds object crosses the 180th Meridian.
|
---|
| 382 | */
|
---|
| 383 | public boolean crosses180thMeridian() {
|
---|
| 384 | return this.minLon > this.maxLon;
|
---|
| 385 | }
|
---|
[6069] | 386 |
|
---|
[4580] | 387 | /**
|
---|
[1169] | 388 | * Converts the lat/lon bounding box to an object of type Rectangle2D.Double
|
---|
| 389 | * @return the bounding box to Rectangle2D.Double
|
---|
| 390 | */
|
---|
| 391 | public Rectangle2D.Double asRect() {
|
---|
[4580] | 392 | double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
|
---|
| 393 | return new Rectangle2D.Double(minLon, minLat, w, maxLat-minLat);
|
---|
[1169] | 394 | }
|
---|
[2456] | 395 |
|
---|
[2327] | 396 | public double getArea() {
|
---|
[4580] | 397 | double w = maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
|
---|
| 398 | return w * (maxLat - minLat);
|
---|
[2327] | 399 | }
|
---|
[1169] | 400 |
|
---|
[2327] | 401 | public String encodeAsString(String separator) {
|
---|
[6822] | 402 | StringBuilder sb = new StringBuilder();
|
---|
[2805] | 403 | sb.append(minLat).append(separator).append(minLon)
|
---|
| 404 | .append(separator).append(maxLat).append(separator)
|
---|
| 405 | .append(maxLon);
|
---|
[2327] | 406 | return sb.toString();
|
---|
| 407 | }
|
---|
[2456] | 408 |
|
---|
[4087] | 409 | /**
|
---|
| 410 | * <p>Replies true, if this bounds are <em>collapsed</em>, i.e. if the min
|
---|
| 411 | * and the max corner are equal.</p>
|
---|
[6069] | 412 | *
|
---|
[4087] | 413 | * @return true, if this bounds are <em>collapsed</em>
|
---|
| 414 | */
|
---|
| 415 | public boolean isCollapsed() {
|
---|
[6830] | 416 | return Double.doubleToLongBits(minLat) == Double.doubleToLongBits(maxLat)
|
---|
[6204] | 417 | && Double.doubleToLongBits(minLon) == Double.doubleToLongBits(maxLon);
|
---|
[4087] | 418 | }
|
---|
| 419 |
|
---|
[4178] | 420 | public boolean isOutOfTheWorld() {
|
---|
| 421 | return
|
---|
| 422 | minLat < -90 || minLat > 90 ||
|
---|
| 423 | maxLat < -90 || maxLat > 90 ||
|
---|
| 424 | minLon < -180 || minLon > 180 ||
|
---|
| 425 | maxLon < -180 || maxLon > 180;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | public void normalize() {
|
---|
[4580] | 429 | minLat = LatLon.toIntervalLat(minLat);
|
---|
| 430 | maxLat = LatLon.toIntervalLat(maxLat);
|
---|
| 431 | minLon = LatLon.toIntervalLon(minLon);
|
---|
| 432 | maxLon = LatLon.toIntervalLon(maxLon);
|
---|
[4178] | 433 | }
|
---|
| 434 |
|
---|
[2327] | 435 | @Override
|
---|
| 436 | public int hashCode() {
|
---|
| 437 | final int prime = 31;
|
---|
| 438 | int result = 1;
|
---|
[2805] | 439 | long temp;
|
---|
| 440 | temp = Double.doubleToLongBits(maxLat);
|
---|
| 441 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 442 | temp = Double.doubleToLongBits(maxLon);
|
---|
| 443 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 444 | temp = Double.doubleToLongBits(minLat);
|
---|
| 445 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 446 | temp = Double.doubleToLongBits(minLon);
|
---|
| 447 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
[2327] | 448 | return result;
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 | @Override
|
---|
| 452 | public boolean equals(Object obj) {
|
---|
| 453 | if (this == obj)
|
---|
| 454 | return true;
|
---|
| 455 | if (obj == null)
|
---|
| 456 | return false;
|
---|
| 457 | if (getClass() != obj.getClass())
|
---|
| 458 | return false;
|
---|
| 459 | Bounds other = (Bounds) obj;
|
---|
[2805] | 460 | if (Double.doubleToLongBits(maxLat) != Double.doubleToLongBits(other.maxLat))
|
---|
[2327] | 461 | return false;
|
---|
[2805] | 462 | if (Double.doubleToLongBits(maxLon) != Double.doubleToLongBits(other.maxLon))
|
---|
[2327] | 463 | return false;
|
---|
[2805] | 464 | if (Double.doubleToLongBits(minLat) != Double.doubleToLongBits(other.minLat))
|
---|
| 465 | return false;
|
---|
| 466 | if (Double.doubleToLongBits(minLon) != Double.doubleToLongBits(other.minLon))
|
---|
| 467 | return false;
|
---|
[2327] | 468 | return true;
|
---|
| 469 | }
|
---|
[71] | 470 | }
|
---|