~ubuntu-branches/ubuntu/natty/jts/natty

« back to all changes in this revision

Viewing changes to src/com/vividsolutions/jts/geom/Geometry.java

  • Committer: Bazaar Package Importer
  • Author(s): Wolfgang Baer
  • Date: 2005-08-07 14:12:35 UTC
  • Revision ID: james.westby@ubuntu.com-20050807141235-7hy3ll3xpq79djcb
Tags: upstream-1.6
ImportĀ upstreamĀ versionĀ 1.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
 
 
3
/*
 
4
 * The JTS Topology Suite is a collection of Java classes that
 
5
 * implement the fundamental operations required to validate a given
 
6
 * geo-spatial data set to a known topological specification.
 
7
 *
 
8
 * Copyright (C) 2001 Vivid Solutions
 
9
 *
 
10
 * This library is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU Lesser General Public
 
12
 * License as published by the Free Software Foundation; either
 
13
 * version 2.1 of the License, or (at your option) any later version.
 
14
 *
 
15
 * This library is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * Lesser General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU Lesser General Public
 
21
 * License along with this library; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
23
 *
 
24
 * For more information, contact:
 
25
 *
 
26
 *     Vivid Solutions
 
27
 *     Suite #1A
 
28
 *     2328 Government Street
 
29
 *     Victoria BC  V8T 5G5
 
30
 *     Canada
 
31
 *
 
32
 *     (250)385-6040
 
33
 *     www.vividsolutions.com
 
34
 */
 
35
package com.vividsolutions.jts.geom;
 
36
 
 
37
import java.io.Serializable;
 
38
import java.util.Collection;
 
39
import java.util.Iterator;
 
40
 
 
41
import com.vividsolutions.jts.algorithm.*;
 
42
import com.vividsolutions.jts.io.WKTWriter;
 
43
import com.vividsolutions.jts.operation.buffer.BufferOp;
 
44
import com.vividsolutions.jts.operation.distance.DistanceOp;
 
45
import com.vividsolutions.jts.operation.overlay.OverlayOp;
 
46
import com.vividsolutions.jts.operation.predicate.RectangleIntersects;
 
47
import com.vividsolutions.jts.operation.predicate.RectangleContains;
 
48
import com.vividsolutions.jts.operation.relate.RelateOp;
 
49
import com.vividsolutions.jts.operation.valid.IsValidOp;
 
50
import com.vividsolutions.jts.util.Assert;
 
51
/**
 
52
 *  Basic implementation of <code>Geometry</code>. <P>
 
53
 *
 
54
 *  <code>clone</code> returns a deep copy of the object.
 
55
 *
 
56
 *  <H3>Binary Predicates</H3>
 
57
 * Because it is not clear at this time
 
58
 * what semantics for spatial
 
59
 *  analysis methods involving <code>GeometryCollection</code>s would be useful,
 
60
 *  <code>GeometryCollection</code>s are not supported as arguments to binary
 
61
 *  predicates (other than <code>convexHull</code>) or the <code>relate</code>
 
62
 *  method.
 
63
 *
 
64
 *  <H3>Set-Theoretic Methods</H3>
 
65
 *
 
66
 *  The spatial analysis methods will
 
67
 *  return the most specific class possible to represent the result. If the
 
68
 *  result is homogeneous, a <code>Point</code>, <code>LineString</code>, or
 
69
 *  <code>Polygon</code> will be returned if the result contains a single
 
70
 *  element; otherwise, a <code>MultiPoint</code>, <code>MultiLineString</code>,
 
71
 *  or <code>MultiPolygon</code> will be returned. If the result is
 
72
 *  heterogeneous a <code>GeometryCollection</code> will be returned. <P>
 
73
 *
 
74
 *  Because it is not clear at this time what semantics for set-theoretic
 
75
 *  methods involving <code>GeometryCollection</code>s would be useful,
 
76
 * <code>GeometryCollections</code>
 
77
 *  are not supported as arguments to the set-theoretic methods.
 
78
 *
 
79
 *  <H4>Representation of Computed Geometries </H4>
 
80
 *
 
81
 *  The SFS states that the result
 
82
 *  of a set-theoretic method is the "point-set" result of the usual
 
83
 *  set-theoretic definition of the operation (SFS 3.2.21.1). However, there are
 
84
 *  sometimes many ways of representing a point set as a <code>Geometry</code>.
 
85
 *  <P>
 
86
 *
 
87
 *  The SFS does not specify an unambiguous representation of a given point set
 
88
 *  returned from a spatial analysis method. One goal of JTS is to make this
 
89
 *  specification precise and unambiguous. JTS will use a canonical form for
 
90
 *  <code>Geometry</code>s returned from spatial analysis methods. The canonical
 
91
 *  form is a <code>Geometry</code> which is simple and noded:
 
92
 *  <UL>
 
93
 *    <LI> Simple means that the Geometry returned will be simple according to
 
94
 *    the JTS definition of <code>isSimple</code>.
 
95
 *    <LI> Noded applies only to overlays involving <code>LineString</code>s. It
 
96
 *    means that all intersection points on <code>LineString</code>s will be
 
97
 *    present as endpoints of <code>LineString</code>s in the result.
 
98
 *  </UL>
 
99
 *  This definition implies that non-simple geometries which are arguments to
 
100
 *  spatial analysis methods must be subjected to a line-dissolve process to
 
101
 *  ensure that the results are simple.
 
102
 *
 
103
 *  <H4> Constructed Points And The Precision Model </H4>
 
104
 *
 
105
 *  The results computed by the set-theoretic methods may
 
106
 *  contain constructed points which are not present in the input <code>Geometry</code>
 
107
 *  s. These new points arise from intersections between line segments in the
 
108
 *  edges of the input <code>Geometry</code>s. In the general case it is not
 
109
 *  possible to represent constructed points exactly. This is due to the fact
 
110
 *  that the coordinates of an intersection point may contain twice as many bits
 
111
 *  of precision as the coordinates of the input line segments. In order to
 
112
 *  represent these constructed points explicitly, JTS must truncate them to fit
 
113
 *  the <code>PrecisionModel</code>. <P>
 
114
 *
 
115
 *  Unfortunately, truncating coordinates moves them slightly. Line segments
 
116
 *  which would not be coincident in the exact result may become coincident in
 
117
 *  the truncated representation. This in turn leads to "topology collapses" --
 
118
 *  situations where a computed element has a lower dimension than it would in
 
119
 *  the exact result. <P>
 
120
 *
 
121
 *  When JTS detects topology collapses during the computation of spatial
 
122
 *  analysis methods, it will throw an exception. If possible the exception will
 
123
 *  report the location of the collapse. <P>
 
124
 *
 
125
 *  #equals(Object) and #hashCode are not overridden, so that when two
 
126
 *  topologically equal Geometries are added to HashMaps and HashSets, they
 
127
 *  remain distinct. This behaviour is desired in many cases.
 
128
 *
 
129
 *@version 1.6
 
130
 */
 
