/*---------------- FILE HEADER ------------------------------------------
This file is part of deegree.
Copyright (C) 2001-2006 by:
EXSE, Department of Geography, University of Bonn
http://www.giub.uni-bonn.de/deegree/
lat/lon GmbH
http://www.lat-lon.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact:
Andreas Poth
lat/lon GmbH
Aennchenstr. 19
53177 Bonn
Germany
E-Mail: poth@lat-lon.de
Prof. Dr. Klaus Greve
Department of Geography
University of Bonn
Meckenheimer Allee 166
53115 Bonn
Germany
E-Mail: greve@giub.uni-bonn.de
---------------------------------------------------------------------------*/
package org.deegree.model.spatialschema;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
import org.deegree.model.crs.CoordinateSystem;
/**
* a boundingbox as child of a Polygon isn't part
* of the iso19107 spec but it simplifies the geometry handling
*
* <P>------------------------------------------------------------</P>
* @author Andreas Poth href="mailto:poth@lat-lon.de"
* @author Markus Bedel href="mailto:bedel@giub.uni-bonn.de"
* @version $Id: EnvelopeImpl.java,v 1.15 2006/12/04 17:05:44 bezema Exp $
*/
public class EnvelopeImpl implements Envelope, Serializable {
/** Use serialVersionUID for interoperability. */
private final static long serialVersionUID = 1081219767894344990L;
protected Position max = null;
protected Position min = null;
protected CoordinateSystem crs = null;
/**
* Creates a new EnvelopeImpl object.
*/
protected EnvelopeImpl() {
this.min = new PositionImpl();
this.max = new PositionImpl();
}
/**
* Creates a new EnvelopeImpl object.
*
* @param min
* @param max
*/
protected EnvelopeImpl( Position min, Position max ) {
this.min = min;
this.max = max;
}
/**
* Creates a new EnvelopeImpl object.
*
* @param min
* @param max
* @param crs
*/
protected EnvelopeImpl( Position min, Position max, CoordinateSystem crs ) {
this.min = min;
this.max = max;
this.crs = crs;
}
/**
*
*
* @return a shallow copy of this Envelope
*/
@Override
public Object clone() {
return new EnvelopeImpl( (Position) ( (PositionImpl) min ).clone(),
(Position) ( (PositionImpl) max ).clone(), this.crs );
}
/**
* returns the spatial reference system of a geometry
*/
public CoordinateSystem getCoordinateSystem() {
return crs;
}
/**
* returns the minimum coordinates of bounding box
*/
public Position getMin() {
return min;
}
/**
* returns the maximum coordinates of bounding box
*/
public Position getMax() {
return max;
}
/**
* returns the width of bounding box
*/
public double getWidth() {
return this.getMax().getX() - this.getMin().getX();
}
/**
* returns the height of bounding box
*/
public double getHeight() {
return this.getMax().getY() - this.getMin().getY();
}
/**
* returns true if the bounding box conatins the specified Point
*/
public boolean contains( Position point ) {
if ( ( point.getX() >= min.getX() ) && ( point.getX() <= max.getX() )
&& ( point.getY() >= min.getY() ) && ( point.getY() <= max.getY() ) ) {
return true;
}
return false;
}
/**
* returns true if this envelope and the submitted intersects
*/
public boolean intersects( Envelope bb ) {
// coordinates of this Envelope's BBOX
double west1 = min.getX();
double south1 = min.getY();
double east1 = max.getX();
double north1 = max.getY();
// coordinates of the other Envelope's BBOX
double west2 = bb.getMin().getX();
double south2 = bb.getMin().getY();
double east2 = bb.getMax().getX();
double north2 = bb.getMax().getY();
// special cases: one box lays completly inside the other one
if ( ( west1 <= west2 ) && ( south1 <= south2 ) && ( east1 >= east2 )
&& ( north1 >= north2 ) ) {
return true;
}
if ( ( west1 >= west2 ) && ( south1 >= south2 ) && ( east1 <= east2 )
&& ( north1 <= north2 ) ) {
return true;
}
// in any other case of intersection, at least one line of the BBOX has
// to cross a line of the other BBOX
// check western boundary of box 1
// "touching" boxes must not intersect
if ( ( west1 >= west2 ) && ( west1 < east2 ) ) {
if ( ( south1 <= south2 ) && ( north1 > south2 ) ) {
return true;
}
if ( ( south1 < north2 ) && ( north1 >= north2 ) ) {
return true;
}
}
// check eastern boundary of box 1
// "touching" boxes must not intersect
if ( ( east1 > west2 ) && ( east1 <= east2 ) ) {
if ( ( south1 <= south2 ) && ( north1 > south2 ) ) {
return true;
}
if ( ( south1 < north2 ) && ( north1 >= north2 ) ) {
return true;
}
}
// check southern boundary of box 1
// "touching" boxes must not intersect
if ( ( south1 >= south2 ) && ( south1 < north2 ) ) {
if ( ( west1 <= west2 ) && ( east1 > west2 ) ) {
return true;
}
if ( ( west1 < east2 ) && ( east1 >= east2 ) ) {
return true;
}
}
// check northern boundary of box 1
// "touching" boxes must not intersect
if ( ( north1 > south2 ) && ( north1 <= north2 ) ) {
if ( ( west1 <= west2 ) && ( east1 > west2 ) ) {
return true;
}
if ( ( west1 < east2 ) && ( east1 >= east2 ) ) {
return true;
}
}
return false;
}
/**
* returns true if all points of the submitted
* bounding box are within this bounding box
*/
public boolean contains( Envelope bb ) {
Position p1 = new PositionImpl( bb.getMin().getX(), bb.getMin().getY() );
Position p2 = new PositionImpl( bb.getMin().getX(), bb.getMax().getY() );
Position p3 = new PositionImpl( bb.getMax().getX(), bb.getMin().getY() );
Position p4 = new PositionImpl( bb.getMax().getX(), bb.getMax().getY() );
boolean ins = ( this.contains( p1 ) && this.contains( p2 ) && this.contains( p3 ) && this.contains( p4 ) );
return ins;
}
/**
* returns a new Envelope object representing the intersection of this
* Envelope with the specified Envelope. * Note: If there is no
* intersection at all Envelope will be null.
* @param bb the Envelope to be intersected with this Envelope
* @return the largest Envelope contained in both the specified Envelope
* and in this Envelope.
*/
public Envelope createIntersection( Envelope bb ) {
Rectangle2D rect = new Rectangle2D.Double( bb.getMin().getX(), bb.getMin().getY(),
bb.getWidth(), bb.getHeight() );
Rectangle2D rect2 = new Rectangle2D.Double( this.getMin().getX(), this.getMin().getY(),
this.getWidth(), this.getHeight() );
if ( rect2.intersects( bb.getMin().getX(), bb.getMin().getY(), bb.getWidth(),
bb.getHeight() ) ) {
rect = rect.createIntersection( rect2 );
} else {
rect = null;
}
if ( rect == null ) {
return null;
}
double xmin = rect.getX();
double ymin = rect.getY();
double xmax = rect.getX() + rect.getWidth();
double ymax = rect.getY() + rect.getHeight();
Position p1 = new PositionImpl( xmin, ymin );
Position p2 = new PositionImpl( xmax, ymax );
return new EnvelopeImpl( p1, p2, this.crs );
}
/**
* checks if this point is completly equal to the submitted geometry
*/
@Override
public boolean equals( Object other ) {
if ( ( other == null ) || !( other instanceof EnvelopeImpl ) ) {
return false;
}
Envelope envelope = (Envelope) other;
if ( ( envelope.getCoordinateSystem() == null && getCoordinateSystem() != null )
|| ( envelope.getCoordinateSystem() != null && getCoordinateSystem() == null )
|| ( getCoordinateSystem() != null && !getCoordinateSystem().equals(
envelope.getCoordinateSystem() ) ) ) {
return false;
}
return ( min.equals( ( (Envelope) other ).getMin() ) && max.equals( ( (Envelope) other ).getMax() ) );
}
public Envelope getBuffer( double b ) {
Position bmin = new PositionImpl( new double[] { min.getX() - b, min.getY() - b } );
Position bmax = new PositionImpl( new double[] { max.getX() + b, max.getY() + b } );
return GeometryFactory.createEnvelope( bmin, bmax, getCoordinateSystem() );
}
/**
* @see org.deegree.model.spatialschema.Envelope#merge(org.deegree.model.spatialschema.Envelope)
*/
public Envelope merge( Envelope envelope )
throws GeometryException {
CoordinateSystem crs1 = this.getCoordinateSystem();
CoordinateSystem crs2 = envelope.getCoordinateSystem();
if ( ( crs1 == null && crs2 != null ) || ( crs1 != null && crs2 == null )
|| ( crs1 != null && !crs1.equals( crs2 ) ) ) {
String crs1Name = null;
String crs2Name = null;
if ( crs1 != null ) {
crs1Name = crs1.getName();
}
if ( crs2 != null ) {
crs2Name = crs2.getName();
}
throw new GeometryException( "Cannot merge envelopes with different CRS (" + crs1Name
+ "/" + crs2Name + ")!" );
}
double minx = min.getX();
double miny = min.getY();
double minz = min.getZ();
double maxx = max.getX();
double maxy = max.getY();
double maxz = max.getZ();
if ( envelope != null ) {
if ( envelope.getMin().getX() < minx ) {
minx = envelope.getMin().getX();
}
if ( envelope.getMin().getY() < miny ) {
miny = envelope.getMin().getY();
}
if ( envelope.getMax().getX() > maxx ) {
maxx = envelope.getMax().getX();
}
if ( envelope.getMax().getY() > maxy ) {
maxy = envelope.getMax().getY();
}
if( !Double.isNaN( maxz ) && !Double.isNaN( envelope.getMax().getZ() ) ){
if ( envelope.getMax().getZ() > maxz ) {
maxz = envelope.getMax().getZ();
}
} else if( Double.isNaN( maxz ) ){
maxz = envelope.getMax().getZ();
}
if( !Double.isNaN( minz ) && !Double.isNaN( envelope.getMin().getZ() ) ){
if ( envelope.getMin().getZ() < minz ) {
minz = envelope.getMin().getZ();
}
} else if( Double.isNaN( minz ) ){
minz = envelope.getMin().getZ();
}
}
Position minPos = GeometryFactory.createPosition( minx, miny, minz );
Position maxPos = GeometryFactory.createPosition( maxx, maxy, maxz );
return GeometryFactory.createEnvelope( minPos, maxPos, this.getCoordinateSystem() );
}
/**
* ensures that the passed Envepole is contained within this.Envelope
* @param other
*/
public void expandToContain( Envelope other ) {
double minx = min.getX();
double miny = min.getY();
double maxx = max.getX();
double maxy = max.getY();
if ( other.getMin().getX() < minx ) {
minx = other.getMin().getX();
}
if ( other.getMax().getX() > maxx ) {
maxx = other.getMax().getX();
}
if ( other.getMin().getY() < miny ) {
miny = other.getMin().getY();
}
if ( other.getMax().getY() > maxy ) {
maxy = other.getMax().getY();
}
min = new PositionImpl( minx, miny );
max = new PositionImpl( maxx, maxy );
}
/**
* translate a envelope in the direction defined by the two passed
* values and retiurns the resulting envelope
* @param x
* @param y
*/
public Envelope translate( double x, double y ) {
min = new PositionImpl( this.getMin().getX() + x, this.getMin().getY() + y );
max = new PositionImpl( this.getMax().getX() + x, this.getMax().getY() + y );
return new EnvelopeImpl( min, max, this.crs );
}
@Override
public String toString() {
String ret = "min = " + min;
ret += ( " max = " + max );
return ret;
}
}
/*
* Changes to this class. What the people haven been up to:
*
* $Log: EnvelopeImpl.java,v $
* Revision 1.15 2006/12/04 17:05:44 bezema
* removed _
*
* Revision 1.14 2006/12/04 17:02:13 bezema
* removed the null statement
*
* Revision 1.13 2006/11/23 09:13:02 bezema
* Made the merge operetion 3d compatible
*
* Revision 1.12 2006/11/02 10:20:17 mschneider
* Fixed #merge(Envelope). Changed visibility of constructors to package protected.
*
* Revision 1.11 2006/10/31 13:57:42 mschneider
* Improved error message when merging envelopes that use different CRS.
*
* Revision 1.10 2006/09/18 14:11:09 bezema
* added annotations and javadoc
*
* Revision 1.9 2006/07/05 12:57:05 poth
* toString method corrected (line break removed)
*
* Revision 1.8 2006/05/31 12:59:36 poth
* translate method added
*
* Revision 1.7 2006/05/01 20:15:25 poth
* *** empty log message ***
*
* Revision 1.6 2006/04/06 20:25:22 poth
* *** empty log message ***
*
* Revision 1.5 2006/04/04 20:39:41 poth
* *** empty log message ***
*
* Revision 1.4 2006/03/30 21:20:23 poth
* *** empty log message ***
*
* Revision 1.3 2005/10/23 20:53:56 poth
* no message
*
* Revision 1.2 2005/01/18 22:08:54 poth
* no message
*
* Revision 1.3 2004/09/01 08:06:03 ap
* no message
*
* Revision 1.2 2004/08/12 10:39:32 ap
* no message
*
* Revision 1.1 2004/06/28 06:39:46 ap
* no message
*
* Revision 1.1 2004/05/24 07:05:33 ap
* no message
*
* Revision 1.13 2004/03/02 07:38:14 poth
* no message
*
* Revision 1.12 2004/02/23 07:47:50 poth
* no message
*
* Revision 1.11 2004/01/27 07:55:44 poth
* no message
*
* Revision 1.10 2004/01/08 09:50:22 poth
* no message
*
* Revision 1.9 2003/09/14 14:05:08 poth
* no message
*
* Revision 1.8 2003/07/10 15:24:23 mrsnyder
* Started to implement LabelDisplayElements that are bound to a Polygon.
* Fixed error in MultiSurfaceImpl.calculateCentroidArea().
*
* Revision 1.7 2003/07/03 12:32:26 poth
* no message
*
* Revision 1.6 2003/03/20 12:10:29 mrsnyder
* Rewrote intersects() method.
*
* Revision 1.5 2003/03/19 15:30:04 axel_schaefer
* Intersects: crossing envelopes, but points are not in envelope
*
*
*/