/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2006-2008, Open Source Geospatial Foundation (OSGeo)
*
* 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotools.geometry.iso.coordinate;
import java.io.Serializable;
import org.geotools.geometry.iso.DimensionModel;
import org.geotools.geometry.iso.UnsupportedDimensionException;
import org.geotools.geometry.iso.util.algorithmND.AlgoRectangleND;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.PositionFactory;
import org.opengis.geometry.coordinate.Position;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
* An envlope represents the bounding box of a geometric object.
* Regardless to the dimension, the envelope can be encoded by two <code>DirectPosition</code>s.
*
* @source $URL$
*/
public class EnvelopeImpl implements Envelope, Serializable {
private static final long serialVersionUID = -6397319034308589090L;
static final int X = 0;
static final int Y = 1;
static final int Z = 2;
// protected DirectPositionImpl pMin = null; // Lower Corner (Left bottom)
private DirectPosition pMin = null; // Lower Corner (Left bottom)
// protected DirectPositionImpl pMax = null; // Upper Corner (Right top)
private DirectPosition pMax = null; // Upper Corner (Right top)
/** Used to create Envelope on request */
private PositionFactory factory;
/**
* Constructor
*
* @param env
*/
public EnvelopeImpl(Envelope env) {
pMin = new DirectPositionImpl(env.getLowerCorner());
pMax = new DirectPositionImpl(env.getUpperCorner());
}
/**
* Constructor
*
* @param p0
* @param p1
*/
public EnvelopeImpl(DirectPosition p0, DirectPosition p1) {
this.setValues(p0, p1);
}
/**
* @param p0
*/
public EnvelopeImpl(Position position) {
this( position.getPosition() );
}
/**
* @param p0
*/
public EnvelopeImpl(DirectPosition position) {
this.pMin = new DirectPositionImpl(position);
this.pMax = new DirectPositionImpl(position);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getDimension()
*/
public int getDimension() {
// TODO semantic JR
// The coordinate dimension of the envelope is the same as the
// coordinate dimension of one of his points
return this.pMin.getDimension();
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getCoordinateReferenceSystem()
*/
public CoordinateReferenceSystem getCoordinateReferenceSystem() {
return pMin.getCoordinateReferenceSystem();
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getMinimum(int)
*/
public double getMinimum(int dimension) {
// TODO semantic JR, SJ Was soll diese Methode bewirken? Ich verstehe die JavaDoc nicht ganz.
// TODO implementation
// TODO test
// TODO documentation
// Return zero, which is the lowest index the coordinate could have
return pMin.getOrdinate(dimension);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getMaximum(int)
*/
public double getMaximum(int dimension) {
// TODO semantic JR, SJ Was soll diese Methode bewirken? Ich verstehe die JavaDoc nicht ganz.
// TODO implementation
// TODO test
// TODO documentation
// Return the coordinate dimension minus 1
//return this.pMin.getDimension() - 1;
return pMax.getOrdinate(dimension);
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getCenter(int)
*/
public double getCenter(int dimension) {
return (pMax.getOrdinate(dimension)-pMin.getOrdinate(dimension))/2;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getMedian(int)
*/
public double getMedian(int dimension) {
return (pMax.getOrdinate(dimension)-pMin.getOrdinate(dimension))/2;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getLength(int)
*/
public double getLength(int dimension) {
return (pMax.getOrdinate(dimension)-pMin.getOrdinate(dimension));
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getSpan(int)
*/
public double getSpan(int dimension) {
return (pMax.getOrdinate(dimension)-pMin.getOrdinate(dimension));
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getUpperCorner()
*/
public DirectPosition getUpperCorner() {
// Return the upper corner of the envelope
return this.pMax;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.Envelope#getLowerCorner()
*/
public DirectPosition getLowerCorner() {
// Return the lower corner of the envelope
return this.pMin;
}
/**
* @param p0
* @param p1
*/
public void setValues(DirectPosition p0, DirectPosition p1) {
if (p0 == null || p1 == null || p0.getDimension() != p1.getDimension())
throw new IllegalArgumentException("Error 1 on setValues"); //$NON-NLS-1$
CoordinateReferenceSystem crs = p0.getCoordinateReferenceSystem();
double[] min = p0.getCoordinates();
double[] max = p1.getCoordinates();
// Check wheater all Min values are smaller than max values
for (int i = 0, n = p0.getDimension(); i < n; ++i) {
if (min[i] > max[i]) {
double tmp = min[i];
min[i] = max[i];
max[i] = tmp;
}
}
this.pMin = new DirectPositionImpl( crs, min);
this.pMax = new DirectPositionImpl( crs, max);
}
/**
* @param env
*/
public void setValues(EnvelopeImpl env) {
this.pMin = new DirectPositionImpl(env.getLowerCorner());
this.pMax = new DirectPositionImpl(env.getUpperCorner());
}
/**
* @param p
* @return EnvelopeImpl
*/
public static EnvelopeImpl createEnvelope(DirectPosition[] p) {
if (p.length == 0){
return null;
}
EnvelopeImpl result = new EnvelopeImpl(p[0]);
for (int i = 1; i < p.length; ++i) {
if (p[i] != null){
result.add(p[i]);
}
}
return result;
}
/**
* Unions an envelope with an another envelope
*
* @param env
*/
public void expand(Envelope env) {
this.expand(env.getLowerCorner().getCoordinates());
this.expand(env.getUpperCorner().getCoordinates());
}
/**
* Expands the envelope with a direct Position
*
* @param coord
*/
public void expand(double coord[]) {
int n = Math.min(this.getDimension(), coord.length);
double min[] = this.pMin.getCoordinates();
double max[] = this.pMax.getCoordinates();
for (int i = 0; i < n; ++i) {
if (coord[i] < min[i])
this.pMin.setOrdinate(i, coord[i]);
if (coord[i] > max[i])
this.pMax.setOrdinate(i, coord[i]);
}
}
public String toString() {
return "[Envelope: " + this.getLowerCorner() + " - " //$NON-NLS-1$//$NON-NLS-2$
+ this.getUpperCorner() + "]"; //$NON-NLS-1$
}
/**
* @param coord
*/
public void add(double[] coord) {
assert (coord.length == this.getDimension());
double[] minCoord = this.pMin.getCoordinates();
double[] maxCoord = this.pMax.getCoordinates();
for (int i = 0; i < this.getDimension(); ++i) {
double ci = coord[i];
double cmini = minCoord[i];
double cmaxi = maxCoord[i];
if (!Double.isNaN(ci) && ((ci < cmini) || Double.isNaN(cmini)))
this.pMin.setOrdinate(i, ci);
if (!Double.isNaN(ci) && ((ci > cmaxi) || Double.isNaN(cmaxi)))
this.pMax.setOrdinate(i, ci);
}
}
/**
* @param p
*/
public void add(DirectPosition p) {
this.add(p.getCoordinates());
}
/**
* @param env
*/
public void add(EnvelopeImpl env) {
this.add( env.getLowerCorner() );
this.add( env.getUpperCorner() );
}
// Auskommentiert, da es die scale methode von DP nutzt. diese ist nicht robust.
// /**
// * @return DirectPositionImpl
// */
// public DirectPositionImpl center() {
// return (this.pMin.add(this.pMax)).scale(0.5);
// }
/**
* Compares coordinates between the envelope and another envelope Test OK
*
* @param env
* @return boolean
*/
public boolean equals(Envelope env) {
return (this.getUpperCorner().equals(env.getUpperCorner()) && this
.getLowerCorner().equals(env.getLowerCorner()));
}
/**
* Verifies whether another envelope intersects with this envelope
*
* @param other
* @return TRUE, if envelopes intersect; FALSE, if they dont intersect
*/
public boolean intersects(Envelope other) {
return AlgoRectangleND.intersects(this.pMin.getCoordinates(), this.pMax
.getCoordinates(), other.getLowerCorner().getCoordinates(),
other.getUpperCorner().getCoordinates());
}
/**
* Verifies wheater the coordinate of a Direct Position intersects with the
* envelope
*
* @param dp
* @return boolean
*/
public boolean intersects(DirectPosition dp) {
// return AlgoRectangleND.intersects(this.pMin.getCoordinates(), this.pMax
// .getCoordinates(), dp.getCoordinates());
return AlgoRectangleND.contains(this.pMin.getCoordinates(), this.pMax
.getCoordinates(), dp.getCoordinates());
}
/**
* The North East corner of this Envelope
*
* @return
*/
public DirectPosition getNECorner() {
// Test ok
return this.getUpperCorner();
}
/**
* The South West corner of this Envelope
*
* @return
*/
public DirectPosition getSWCorner() {
// Test ok
return this.getLowerCorner();
}
/**
* The South East corner of this Envelope
* 2D and 2.5D only!
*
* In 2.5D, the z value will be set equal to the z value of the lower corner z value.
*
* @return
* @throws UnsupportedDimensionException
*/
public DirectPosition getSECorner() throws UnsupportedDimensionException {
DirectPosition rDP = null;
CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
int D = DimensionModel.toD( getCoordinateReferenceSystem() );
if ( D == DimensionModel.TWO_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{
this.pMax.getOrdinate(X),
this.pMin.getOrdinate(Y)
});
} else
if ( D == DimensionModel.TWOoFIVE_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{
this.pMax.getOrdinate(X),
this.pMin.getOrdinate(Y),
this.pMin.getOrdinate(Z)}
);
} else {
throw new UnsupportedDimensionException("3d not supported.");
}
return rDP;
}
/**
* The North West corner of this Envelope
* 2D and 2.5D only!
*
* In 2.5D, the z value will be set equal to the z value of the lower corner z value.
*
* @return
* @throws UnsupportedDimensionException
*/
public DirectPositionImpl getNWCornerOld() throws UnsupportedDimensionException {
DirectPositionImpl rDP = null;
CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
int D = DimensionModel.toD( crs );
if ( D == DimensionModel.TWO_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{this.pMin.getOrdinate(X), this.pMax.getOrdinate(Y)});
} else
if ( D == DimensionModel.TWOoFIVE_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{this.pMin.getOrdinate(X), this.pMax.getOrdinate(Y), this.pMin.getOrdinate(Z)});
} else {
throw new UnsupportedDimensionException("3d not supported.");
}
return rDP;
}
public DirectPositionImpl getNWCorner() throws UnsupportedDimensionException {
DirectPositionImpl rDP = null;
CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
int D = DimensionModel.toD( crs );
if ( D == DimensionModel.TWO_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{this.pMin.getOrdinate(X), this.pMax.getOrdinate(Y)});
} else
if ( D == DimensionModel.TWOoFIVE_DIMENSIONIAL ) {
rDP = new DirectPositionImpl( crs, new double[]{this.pMin.getOrdinate(X), this.pMax.getOrdinate(Y), this.pMin.getOrdinate(Z)});
} else {
throw new UnsupportedDimensionException("3d not supported.");
}
return rDP;
}
/**
* Verifies whether a DirectPosition2D lays within the envelope or at its
* border Test OK
*
* @param p
* @return TRUE, if the DirectPosition2D lays within the envelope
*/
public boolean contains(DirectPosition p) {
// TODO Semantics: Should return true, if a DirectPosition lays on the
// border of the envelope?
return AlgoRectangleND.contains(this.pMin.getCoordinates(), this.pMax
.getCoordinates(), p.getCoordinates());
}
// /**
// * @param p
// * @return boolean
// */
// public boolean touches(DirectPosition p) {
// return AlgoRectangleND.touches(this.pMin.getCoordinates(), this.pMax
// .getCoordinates(), p.getCoordinates());
// }
// /**
// * @param p
// * @param side
// * @return boolean
// */
// public boolean touches(DirectPositionImpl p, int side) {
// return AlgoRectangleND.touches(this.pMin.getCoordinates(), this.pMax
// .getCoordinates(), p.getCoordinates(), side);
// }
// /**
// * @param env
// * @return boolean
// */
// public boolean contains(Envelope env) {
// double[] min = this.pMin.getCoordinates();
// double[] max = this.pMax.getCoordinates();
// return AlgoRectangleND.contains(min, max, env.getLowerCorner()
// .getCoordinates())
// && AlgoRectangleND.contains(min, max, env.getUpperCorner()
// .getCoordinates());
// }
// /**
// * @param factor
// * @return EnvelopeImpl
// */
// public EnvelopeImpl scale(double factor) {
// EnvelopeImpl result = new EnvelopeImpl(this);
// if (factor <= 0.0 || factor == 1.0)
// return result;
// DirectPositionImpl p0 = this.center();
// DirectPositionImpl p1;
// p1 = this.pMin.subtract(p0);
// p1 = p1.scale(factor);
// result.pMin = p0.add(p1);
// p1 = this.pMax.subtract(p0);
// p1 = p1.scale(factor);
// result.pMax = p0.add(p1);
// return result;
// }
// /**
// * @return double
// */
// public double maxLength() {
// double result = 0.0;
// double minCoord[] = this.pMin.getCoordinates();
// double maxCoord[] = this.pMax.getCoordinates();
// int n = Math.min(minCoord.length, maxCoord.length);
// for (int i = 1; i < n; ++i) {
// if ((maxCoord[i] - minCoord[i]) > result)
// result = maxCoord[i] - minCoord[i];
// }
// return result;
// }
}