1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2009 2011 Sandro Santilli <strk@keybit.net>
7 * Copyright (C) 2005-2006 Refractions Research Inc.
8 * Copyright (C) 2001-2002 Vivid Solutions Inc.
10 * This is free software; you can redistribute and/or modify it under
11 * the terms of the GNU Lesser General Public Licence as published
12 * by the Free Software Foundation.
13 * See the COPYING file for more information.
15 **********************************************************************
17 * Last port: geom/Geometry.java rev. 1.112
19 **********************************************************************/
21 #include <geos/geom/BinaryOp.h>
22 #include <geos/geom/Geometry.h>
23 #include <geos/geom/GeometryFactory.h>
24 #include <geos/geom/PrecisionModel.h>
25 #include <geos/geom/CoordinateSequence.h>
26 #include <geos/geom/GeometryComponentFilter.h>
27 #include <geos/geom/GeometryFilter.h>
28 #include <geos/geom/GeometryCollection.h>
29 #include <geos/geom/Point.h>
30 #include <geos/geom/MultiPoint.h>
31 #include <geos/geom/LineString.h>
32 #include <geos/geom/LinearRing.h>
33 #include <geos/geom/MultiLineString.h>
34 #include <geos/geom/MultiPolygon.h>
35 #include <geos/geom/IntersectionMatrix.h>
36 #include <geos/util/IllegalArgumentException.h>
37 #include <geos/algorithm/Centroid.h>
38 #include <geos/algorithm/InteriorPointPoint.h>
39 #include <geos/algorithm/InteriorPointLine.h>
40 #include <geos/algorithm/InteriorPointArea.h>
41 #include <geos/algorithm/ConvexHull.h>
42 #include <geos/operation/predicate/RectangleContains.h>
43 #include <geos/operation/predicate/RectangleIntersects.h>
44 #include <geos/operation/relate/RelateOp.h>
45 #include <geos/operation/valid/IsValidOp.h>
46 #include <geos/operation/overlay/OverlayOp.h>
47 #include <geos/operation/union/UnaryUnionOp.h>
48 #include <geos/operation/overlay/snap/SnapIfNeededOverlayOp.h>
49 #include <geos/operation/buffer/BufferOp.h>
50 #include <geos/operation/distance/DistanceOp.h>
51 #include <geos/operation/IsSimpleOp.h>
52 #include <geos/io/WKBWriter.h>
53 #include <geos/io/WKTWriter.h>
54 #include <geos/version.h>
63 #define SHORTCIRCUIT_PREDICATES 1
66 using namespace geos::algorithm
;
67 using namespace geos::operation::valid
;
68 using namespace geos::operation::relate
;
69 using namespace geos::operation::buffer
;
70 using namespace geos::operation::overlay
;
71 using namespace geos::operation::overlay::snap
;
72 using namespace geos::operation::distance
;
73 using namespace geos::operation
;
76 namespace geom
{ // geos::geom
80 * Return current GEOS version
89 * Return the version of JTS this GEOS
90 * release has been ported from.
98 Geometry::GeometryChangedFilter
Geometry::geometryChangedFilter
;
100 Geometry::Geometry(const GeometryFactory
*newFactory
)
106 if ( factory
== NULL
) {
107 factory
= GeometryFactory::getDefaultInstance();
109 SRID
=factory
->getSRID();
112 Geometry::Geometry(const Geometry
&geom
)
114 SRID(geom
.getSRID()),
115 factory(geom
.factory
),
118 if ( geom
.envelope
.get() )
120 envelope
.reset(new Envelope(*(geom
.envelope
)));
122 //factory=geom.factory;
123 //envelope(new Envelope(*(geom.envelope.get())));
124 //SRID=geom.getSRID();
129 Geometry::hasNonEmptyElements(const vector
<Geometry
*>* geometries
)
131 for (size_t i
=0; i
<geometries
->size(); i
++) {
132 if (!(*geometries
)[i
]->isEmpty()) {
140 Geometry::hasNullElements(const CoordinateSequence
* list
)
142 size_t npts
=list
->getSize();
143 for (size_t i
=0; i
<npts
; ++i
) {
144 if (list
->getAt(i
).isNull()) {
152 Geometry::hasNullElements(const vector
<Geometry
*>* lrs
)
154 size_t n
=lrs
->size();
155 for (size_t i
=0; i
<n
; ++i
) {
156 if ((*lrs
)[i
]==NULL
) {
165 Geometry::isWithinDistance(const Geometry
*geom
,double cDistance
) const
167 const Envelope
*env0
=getEnvelopeInternal();
168 const Envelope
*env1
=geom
->getEnvelopeInternal();
169 double envDist
=env0
->distance(env1
);
172 if (envDist
>cDistance
)
176 // NOTE: this could be implemented more efficiently
177 double geomDist
=distance(geom
);
178 if (geomDist
>cDistance
)
187 Geometry::getCentroid() const
190 if ( ! getCentroid(centPt
) ) return NULL
;
192 // We don't use createPointFromInternalCoord here
193 // because ::getCentroid() takes care about rounding
194 Point
*pt
=getFactory()->createPoint(centPt
);
200 Geometry::getCentroid(Coordinate
& ret
) const
202 if ( isEmpty() ) { return false; }
203 if ( ! Centroid::getCentroid(*this, ret
) ) return false;
204 getPrecisionModel()->makePrecise(ret
); // not in JTS
209 Geometry::getInteriorPoint() const
211 Coordinate interiorPt
;
212 int dim
=getDimension();
214 InteriorPointPoint
intPt(this);
215 if ( ! intPt
.getInteriorPoint(interiorPt
) ) return NULL
;
217 InteriorPointLine
intPt(this);
218 if ( ! intPt
.getInteriorPoint(interiorPt
) ) return NULL
;
220 InteriorPointArea
intPt(this);
221 if ( ! intPt
.getInteriorPoint(interiorPt
) ) return NULL
;
223 Point
*p
=getFactory()->createPointFromInternalCoord(&interiorPt
, this);
228 * Notifies this Geometry that its Coordinates have been changed by an external
229 * party (using a CoordinateFilter, for example). The Geometry will flush
230 * and/or update any information it has cached (such as its {@link Envelope} ).
233 Geometry::geometryChanged()
235 apply_rw(&geometryChangedFilter
);
239 * Notifies this Geometry that its Coordinates have been changed by an external
240 * party. When geometryChanged is called, this method will be called for
241 * this Geometry and its component Geometries.
242 * @see apply(GeometryComponentFilter *)
245 Geometry::geometryChangedAction()
248 envelope
.reset(NULL
);
252 Geometry::isValid() const
254 return IsValidOp(this).isValid();
258 Geometry::getEnvelope() const
260 return getFactory()->toGeometry(getEnvelopeInternal());
264 Geometry::getEnvelopeInternal() const
266 if (!envelope
.get()) {
267 envelope
= computeEnvelopeInternal();
269 return envelope
.get();
273 Geometry::disjoint(const Geometry
*g
) const
275 #ifdef SHORTCIRCUIT_PREDICATES
276 // short-circuit test
277 if (! getEnvelopeInternal()->intersects(g
->getEnvelopeInternal()))
280 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
281 bool res
=im
->isDisjoint();
286 Geometry::touches(const Geometry
*g
) const
288 #ifdef SHORTCIRCUIT_PREDICATES
289 // short-circuit test
290 if (! getEnvelopeInternal()->intersects(g
->getEnvelopeInternal()))
293 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
294 bool res
=im
->isTouches(getDimension(), g
->getDimension());
299 Geometry::intersects(const Geometry
*g
) const
301 #ifdef SHORTCIRCUIT_PREDICATES
302 // short-circuit test
303 if (! getEnvelopeInternal()->intersects(g
->getEnvelopeInternal()))
308 * TODO: (MD) Add optimizations:
311 * If P is in env(A), test for point-in-poly
314 * If env(A1).overlaps(env(A2))
315 * test for overlaps via point-in-poly first (both ways)
316 * Possibly optimize selection of point to test by finding point of A1
317 * closest to centre of env(A2).
318 * (Is there a test where we shouldn't bother - e.g. if env A
319 * is much smaller than env B, maybe there's no point in testing
323 // optimization for rectangle arguments
325 const Polygon
* p
= dynamic_cast<const Polygon
*>(this);
326 return predicate::RectangleIntersects::intersects(*p
, *g
);
328 if (g
->isRectangle()) {
329 const Polygon
* p
= dynamic_cast<const Polygon
*>(g
);
330 return predicate::RectangleIntersects::intersects(*p
, *this);
333 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
334 bool res
=im
->isIntersects();
340 Geometry::covers(const Geometry
* g
) const
342 #ifdef SHORTCIRCUIT_PREDICATES
343 // short-circuit test
344 if (! getEnvelopeInternal()->covers(g
->getEnvelopeInternal()))
348 // optimization for rectangle arguments
350 // since we have already tested that the test envelope
355 auto_ptr
<IntersectionMatrix
> im(relate(g
));
356 return im
->isCovers();
361 Geometry::crosses(const Geometry
*g
) const
363 #ifdef SHORTCIRCUIT_PREDICATES
364 // short-circuit test
365 if (! getEnvelopeInternal()->intersects(g
->getEnvelopeInternal()))
368 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
369 bool res
=im
->isCrosses(getDimension(), g
->getDimension());
374 Geometry::within(const Geometry
*g
) const
376 return g
->contains(this);
380 Geometry::contains(const Geometry
*g
) const
382 #ifdef SHORTCIRCUIT_PREDICATES
383 // short-circuit test
384 if (! getEnvelopeInternal()->contains(g
->getEnvelopeInternal()))
388 // optimization for rectangle arguments
390 const Polygon
* p
= dynamic_cast<const Polygon
*>(this);
391 return predicate::RectangleContains::contains(*p
, *g
);
393 // Incorrect: contains is not commutative
394 //if (g->isRectangle()) {
395 // return predicate::RectangleContains::contains((const Polygon&)*g, *this);
398 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
399 bool res
=im
->isContains();
404 Geometry::overlaps(const Geometry
*g
) const
406 #ifdef SHORTCIRCUIT_PREDICATES
407 // short-circuit test
408 if (! getEnvelopeInternal()->intersects(g
->getEnvelopeInternal()))
411 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
412 bool res
=im
->isOverlaps(getDimension(), g
->getDimension());
417 Geometry::relate(const Geometry
*g
, const string
&intersectionPattern
) const
419 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
420 bool res
=im
->matches(intersectionPattern
);
425 Geometry::equals(const Geometry
*g
) const
427 #ifdef SHORTCIRCUIT_PREDICATES
428 // short-circuit test
429 if (! getEnvelopeInternal()->equals(g
->getEnvelopeInternal()))
432 auto_ptr
<IntersectionMatrix
> im ( relate(g
) );
433 bool res
=im
->isEquals(getDimension(), g
->getDimension());
438 Geometry::relate(const Geometry
*other
) const
439 //throw(IllegalArgumentException *)
441 return RelateOp::relate(this, other
);
445 Geometry::toString() const
451 operator<< (std::ostream
& os
, const Geometry
& geom
)
453 io::WKBWriter writer
;
454 writer
.writeHEX(geom
, os
);
459 Geometry::toText() const
461 io::WKTWriter writer
;
462 return writer
.write(this);
466 Geometry::buffer(double distance
) const
468 return BufferOp::bufferOp(this, distance
);
472 Geometry::buffer(double distance
,int quadrantSegments
) const
474 return BufferOp::bufferOp(this, distance
, quadrantSegments
);
478 Geometry::buffer(double distance
, int quadrantSegments
, int endCapStyle
) const
480 return BufferOp::bufferOp(this, distance
, quadrantSegments
, endCapStyle
);
484 Geometry::convexHull() const
486 return ConvexHull(this).getConvexHull();
490 Geometry::intersection(const Geometry
*other
) const
493 * TODO: MD - add optimization for P-A case using Point-In-Polygon
496 // special case: if one input is empty ==> empty
497 if (isEmpty() || other
->isEmpty() )
499 return getFactory()->createGeometryCollection();
502 return BinaryOp(this, other
, overlayOp(OverlayOp::opINTERSECTION
)).release();
506 Geometry::Union(const Geometry
*other
) const
507 //throw(TopologyException *, IllegalArgumentException *)
510 // special case: if one input is empty ==> other input
511 if ( isEmpty() ) return other
->clone();
512 if ( other
->isEmpty() ) return clone();
514 Geometry
*out
= NULL
;
516 #ifdef SHORTCIRCUIT_PREDICATES
517 // if envelopes are disjoint return a MULTI geom or
518 // a geometrycollection
519 if ( ! getEnvelopeInternal()->intersects(other
->getEnvelopeInternal()) )
521 //cerr<<"SHORTCIRCUITED-UNION engaged"<<endl;
522 const GeometryCollection
*coll
;
524 size_t ngeomsThis
= getNumGeometries();
525 size_t ngeomsOther
= other
->getNumGeometries();
527 // Allocated for ownership transfer
528 vector
<Geometry
*> *v
= new vector
<Geometry
*>();
529 v
->reserve(ngeomsThis
+ngeomsOther
);
532 if ( NULL
!= (coll
= dynamic_cast<const GeometryCollection
*>(this)) )
534 for (size_t i
=0; i
<ngeomsThis
; ++i
)
535 v
->push_back(coll
->getGeometryN(i
)->clone());
537 v
->push_back(this->clone());
540 if ( NULL
!= (coll
= dynamic_cast<const GeometryCollection
*>(other
)) )
542 for (size_t i
=0; i
<ngeomsOther
; ++i
)
543 v
->push_back(coll
->getGeometryN(i
)->clone());
545 v
->push_back(other
->clone());
548 out
= factory
->buildGeometry(v
);
553 return BinaryOp(this, other
, overlayOp(OverlayOp::opUNION
)).release();
558 Geometry::Union() const
560 using geos::operation::geounion::UnaryUnionOp
;
561 return UnaryUnionOp::Union(*this);
565 Geometry::difference(const Geometry
*other
) const
566 //throw(IllegalArgumentException *)
568 // special case: if A.isEmpty ==> empty; if B.isEmpty ==> A
569 if (isEmpty()) return getFactory()->createGeometryCollection();
570 if (other
->isEmpty()) return clone();
572 return BinaryOp(this, other
, overlayOp(OverlayOp::opDIFFERENCE
)).release();
576 Geometry::symDifference(const Geometry
*other
) const
578 // special case: if either input is empty ==> other input
579 if ( isEmpty() ) return other
->clone();
580 if ( other
->isEmpty() ) return clone();
582 // if envelopes are disjoint return a MULTI geom or
583 // a geometrycollection
584 if ( ! getEnvelopeInternal()->intersects(other
->getEnvelopeInternal()) )
586 const GeometryCollection
*coll
;
588 size_t ngeomsThis
= getNumGeometries();
589 size_t ngeomsOther
= other
->getNumGeometries();
591 // Allocated for ownership transfer
592 vector
<Geometry
*> *v
= new vector
<Geometry
*>();
593 v
->reserve(ngeomsThis
+ngeomsOther
);
596 if ( NULL
!= (coll
= dynamic_cast<const GeometryCollection
*>(this)) )
598 for (size_t i
=0; i
<ngeomsThis
; ++i
)
599 v
->push_back(coll
->getGeometryN(i
)->clone());
601 v
->push_back(this->clone());
604 if ( NULL
!= (coll
= dynamic_cast<const GeometryCollection
*>(other
)) )
606 for (size_t i
=0; i
<ngeomsOther
; ++i
)
607 v
->push_back(coll
->getGeometryN(i
)->clone());
609 v
->push_back(other
->clone());
612 return factory
->buildGeometry(v
);
615 return BinaryOp(this, other
, overlayOp(OverlayOp::opSYMDIFFERENCE
)).release();
619 Geometry::compareTo(const Geometry
*geom
) const
622 if ( this == geom
) return 0;
624 if (getClassSortIndex()!=geom
->getClassSortIndex()) {
625 return getClassSortIndex()-geom
->getClassSortIndex();
627 if (isEmpty() && geom
->isEmpty()) {
633 if (geom
->isEmpty()) {
636 return compareToSameClass(geom
);
640 Geometry::isEquivalentClass(const Geometry
*other
) const
642 if (typeid(*this)==typeid(*other
))
649 Geometry::checkNotGeometryCollection(const Geometry
*g
)
650 //throw(IllegalArgumentException *)
652 if ((typeid(*g
)==typeid(GeometryCollection
))) {
653 throw geos::util::IllegalArgumentException("This method does not support GeometryCollection arguments\n");
658 Geometry::getClassSortIndex() const
660 //const type_info &t=typeid(*this);
662 if ( typeid(*this) == typeid(Point
) ) return 0;
663 else if ( typeid(*this) == typeid(MultiPoint
) ) return 1;
664 else if ( typeid(*this) == typeid(LineString
) ) return 2;
665 else if ( typeid(*this) == typeid(LinearRing
) ) return 3;
666 else if ( typeid(*this) == typeid(MultiLineString
) ) return 4;
667 else if ( typeid(*this) == typeid(Polygon
) ) return 5;
668 else if ( typeid(*this) == typeid(MultiPolygon
) ) return 6;
671 assert(typeid(*this) == typeid(GeometryCollection
)); // unsupported class
676 string str
="Class not supported: ";
677 str
.append(typeid(*this).name());
679 Assert::shouldNeverReachHere(str
);
685 Geometry::compare(vector
<Coordinate
> a
, vector
<Coordinate
> b
) const
689 while (i
<a
.size() && j
<b
.size()) {
690 Coordinate
& aCoord
=a
[i
];
691 Coordinate
& bCoord
=b
[j
];
692 int comparison
=aCoord
.compareTo(bCoord
);
709 Geometry::compare(vector
<Geometry
*> a
, vector
<Geometry
*> b
) const
713 while (i
<a
.size() && j
<b
.size()) {
714 Geometry
*aGeom
=a
[i
];
715 Geometry
*bGeom
=b
[j
];
716 int comparison
=aGeom
->compareTo(bGeom
);
733 * Returns the minimum distance between this Geometry
734 * and the other Geometry
736 * @param other the Geometry from which to compute the distance
739 Geometry::distance(const Geometry
*other
) const
741 return DistanceOp::distance(this, other
);
745 * Returns the area of this <code>Geometry</code>.
746 * Areal Geometries have a non-zero area.
747 * They override this function to compute the area.
750 * @return the area of the Geometry
753 Geometry::getArea() const
759 * Returns the length of this <code>Geometry</code>.
760 * Linear geometries return their length.
761 * Areal geometries return their perimeter.
762 * They override this function to compute the area.
765 * @return the length of the Geometry
768 Geometry::getLength() const
773 Geometry::~Geometry()
779 GeometryGreaterThen::operator()(const Geometry
*first
, const Geometry
*second
)
781 if (first
->compareTo(second
)>0)
788 Geometry::equal(const Coordinate
& a
, const Coordinate
& b
,
789 double tolerance
) const
793 return a
== b
; // 2D only !!!
795 //double dist=a.distance(b);
796 return a
.distance(b
)<=tolerance
;
800 Geometry::apply_ro(GeometryFilter
*filter
) const
802 filter
->filter_ro(this);
806 Geometry::apply_rw(GeometryFilter
*filter
)
808 filter
->filter_rw(this);
812 Geometry::apply_ro(GeometryComponentFilter
*filter
) const
814 filter
->filter_ro(this);
818 Geometry::apply_rw(GeometryComponentFilter
*filter
)
820 filter
->filter_rw(this);
824 Geometry::isSimple() const
826 checkNotGeometryCollection(this);
827 operation::IsSimpleOp
op(*this);
828 return op
.isSimple();
832 const PrecisionModel
*
833 Geometry::getPrecisionModel() const
835 return factory
->getPrecisionModel();
838 } // namespace geos::geom