131
public abstract class Geometry
 
132
    implements Cloneable, Comparable, Serializable
 
133
{
 
134
    private static final long serialVersionUID = 8763622679187376702L;
 
135
 
 
136
  /**
 
137
   *  The bounding box of this <code>Geometry</code>.
 
138
   */
 
139
  protected Envelope envelope;
 
140
 
 
141
  private final static Class[] sortedClasses = new Class[] {
 
142
      Point.class,
 
143
      MultiPoint.class,
 
144
      LineString.class,
 
145
      LinearRing.class,
 
146
      MultiLineString.class,
 
147
      Polygon.class,
 
148
      MultiPolygon.class,
 
149
      GeometryCollection.class
 
150
      };
 
151
 
 
152
  private final static GeometryComponentFilter geometryChangedFilter = new GeometryComponentFilter() {
 
153
    public void filter(Geometry geom) {
 
154
      geom.geometryChangedAction();
 
155
    }
 
156
  };
 
157
 
 
158
  public Geometry(GeometryFactory factory) {
 
159
    this.factory = factory;
 
160
    this.SRID = factory.getSRID();
 
161
  }
 
162
 
 
163
  private GeometryFactory factory;
 
164
 
 
165
  // MD - no longer used.  Remove in next version
 
166
  //private static final GeometryFactory INTERNAL_GEOMETRY_FACTORY = new GeometryFactory();
 
167
 
 
168
  /**
 
169
   *  The ID of the Spatial Reference System used by this <code>Geometry</code>
 
170
   */
 
171
  protected int SRID;
 
172
 
 
173
  /**
 
174
   *  Returns the name of this object's <code>com.vivid.jts.geom</code>
 
175
   *  interface.
 
176
   *
 
177
   *@return    the name of this <code>Geometry</code>s most specific <code>com.vividsolutions.jts.geom</code>
 
178
   *      interface
 
179
   */
 
180
  //I wonder if we need this method, now that we have renamed the classes to
 
181
  //what their old interfaces were named. Now we can perhaps simply use
 
182
  //getClass().getName(). Who calls this method anyway? [Jon Aquino]
 
183
  public abstract String getGeometryType();
 
184
 
 
185
  /**
 
186
   *  Returns true if the array contains any non-empty <code>Geometry</code>s.
 
187
   *
 
188
   *@param  geometries  an array of <code>Geometry</code>s; no elements may be
 
189
   *      <code>null</code>
 
190
   *@return             <code>true</code> if any of the <code>Geometry</code>s
 
191
   *      <code>isEmpty</code> methods return <code>false</code>
 
192
   */
 
193
  protected static boolean hasNonEmptyElements(Geometry[] geometries) {
 
194
    for (int i = 0; i < geometries.length; i++) {
 
195
      if (!geometries[i].isEmpty()) {
 
196
        return true;
 
197
      }
 
198
    }
 
199
    return false;
 
200
  }
 
201
 
 
202
  /**
 
203
   *  Returns true if the array contains any <code>null</code> elements.
 
204
   *
 
205
   *@param  array  an array to validate
 
206
   *@return        <code>true</code> if any of <code>array</code>s elements are
 
207
   *      <code>null</code>
 
208
   */
 
209
  protected static boolean hasNullElements(Object[] array) {
 
210
    for (int i = 0; i < array.length; i++) {
 
211
      if (array[i] == null) {
 
212
        return true;
 
213
      }
 
214
    }
 
215
    return false;
 
216
  }
 
217
 
 
218
 
 
219
 
 
220
  /**
 
221
   *  Returns the ID of the Spatial Reference System used by the <code>Geometry</code>.
 
222
   *  <P>
 
223
   *
 
224
   *  JTS supports Spatial Reference System information in the simple way
 
225
   *  defined in the SFS. A Spatial Reference System ID (SRID) is present in
 
226
   *  each <code>Geometry</code> object. <code>Geometry</code> provides basic
 
227
   *  accessor operations for this field, but no others. The SRID is represented
 
228
   *  as an integer.
 
229
   *
 
230
   *@return    the ID of the coordinate space in which the <code>Geometry</code>
 
231
   *      is defined.
 
232
   *
 
233
   *  @deprecated use {@link getUserData} instead
 
234
   */
 
235
  public int getSRID() {
 
236
    return SRID;
 
237
  }
 
238
    /**
 
239
   *  Sets the ID of the Spatial Reference System used by the <code>Geometry</code>.
 
240
   *  @deprecated use {@link setUserData} instead
 
241
   */
 
242
  public void setSRID(int SRID) {
 
243
    this.SRID = SRID;
 
244
  }
 
245
 
 
246
  private Object userData = null;
 
247
 
 
248
  /**
 
249
   * Gets the factory which contains the context in which this geometry was created.
 
250
   *
 
251
   * @return the factory for this geometry
 
252
   */
 
253
  public GeometryFactory getFactory() {
 
254
         return factory;
 
255
  }
 
256
 
 
257
  /**
 
258
   * Gets the user data object for this geometry, if any.
 
259
   *
 
260
   * @return the user data object, or <code>null</code> if none set
 
261
   */
 
262
  public Object getUserData() {
 
263
        return userData;
 
264
  }
 
265
 
 
266
  /**
 
267
   * Returns the number of {@link Geometry}s in a {@link GeometryCollection}
 
268
   * (or 1, if the geometry is not a collection).
 
269
   *
 
270
   * @return the number of geometries contained in this geometry
 
271
   */
 
272
  public int getNumGeometries() {
 
273
    return 1;
 
274
  }
 
275
 
 
276
  /**
 
277
   * Returns an element {@link Geometry} from a {@link GeometryCollection}
 
278
   * (or <code>this</code>, if the geometry is not a collection).
 
279
   *
 
280
   * @param n the index of the geometry element
 
281
   * @return the n'th geometry contained in this geometry
 
282
   */
 
283
  public Geometry getGeometryN(int n) {
 
284
    return this;
 
285
  }
 
286
 
 
287
 
 
288
  /**
 
289
   * A simple scheme for applications to add their own custom data to a Geometry.
 
290
   * An example use might be to add an object representing a Coordinate Reference System.
 
291
   * <p>
 
292
   * Note that user data objects are not present in geometries created by
 
293
   * construction methods.
 
294
   *
 
295
   * @param userData an object, the semantics for which are defined by the
 
296
   * application using this Geometry
 
297
   */
 
298
  public void setUserData(Object userData) {
 
299
        this.userData = userData;
 
300
  }
 
301
 
 
302
 
 
303
  /**
 
304
   *  Returns the <code>PrecisionModel</code> used by the <code>Geometry</code>.
 
305
   *
 
306
   *@return    the specification of the grid of allowable points, for this
 
307
   *      <code>Geometry</code> and all other <code>Geometry</code>s
 
308
   */
 
309
  public PrecisionModel getPrecisionModel() {
 
310
    return factory.getPrecisionModel();
 
311
  }
 
312
 
 
313
  /**
 
314
   *  Returns a vertex of this <code>Geometry</code>.
 
315
   *
 
316
   *@return    a {@link Coordinate} which is a vertex of this <code>Geometry</code>.
 
317
   *          Returns <code>null</code> if this Geometry is empty
 
318
   */
 
319
  public abstract Coordinate getCoordinate();
 
320
  /**
 
321
   *  Returns this <code>Geometry</code> s vertices. If you modify the coordinates
 
322
   *  in this array, be sure to call #geometryChanged afterwards.
 
323
   *  The <code>Geometry</code>s contained by composite <code>Geometry</code>s
 
324
   *  must be Geometry's; that is, they must implement <code>getCoordinates</code>.
 
325
   *
 
326
   *@return    the vertices of this <code>Geometry</code>
 
327
   */
 
328
  public abstract Coordinate[] getCoordinates();
 
329
 
 
330
  /**
 
331
   *  Returns the count of this <code>Geometry</code>s vertices. The <code>Geometry</code>
 
332
   *  s contained by composite <code>Geometry</code>s must be
 
333
   *  Geometry's; that is, they must implement <code>getNumPoints</code>
 
334
   *
 
335
   *@return    the number of vertices in this <code>Geometry</code>
 
336
   */
 
337
  public abstract int getNumPoints();
 
338
 
 
339
  /**
 
340
   *  Returns false if the <code>Geometry</code> not simple.
 
341
   *  Subclasses provide their own definition of "simple". If
 
342
   *  this <code>Geometry</code> is empty, returns <code>true</code>. <P>
 
343
   *
 
344
   *  In general, the SFS specifications of simplicity seem to follow the
 
345
   *  following rule:
 
346
   *  <UL>
 
347
   *    <LI> A Geometry is simple iff the only self-intersections are at
 
348
   *    boundary points.
 
349
   *  </UL>
 
350
   *  For all empty <code>Geometry</code>s, <code>isSimple</code> = <code>true</code>.
 
351
   *
 
352
   *@return    <code>true</code> if this <code>Geometry</code> has any points of
 
353
   *      self-tangency, self-intersection or other anomalous points
 
354
   */
 
355
  public abstract boolean isSimple();
 
356
 
 
357
  /**
 
358
   *  Tests the validity of this <code>Geometry</code>.
 
359
   *  Subclasses provide their own definition of "valid".
 
360
   *
 
361
   *@return    <code>true</code> if this <code>Geometry</code> is valid
 
362
   *
 
363
   * @see IsValidOp
 
364
   */
 
365
  public boolean isValid()
 
366
  {
 
367
    IsValidOp isValidOp = new IsValidOp(this);
 
368
    return isValidOp.isValid();
 
369
  }
 
370
 
 
371
  /**
 
372
   *  Returns whether or not the set of points in this <code>Geometry</code> is
 
373
   *  empty.
 
374
   *
 
375
   *@return    <code>true</code> if this <code>Geometry</code> equals the empty
 
376
   *      geometry
 
377
   */
 
378
  public abstract boolean isEmpty();
 
379
 
 
380
  /**
 
381
   *  Returns the minimum distance between this <code>Geometry</code>
 
382
   *  and the <code>Geometry</code> g
 
383
   *
 
384
   *@param  g  the <code>Geometry</code> from which to compute the distance
 
385
   */
 
386
  public double distance(Geometry g)
 
387
  {
 
388
    return DistanceOp.distance(this, g);
 
389
  }
 
390
 
 
391
  /**
 
392
   * Tests whether the distance from this <code>Geometry</code>
 
393
   * to another is less than or equal to a specified value.
 
394
   *
 
395
   * @param geom the Geometry to check the distance to
 
396
   * @param distance the distance value to compare
 
397
   * @return <code>true</code> if the geometries are less than <code>distance</code> apart.
 
398
   */
 
399
  public boolean isWithinDistance(Geometry geom, double distance)
 
400
  {
 
401
    double envDist = getEnvelopeInternal().distance(geom.getEnvelopeInternal());
 
402
    if (envDist > distance)
 
403
      return false;
 
404
    // NOTE: this could be implemented more efficiently
 
405
    double geomDist = this.distance(geom);
 
406
    if (geomDist > distance)
 
407
      return false;
 
408
    return true;
 
409
  }
 
410
 
 
411
  public boolean isRectangle()
 
412
  {
 
413
    // Polygon overrides to check for actual rectangle
 
414
    return false;
 
415
  }
 
416
 
 
417
  /**
 
418
   *  Returns the area of this <code>Geometry</code>.
 
419
   *  Areal Geometries have a non-zero area.
 
420
   *  They override this function to compute the area.
 
421
   *  Others return 0.0
 
422
   *
 
423
   *@return the area of the Geometry
 
424
   */
 
425
  public double getArea()
 
426
  {
 
427
    return 0.0;
 
428
  }
 
429
 
 
430
  /**
 
431
   *  Returns the length of this <code>Geometry</code>.
 
432
   *  Linear geometries return their length.
 
433
   *  Areal geometries return their perimeter.
 
434
   *  They override this function to compute the area.
 
435
   *  Others return 0.0
 
436
   *
 
437
   *@return the length of the Geometry
 
438
   */
 
439
  public double getLength()
 
440
  {
 
441
    return 0.0;
 
442
  }
 
443
 
 
444
  /**
 
445
   * Computes the centroid of this <code>Geometry</code>.
 
446
   * The centroid
 
447
   * is equal to the centroid of the set of component Geometries of highest
 
448
   * dimension (since the lower-dimension geometries contribute zero
 
449
   * "weight" to the centroid)
 
450
   *
 
451
   * @return a {@link Point} which is the centroid of this Geometry
 
452
   */
 
453
  public Point getCentroid()
 
454
  {
 
455
    if (isEmpty()) { return null; }
 
456
    Coordinate centPt = null;
 
457
    int dim = getDimension();
 
458
    if (dim == 0) {
 
459
      CentroidPoint cent = new CentroidPoint();
 
460
      cent.add(this);
 
461
      centPt = cent.getCentroid();
 
462
    }
 
463
    else if (dim == 1) {
 
464
      CentroidLine cent = new CentroidLine();
 
465
      cent.add(this);
 
466
      centPt = cent.getCentroid();
 
467
    }
 
468
    else {
 
469
      CentroidArea cent = new CentroidArea();
 
470
      cent.add(this);
 
471
      centPt = cent.getCentroid();
 
472
    }
 
473
    return createPointFromInternalCoord(centPt, this);
 
474
 
 
475
  }
 
476
 
 
477
  /**
 
478
   * Computes an interior point of this <code>Geometry</code>.
 
479
   * An interior point is guaranteed to lie in the interior of the Geometry,
 
480
   * if it possible to calculate such a point exactly. Otherwise,
 
481
   * the point may lie on the boundary of the geometry.
 
482
   *
 
483
   * @return a {@link Point} which is in the interior of this Geometry
 
484
   */
 
485
  public Point getInteriorPoint()
 
486
  {
 
487
    Coordinate interiorPt = null;
 
488
    int dim = getDimension();
 
489
    if (dim == 0) {
 
490
      InteriorPointPoint intPt = new InteriorPointPoint(this);
 
491
      interiorPt = intPt.getInteriorPoint();
 
492
    }
 
493
    else if (dim == 1) {
 
494
      InteriorPointLine intPt = new InteriorPointLine(this);
 
495
      interiorPt = intPt.getInteriorPoint();
 
496
    }
 
497
    else {
 
498
      InteriorPointArea intPt = new InteriorPointArea(this);
 
499
      interiorPt = intPt.getInteriorPoint();
 
500
    }
 
501
    return createPointFromInternalCoord(interiorPt, this);
 
502
  }
 
503
 
 
504
  /**
 
505
   *  Returns the dimension of this <code>Geometry</code>.
 
506
   *
 
507
   *@return    the dimension of the class implementing this interface, whether
 
508
   *      or not this object is the empty geometry
 
509
   */
 
510
  public abstract int getDimension();
 
511
  /**
 
512
   *  Returns the boundary, or the empty geometry if this <code>Geometry</code>
 
513
   *  is empty. For a discussion of this function, see the OpenGIS Simple
 
514
   *  Features Specification. As stated in SFS Section 2.1.13.1, "the boundary
 
515
   *  of a Geometry is a set of Geometries of the next lower dimension."
 
516
   *
 
517
   *@return    the closure of the combinatorial boundary of this <code>Geometry</code>
 
518
   */
 
519
  public abstract Geometry getBoundary();
 
520
 
 
521
  /**
 
522
   *  Returns the dimension of this <code>Geometry</code>s inherent boundary.
 
523
   *
 
524
   *@return    the dimension of the boundary of the class implementing this
 
525
   *      interface, whether or not this object is the empty geometry. Returns
 
526
   *      <code>Dimension.FALSE</code> if the boundary is the empty geometry.
 
527
   */
 
528
  public abstract int getBoundaryDimension();
 
529
 
 
530
  /**
 
531
   *  Returns this <code>Geometry</code>s bounding box. If this <code>Geometry</code>
 
532
   *  is the empty geometry, returns an empty <code>Point</code>. If the <code>Geometry</code>
 
533
   *  is a point, returns a non-empty <code>Point</code>. Otherwise, returns a
 
534
   *  <code>Polygon</code> whose points are (minx, miny), (maxx, miny), (maxx,
 
535
   *  maxy), (minx, maxy), (minx, miny).
 
536
   *
 
537
   *@return    an empty <code>Point</code> (for empty <code>Geometry</code>s), a
 
538
   *      <code>Point</code> (for <code>Point</code>s) or a <code>Polygon</code>
 
539
   *      (in all other cases)
 
540
   */
 
541
  public Geometry getEnvelope() {
 
542
    return getFactory().toGeometry(getEnvelopeInternal());
 
543
  }
 
544
 
 
545
  /**
 
546
   *  Returns the minimum and maximum x and y values in this <code>Geometry</code>
 
547
   *  , or a null <code>Envelope</code> if this <code>Geometry</code> is empty.
 
548
   *
 
549
   *@return    this <code>Geometry</code>s bounding box; if the <code>Geometry</code>
 
550
   *      is empty, <code>Envelope#isNull</code> will return <code>true</code>
 
551
   */
 
552
  public Envelope getEnvelopeInternal() {
 
553
    if (envelope == null) {
 
554
      envelope = computeEnvelopeInternal();
 
555
    }
 
556
    return envelope;
 
557
  }
 
558
 
 
559
  /**
 
560
   * Notifies this Geometry that its Coordinates have been changed by an external
 
561
   * party (using a CoordinateFilter, for example). The Geometry will flush
 
562
   * and/or update any information it has cached (such as its {@link Envelope} ).
 
563
   */
 
564
  public void geometryChanged() {
 
565
    apply(geometryChangedFilter);
 
566
  }
 
567
 
 
568
  /**
 
569
   * Notifies this Geometry that its Coordinates have been changed by an external
 
570
   * party. When #geometryChanged is called, this method will be called for
 
571
   * this Geometry and its component Geometries.
 
572
   * @see #apply(GeometryComponentFilter)
 
573
   */
 
574
  protected void geometryChangedAction() {
 
575
    envelope = null;
 
576
  }
 
577
 
 
578
  /**
 
579
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
580
   *  <code>Geometry</code>s is FF*FF****.
 
581
   *
 
582
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
583
   *@return        <code>true</code> if the two <code>Geometry</code>s are
 
584
   *      disjoint
 
585
   */
 
586
  public boolean disjoint(Geometry g) {
 
587
    return ! intersects(g);
 
588
  }
 
589
 
 
590
  /**
 
591
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
592
   *  <code>Geometry</code>s is FT*******, F**T***** or F***T****.
 
593
   *
 
594
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
595
   *@return        <code>true</code> if the two <code>Geometry</code>s touch;
 
596
   *      Returns false if both <code>Geometry</code>s are points
 
597
   */
 
598
  public boolean touches(Geometry g) {
 
599
    // short-circuit test
 
600
    if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
 
601
      return false;
 
602
    return relate(g).isTouches(getDimension(), g.getDimension());
 
603
  }
 
604
 
 
605
  /**
 
606
   *  Returns <code>true</code> if <code>disjoint</code> returns false.
 
607
   *
 
608
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
609
   *@return        <code>true</code> if the two <code>Geometry</code>s intersect
 
610
   */
 
611
  public boolean intersects(Geometry g) {
 
612
    // short-circuit envelope test
 
613
    if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
 
614
      return false;
 
615
    // optimizations for rectangle arguments
 
616
    if (isRectangle()) {
 
617
      return RectangleIntersects.intersects((Polygon) this, g);
 
618
    }
 
619
    if (g.isRectangle()) {
 
620
      return RectangleIntersects.intersects((Polygon) g, this);
 
621
    }
 
622
    // general case
 
623
    return relate(g).isIntersects();
 
624
  }
 
625
 
 
626
  /**
 
627
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
628
   *  <code>Geometry</code>s is
 
629
   *  <UL>
 
630
   *    <LI> T*T****** (for a point and a curve, a point and an area or a line
 
631
   *    and an area)
 
632
   *    <LI> 0******** (for two curves)
 
633
   *  </UL>
 
634
   *  .
 
635
   *
 
636
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
637
   *@return        <code>true</code> if the two <code>Geometry</code>s cross.
 
638
   *      For this function to return <code>true</code>, the <code>Geometry</code>
 
639
   *      s must be a point and a curve; a point and a surface; two curves; or a
 
640
   *      curve and a surface.
 
641
   */
 
642
  public boolean crosses(Geometry g) {
 
643
    // short-circuit test
 
644
    if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
 
645
      return false;
 
646
    return relate(g).isCrosses(getDimension(), g.getDimension());
 
647
  }
 
648
 
 
649
  /**
 
650
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
651
   *  <code>Geometry</code>s is T*F**F***.
 
652
   *
 
653
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
654
   *@return        <code>true</code> if this <code>Geometry</code> is within
 
655
   *      <code>other</code>
 
656
   */
 
657
  public boolean within(Geometry g) {
 
658
    return g.contains(this);
 
659
  }
 
660
 
 
661
  /**
 
662
   *  Returns <code>true</code> if <code>other.within(this)</code> returns
 
663
   *  <code>true</code>.
 
664
   *
 
665
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
666
   *@return        <code>true</code> if this <code>Geometry</code> contains
 
667
   *      <code>other</code>
 
668
   */
 
669
  public boolean contains(Geometry g) {
 
670
    // short-circuit test
 
671
    if (! getEnvelopeInternal().contains(g.getEnvelopeInternal()))
 
672
      return false;
 
673
    // optimizations for rectangle arguments
 
674
    if (isRectangle()) {
 
675
      return RectangleContains.contains((Polygon) this, g);
 
676
    }
 
677
    // general case
 
678
    return relate(g).isContains();
 
679
  }
 
680
 
 
681
  /**
 
682
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
683
   *  <code>Geometry</code>s is
 
684
   *  <UL>
 
685
   *    <LI> T*T***T** (for two points or two surfaces)
 
686
   *    <LI> 1*T***T** (for two curves)
 
687
   *  </UL>
 
688
   *  .
 
689
   *
 
690
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
691
   *@return        <code>true</code> if the two <code>Geometry</code>s overlap.
 
692
   *      For this function to return <code>true</code>, the <code>Geometry</code>
 
693
   *      s must be two points, two curves or two surfaces.
 
694
   */
 
695
  public boolean overlaps(Geometry g) {
 
696
    // short-circuit test
 
697
    if (! getEnvelopeInternal().intersects(g.getEnvelopeInternal()))
 
698
      return false;
 
699
    return relate(g).isOverlaps(getDimension(), g.getDimension());
 
700
  }
 
701
 
 
702
  /**
 
703
   *  Returns <code>true</code> if the elements in the DE-9IM intersection
 
704
   *  matrix for the two <code>Geometry</code>s match the elements in <code>intersectionPattern</code>
 
705
   *  , which may be:
 
706
   *  <UL>
 
707
   *    <LI> 0
 
708
   *    <LI> 1
 
709
   *    <LI> 2
 
710
   *    <LI> T ( = 0, 1 or 2)
 
711
   *    <LI> F ( = -1)
 
712
   *    <LI> * ( = -1, 0, 1 or 2)
 
713
   *  </UL>
 
714
   *  For more information on the DE-9IM, see the OpenGIS Simple Features
 
715
   *  Specification.
 
716
   *
 
717
   *@param  other                the <code>Geometry</code> with which to compare
 
718
   *      this <code>Geometry</code>
 
719
   *@param  intersectionPattern  the pattern against which to check the
 
720
   *      intersection matrix for the two <code>Geometry</code>s
 
721
   *@return                      <code>true</code> if the DE-9IM intersection
 
722
   *      matrix for the two <code>Geometry</code>s match <code>intersectionPattern</code>
 
723
   */
 
724
  public boolean relate(Geometry g, String intersectionPattern) {
 
725
    return relate(g).matches(intersectionPattern);
 
726
  }
 
727
 
 
728
  /**
 
729
   *  Returns the DE-9IM intersection matrix for the two <code>Geometry</code>s.
 
730
   *
 
731
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
732
   *@return        a matrix describing the intersections of the interiors,
 
733
   *      boundaries and exteriors of the two <code>Geometry</code>s
 
734
   */
 
735
  public IntersectionMatrix relate(Geometry g) {
 
736
    checkNotGeometryCollection(this);
 
737
    checkNotGeometryCollection(g);
 
738
    return RelateOp.relate(this, g);
 
739
  }
 
740
 
 
741
  /**
 
742
   *  Returns <code>true</code> if the DE-9IM intersection matrix for the two
 
743
   *  <code>Geometry</code>s is T*F**FFF*.
 
744
   *
 
745
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
746
   *@return        <code>true</code> if the two <code>Geometry</code>s are equal
 
747
   */
 
748
  public boolean equals(Geometry g) {
 
749
    // short-circuit test
 
750
    if (! getEnvelopeInternal().equals(g.getEnvelopeInternal()))
 
751
      return false;
 
752
    return relate(g).isEquals(getDimension(), g.getDimension());
 
753
  }
 
754
 
 
755
  //<<PERHAPS:DESIGN>> Override Object#equals [Jon Aquino]
 
756
 
 
757
  public String toString() {
 
758
    return toText();
 
759
  }
 
760
 
 
761
  /**
 
762
   *  Returns the Well-known Text representation of this <code>Geometry</code>.
 
763
   *  For a definition of the Well-known Text format, see the OpenGIS Simple
 
764
   *  Features Specification.
 
765
   *
 
766
   *@return    the Well-known Text representation of this <code>Geometry</code>
 
767
   */
 
768
  public String toText() {
 
769
    WKTWriter writer = new WKTWriter();
 
770
    return writer.write(this);
 
771
  }
 
772
 
 
773
  /**
 
774
   *  Returns a buffer region around this <code>Geometry</code> having the given
 
775
   *  width.
 
776
   * The buffer of a Geometry is
 
777
   * the Minkowski sum or difference
 
778
   * of the Geometry with
 
779
   * a disc of radius <code>distance</code>.
 
780
   *
 
781
   *@param  distance  the width of the buffer, interpreted according to the
 
782
   *      <code>PrecisionModel</code> of the <code>Geometry</code>
 
783
   *@return           all points whose distance from this <code>Geometry</code>
 
784
   *      are less than or equal to <code>distance</code>
 
785
   */
 
786
  public Geometry buffer(double distance) {
 
787
    return BufferOp.bufferOp(this, distance);
 
788
  }
 
789
 
 
790
  /**
 
791
   *  Returns a buffer region around this {@link Geometry} having the given
 
792
   *  width and with a specified number of segments used to approximate curves.
 
793
   * The buffer of a Geometry is the Minkowski sum of the Geometry with
 
794
   * a disc of radius <code>distance</code>.  Curves in the buffer polygon are
 
795
   * approximated with line segments.  This method allows specifying the
 
796
   * accuracy of that approximation.
 
797
   *
 
798
   *@param  distance  the width of the buffer, interpreted according to the
 
799
   *      <code>PrecisionModel</code> of the <code>Geometry</code>
 
800
   *@param quadrantSegments the number of segments to use to approximate a quadrant of a circle
 
801
   *@return           all points whose distance from this <code>Geometry</code>
 
802
   *      are less than or equal to <code>distance</code>
 
803
   */
 
804
  public Geometry buffer(double distance, int quadrantSegments) {
 
805
    return BufferOp.bufferOp(this, distance, quadrantSegments);
 
806
  }
 
807
 
 
808
  /**
 
809
   *  Returns the smallest convex <code>Polygon</code> that contains all the
 
810
   *  points in the <code>Geometry</code>. This obviously applies only to <code>Geometry</code>
 
811
   *  s which contain 3 or more points; the results for degenerate cases are
 
812
   *  specified as follows:
 
813
   *  <TABLE>
 
814
   *    <TR>
 
815
   *      <TH>    Number of <code>Point</code>s in argument <code>Geometry</code>   </TH>
 
816
   *      <TH>    <code>Geometry</code> class of result     </TH>
 
817
   *    </TR>
 
818
   *    <TR>
 
819
   *      <TD>        0      </TD>
 
820
   *      <TD>        empty <code>GeometryCollection</code>      </TD>
 
821
   *    </TR>
 
822
   *    <TR>  <TD>      1     </TD>
 
823
   *      <TD>     <code>Point</code>     </TD>
 
824
   *    </TR>
 
825
   *    <TR>
 
826
   *      <TD>      2     </TD>
 
827
   *      <TD>     <code>LineString</code>     </TD>
 
828
   *    </TR>
 
829
   *    <TR>
 
830
   *      <TD>       3 or more     </TD>
 
831
   *      <TD>      <code>Polygon</code>     </TD>
 
832
   *    </TR>
 
833
   *  </TABLE>
 
834
   *
 
835
   *@return    the minimum-area convex polygon containing this <code>Geometry</code>'
 
836
   *      s points
 
837
   */
 
838
  public Geometry convexHull() {
 
839
    return (new ConvexHull(this)).getConvexHull();
 
840
  }
 
841
 
 
842
  /**
 
843
   *  Returns a <code>Geometry</code> representing the points shared by this
 
844
   *  <code>Geometry</code> and <code>other</code>.
 
845
   *
 
846
   *@param  other  the <code>Geometry</code> with which to compute the
 
847
   *      intersection
 
848
   *@return        the points common to the two <code>Geometry</code>s
 
849
   */
 
850
  public Geometry intersection(Geometry other) {
 
851
    checkNotGeometryCollection(this);
 
852
    checkNotGeometryCollection(other);
 
853
    return OverlayOp.overlayOp(this, other, OverlayOp.INTERSECTION);
 
854
  }
 
855
 
 
856
  /**
 
857
   *  Returns a <code>Geometry</code> representing all the points in this <code>Geometry</code>
 
858
   *  and <code>other</code>.
 
859
   *
 
860
   *@param  other  the <code>Geometry</code> with which to compute the union
 
861
   *@return        a set combining the points of this <code>Geometry</code> and
 
862
   *      the points of <code>other</code>
 
863
   */
 
864
  public Geometry union(Geometry other) {
 
865
    checkNotGeometryCollection(this);
 
866
    checkNotGeometryCollection(other);
 
867
    return OverlayOp.overlayOp(this, other, OverlayOp.UNION);
 
868
  }
 
869
 
 
870
  /**
 
871
   *  Returns a <code>Geometry</code> representing the points making up this
 
872
   *  <code>Geometry</code> that do not make up <code>other</code>. This method
 
873
   *  returns the closure of the resultant <code>Geometry</code>.
 
874
   *
 
875
   *@param  other  the <code>Geometry</code> with which to compute the
 
876
   *      difference
 
877
   *@return        the point set difference of this <code>Geometry</code> with
 
878
   *      <code>other</code>
 
879
   */
 
880
  public Geometry difference(Geometry other) {
 
881
    checkNotGeometryCollection(this);
 
882
    checkNotGeometryCollection(other);
 
883
    return OverlayOp.overlayOp(this, other, OverlayOp.DIFFERENCE);
 
884
  }
 
885
 
 
886
  /**
 
887
   *  Returns a set combining the points in this <code>Geometry</code> not in
 
888
   *  <code>other</code>, and the points in <code>other</code> not in this
 
889
   *  <code>Geometry</code>. This method returns the closure of the resultant
 
890
   *  <code>Geometry</code>.
 
891
   *
 
892
   *@param  other  the <code>Geometry</code> with which to compute the symmetric
 
893
   *      difference
 
894
   *@return        the point set symmetric difference of this <code>Geometry</code>
 
895
   *      with <code>other</code>
 
896
   */
 
897
  public Geometry symDifference(Geometry other) {
 
898
    checkNotGeometryCollection(this);
 
899
    checkNotGeometryCollection(other);
 
900
    return OverlayOp.overlayOp(this, other, OverlayOp.SYMDIFFERENCE);
 
901
  }
 
902
 
 
903
  /**
 
904
   *  Returns true if the two <code>Geometry</code>s are exactly equal,
 
905
   * up to a specified tolerance.
 
906
   * Two Geometries are exactly within a tolerance equal iff:
 
907
   * <ul>
 
908
   * <li>they have the same class
 
909
   * <li>they have the same values of Coordinates,
 
910
   * within the given tolerance distance, in their internal
 
911
   * Coordinate lists, in exactly the same order.
 
912
   * </ul>
 
913
   * If this and the other <code>Geometry</code>s are
 
914
   *  composites and any children are not <code>Geometry</code>s, returns
 
915
   *  false.
 
916
   *
 
917
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
918
   *@parm tolerance distance at or below which two Coordinates will be considered
 
919
   * equal
 
920
   *@return        <code>true</code> if this and the other <code>Geometry</code>
 
921
   *      are of the same class and have equal internal data.
 
922
   */
 
923
  public abstract boolean equalsExact(Geometry other, double tolerance);
 
924
 
 
925
  /**
 
926
   *  Returns true if the two <code>Geometry</code>s are exactly equal.
 
927
   * Two Geometries are exactly equal iff:
 
928
   * <ul>
 
929
   * <li>they have the same class
 
930
   * <li>they have the same values of Coordinates in their internal
 
931
   * Coordinate lists, in exactly the same order.
 
932
   * </ul>
 
933
   * If this and the other <code>Geometry</code>s are
 
934
   *  composites and any children are not <code>Geometry</code>s, returns
 
935
   *  false.
 
936
   * <p>
 
937
   *  This provides a stricter test of equality than
 
938
   *  <code>equals</code>.
 
939
   *
 
940
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
941
   *@return        <code>true</code> if this and the other <code>Geometry</code>
 
942
   *      are of the same class and have equal internal data.
 
943
   */
 
944
  public boolean equalsExact(Geometry other) { return equalsExact(other, 0); }
 
945
 
 
946
  /**
 
947
   *  Performs an operation with or on this <code>Geometry</code>'s
 
948
   *  coordinates. If you are using this method to modify the geometry, be sure
 
949
   *  to call #geometryChanged() afterwards. Note that you cannot use this
 
950
   *  method to
 
951
   *  modify this Geometry if its underlying CoordinateSequence's #get method
 
952
   *  returns a copy of the Coordinate, rather than the actual Coordinate stored
 
953
   *  (if it even stores Coordinates at all).
 
954
   *
 
955
   *@param  filter  the filter to apply to this <code>Geometry</code>'s
 
956
   *      coordinates
 
957
   */
 
958
  public abstract void apply(CoordinateFilter filter);
 
959
 
 
960
  /**
 
961
   *  Performs an operation with or on this <code>Geometry</code> and its
 
962
   *  subelement <code>Geometry</code>s (if any).
 
963
   *  Only GeometryCollections and subclasses
 
964
   *  have subelement Geometry's.
 
965
   *
 
966
   *@param  filter  the filter to apply to this <code>Geometry</code> (and
 
967
   *      its children, if it is a <code>GeometryCollection</code>).
 
968
   */
 
969
  public abstract void apply(GeometryFilter filter);
 
970
 
 
971
  /**
 
972
   *  Performs an operation with or on this Geometry and its
 
973
   *  component Geometry's.  Only GeometryCollections and
 
974
   *  Polygons have component Geometry's; for Polygons they are the LinearRings
 
975
   *  of the shell and holes.
 
976
   *
 
977
   *@param  filter  the filter to apply to this <code>Geometry</code>.
 
978
   */
 
979
  public abstract void apply(GeometryComponentFilter filter);
 
980
 
 
981
  public Object clone() {
 
982
    try {
 
983
      Geometry clone = (Geometry) super.clone();
 
984
      if (clone.envelope != null) { clone.envelope = new Envelope(clone.envelope); }
 
985
      return clone;
 
986
    }
 
987
    catch (CloneNotSupportedException e) {
 
988
      Assert.shouldNeverReachHere();
 
989
      return null;
 
990
    }
 
991
  }
 
992
 
 
993
  /**
 
994
   *  Converts this <code>Geometry</code> to <b>normal form</b> (or <b>
 
995
   *  canonical form</b> ). Normal form is a unique representation for <code>Geometry</code>
 
996
   *  s. It can be used to test whether two <code>Geometry</code>s are equal
 
997
   *  in a way that is independent of the ordering of the coordinates within
 
998
   *  them. Normal form equality is a stronger condition than topological
 
999
   *  equality, but weaker than pointwise equality. The definitions for normal
 
1000
   *  form use the standard lexicographical ordering for coordinates. "Sorted in
 
1001
   *  order of coordinates" means the obvious extension of this ordering to
 
1002
   *  sequences of coordinates.
 
1003
   */
 
1004
  public abstract void normalize();
 
1005
 
 
1006
  /**
 
1007
   *  Returns whether this <code>Geometry</code> is greater than, equal to,
 
1008
   *  or less than another <code>Geometry</code>. <P>
 
1009
   *
 
1010
   *  If their classes are different, they are compared using the following
 
1011
   *  ordering:
 
1012
   *  <UL>
 
1013
   *    <LI> Point (lowest)
 
1014
   *    <LI> MultiPoint
 
1015
   *    <LI> LineString
 
1016
   *    <LI> LinearRing
 
1017
   *    <LI> MultiLineString
 
1018
   *    <LI> Polygon
 
1019
   *    <LI> MultiPolygon
 
1020
   *    <LI> GeometryCollection (highest)
 
1021
   *  </UL>
 
1022
   *  If the two <code>Geometry</code>s have the same class, their first
 
1023
   *  elements are compared. If those are the same, the second elements are
 
1024
   *  compared, etc.
 
1025
   *
 
1026
   *@param  o  a <code>Geometry</code> with which to compare this <code>Geometry</code>
 
1027
   *@return    a positive number, 0, or a negative number, depending on whether
 
1028
   *      this object is greater than, equal to, or less than <code>o</code>, as
 
1029
   *      defined in "Normal Form For Geometry" in the JTS Technical
 
1030
   *      Specifications
 
1031
   */
 
1032
  public int compareTo(Object o) {
 
1033
    Geometry other = (Geometry) o;
 
1034
    if (getClassSortIndex() != other.getClassSortIndex()) {
 
1035
      return getClassSortIndex() - other.getClassSortIndex();
 
1036
    }
 
1037
    if (isEmpty() && other.isEmpty()) {
 
1038
      return 0;
 
1039
    }
 
1040
    if (isEmpty()) {
 
1041
      return -1;
 
1042
    }
 
1043
    if (other.isEmpty()) {
 
1044
      return 1;
 
1045
    }
 
1046
    return compareToSameClass(o);
 
1047
  }
 
1048
 
 
1049
  /**
 
1050
   *  Returns whether the two <code>Geometry</code>s are equal, from the point
 
1051
   *  of view of the <code>equalsExact</code> method. Called by <code>equalsExact</code>
 
1052
   *  . In general, two <code>Geometry</code> classes are considered to be
 
1053
   *  "equivalent" only if they are the same class. An exception is <code>LineString</code>
 
1054
   *  , which is considered to be equivalent to its subclasses.
 
1055
   *
 
1056
   *@param  other  the <code>Geometry</code> with which to compare this <code>Geometry</code>
 
1057
   *      for equality
 
1058
   *@return        <code>true</code> if the classes of the two <code>Geometry</code>
 
1059
   *      s are considered to be equal by the <code>equalsExact</code> method.
 
1060
   */
 
1061
  protected boolean isEquivalentClass(Geometry other) {
 
1062
    return this.getClass().getName().equals(other.getClass().getName());
 
1063
  }
 
1064
 
 
1065
  /**
 
1066
   *  Throws an exception if <code>g</code>'s class is <code>GeometryCollection</code>
 
1067
   *  . (Its subclasses do not trigger an exception).
 
1068
   *
 
1069
   *@param  g                          the <code>Geometry</code> to check
 
1070
   *@throws  IllegalArgumentException  if <code>g</code> is a <code>GeometryCollection</code>
 
1071
   *      but not one of its subclasses
 
1072
   */
 
1073
  protected void checkNotGeometryCollection(Geometry g) {
 
1074
    //Don't use instanceof because we want to allow subclasses
 
1075
    if (g.getClass().getName().equals("com.vividsolutions.jts.geom.GeometryCollection")) {
 
1076
      throw new IllegalArgumentException("This method does not support GeometryCollection arguments");
 
1077
    }
 
1078
  }
 
1079
 
 
1080
 
 
1081
  /**
 
1082
   *  Returns the minimum and maximum x and y values in this <code>Geometry</code>
 
1083
   *  , or a null <code>Envelope</code> if this <code>Geometry</code> is empty.
 
1084
   *  Unlike <code>getEnvelopeInternal</code>, this method calculates the <code>Envelope</code>
 
1085
   *  each time it is called; <code>getEnvelopeInternal</code> caches the result
 
1086
   *  of this method.
 
1087
   *
 
1088
   *@return    this <code>Geometry</code>s bounding box; if the <code>Geometry</code>
 
1089
   *      is empty, <code>Envelope#isNull</code> will return <code>true</code>
 
1090
   */
 
1091
  protected abstract Envelope computeEnvelopeInternal();
 
1092
 
 
1093
  /**
 
1094
   *  Returns whether this <code>Geometry</code> is greater than, equal to,
 
1095
   *  or less than another <code>Geometry</code> having the same class.
 
1096
   *
 
1097
   *@param  o  a <code>Geometry</code> having the same class as this <code>Geometry</code>
 
1098
   *@return    a positive number, 0, or a negative number, depending on whether
 
1099
   *      this object is greater than, equal to, or less than <code>o</code>, as
 
1100
   *      defined in "Normal Form For Geometry" in the JTS Technical
 
1101
   *      Specifications
 
1102
   */
 
1103
  protected abstract int compareToSameClass(Object o);
 
1104
 
 
1105
  /**
 
1106
   *  Returns the first non-zero result of <code>compareTo</code> encountered as
 
1107
   *  the two <code>Collection</code>s are iterated over. If, by the time one of
 
1108
   *  the iterations is complete, no non-zero result has been encountered,
 
1109
   *  returns 0 if the other iteration is also complete. If <code>b</code>
 
1110
   *  completes before <code>a</code>, a positive number is returned; if a
 
1111
   *  before b, a negative number.
 
1112
   *
 
1113
   *@param  a  a <code>Collection</code> of <code>Comparable</code>s
 
1114
   *@param  b  a <code>Collection</code> of <code>Comparable</code>s
 
1115
   *@return    the first non-zero <code>compareTo</code> result, if any;
 
1116
   *      otherwise, zero
 
1117
   */
 
1118
  protected int compare(Collection a, Collection b) {
 
1119
    Iterator i = a.iterator();
 
1120
    Iterator j = b.iterator();
 
1121
    while (i.hasNext() && j.hasNext()) {
 
1122
      Comparable aElement = (Comparable) i.next();
 
1123
      Comparable bElement = (Comparable) j.next();
 
1124
      int comparison = aElement.compareTo(bElement);
 
1125
      if (comparison != 0) {
 
1126
        return comparison;
 
1127
      }
 
1128
    }
 
1129
    if (i.hasNext()) {
 
1130
      return 1;
 
1131
    }
 
1132
    if (j.hasNext()) {
 
1133
      return -1;
 
1134
    }
 
1135
    return 0;
 
1136
  }
 
1137
 
 
1138
  protected boolean equal(Coordinate a, Coordinate b, double tolerance) {
 
1139
    if (tolerance == 0) { return a.equals(b); }
 
1140
    return a.distance(b) <= tolerance;
 
1141
  }
 
1142
 
 
1143
  private int getClassSortIndex() {
 
1144
    for (int i = 0; i < sortedClasses.length; i++) {
 
1145
      if (sortedClasses[i].isInstance(this)) {
 
1146
        return i;
 
1147
      }
 
1148
    }
 
1149
    Assert.shouldNeverReachHere("Class not supported: " + this.getClass());
 
1150
    return -1;
 
1151
  }
 
1152
 
 
1153
  private Point createPointFromInternalCoord(Coordinate coord, Geometry exemplar)
 
1154
  {
 
1155
    exemplar.getPrecisionModel().makePrecise(coord);
 
1156
    return exemplar.getFactory().createPoint(coord);
 
1157
  }
 
1158
 
 
1159
 
 
1160
}
 
1161