001: //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/trunk/src/org/deegree/model/spatialschema/EnvelopeImpl.java $
002: /*---------------- FILE HEADER ------------------------------------------
003:
004: This file is part of deegree.
005: Copyright (C) 2001-2008 by:
006: EXSE, Department of Geography, University of Bonn
007: http://www.giub.uni-bonn.de/deegree/
008: lat/lon GmbH
009: http://www.lat-lon.de
010:
011: This library is free software; you can redistribute it and/or
012: modify it under the terms of the GNU Lesser General Public
013: License as published by the Free Software Foundation; either
014: version 2.1 of the License, or (at your option) any later version.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: Contact:
026:
027: Andreas Poth
028: lat/lon GmbH
029: Aennchenstr. 19
030: 53177 Bonn
031: Germany
032: E-Mail: poth@lat-lon.de
033:
034: Prof. Dr. Klaus Greve
035: Department of Geography
036: University of Bonn
037: Meckenheimer Allee 166
038: 53115 Bonn
039: Germany
040: E-Mail: greve@giub.uni-bonn.de
041:
042:
043: ---------------------------------------------------------------------------*/
044: package org.deegree.model.spatialschema;
045:
046: import java.awt.geom.Rectangle2D;
047: import java.io.Serializable;
048:
049: import org.deegree.framework.log.ILogger;
050: import org.deegree.framework.log.LoggerFactory;
051: import org.deegree.model.crs.CoordinateSystem;
052:
053: /**
054: * a boundingbox as child of a Polygon isn't part of the iso19107 spec but it simplifies the
055: * geometry handling
056: *
057: * <P>
058: * ------------------------------------------------------------
059: * </P>
060: *
061: * @author Andreas Poth href="mailto:poth@lat-lon.de"
062: * @author Markus Bedel href="mailto:bedel@giub.uni-bonn.de"
063: * @version $Id: EnvelopeImpl.java 9343 2007-12-27 13:30:32Z apoth $
064: */
065: public class EnvelopeImpl implements Envelope, Serializable {
066:
067: private static final ILogger LOG = LoggerFactory
068: .getLogger(EnvelopeImpl.class);
069:
070: /** Use serialVersionUID for interoperability. */
071: private final static long serialVersionUID = 1081219767894344990L;
072:
073: protected Position max = null;
074:
075: protected Position min = null;
076:
077: protected CoordinateSystem crs = null;
078:
079: /**
080: * Creates a new EnvelopeImpl object.
081: */
082: protected EnvelopeImpl() {
083: this .min = new PositionImpl();
084: this .max = new PositionImpl();
085: }
086:
087: /**
088: * Creates a new EnvelopeImpl object.
089: *
090: * @param min
091: * @param max
092: */
093: protected EnvelopeImpl(Position min, Position max) {
094: this .min = min;
095: this .max = max;
096: }
097:
098: /**
099: * Creates a new EnvelopeImpl object.
100: *
101: * @param min
102: * @param max
103: * @param crs
104: */
105: protected EnvelopeImpl(Position min, Position max,
106: CoordinateSystem crs) {
107: this .min = min;
108: this .max = max;
109: this .crs = crs;
110: }
111:
112: /**
113: *
114: *
115: * @return a shallow copy of this Envelope
116: */
117: @Override
118: public Object clone() {
119: return new EnvelopeImpl(
120: (Position) ((PositionImpl) min).clone(),
121: (Position) ((PositionImpl) max).clone(), this .crs);
122: }
123:
124: /**
125: * returns the spatial reference system of a geometry
126: */
127: public CoordinateSystem getCoordinateSystem() {
128: return crs;
129: }
130:
131: /**
132: * returns the minimum coordinates of bounding box
133: */
134: public Position getMin() {
135: return min;
136: }
137:
138: /**
139: * returns the maximum coordinates of bounding box
140: */
141: public Position getMax() {
142: return max;
143: }
144:
145: /**
146: * returns the width of bounding box
147: */
148: public double getWidth() {
149: return this .getMax().getX() - this .getMin().getX();
150: }
151:
152: /**
153: * returns the height of bounding box
154: */
155: public double getHeight() {
156: return this .getMax().getY() - this .getMin().getY();
157: }
158:
159: /**
160: * returns true if the bounding box conatins the specified Point
161: */
162: public boolean contains(Position point) {
163: if ((point.getX() >= min.getX())
164: && (point.getX() <= max.getX())
165: && (point.getY() >= min.getY())
166: && (point.getY() <= max.getY())) {
167: return true;
168: }
169:
170: return false;
171: }
172:
173: /**
174: * returns true if this envelope and the submitted intersects
175: */
176: public boolean intersects(Envelope bb) {
177: // coordinates of this Envelope's BBOX
178: double west1 = min.getX();
179: double south1 = min.getY();
180: double east1 = max.getX();
181: double north1 = max.getY();
182:
183: // coordinates of the other Envelope's BBOX
184: double west2 = bb.getMin().getX();
185: double south2 = bb.getMin().getY();
186: double east2 = bb.getMax().getX();
187: double north2 = bb.getMax().getY();
188:
189: // special cases: one box lays completly inside the other one
190: if ((west1 <= west2) && (south1 <= south2) && (east1 >= east2)
191: && (north1 >= north2)) {
192: return true;
193: }
194:
195: if ((west1 >= west2) && (south1 >= south2) && (east1 <= east2)
196: && (north1 <= north2)) {
197: return true;
198: }
199:
200: // in any other case of intersection, at least one line of the BBOX has
201: // to cross a line of the other BBOX
202: // check western boundary of box 1
203: // "touching" boxes must not intersect
204: if ((west1 >= west2) && (west1 < east2)) {
205: if ((south1 <= south2) && (north1 > south2)) {
206: return true;
207: }
208:
209: if ((south1 < north2) && (north1 >= north2)) {
210: return true;
211: }
212: }
213:
214: // check eastern boundary of box 1
215: // "touching" boxes must not intersect
216: if ((east1 > west2) && (east1 <= east2)) {
217: if ((south1 <= south2) && (north1 > south2)) {
218: return true;
219: }
220:
221: if ((south1 < north2) && (north1 >= north2)) {
222: return true;
223: }
224: }
225:
226: // check southern boundary of box 1
227: // "touching" boxes must not intersect
228: if ((south1 >= south2) && (south1 < north2)) {
229: if ((west1 <= west2) && (east1 > west2)) {
230: return true;
231: }
232:
233: if ((west1 < east2) && (east1 >= east2)) {
234: return true;
235: }
236: }
237:
238: // check northern boundary of box 1
239: // "touching" boxes must not intersect
240: if ((north1 > south2) && (north1 <= north2)) {
241: if ((west1 <= west2) && (east1 > west2)) {
242: return true;
243: }
244:
245: if ((west1 < east2) && (east1 >= east2)) {
246: return true;
247: }
248: }
249:
250: return false;
251: }
252:
253: /**
254: * returns true if all points of the submitted bounding box are within this bounding box
255: */
256: public boolean contains(Envelope bb) {
257: Position p1 = new PositionImpl(bb.getMin().getX(), bb.getMin()
258: .getY());
259: Position p2 = new PositionImpl(bb.getMin().getX(), bb.getMax()
260: .getY());
261: Position p3 = new PositionImpl(bb.getMax().getX(), bb.getMin()
262: .getY());
263: Position p4 = new PositionImpl(bb.getMax().getX(), bb.getMax()
264: .getY());
265:
266: boolean ins = (this .contains(p1) && this .contains(p2)
267: && this .contains(p3) && this .contains(p4));
268: return ins;
269: }
270:
271: /**
272: * returns a new Envelope object representing the intersection of this Envelope with the
273: * specified Envelope. * Note: If there is no intersection at all Envelope will be null.
274: *
275: * @param bb
276: * the Envelope to be intersected with this Envelope
277: * @return the largest Envelope contained in both the specified Envelope and in this Envelope.
278: */
279: public Envelope createIntersection(Envelope bb) {
280: Rectangle2D rect = new Rectangle2D.Double(bb.getMin().getX(),
281: bb.getMin().getY(), bb.getWidth(), bb.getHeight());
282: Rectangle2D rect2 = new Rectangle2D.Double(
283: this .getMin().getX(), this .getMin().getY(), this
284: .getWidth(), this .getHeight());
285:
286: if (rect2.intersects(bb.getMin().getX(), bb.getMin().getY(), bb
287: .getWidth(), bb.getHeight())) {
288: rect = rect.createIntersection(rect2);
289: } else {
290: rect = null;
291: }
292:
293: if (rect == null) {
294: return null;
295: }
296:
297: double xmin = rect.getX();
298: double ymin = rect.getY();
299: double xmax = rect.getX() + rect.getWidth();
300: double ymax = rect.getY() + rect.getHeight();
301:
302: Position p1 = new PositionImpl(xmin, ymin);
303: Position p2 = new PositionImpl(xmax, ymax);
304:
305: return new EnvelopeImpl(p1, p2, this .crs);
306: }
307:
308: /**
309: * checks if this point is completly equal to the submitted geometry
310: */
311: @Override
312: public boolean equals(Object other) {
313: if ((other == null) || !(other instanceof EnvelopeImpl)) {
314: return false;
315: }
316: Envelope envelope = (Envelope) other;
317: if ((envelope.getCoordinateSystem() == null && getCoordinateSystem() != null)
318: || (envelope.getCoordinateSystem() != null && getCoordinateSystem() == null)
319: || (getCoordinateSystem() != null && !getCoordinateSystem()
320: .equals(envelope.getCoordinateSystem()))) {
321: return false;
322: }
323:
324: return (min.equals(((Envelope) other).getMin()) && max
325: .equals(((Envelope) other).getMax()));
326: }
327:
328: public Envelope getBuffer(double b) {
329: Position bmin = new PositionImpl(new double[] { min.getX() - b,
330: min.getY() - b });
331: Position bmax = new PositionImpl(new double[] { max.getX() + b,
332: max.getY() + b });
333: return GeometryFactory.createEnvelope(bmin, bmax,
334: getCoordinateSystem());
335: }
336:
337: /**
338: * @see org.deegree.model.spatialschema.Envelope#merge(org.deegree.model.spatialschema.Envelope)
339: */
340: public Envelope merge(Envelope envelope) throws GeometryException {
341:
342: CoordinateSystem crs1 = this .getCoordinateSystem();
343: CoordinateSystem crs2 = envelope.getCoordinateSystem();
344:
345: LOG.logDebug("Merging envelopes with " + crs1 + " => " + crs2);
346:
347: if ((crs1 == null && crs2 != null)
348: || (crs1 != null && crs2 == null)
349: || (crs1 != null && !crs1.equals(crs2))) {
350: String crs1Name = null;
351: String crs2Name = null;
352: if (crs1 != null) {
353: crs1Name = crs1.getName();
354: }
355: if (crs2 != null) {
356: crs2Name = crs2.getName();
357: }
358: throw new GeometryException(
359: "Cannot merge envelopes with different CRS ("
360: + crs1Name + "/" + crs2Name + ")!");
361: }
362: double minx = min.getX();
363: double miny = min.getY();
364: double minz = min.getZ();
365: double maxx = max.getX();
366: double maxy = max.getY();
367: double maxz = max.getZ();
368:
369: if (envelope != null) {
370: if (envelope.getMin().getX() < minx) {
371: minx = envelope.getMin().getX();
372: }
373: if (envelope.getMin().getY() < miny) {
374: miny = envelope.getMin().getY();
375: }
376: if (envelope.getMax().getX() > maxx) {
377: maxx = envelope.getMax().getX();
378: }
379: if (envelope.getMax().getY() > maxy) {
380: maxy = envelope.getMax().getY();
381: }
382: if (!Double.isNaN(maxz)
383: && !Double.isNaN(envelope.getMax().getZ())) {
384: if (envelope.getMax().getZ() > maxz) {
385: maxz = envelope.getMax().getZ();
386: }
387: } else if (Double.isNaN(maxz)) {
388: maxz = envelope.getMax().getZ();
389: }
390: if (!Double.isNaN(minz)
391: && !Double.isNaN(envelope.getMin().getZ())) {
392: if (envelope.getMin().getZ() < minz) {
393: minz = envelope.getMin().getZ();
394: }
395: } else if (Double.isNaN(minz)) {
396: minz = envelope.getMin().getZ();
397: }
398:
399: }
400: Position minPos = GeometryFactory.createPosition(minx, miny,
401: minz);
402: Position maxPos = GeometryFactory.createPosition(maxx, maxy,
403: maxz);
404: return GeometryFactory.createEnvelope(minPos, maxPos, this
405: .getCoordinateSystem());
406: }
407:
408: /**
409: * ensures that the passed Envepole is contained within this.Envelope
410: *
411: * @param other
412: */
413: public void expandToContain(Envelope other) {
414: double minx = min.getX();
415: double miny = min.getY();
416: double maxx = max.getX();
417: double maxy = max.getY();
418: if (other.getMin().getX() < minx) {
419: minx = other.getMin().getX();
420: }
421: if (other.getMax().getX() > maxx) {
422: maxx = other.getMax().getX();
423: }
424: if (other.getMin().getY() < miny) {
425: miny = other.getMin().getY();
426: }
427: if (other.getMax().getY() > maxy) {
428: maxy = other.getMax().getY();
429: }
430: min = new PositionImpl(minx, miny);
431: max = new PositionImpl(maxx, maxy);
432: }
433:
434: /**
435: * translate a envelope in the direction defined by the two passed values and retiurns the
436: * resulting envelope
437: *
438: * @param x
439: * @param y
440: */
441: public Envelope translate(double x, double y) {
442: min = new PositionImpl(this .getMin().getX() + x, this .getMin()
443: .getY()
444: + y);
445: max = new PositionImpl(this .getMax().getX() + x, this .getMax()
446: .getY()
447: + y);
448: return new EnvelopeImpl(min, max, this .crs);
449: }
450:
451: /**
452: * returns the centroid of an Envelope
453: *
454: * @return centroid of an Envelope
455: */
456: public Point getCentroid() {
457:
458: double x = min.getX() + (max.getX() - min.getX()) / 2d;
459: double y = min.getY() + (max.getY() - min.getY()) / 2d;
460: double z = 0;
461: Point point = null;
462: if (min.getCoordinateDimension() == 3) {
463: z = min.getZ() + (max.getZ() - min.getZ()) / 2d;
464: point = new PointImpl(x, y, z, crs);
465: } else {
466: point = new PointImpl(x, y, crs);
467: }
468:
469: return point;
470: }
471:
472: @Override
473: public String toString() {
474: String ret = "min = " + min;
475: ret += (" max = " + max);
476: return ret;
477: }
478:
479: }
|