0001: /*
0002: * The JTS Topology Suite is a collection of Java classes that
0003: * implement the fundamental operations required to validate a given
0004: * geo-spatial data set to a known topological specification.
0005: *
0006: * Copyright (C) 2001 Vivid Solutions
0007: *
0008: * This library is free software; you can redistribute it and/or
0009: * modify it under the terms of the GNU Lesser General Public
0010: * License as published by the Free Software Foundation; either
0011: * version 2.1 of the License, or (at your option) any later version.
0012: *
0013: * This library is distributed in the hope that it will be useful,
0014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0016: * Lesser General Public License for more details.
0017: *
0018: * You should have received a copy of the GNU Lesser General Public
0019: * License along with this library; if not, write to the Free Software
0020: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0021: *
0022: * For more information, contact:
0023: *
0024: * Vivid Solutions
0025: * Suite #1A
0026: * 2328 Government Street
0027: * Victoria BC V8T 5G5
0028: * Canada
0029: *
0030: * (250)385-6040
0031: * www.vividsolutions.com
0032: */
0033: package com.vividsolutions.jts.geom;
0034:
0035: import java.io.Serializable;
0036: import java.util.Collection;
0037: import java.util.Iterator;
0038:
0039: import com.vividsolutions.jts.algorithm.*;
0040: import com.vividsolutions.jts.io.WKTWriter;
0041: import com.vividsolutions.jts.operation.*;
0042: import com.vividsolutions.jts.operation.buffer.BufferOp;
0043: import com.vividsolutions.jts.operation.distance.DistanceOp;
0044: import com.vividsolutions.jts.operation.overlay.OverlayOp;
0045: import com.vividsolutions.jts.operation.overlay.snap.SnapIfNeededOverlayOp;
0046: import com.vividsolutions.jts.operation.predicate.RectangleIntersects;
0047: import com.vividsolutions.jts.operation.predicate.RectangleContains;
0048: import com.vividsolutions.jts.operation.relate.RelateOp;
0049: import com.vividsolutions.jts.operation.valid.IsValidOp;
0050: import com.vividsolutions.jts.util.Assert;
0051:
0052: /**
0053: * The base class for all geometric objects.
0054: * <P>
0055: *
0056: * <H3>Binary Predicates</H3>
0057: * Because it is not clear at this time
0058: * what semantics for spatial
0059: * analysis methods involving <code>GeometryCollection</code>s would be useful,
0060: * <code>GeometryCollection</code>s are not supported as arguments to binary
0061: * predicates (other than <code>convexHull</code>) or the <code>relate</code>
0062: * method.
0063: *
0064: * <H3>Set-Theoretic Methods</H3>
0065: *
0066: * The spatial analysis methods will
0067: * return the most specific class possible to represent the result. If the
0068: * result is homogeneous, a <code>Point</code>, <code>LineString</code>, or
0069: * <code>Polygon</code> will be returned if the result contains a single
0070: * element; otherwise, a <code>MultiPoint</code>, <code>MultiLineString</code>,
0071: * or <code>MultiPolygon</code> will be returned. If the result is
0072: * heterogeneous a <code>GeometryCollection</code> will be returned. <P>
0073: *
0074: * Because it is not clear at this time what semantics for set-theoretic
0075: * methods involving <code>GeometryCollection</code>s would be useful,
0076: * <code>GeometryCollections</code>
0077: * are not supported as arguments to the set-theoretic methods.
0078: *
0079: * <H4>Representation of Computed Geometries </H4>
0080: *
0081: * The SFS states that the result
0082: * of a set-theoretic method is the "point-set" result of the usual
0083: * set-theoretic definition of the operation (SFS 3.2.21.1). However, there are
0084: * sometimes many ways of representing a point set as a <code>Geometry</code>.
0085: * <P>
0086: *
0087: * The SFS does not specify an unambiguous representation of a given point set
0088: * returned from a spatial analysis method. One goal of JTS is to make this
0089: * specification precise and unambiguous. JTS will use a canonical form for
0090: * <code>Geometry</code>s returned from spatial analysis methods. The canonical
0091: * form is a <code>Geometry</code> which is simple and noded:
0092: * <UL>
0093: * <LI> Simple means that the Geometry returned will be simple according to
0094: * the JTS definition of <code>isSimple</code>.
0095: * <LI> Noded applies only to overlays involving <code>LineString</code>s. It
0096: * means that all intersection points on <code>LineString</code>s will be
0097: * present as endpoints of <code>LineString</code>s in the result.
0098: * </UL>
0099: * This definition implies that non-simple geometries which are arguments to
0100: * spatial analysis methods must be subjected to a line-dissolve process to
0101: * ensure that the results are simple.
0102: *
0103: * <H4> Constructed Points And The Precision Model </H4>
0104: *
0105: * The results computed by the set-theoretic methods may
0106: * contain constructed points which are not present in the input <code>Geometry</code>
0107: * s. These new points arise from intersections between line segments in the
0108: * edges of the input <code>Geometry</code>s. In the general case it is not
0109: * possible to represent constructed points exactly. This is due to the fact
0110: * that the coordinates of an intersection point may contain twice as many bits
0111: * of precision as the coordinates of the input line segments. In order to
0112: * represent these constructed points explicitly, JTS must truncate them to fit
0113: * the <code>PrecisionModel</code>. <P>
0114: *
0115: * Unfortunately, truncating coordinates moves them slightly. Line segments
0116: * which would not be coincident in the exact result may become coincident in
0117: * the truncated representation. This in turn leads to "topology collapses" --
0118: * situations where a computed element has a lower dimension than it would in
0119: * the exact result. <P>
0120: *
0121: * When JTS detects topology collapses during the computation of spatial
0122: * analysis methods, it will throw an exception. If possible the exception will
0123: * report the location of the collapse. <P>
0124: *
0125: * #equals(Object) and #hashCode are not overridden, so that when two
0126: * topologically equal Geometries are added to HashMaps and HashSets, they
0127: * remain distinct. This behaviour is desired in many cases.
0128: *
0129: *@version 1.7
0130: */
0131: public abstract class Geometry implements Cloneable, Comparable,
0132: Serializable {
0133: private static final long serialVersionUID = 8763622679187376702L;
0134:
0135: private final static Class[] sortedClasses = new Class[] {
0136: Point.class, MultiPoint.class, LineString.class,
0137: LinearRing.class, MultiLineString.class, Polygon.class,
0138: MultiPolygon.class, GeometryCollection.class };
0139:
0140: private final static GeometryComponentFilter geometryChangedFilter = new GeometryComponentFilter() {
0141: public void filter(Geometry geom) {
0142: geom.geometryChangedAction();
0143: }
0144: };
0145:
0146: /**
0147: * The bounding box of this <code>Geometry</code>.
0148: */
0149: protected Envelope envelope;
0150:
0151: /**
0152: * The {@link GeometryFactory} used to create this Geometry
0153: */
0154: protected final GeometryFactory factory;
0155:
0156: /**
0157: * The ID of the Spatial Reference System used by this <code>Geometry</code>
0158: */
0159: protected int SRID;
0160:
0161: /**
0162: * Creates a new <tt>Geometry</tt> via the specified GeometryFactory.
0163: *
0164: * @param factory
0165: */
0166: public Geometry(GeometryFactory factory) {
0167: this .factory = factory;
0168: this .SRID = factory.getSRID();
0169: }
0170:
0171: /**
0172: * Returns the name of this object's <code>com.vivid.jts.geom</code>
0173: * interface.
0174: *
0175: *@return the name of this <code>Geometry</code>s most specific <code>com.vividsolutions.jts.geom</code>
0176: * interface
0177: */
0178: public abstract String getGeometryType();
0179:
0180: /**
0181: * Returns true if the array contains any non-empty <code>Geometry</code>s.
0182: *
0183: *@param geometries an array of <code>Geometry</code>s; no elements may be
0184: * <code>null</code>
0185: *@return <code>true</code> if any of the <code>Geometry</code>s
0186: * <code>isEmpty</code> methods return <code>false</code>
0187: */
0188: protected static boolean hasNonEmptyElements(Geometry[] geometries) {
0189: for (int i = 0; i < geometries.length; i++) {
0190: if (!geometries[i].isEmpty()) {
0191: return true;
0192: }
0193: }
0194: return false;
0195: }
0196:
0197: /**
0198: * Returns true if the array contains any <code>null</code> elements.
0199: *
0200: *@param array an array to validate
0201: *@return <code>true</code> if any of <code>array</code>s elements are
0202: * <code>null</code>
0203: */
0204: protected static boolean hasNullElements(Object[] array) {
0205: for (int i = 0; i < array.length; i++) {
0206: if (array[i] == null) {
0207: return true;
0208: }
0209: }
0210: return false;
0211: }
0212:
0213: /**
0214: * Returns the ID of the Spatial Reference System used by the <code>Geometry</code>.
0215: * <P>
0216: *
0217: * JTS supports Spatial Reference System information in the simple way
0218: * defined in the SFS. A Spatial Reference System ID (SRID) is present in
0219: * each <code>Geometry</code> object. <code>Geometry</code> provides basic
0220: * accessor operations for this field, but no others. The SRID is represented
0221: * as an integer.
0222: *
0223: *@return the ID of the coordinate space in which the <code>Geometry</code>
0224: * is defined.
0225: *
0226: */
0227: public int getSRID() {
0228: return SRID;
0229: }
0230:
0231: /**
0232: * Sets the ID of the Spatial Reference System used by the <code>Geometry</code>.
0233: */
0234: public void setSRID(int SRID) {
0235: this .SRID = SRID;
0236: }
0237:
0238: private Object userData = null;
0239:
0240: /**
0241: * Gets the factory which contains the context in which this geometry was created.
0242: *
0243: * @return the factory for this geometry
0244: */
0245: public GeometryFactory getFactory() {
0246: return factory;
0247: }
0248:
0249: /**
0250: * Gets the user data object for this geometry, if any.
0251: *
0252: * @return the user data object, or <code>null</code> if none set
0253: */
0254: public Object getUserData() {
0255: return userData;
0256: }
0257:
0258: /**
0259: * Returns the number of {@link Geometry}s in a {@link GeometryCollection}
0260: * (or 1, if the geometry is not a collection).
0261: *
0262: * @return the number of geometries contained in this geometry
0263: */
0264: public int getNumGeometries() {
0265: return 1;
0266: }
0267:
0268: /**
0269: * Returns an element {@link Geometry} from a {@link GeometryCollection}
0270: * (or <code>this</code>, if the geometry is not a collection).
0271: *
0272: * @param n the index of the geometry element
0273: * @return the n'th geometry contained in this geometry
0274: */
0275: public Geometry getGeometryN(int n) {
0276: return this ;
0277: }
0278:
0279: /**
0280: * A simple scheme for applications to add their own custom data to a Geometry.
0281: * An example use might be to add an object representing a Coordinate Reference System.
0282: * <p>
0283: * Note that user data objects are not present in geometries created by
0284: * construction methods.
0285: *
0286: * @param userData an object, the semantics for which are defined by the
0287: * application using this Geometry
0288: */
0289: public void setUserData(Object userData) {
0290: this .userData = userData;
0291: }
0292:
0293: /**
0294: * Returns the <code>PrecisionModel</code> used by the <code>Geometry</code>.
0295: *
0296: *@return the specification of the grid of allowable points, for this
0297: * <code>Geometry</code> and all other <code>Geometry</code>s
0298: */
0299: public PrecisionModel getPrecisionModel() {
0300: return factory.getPrecisionModel();
0301: }
0302:
0303: /**
0304: * Returns a vertex of this <code>Geometry</code>.
0305: *
0306: *@return a {@link Coordinate} which is a vertex of this <code>Geometry</code>.
0307: * Returns <code>null</code> if this Geometry is empty
0308: */
0309: public abstract Coordinate getCoordinate();
0310:
0311: /**
0312: * Returns this <code>Geometry</code> s vertices. If you modify the coordinates
0313: * in this array, be sure to call #geometryChanged afterwards.
0314: * The <code>Geometry</code>s contained by composite <code>Geometry</code>s
0315: * must be Geometry's; that is, they must implement <code>getCoordinates</code>.
0316: *
0317: *@return the vertices of this <code>Geometry</code>
0318: */
0319: public abstract Coordinate[] getCoordinates();
0320:
0321: /**
0322: * Returns the count of this <code>Geometry</code>s vertices. The <code>Geometry</code>
0323: * s contained by composite <code>Geometry</code>s must be
0324: * Geometry's; that is, they must implement <code>getNumPoints</code>
0325: *
0326: *@return the number of vertices in this <code>Geometry</code>
0327: */
0328: public abstract int getNumPoints();
0329:
0330: /**
0331: * Tests whether this {@link Geometry} is simple.
0332: * In general, the SFS specification of simplicity
0333: * follows the rule:
0334: * <UL>
0335: * <LI> A Geometry is simple iff the only self-intersections are at
0336: * boundary points.
0337: * </UL>
0338: * Simplicity is defined for each {@link Geometry} subclass as follows:
0339: * <ul>
0340: * <li>Valid polygonal geometries are simple by definition, so
0341: * <code>isSimple</code> trivially returns true.
0342: * <li>Linear geometries are simple iff they do not self-intersect at points
0343: * other than boundary points.
0344: * <li>Zero-dimensional geometries (points) are simple iff they have no
0345: * repeated points.
0346: * <li>Empty <code>Geometry</code>s are always simple
0347: * <ul>
0348: *
0349: * @return <code>true</code> if this <code>Geometry</code> has any points of
0350: * self-tangency, self-intersection or other anomalous points
0351: * @see #isValid
0352: */
0353: public boolean isSimple() {
0354: checkNotGeometryCollection(this );
0355: IsSimpleOp op = new IsSimpleOp(this );
0356: return op.isSimple();
0357: }
0358:
0359: /**
0360: * Tests the validity of this <code>Geometry</code>.
0361: * Subclasses provide their own definition of "valid".
0362: *
0363: *@return <code>true</code> if this <code>Geometry</code> is valid
0364: *
0365: * @see IsValidOp
0366: */
0367: public boolean isValid() {
0368: IsValidOp isValidOp = new IsValidOp(this );
0369: return isValidOp.isValid();
0370: }
0371:
0372: /**
0373: * Returns whether or not the set of points in this <code>Geometry</code> is
0374: * empty.
0375: *
0376: *@return <code>true</code> if this <code>Geometry</code> equals the empty
0377: * geometry
0378: */
0379: public abstract boolean isEmpty();
0380:
0381: /**
0382: * Returns the minimum distance between this <code>Geometry</code>
0383: * and the <code>Geometry</code> g
0384: *
0385: *@param g the <code>Geometry</code> from which to compute the distance
0386: */
0387: public double distance(Geometry g) {
0388: return DistanceOp.distance(this , g);
0389: }
0390:
0391: /**
0392: * Tests whether the distance from this <code>Geometry</code>
0393: * to another is less than or equal to a specified value.
0394: *
0395: * @param geom the Geometry to check the distance to
0396: * @param distance the distance value to compare
0397: * @return <code>true</code> if the geometries are less than <code>distance</code> apart.
0398: */
0399: public boolean isWithinDistance(Geometry geom, double distance) {
0400: double envDist = getEnvelopeInternal().distance(
0401: geom.getEnvelopeInternal());
0402: if (envDist > distance)
0403: return false;
0404: return DistanceOp.isWithinDistance(this , geom, distance);
0405: /*
0406: double geomDist = this.distance(geom);
0407: if (geomDist > distance)
0408: return false;
0409: return true;
0410: */
0411: }
0412:
0413: public boolean isRectangle() {
0414: // Polygon overrides to check for actual rectangle
0415: return false;
0416: }
0417:
0418: /**
0419: * Returns the area of this <code>Geometry</code>.
0420: * Areal Geometries have a non-zero area.
0421: * They override this function to compute the area.
0422: * Others return 0.0
0423: *
0424: *@return the area of the Geometry
0425: */
0426: public double getArea() {
0427: return 0.0;
0428: }
0429:
0430: /**
0431: * Returns the length of this <code>Geometry</code>.
0432: * Linear geometries return their length.
0433: * Areal geometries return their perimeter.
0434: * They override this function to compute the area.
0435: * Others return 0.0
0436: *
0437: *@return the length of the Geometry
0438: */
0439: public double getLength() {
0440: return 0.0;
0441: }
0442:
0443: /**
0444: * Computes the centroid of this <code>Geometry</code>.
0445: * The centroid
0446: * is equal to the centroid of the set of component Geometries of highest
0447: * dimension (since the lower-dimension geometries contribute zero
0448: * "weight" to the centroid)
0449: *
0450: * @return a {@link Point} which is the centroid of this Geometry
0451: */
0452: public Point getCentroid() {
0453: if (isEmpty()) {
0454: return null;
0455: }
0456: Coordinate centPt = null;
0457: int dim = getDimension();
0458: if (dim == 0) {
0459: CentroidPoint cent = new CentroidPoint();
0460: cent.add(this );
0461: centPt = cent.getCentroid();
0462: } else if (dim == 1) {
0463: CentroidLine cent = new CentroidLine();
0464: cent.add(this );
0465: centPt = cent.getCentroid();
0466: } else {
0467: CentroidArea cent = new CentroidArea();
0468: cent.add(this );
0469: centPt = cent.getCentroid();
0470: }
0471: return createPointFromInternalCoord(centPt, this );
0472:
0473: }
0474:
0475: /**
0476: * Computes an interior point of this <code>Geometry</code>.
0477: * An interior point is guaranteed to lie in the interior of the Geometry,
0478: * if it possible to calculate such a point exactly. Otherwise,
0479: * the point may lie on the boundary of the geometry.
0480: *
0481: * @return a {@link Point} which is in the interior of this Geometry
0482: */
0483: public Point getInteriorPoint() {
0484: Coordinate interiorPt = null;
0485: int dim = getDimension();
0486: if (dim == 0) {
0487: InteriorPointPoint intPt = new InteriorPointPoint(this );
0488: interiorPt = intPt.getInteriorPoint();
0489: } else if (dim == 1) {
0490: InteriorPointLine intPt = new InteriorPointLine(this );
0491: interiorPt = intPt.getInteriorPoint();
0492: } else {
0493: InteriorPointArea intPt = new InteriorPointArea(this );
0494: interiorPt = intPt.getInteriorPoint();
0495: }
0496: return createPointFromInternalCoord(interiorPt, this );
0497: }
0498:
0499: /**
0500: * Returns the dimension of this <code>Geometry</code>.
0501: *
0502: *@return the dimension of the class implementing this interface, whether
0503: * or not this object is the empty geometry
0504: */
0505: public abstract int getDimension();
0506:
0507: /**
0508: * Returns the boundary, or an empty geometry of appropriate dimension
0509: * if this <code>Geometry</code> is empty.
0510: * (In the case of zero-dimensional geometries, '
0511: * an empty GeometryCollection is returned.)
0512: * For a discussion of this function, see the OpenGIS Simple
0513: * Features Specification. As stated in SFS Section 2.1.13.1, "the boundary
0514: * of a Geometry is a set of Geometries of the next lower dimension."
0515: *
0516: *@return the closure of the combinatorial boundary of this <code>Geometry</code>
0517: */
0518: public abstract Geometry getBoundary();
0519:
0520: /**
0521: * Returns the dimension of this <code>Geometry</code>s inherent boundary.
0522: *
0523: *@return the dimension of the boundary of the class implementing this
0524: * interface, whether or not this object is the empty geometry. Returns
0525: * <code>Dimension.FALSE</code> if the boundary is the empty geometry.
0526: */
0527: public abstract int getBoundaryDimension();
0528:
0529: /**
0530: * Returns this <code>Geometry</code>s bounding box. If this <code>Geometry</code>
0531: * is the empty geometry, returns an empty <code>Point</code>. If the <code>Geometry</code>
0532: * is a point, returns a non-empty <code>Point</code>. Otherwise, returns a
0533: * <code>Polygon</code> whose points are (minx, miny), (maxx, miny), (maxx,
0534: * maxy), (minx, maxy), (minx, miny).
0535: *
0536: *@return an empty <code>Point</code> (for empty <code>Geometry</code>s), a
0537: * <code>Point</code> (for <code>Point</code>s) or a <code>Polygon</code>
0538: * (in all other cases)
0539: */
0540: public Geometry getEnvelope() {
0541: return getFactory().toGeometry(getEnvelopeInternal());
0542: }
0543:
0544: /**
0545: * Returns the minimum and maximum x and y values in this <code>Geometry</code>
0546: * , or a null <code>Envelope</code> if this <code>Geometry</code> is empty.
0547: *
0548: *@return this <code>Geometry</code>s bounding box; if the <code>Geometry</code>
0549: * is empty, <code>Envelope#isNull</code> will return <code>true</code>
0550: */
0551: public Envelope getEnvelopeInternal() {
0552: if (envelope == null) {
0553: envelope = computeEnvelopeInternal();
0554: }
0555: return envelope;
0556: }
0557:
0558: /**
0559: * Notifies this Geometry that its Coordinates have been changed by an external
0560: * party (using a CoordinateFilter, for example). The Geometry will flush
0561: * and/or update any information it has cached (such as its {@link Envelope} ).
0562: */
0563: public void geometryChanged() {
0564: apply(geometryChangedFilter);
0565: }
0566:
0567: /**
0568: * Notifies this Geometry that its Coordinates have been changed by an external
0569: * party. When #geometryChanged is called, this method will be called for
0570: * this Geometry and its component Geometries.
0571: * @see #apply(GeometryComponentFilter)
0572: */
0573: protected void geometryChangedAction() {
0574: envelope = null;
0575: }
0576:
0577: /**
0578: * Returns <code>true</code> if this geometry is disjoint to the specified geometry.
0579: * <p>
0580: * The <code>disjoint</code> predicate has the following equivalent definitions:
0581: * <ul>
0582: * <li>The two geometries have no point in common
0583: * <li>The DE-9IM Intersection Matrix for the two geometries is FF*FF****
0584: * <li>! <code>g.intersects(this)</code>
0585: * (<code>disjoint</code> is the inverse of <code>intersects</code>)
0586: * </ul>
0587: *
0588: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0589: *@return <code>true</code> if the two <code>Geometry</code>s are
0590: * disjoint
0591: *
0592: * @see Geometry#intersects
0593: */
0594: public boolean disjoint(Geometry g) {
0595: return !intersects(g);
0596: }
0597:
0598: /**
0599: * Returns <code>true</code> if this geometry touches the
0600: * specified geometry.
0601: * <p>
0602: * The <code>touches</code> predicate has the following equivalent definitions:
0603: * <ul>
0604: * <li>The geometries have at least one point in common, but their interiors do not intersect.
0605: * <li>The DE-9IM Intersection Matrix for the two geometries is
0606: * FT*******, F**T***** or F***T****
0607: * </ul>
0608: * If both geometries have dimension 0, this predicate returns <code>false</code>
0609: *
0610: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0611: *@return <code>true</code> if the two <code>Geometry</code>s touch;
0612: * Returns <code>false</code> if both <code>Geometry</code>s are points
0613: */
0614: public boolean touches(Geometry g) {
0615: // short-circuit test
0616: if (!getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
0617: return false;
0618: return relate(g).isTouches(getDimension(), g.getDimension());
0619: }
0620:
0621: /**
0622: * Returns <code>true</code> if this geometry intersects the specified geometry.
0623: * <p>
0624: * The <code>intersects</code> predicate has the following equivalent definitions:
0625: * <ul>
0626: * <li>The two geometries have at least one point in common
0627: * <li>! <code>g.disjoint(this)</code>
0628: * (<code>intersects</code> is the inverse of <code>disjoint</code>)
0629: * </ul>
0630: *
0631: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0632: *@return <code>true</code> if the two <code>Geometry</code>s intersect
0633: *
0634: * @see Geometry#disjoint
0635: */
0636: public boolean intersects(Geometry g) {
0637:
0638: // short-circuit envelope test
0639: if (!getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
0640: return false;
0641:
0642: /**
0643: * TODO: (MD) Add optimizations:
0644: *
0645: * - for P-A case:
0646: * If P is in env(A), test for point-in-poly
0647: *
0648: * - for A-A case:
0649: * If env(A1).overlaps(env(A2))
0650: * test for overlaps via point-in-poly first (both ways)
0651: * Possibly optimize selection of point to test by finding point of A1
0652: * closest to centre of env(A2).
0653: * (Is there a test where we shouldn't bother - e.g. if env A
0654: * is much smaller than env B, maybe there's no point in testing
0655: * pt(B) in env(A)?
0656: */
0657:
0658: // optimization for rectangle arguments
0659: if (isRectangle()) {
0660: return RectangleIntersects.intersects((Polygon) this , g);
0661: }
0662: if (g.isRectangle()) {
0663: return RectangleIntersects.intersects((Polygon) g, this );
0664: }
0665: // general case
0666: return relate(g).isIntersects();
0667: }
0668:
0669: /**
0670: * Returns <code>true</code> if this geometry crosses the
0671: * specified geometry.
0672: * <p>
0673: * The <code>crosses</code> predicate has the following equivalent definitions:
0674: * <ul>
0675: * <li>The geometries have some but not all interior points in common.
0676: * <li>The DE-9IM Intersection Matrix for the two geometries is
0677: * <ul>
0678: * <li>T*T****** (for P/L, P/A, and L/A situations)
0679: * <li>T*****T** (for L/P, L/A, and A/L situations)
0680: * <li>0******** (for L/L situations)
0681: * </ul>
0682: * </ul>
0683: * For any other combination of dimensions this predicate returns <code>false</code>.
0684: * <p>
0685: * The SFS defined this predicate only for P/L, P/A, L/L, and L/A situations.
0686: * JTS extends the definition to apply to L/P, A/P and A/L situations as well.
0687: * This makes the relation symmetric.
0688: *
0689: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0690: *@return <code>true</code> if the two <code>Geometry</code>s cross.
0691: */
0692: public boolean crosses(Geometry g) {
0693: // short-circuit test
0694: if (!getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
0695: return false;
0696: return relate(g).isCrosses(getDimension(), g.getDimension());
0697: }
0698:
0699: /**
0700: * Returns <code>true</code> if this geometry is within the
0701: * specified geometry.
0702: * <p>
0703: * The <code>within</code> predicate has the following equivalent definitions:
0704: * <ul>
0705: * <li>Every point of this geometry is a point of the other geometry,
0706: * and the interiors of the two geometries have at least one point in common.
0707: * <li>The DE-9IM Intersection Matrix for the two geometries is T*F**F***
0708: * <li><code>g.contains(this)</code>
0709: * (<code>within</code> is the inverse of <code>contains</code>)
0710: * </ul>
0711: * An implication of the definition is that
0712: * "The boundary of a Polygon is not within the Polygon".
0713: * In other words, if a geometry G is a subset of
0714: * the points in the boundary of a polygon P, <code>G.within(P) = false</code>
0715: *
0716: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0717: *@return <code>true</code> if this <code>Geometry</code> is within
0718: * <code>other</code>
0719: *
0720: * @see Geometry#contains
0721: */
0722: public boolean within(Geometry g) {
0723: return g.contains(this );
0724: }
0725:
0726: /**
0727: * Returns <code>true</code> if this geometry contains the
0728: * specified geometry.
0729: * <p>
0730: * The <code>contains</code> predicate has the following equivalent definitions:
0731: * <ul>
0732: * <li>Every point of the other geometry is a point of this geometry,
0733: * and the interiors of the two geometries have at least one point in common.
0734: * <li>The DE-9IM Intersection Matrix for the two geometries is <code>T*****FF*</code>
0735: * <li><code>g.within(this)</code>
0736: * (<code>contains</code> is the inverse of <code>within</code>)
0737: * </ul>
0738: * An implication of the definition is that "Polygons do not
0739: * contain their boundary". In other words, if a geometry G is a subset of
0740: * the points in the boundary of a polygon P, <code>P.contains(G) = false</code>
0741: *
0742: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0743: *@return <code>true</code> if this <code>Geometry</code> contains <code>g</code>
0744: *
0745: * @see Geometry#within
0746: */
0747: public boolean contains(Geometry g) {
0748: // short-circuit test
0749: if (!getEnvelopeInternal().contains(g.getEnvelopeInternal()))
0750: return false;
0751: // optimization for rectangle arguments
0752: if (isRectangle()) {
0753: return RectangleContains.contains((Polygon) this , g);
0754: }
0755: // general case
0756: return relate(g).isContains();
0757: }
0758:
0759: /**
0760: * Returns <code>true</code> if this geometry overlaps the
0761: * specified geometry.
0762: * <p>
0763: * The <code>overlaps</code> predicate has the following equivalent definitions:
0764: * <ul>
0765: * <li>The geometries have some but not all points in common,
0766: * they have the same dimension,
0767: * and the intersection of the interiors of the two geometries has
0768: * the same dimension as the geometries themselves.
0769: * <li>The DE-9IM Intersection Matrix for the two geometries is
0770: * <code>T*T***T**</code> (for two points or two surfaces)
0771: * or <code>1*T***T**</code> (for two curves)
0772: * </ul>
0773: * If the geometries are of different dimension this predicate returns <code>false</code>.
0774: *
0775: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0776: *@return <code>true</code> if the two <code>Geometry</code>s overlap.
0777: */
0778: public boolean overlaps(Geometry g) {
0779: // short-circuit test
0780: if (!getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
0781: return false;
0782: return relate(g).isOverlaps(getDimension(), g.getDimension());
0783: }
0784:
0785: /**
0786: * Returns <code>true</code> if this geometry covers the
0787: * specified geometry.
0788: * <p>
0789: * The <code>covers</code> predicate has the following equivalent definitions:
0790: * <ul>
0791: * <li>Every point of the other geometry is a point of this geometry.
0792: * <li>The DE-9IM Intersection Matrix for the two geometries is
0793: * <code>T*****FF*</code>
0794: * or <code>*T****FF*</code>
0795: * or <code>***T**FF*</code>
0796: * or <code>****T*FF*</code>
0797: * <li><code>g.coveredBy(this)</code>
0798: * (<code>covers</code> is the inverse of <code>coverdBy</code>)
0799: * </ul>
0800: * Note the difference between <code>covers</code> and <code>contains</code>
0801: * - <code>covers</code> is a more inclusive relation.
0802: * In particular, unlike <code>contains</code> it does not distinguish between
0803: * points in the boundary and in the interior of geometries.
0804: * For most situations, <code>covers</code> should be used in preference to <code>contains</code>.
0805: * As an added benefit, <code>covers</code> is more amenable to optimization,
0806: * and hence should be more performant.
0807: *
0808: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0809: *@return <code>true</code> if this <code>Geometry</code> covers <code>g</code>
0810: *
0811: * @see Geometry#contains
0812: * @see Geometry#coveredBy
0813: */
0814: public boolean covers(Geometry g) {
0815: // short-circuit test
0816: if (!getEnvelopeInternal().contains(g.getEnvelopeInternal()))
0817: return false;
0818: // optimization for rectangle arguments
0819: if (isRectangle()) {
0820: return getEnvelopeInternal().contains(
0821: g.getEnvelopeInternal());
0822: }
0823: return relate(g).isCovers();
0824: }
0825:
0826: /**
0827: * Returns <code>true</code> if this geometry is covered by the
0828: * specified geometry.
0829: * <p>
0830: * The <code>coveredBy</code> predicate has the following equivalent definitions:
0831: * <ul>
0832: * <li>Every point of this geometry is a point of the other geometry.
0833: * <li>The DE-9IM Intersection Matrix for the two geometries is
0834: * <code>T*F**F***</code>
0835: * or <code>*TF**F***</code>
0836: * or <code>**FT*F***</code>
0837: * or <code>**F*TF***</code>
0838: * <li><code>g.covers(this)</code>
0839: * (<code>coveredBy</code> is the inverse of <code>covers</code>)
0840: * </ul>
0841: * Note the difference between <code>coveredBy</code> and <code>within</code>
0842: * - <code>coveredBy</code> is a more inclusive relation.
0843: *
0844: *@param g the <code>Geometry</code> with which to compare this <code>Geometry</code>
0845: *@return <code>true</code> if this <code>Geometry</code> is covered by <code>g</code>
0846: *
0847: * @see Geometry#within
0848: * @see Geometry#covers
0849: */
0850: public boolean coveredBy(Geometry g) {
0851: return g.covers(this );
0852: }
0853:
0854: /**
0855: * Returns <code>true</code> if the elements in the DE-9IM
0856: * {@link IntersectionMatrix} for the two <code>Geometry</code>s match the elements in <code>intersectionPattern</code>.
0857: * The pattern is a 9-character string, with symbols drawn from the following set:
0858: * <UL>
0859: * <LI> 0 (dimension 0)
0860: * <LI> 1 (dimension 1)
0861: * <LI> 2 (dimension 2)
0862: * <LI> T ( matches 0, 1 or 2)
0863: * <LI> F ( matches FALSE)
0864: * <LI> * ( matches any value)
0865: * </UL>
0866: * For more information on the DE-9IM, see the <i>OpenGIS Simple Features
0867: * Specification</i>.
0868: *
0869: *@param other the <code>Geometry</code> with which to compare
0870: * this <code>Geometry</code>
0871: *@param intersectionPattern the pattern against which to check the
0872: * intersection matrix for the two <code>Geometry</code>s
0873: *@return <code>true</code> if the DE-9IM intersection
0874: * matrix for the two <code>Geometry</code>s match <code>intersectionPattern</code>
0875: * @see IntersectionMatrix
0876: */
0877: public boolean relate(Geometry g, String intersectionPattern) {
0878: return relate(g).matches(intersectionPattern);
0879: }
0880:
0881: /**
0882: * Returns the DE-9IM {@link IntersectionMatrix} for the two <code>Geometry</code>s.
0883: *
0884: *@param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
0885: *@return an {@link IntersectionMatrix} describing the intersections of the interiors,
0886: * boundaries and exteriors of the two <code>Geometry</code>s
0887: */
0888: public IntersectionMatrix relate(Geometry g) {
0889: checkNotGeometryCollection(this );
0890: checkNotGeometryCollection(g);
0891: return RelateOp.relate(this , g);
0892: }
0893:
0894: /**
0895: * Returns <code>true</code> if this geometry is equal to the
0896: * specified geometry.
0897: * <p>
0898: * The <code>equals</code> predicate has the following equivalent definitions:
0899: * <ul>
0900: * <li>The two geometries have at least one point in common,
0901: * and no point of either geometry lies in the exterior of the other geometry.
0902: * <li>The DE-9IM Intersection Matrix for the two geometries is T*F**FFF*
0903: * </ul>
0904: *
0905: *@param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
0906: *@return <code>true</code> if the two <code>Geometry</code>s are equal
0907: */
0908: public boolean equals(Geometry g) {
0909: // short-circuit test
0910: if (!getEnvelopeInternal().equals(g.getEnvelopeInternal()))
0911: return false;
0912: return relate(g).isEquals(getDimension(), g.getDimension());
0913: }
0914:
0915: //<<PERHAPS:DESIGN>> Override Object#equals [Jon Aquino]
0916:
0917: public String toString() {
0918: return toText();
0919: }
0920:
0921: /**
0922: * Returns the Well-known Text representation of this <code>Geometry</code>.
0923: * For a definition of the Well-known Text format, see the OpenGIS Simple
0924: * Features Specification.
0925: *
0926: *@return the Well-known Text representation of this <code>Geometry</code>
0927: */
0928: public String toText() {
0929: WKTWriter writer = new WKTWriter();
0930: return writer.write(this );
0931: }
0932:
0933: /**
0934: * Computes a buffer area around this geometry having the given
0935: * width.
0936: * The buffer of a Geometry is the Minkowski sum or difference
0937: * of the geometry with a disc of radius <code>abs(distance)</code>.
0938: * The buffer is constructed using 8 segments per quadrant to represent curves.
0939: * The end cap style is <tt>CAP_ROUND</tt>.
0940: *
0941: *@param distance the width of the buffer (may be positive, negative or 0)
0942: *@return an area geometry representing the buffer region
0943: *
0944: * @throws TopologyException if a robustness error occurs
0945: *
0946: * @see #buffer(double, int)
0947: * @see #buffer(double, int, int)
0948: */
0949: public Geometry buffer(double distance) {
0950: return BufferOp.bufferOp(this , distance);
0951: }
0952:
0953: /**
0954: * Computes a buffer area around this geometry having the given
0955: * width and with a specified accuracy of approximation for circular arcs.
0956: * <p>
0957: * Buffer area boundaries can contain circular arcs.
0958: * To represent these arcs using linear geometry they must be approximated with line segments.
0959: * The <code>quadrantSegments</code> argument allows controlling the
0960: * accuracy of the approximation
0961: * by specifying the number of line segments used to represent a quadrant of a circle
0962: *
0963: *@param distance the width of the buffer (may be positive, negative or 0)
0964: *@param quadrantSegments the number of line segments used to represent a quadrant of a circle
0965: *@return an area geometry representing the buffer region
0966: *
0967: * @throws TopologyException if a robustness error occurs
0968: *
0969: * @see #buffer(double)
0970: * @see #buffer(double, int, int)
0971: */
0972: public Geometry buffer(double distance, int quadrantSegments) {
0973: return BufferOp.bufferOp(this , distance, quadrantSegments);
0974: }
0975:
0976: /**
0977: * Computes a buffer area around this geometry having the given
0978: * width and with a specified accuracy of approximation for circular arcs,
0979: * and using a specified end cap style.
0980: * <p>
0981: * Buffer area boundaries can contain circular arcs.
0982: * To represent these arcs using linear geometry they must be approximated with line segments.
0983: * The <code>quadrantSegments</code> argument allows controlling the
0984: * accuracy of the approximation
0985: * by specifying the number of line segments used to represent a quadrant of a circle
0986: * <p>
0987: * The end cap style specifies the buffer geometry that will be
0988: * created at the ends of linestrings. The styles provided are:
0989: * <ul>
0990: * <li><tt>BufferOp.CAP_ROUND</tt> - (default) a semi-circle
0991: * <li><tt>BufferOp.CAP_BUTT</tt> - a straight line perpendicular to the end segment
0992: * <li><tt>BufferOp.CAP_SQUARE</tt> - a half-square
0993: * </ul>
0994: *
0995: *@param distance the width of the buffer (may be positive, negative or 0)
0996: *@param quadrantSegments the number of line segments used to represent a quadrant of a circle
0997: *@param endCapStyle the end cap style to use
0998: *@return an area geometry representing the buffer region
0999: *
1000: * @throws TopologyException if a robustness error occurs
1001: *
1002: * @see #buffer(double)
1003: * @see #buffer(double, int)
1004: * @see BufferOp
1005: */
1006: public Geometry buffer(double distance, int quadrantSegments,
1007: int endCapStyle) {
1008: return BufferOp.bufferOp(this , distance, quadrantSegments,
1009: endCapStyle);
1010: }
1011:
1012: /**
1013: * Computes the smallest convex <code>Polygon</code> that contains all the
1014: * points in the <code>Geometry</code>. This obviously applies only to <code>Geometry</code>
1015: * s which contain 3 or more points; the results for degenerate cases are
1016: * specified as follows:
1017: * <TABLE>
1018: * <TR>
1019: * <TH> Number of <code>Point</code>s in argument <code>Geometry</code> </TH>
1020: * <TH> <code>Geometry</code> class of result </TH>
1021: * </TR>
1022: * <TR>
1023: * <TD> 0 </TD>
1024: * <TD> empty <code>GeometryCollection</code> </TD>
1025: * </TR>
1026: * <TR> <TD> 1 </TD>
1027: * <TD> <code>Point</code> </TD>
1028: * </TR>
1029: * <TR>
1030: * <TD> 2 </TD>
1031: * <TD> <code>LineString</code> </TD>
1032: * </TR>
1033: * <TR>
1034: * <TD> 3 or more </TD>
1035: * <TD> <code>Polygon</code> </TD>
1036: * </TR>
1037: * </TABLE>
1038: *
1039: *@return the minimum-area convex polygon containing this <code>Geometry</code>'
1040: * s points
1041: */
1042: public Geometry convexHull() {
1043: return (new ConvexHull(this )).getConvexHull();
1044: }
1045:
1046: /**
1047: * Computes a <code>Geometry</code> representing the points shared by this
1048: * <code>Geometry</code> and <code>other</code>.
1049: *
1050: * @param other the <code>Geometry</code> with which to compute the
1051: * intersection
1052: * @return the points common to the two <code>Geometry</code>s
1053: * @throws TopologyException if a robustness error occurs
1054: * @throws IllegalArgumentException if either input is a non-empty GeometryCollection
1055: */
1056: public Geometry intersection(Geometry other) {
1057: /**
1058: * TODO: MD - add optimization for P-A case using Point-In-Polygon
1059: */
1060: // special case: if one input is empty ==> empty
1061: if (this .isEmpty())
1062: return this .getFactory().createGeometryCollection(null);
1063: if (other.isEmpty())
1064: return this .getFactory().createGeometryCollection(null);
1065:
1066: checkNotGeometryCollection(this );
1067: checkNotGeometryCollection(other);
1068: return SnapIfNeededOverlayOp.overlayOp(this , other,
1069: OverlayOp.INTERSECTION);
1070: }
1071:
1072: /**
1073: * Computes a <code>Geometry</code> representing all the points in this <code>Geometry</code>
1074: * and <code>other</code>.
1075: *
1076: *@param other the <code>Geometry</code> with which to compute the union
1077: *@return a set combining the points of this <code>Geometry</code> and
1078: * the points of <code>other</code>
1079: * @throws TopologyException if a robustness error occurs
1080: * @throws IllegalArgumentException if either input is a non-empty GeometryCollection
1081: */
1082: public Geometry union(Geometry other) {
1083: // special case: if either input is empty ==> other input
1084: if (this .isEmpty())
1085: return (Geometry) other.clone();
1086: if (other.isEmpty())
1087: return (Geometry) clone();
1088:
1089: checkNotGeometryCollection(this );
1090: checkNotGeometryCollection(other);
1091: return SnapIfNeededOverlayOp.overlayOp(this , other,
1092: OverlayOp.UNION);
1093: }
1094:
1095: /**
1096: * Computes a <code>Geometry</code> representing the points making up this
1097: * <code>Geometry</code> that do not make up <code>other</code>. This method
1098: * returns the closure of the resultant <code>Geometry</code>.
1099: *
1100: *@param other the <code>Geometry</code> with which to compute the
1101: * difference
1102: *@return the point set difference of this <code>Geometry</code> with
1103: * <code>other</code>
1104: * @throws TopologyException if a robustness error occurs
1105: * @throws IllegalArgumentException if either input is a non-empty GeometryCollection
1106: */
1107: public Geometry difference(Geometry other) {
1108: // special case: if A.isEmpty ==> empty; if B.isEmpty ==> A
1109: if (this .isEmpty())
1110: return this .getFactory().createGeometryCollection(null);
1111: if (other.isEmpty())
1112: return (Geometry) clone();
1113:
1114: checkNotGeometryCollection(this );
1115: checkNotGeometryCollection(other);
1116: return SnapIfNeededOverlayOp.overlayOp(this , other,
1117: OverlayOp.DIFFERENCE);
1118: }
1119:
1120: /**
1121: * Returns a set combining the points in this <code>Geometry</code> not in
1122: * <code>other</code>, and the points in <code>other</code> not in this
1123: * <code>Geometry</code>. This method returns the closure of the resultant
1124: * <code>Geometry</code>.
1125: *
1126: *@param other the <code>Geometry</code> with which to compute the symmetric
1127: * difference
1128: *@return the point set symmetric difference of this <code>Geometry</code>
1129: * with <code>other</code>
1130: * @throws TopologyException if a robustness error occurs
1131: * @throws IllegalArgumentException if either input is a non-empty GeometryCollection
1132: */
1133: public Geometry symDifference(Geometry other) {
1134: // special case: if either input is empty ==> other input
1135: if (this .isEmpty())
1136: return (Geometry) other.clone();
1137: if (other.isEmpty())
1138: return (Geometry) clone();
1139:
1140: checkNotGeometryCollection(this );
1141: checkNotGeometryCollection(other);
1142: return SnapIfNeededOverlayOp.overlayOp(this , other,
1143: OverlayOp.SYMDIFFERENCE);
1144: }
1145:
1146: /**
1147: * Returns true if the two <code>Geometry</code>s are exactly equal,
1148: * up to a specified distance tolerance.
1149: * Two Geometries are exactly equal within a distance tolerance
1150: * if and only if:
1151: * <ul>
1152: * <li>they have the same class
1153: * <li>they have the same values for their vertices,
1154: * within the given tolerance distance, in exactly the same order.
1155: * </ul>
1156: * If this and the other <code>Geometry</code>s are
1157: * composites and any children are not <code>Geometry</code>s, returns
1158: * <code>false</code>.
1159: *
1160: * @param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
1161: * @parm tolerance distance at or below which two <code>Coordinate</code>s
1162: * are considered equal
1163: * @return <code>true</code> if this and the other <code>Geometry</code>
1164: * are of the same class and have equal internal data.
1165: */
1166: public abstract boolean equalsExact(Geometry other, double tolerance);
1167:
1168: /**
1169: * Returns true if the two <code>Geometry</code>s are exactly equal.
1170: * Two Geometries are exactly equal iff:
1171: * <ul>
1172: * <li>they have the same class
1173: * <li>they have the same values of Coordinates in their internal
1174: * Coordinate lists, in exactly the same order.
1175: * </ul>
1176: * If this and the other <code>Geometry</code>s are
1177: * composites and any children are not <code>Geometry</code>s, returns
1178: * false.
1179: * <p>
1180: * This provides a stricter test of equality than
1181: * <code>equals</code>.
1182: *
1183: *@param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
1184: *@return <code>true</code> if this and the other <code>Geometry</code>
1185: * are of the same class and have equal internal data.
1186: */
1187: public boolean equalsExact(Geometry other) {
1188: return equalsExact(other, 0);
1189: }
1190:
1191: /**
1192: * Performs an operation with or on this <code>Geometry</code>'s
1193: * coordinates.
1194: * If this method modifies any coordinate values,
1195: * #geometryChanged() must be called to update the geometry state.
1196: * Note that you cannot use this
1197: * method to
1198: * modify this Geometry if its underlying CoordinateSequence's #get method
1199: * returns a copy of the Coordinate, rather than the actual Coordinate stored
1200: * (if it even stores Coordinates at all).
1201: *
1202: *@param filter the filter to apply to this <code>Geometry</code>'s
1203: * coordinates
1204: */
1205: public abstract void apply(CoordinateFilter filter);
1206:
1207: /**
1208: * Performs an operation on the coordinates in this <code>Geometry</code>'s
1209: * {@link CoordinateSequence}s.
1210: * If this method modifies any coordinate values,
1211: * #geometryChanged() must be called to update the geometry state.
1212: *
1213: *@param filter the filter to apply
1214: */
1215: public abstract void apply(CoordinateSequenceFilter filter);
1216:
1217: /**
1218: * Performs an operation with or on this <code>Geometry</code> and its
1219: * subelement <code>Geometry</code>s (if any).
1220: * Only GeometryCollections and subclasses
1221: * have subelement Geometry's.
1222: *
1223: *@param filter the filter to apply to this <code>Geometry</code> (and
1224: * its children, if it is a <code>GeometryCollection</code>).
1225: */
1226: public abstract void apply(GeometryFilter filter);
1227:
1228: /**
1229: * Performs an operation with or on this Geometry and its
1230: * component Geometry's. Only GeometryCollections and
1231: * Polygons have component Geometry's; for Polygons they are the LinearRings
1232: * of the shell and holes.
1233: *
1234: *@param filter the filter to apply to this <code>Geometry</code>.
1235: */
1236: public abstract void apply(GeometryComponentFilter filter);
1237:
1238: /**
1239: * Creates and returns a full copy of this {@link Geometry} object
1240: * (including all coordinates contained by it).
1241: * Subclasses are responsible for overriding this method and copying
1242: * their internal data. Overrides should call this method first.
1243: *
1244: * @return a clone of this instance
1245: */
1246: public Object clone() {
1247: try {
1248: Geometry clone = (Geometry) super .clone();
1249: if (clone.envelope != null) {
1250: clone.envelope = new Envelope(clone.envelope);
1251: }
1252: return clone;
1253: } catch (CloneNotSupportedException e) {
1254: Assert.shouldNeverReachHere();
1255: return null;
1256: }
1257: }
1258:
1259: /**
1260: * Converts this <code>Geometry</code> to <b>normal form</b> (or <b>
1261: * canonical form</b> ). Normal form is a unique representation for <code>Geometry</code>
1262: * s. It can be used to test whether two <code>Geometry</code>s are equal
1263: * in a way that is independent of the ordering of the coordinates within
1264: * them. Normal form equality is a stronger condition than topological
1265: * equality, but weaker than pointwise equality. The definitions for normal
1266: * form use the standard lexicographical ordering for coordinates. "Sorted in
1267: * order of coordinates" means the obvious extension of this ordering to
1268: * sequences of coordinates.
1269: */
1270: public abstract void normalize();
1271:
1272: /**
1273: * Returns whether this <code>Geometry</code> is greater than, equal to,
1274: * or less than another <code>Geometry</code>. <P>
1275: *
1276: * If their classes are different, they are compared using the following
1277: * ordering:
1278: * <UL>
1279: * <LI> Point (lowest)
1280: * <LI> MultiPoint
1281: * <LI> LineString
1282: * <LI> LinearRing
1283: * <LI> MultiLineString
1284: * <LI> Polygon
1285: * <LI> MultiPolygon
1286: * <LI> GeometryCollection (highest)
1287: * </UL>
1288: * If the two <code>Geometry</code>s have the same class, their first
1289: * elements are compared. If those are the same, the second elements are
1290: * compared, etc.
1291: *
1292: *@param o a <code>Geometry</code> with which to compare this <code>Geometry</code>
1293: *@return a positive number, 0, or a negative number, depending on whether
1294: * this object is greater than, equal to, or less than <code>o</code>, as
1295: * defined in "Normal Form For Geometry" in the JTS Technical
1296: * Specifications
1297: */
1298: public int compareTo(Object o) {
1299: Geometry other = (Geometry) o;
1300: if (getClassSortIndex() != other.getClassSortIndex()) {
1301: return getClassSortIndex() - other.getClassSortIndex();
1302: }
1303: if (isEmpty() && other.isEmpty()) {
1304: return 0;
1305: }
1306: if (isEmpty()) {
1307: return -1;
1308: }
1309: if (other.isEmpty()) {
1310: return 1;
1311: }
1312: return compareToSameClass(o);
1313: }
1314:
1315: /**
1316: * Returns whether this <code>Geometry</code> is greater than, equal to,
1317: * or less than another <code>Geometry</code>,
1318: * using the given {@link CoordinateSequenceComparator}.
1319: * <P>
1320: *
1321: * If their classes are different, they are compared using the following
1322: * ordering:
1323: * <UL>
1324: * <LI> Point (lowest)
1325: * <LI> MultiPoint
1326: * <LI> LineString
1327: * <LI> LinearRing
1328: * <LI> MultiLineString
1329: * <LI> Polygon
1330: * <LI> MultiPolygon
1331: * <LI> GeometryCollection (highest)
1332: * </UL>
1333: * If the two <code>Geometry</code>s have the same class, their first
1334: * elements are compared. If those are the same, the second elements are
1335: * compared, etc.
1336: *
1337: *@param o a <code>Geometry</code> with which to compare this <code>Geometry</code>
1338: *@param comp a <code>CoordinateSequenceComparator</code>
1339: *
1340: *@return a positive number, 0, or a negative number, depending on whether
1341: * this object is greater than, equal to, or less than <code>o</code>, as
1342: * defined in "Normal Form For Geometry" in the JTS Technical
1343: * Specifications
1344: */
1345: public int compareTo(Object o, CoordinateSequenceComparator comp) {
1346: Geometry other = (Geometry) o;
1347: if (getClassSortIndex() != other.getClassSortIndex()) {
1348: return getClassSortIndex() - other.getClassSortIndex();
1349: }
1350: if (isEmpty() && other.isEmpty()) {
1351: return 0;
1352: }
1353: if (isEmpty()) {
1354: return -1;
1355: }
1356: if (other.isEmpty()) {
1357: return 1;
1358: }
1359: return compareToSameClass(o, comp);
1360: }
1361:
1362: /**
1363: * Returns whether the two <code>Geometry</code>s are equal, from the point
1364: * of view of the <code>equalsExact</code> method. Called by <code>equalsExact</code>
1365: * . In general, two <code>Geometry</code> classes are considered to be
1366: * "equivalent" only if they are the same class. An exception is <code>LineString</code>
1367: * , which is considered to be equivalent to its subclasses.
1368: *
1369: *@param other the <code>Geometry</code> with which to compare this <code>Geometry</code>
1370: * for equality
1371: *@return <code>true</code> if the classes of the two <code>Geometry</code>
1372: * s are considered to be equal by the <code>equalsExact</code> method.
1373: */
1374: protected boolean isEquivalentClass(Geometry other) {
1375: return this .getClass().getName().equals(
1376: other.getClass().getName());
1377: }
1378:
1379: /**
1380: * Throws an exception if <code>g</code>'s class is <code>GeometryCollection</code>
1381: * . (Its subclasses do not trigger an exception).
1382: *
1383: *@param g the <code>Geometry</code> to check
1384: *@throws IllegalArgumentException if <code>g</code> is a <code>GeometryCollection</code>
1385: * but not one of its subclasses
1386: */
1387: protected void checkNotGeometryCollection(Geometry g) {
1388: //Don't use instanceof because we want to allow subclasses
1389: if (g.getClass().getName().equals(
1390: "com.vividsolutions.jts.geom.GeometryCollection")) {
1391: throw new IllegalArgumentException(
1392: "This method does not support GeometryCollection arguments");
1393: }
1394: }
1395:
1396: /**
1397: * Returns the minimum and maximum x and y values in this <code>Geometry</code>
1398: * , or a null <code>Envelope</code> if this <code>Geometry</code> is empty.
1399: * Unlike <code>getEnvelopeInternal</code>, this method calculates the <code>Envelope</code>
1400: * each time it is called; <code>getEnvelopeInternal</code> caches the result
1401: * of this method.
1402: *
1403: *@return this <code>Geometry</code>s bounding box; if the <code>Geometry</code>
1404: * is empty, <code>Envelope#isNull</code> will return <code>true</code>
1405: */
1406: protected abstract Envelope computeEnvelopeInternal();
1407:
1408: /**
1409: * Returns whether this <code>Geometry</code> is greater than, equal to,
1410: * or less than another <code>Geometry</code> having the same class.
1411: *
1412: *@param o a <code>Geometry</code> having the same class as this <code>Geometry</code>
1413: *@return a positive number, 0, or a negative number, depending on whether
1414: * this object is greater than, equal to, or less than <code>o</code>, as
1415: * defined in "Normal Form For Geometry" in the JTS Technical
1416: * Specifications
1417: */
1418: protected abstract int compareToSameClass(Object o);
1419:
1420: /**
1421: * Returns whether this <code>Geometry</code> is greater than, equal to,
1422: * or less than another <code>Geometry</code> of the same class.
1423: * using the given {@link CoordinateSequenceComparator}.
1424: *
1425: *@param o a <code>Geometry</code> having the same class as this <code>Geometry</code>
1426: *@param comp a <code>CoordinateSequenceComparator</code>
1427: *@return a positive number, 0, or a negative number, depending on whether
1428: * this object is greater than, equal to, or less than <code>o</code>, as
1429: * defined in "Normal Form For Geometry" in the JTS Technical
1430: * Specifications
1431: */
1432: protected abstract int compareToSameClass(Object o,
1433: CoordinateSequenceComparator comp);
1434:
1435: /**
1436: * Returns the first non-zero result of <code>compareTo</code> encountered as
1437: * the two <code>Collection</code>s are iterated over. If, by the time one of
1438: * the iterations is complete, no non-zero result has been encountered,
1439: * returns 0 if the other iteration is also complete. If <code>b</code>
1440: * completes before <code>a</code>, a positive number is returned; if a
1441: * before b, a negative number.
1442: *
1443: *@param a a <code>Collection</code> of <code>Comparable</code>s
1444: *@param b a <code>Collection</code> of <code>Comparable</code>s
1445: *@return the first non-zero <code>compareTo</code> result, if any;
1446: * otherwise, zero
1447: */
1448: protected int compare(Collection a, Collection b) {
1449: Iterator i = a.iterator();
1450: Iterator j = b.iterator();
1451: while (i.hasNext() && j.hasNext()) {
1452: Comparable aElement = (Comparable) i.next();
1453: Comparable bElement = (Comparable) j.next();
1454: int comparison = aElement.compareTo(bElement);
1455: if (comparison != 0) {
1456: return comparison;
1457: }
1458: }
1459: if (i.hasNext()) {
1460: return 1;
1461: }
1462: if (j.hasNext()) {
1463: return -1;
1464: }
1465: return 0;
1466: }
1467:
1468: protected boolean equal(Coordinate a, Coordinate b, double tolerance) {
1469: if (tolerance == 0) {
1470: return a.equals(b);
1471: }
1472: return a.distance(b) <= tolerance;
1473: }
1474:
1475: private int getClassSortIndex() {
1476: for (int i = 0; i < sortedClasses.length; i++) {
1477: if (sortedClasses[i].isInstance(this )) {
1478: return i;
1479: }
1480: }
1481: Assert.shouldNeverReachHere("Class not supported: "
1482: + this .getClass());
1483: return -1;
1484: }
1485:
1486: private Point createPointFromInternalCoord(Coordinate coord,
1487: Geometry exemplar) {
1488: exemplar.getPrecisionModel().makePrecise(coord);
1489: return exemplar.getFactory().createPoint(coord);
1490: }
1491:
1492: }
|