Complete Note#1 in the http://wiki.osgeo.org/wiki/GEOS_Provenance_Review to get out...
[geos.git] / src / geom / Geometry.cpp
blobb4e4bc34bbc2da9f4f393678985a3c1f993d6e5e
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/CentroidPoint.h>
38 #include <geos/algorithm/CentroidLine.h>
39 #include <geos/algorithm/CentroidArea.h>
40 #include <geos/algorithm/InteriorPointPoint.h>
41 #include <geos/algorithm/InteriorPointLine.h>
42 #include <geos/algorithm/InteriorPointArea.h>
43 #include <geos/algorithm/ConvexHull.h>
44 #include <geos/operation/predicate/RectangleContains.h>
45 #include <geos/operation/predicate/RectangleIntersects.h>
46 #include <geos/operation/relate/RelateOp.h>
47 #include <geos/operation/valid/IsValidOp.h>
48 #include <geos/operation/overlay/OverlayOp.h>
49 #include <geos/operation/union/UnaryUnionOp.h>
50 #include <geos/operation/overlay/snap/SnapIfNeededOverlayOp.h>
51 #include <geos/operation/buffer/BufferOp.h>
52 #include <geos/operation/distance/DistanceOp.h>
53 #include <geos/operation/IsSimpleOp.h>
54 #include <geos/io/WKBWriter.h>
55 #include <geos/io/WKTWriter.h>
56 #include <geos/version.h>
58 #include <algorithm>
59 #include <string>
60 #include <typeinfo>
61 #include <vector>
62 #include <cassert>
63 #include <memory>
65 #define SHORTCIRCUIT_PREDICATES 1
67 using namespace std;
68 using namespace geos::algorithm;
69 using namespace geos::operation::valid;
70 using namespace geos::operation::relate;
71 using namespace geos::operation::buffer;
72 using namespace geos::operation::overlay;
73 using namespace geos::operation::overlay::snap;
74 using namespace geos::operation::distance;
75 using namespace geos::operation;
77 namespace geos {
78 namespace geom { // geos::geom
82 * Return current GEOS version
84 string
85 geosversion()
87 return GEOS_VERSION;
91 * Return the version of JTS this GEOS
92 * release has been ported from.
94 string
95 jtsport()
97 return GEOS_JTS_PORT;
100 Geometry::GeometryChangedFilter Geometry::geometryChangedFilter;
102 // REMOVE THIS, use GeometryFactory::getDefaultInstance() directly
103 const GeometryFactory* Geometry::INTERNAL_GEOMETRY_FACTORY=GeometryFactory::getDefaultInstance();
105 Geometry::Geometry(const GeometryFactory *newFactory)
107 envelope(NULL),
108 factory(newFactory),
109 userData(NULL)
111 if ( factory == NULL ) {
112 factory = INTERNAL_GEOMETRY_FACTORY;
114 SRID=factory->getSRID();
117 Geometry::Geometry(const Geometry &geom)
119 SRID(geom.getSRID()),
120 factory(geom.factory),
121 userData(NULL)
123 if ( geom.envelope.get() )
125 envelope.reset(new Envelope(*(geom.envelope)));
127 //factory=geom.factory;
128 //envelope(new Envelope(*(geom.envelope.get())));
129 //SRID=geom.getSRID();
130 //userData=NULL;
133 bool
134 Geometry::hasNonEmptyElements(const vector<Geometry *>* geometries)
136 for (size_t i=0; i<geometries->size(); i++) {
137 if (!(*geometries)[i]->isEmpty()) {
138 return true;
141 return false;
144 bool
145 Geometry::hasNullElements(const CoordinateSequence* list)
147 size_t npts=list->getSize();
148 for (size_t i=0; i<npts; ++i) {
149 if (list->getAt(i).isNull()) {
150 return true;
153 return false;
156 bool
157 Geometry::hasNullElements(const vector<Geometry *>* lrs)
159 size_t n=lrs->size();
160 for (size_t i=0; i<n; ++i) {
161 if ((*lrs)[i]==NULL) {
162 return true;
165 return false;
168 /* public */
169 bool
170 Geometry::isWithinDistance(const Geometry *geom,double cDistance) const
172 const Envelope *env0=getEnvelopeInternal();
173 const Envelope *env1=geom->getEnvelopeInternal();
174 double envDist=env0->distance(env1);
175 //delete env0;
176 //delete env1;
177 if (envDist>cDistance)
179 return false;
181 // NOTE: this could be implemented more efficiently
182 double geomDist=distance(geom);
183 if (geomDist>cDistance)
185 return false;
187 return true;
190 /*public*/
191 Point*
192 Geometry::getCentroid() const
194 Coordinate centPt;
195 if ( ! getCentroid(centPt) ) return NULL;
197 // We don't use createPointFromInternalCoord here
198 // because ::getCentroid() takes care about rounding
199 Point *pt=getFactory()->createPoint(centPt);
200 return pt;
203 /*public*/
204 bool
205 Geometry::getCentroid(Coordinate& ret) const
207 if ( isEmpty() ) { return false; }
209 Coordinate c;
211 int dim=getDimension();
212 if(dim==0) {
213 CentroidPoint cent;
214 cent.add(this);
215 if ( ! cent.getCentroid(c) )
216 return false;
217 } else if (dim==1) {
218 CentroidLine cent;
219 cent.add(this);
220 if ( ! cent.getCentroid(c) )
221 return false;
222 } else {
223 CentroidArea cent;
224 cent.add(this);
225 if ( ! cent.getCentroid(c) )
226 return false;
229 getPrecisionModel()->makePrecise(c);
230 ret=c;
232 return true;
235 Point*
236 Geometry::getInteriorPoint() const
238 Coordinate interiorPt;
239 int dim=getDimension();
240 if (dim==0) {
241 InteriorPointPoint intPt(this);
242 if ( ! intPt.getInteriorPoint(interiorPt) ) return NULL;
243 } else if (dim==1) {
244 InteriorPointLine intPt(this);
245 if ( ! intPt.getInteriorPoint(interiorPt) ) return NULL;
246 } else {
247 InteriorPointArea intPt(this);
248 if ( ! intPt.getInteriorPoint(interiorPt) ) return NULL;
250 Point *p=getFactory()->createPointFromInternalCoord(&interiorPt, this);
251 return p;
255 * Notifies this Geometry that its Coordinates have been changed by an external
256 * party (using a CoordinateFilter, for example). The Geometry will flush
257 * and/or update any information it has cached (such as its {@link Envelope} ).
259 void
260 Geometry::geometryChanged()
262 apply_rw(&geometryChangedFilter);
266 * Notifies this Geometry that its Coordinates have been changed by an external
267 * party. When geometryChanged is called, this method will be called for
268 * this Geometry and its component Geometries.
269 * @see apply(GeometryComponentFilter *)
271 void
272 Geometry::geometryChangedAction()
274 //delete envelope;
275 envelope.reset(NULL);
278 bool
279 Geometry::isValid() const
281 return IsValidOp(this).isValid();
284 Geometry*
285 Geometry::getEnvelope() const
287 return getFactory()->toGeometry(getEnvelopeInternal());
290 const Envelope *
291 Geometry::getEnvelopeInternal() const
293 if (!envelope.get()) {
294 envelope = computeEnvelopeInternal();
296 return envelope.get();
299 bool
300 Geometry::disjoint(const Geometry *g) const
302 #ifdef SHORTCIRCUIT_PREDICATES
303 // short-circuit test
304 if (! getEnvelopeInternal()->intersects(g->getEnvelopeInternal()))
305 return true;
306 #endif
307 auto_ptr<IntersectionMatrix> im ( relate(g) );
308 bool res=im->isDisjoint();
309 return res;
312 bool
313 Geometry::touches(const Geometry *g) const
315 #ifdef SHORTCIRCUIT_PREDICATES
316 // short-circuit test
317 if (! getEnvelopeInternal()->intersects(g->getEnvelopeInternal()))
318 return false;
319 #endif
320 auto_ptr<IntersectionMatrix> im ( relate(g) );
321 bool res=im->isTouches(getDimension(), g->getDimension());
322 return res;
325 bool
326 Geometry::intersects(const Geometry *g) const
328 #ifdef SHORTCIRCUIT_PREDICATES
329 // short-circuit test
330 if (! getEnvelopeInternal()->intersects(g->getEnvelopeInternal()))
331 return false;
332 #endif
335 * TODO: (MD) Add optimizations:
337 * - for P-A case:
338 * If P is in env(A), test for point-in-poly
340 * - for A-A case:
341 * If env(A1).overlaps(env(A2))
342 * test for overlaps via point-in-poly first (both ways)
343 * Possibly optimize selection of point to test by finding point of A1
344 * closest to centre of env(A2).
345 * (Is there a test where we shouldn't bother - e.g. if env A
346 * is much smaller than env B, maybe there's no point in testing
347 * pt(B) in env(A)?
350 // optimization for rectangle arguments
351 if (isRectangle()) {
352 const Polygon* p = dynamic_cast<const Polygon*>(this);
353 return predicate::RectangleIntersects::intersects(*p, *g);
355 if (g->isRectangle()) {
356 const Polygon* p = dynamic_cast<const Polygon*>(g);
357 return predicate::RectangleIntersects::intersects(*p, *this);
360 auto_ptr<IntersectionMatrix> im ( relate(g) );
361 bool res=im->isIntersects();
362 return res;
365 /*public*/
366 bool
367 Geometry::covers(const Geometry* g) const
369 #ifdef SHORTCIRCUIT_PREDICATES
370 // short-circuit test
371 if (! getEnvelopeInternal()->covers(g->getEnvelopeInternal()))
372 return false;
373 #endif
375 // optimization for rectangle arguments
376 if (isRectangle()) {
377 // since we have already tested that the test envelope
378 // is covered
379 return true;
382 auto_ptr<IntersectionMatrix> im(relate(g));
383 return im->isCovers();
387 bool
388 Geometry::crosses(const Geometry *g) const
390 #ifdef SHORTCIRCUIT_PREDICATES
391 // short-circuit test
392 if (! getEnvelopeInternal()->intersects(g->getEnvelopeInternal()))
393 return false;
394 #endif
395 auto_ptr<IntersectionMatrix> im ( relate(g) );
396 bool res=im->isCrosses(getDimension(), g->getDimension());
397 return res;
400 bool
401 Geometry::within(const Geometry *g) const
403 return g->contains(this);
406 bool
407 Geometry::contains(const Geometry *g) const
409 #ifdef SHORTCIRCUIT_PREDICATES
410 // short-circuit test
411 if (! getEnvelopeInternal()->contains(g->getEnvelopeInternal()))
412 return false;
413 #endif
415 // optimization for rectangle arguments
416 if (isRectangle()) {
417 const Polygon* p = dynamic_cast<const Polygon*>(this);
418 return predicate::RectangleContains::contains(*p, *g);
420 // Incorrect: contains is not commutative
421 //if (g->isRectangle()) {
422 // return predicate::RectangleContains::contains((const Polygon&)*g, *this);
425 auto_ptr<IntersectionMatrix> im ( relate(g) );
426 bool res=im->isContains();
427 return res;
430 bool
431 Geometry::overlaps(const Geometry *g) const
433 #ifdef SHORTCIRCUIT_PREDICATES
434 // short-circuit test
435 if (! getEnvelopeInternal()->intersects(g->getEnvelopeInternal()))
436 return false;
437 #endif
438 auto_ptr<IntersectionMatrix> im ( relate(g) );
439 bool res=im->isOverlaps(getDimension(), g->getDimension());
440 return res;
443 bool
444 Geometry::relate(const Geometry *g, const string &intersectionPattern) const
446 auto_ptr<IntersectionMatrix> im ( relate(g) );
447 bool res=im->matches(intersectionPattern);
448 return res;
451 bool
452 Geometry::equals(const Geometry *g) const
454 #ifdef SHORTCIRCUIT_PREDICATES
455 // short-circuit test
456 if (! getEnvelopeInternal()->equals(g->getEnvelopeInternal()))
457 return false;
458 #endif
459 auto_ptr<IntersectionMatrix> im ( relate(g) );
460 bool res=im->isEquals(getDimension(), g->getDimension());
461 return res;
464 IntersectionMatrix*
465 Geometry::relate(const Geometry *other) const
466 //throw(IllegalArgumentException *)
468 return RelateOp::relate(this, other);
471 string
472 Geometry::toString() const
474 return toText();
477 std::ostream&
478 operator<< (std::ostream& os, const Geometry& geom)
480 io::WKBWriter writer;
481 writer.writeHEX(geom, os);
482 return os;
485 string
486 Geometry::toText() const
488 io::WKTWriter writer;
489 return writer.write(this);
492 Geometry*
493 Geometry::buffer(double distance) const
495 return BufferOp::bufferOp(this, distance);
498 Geometry*
499 Geometry::buffer(double distance,int quadrantSegments) const
501 return BufferOp::bufferOp(this, distance, quadrantSegments);
504 Geometry*
505 Geometry::buffer(double distance, int quadrantSegments, int endCapStyle) const
507 return BufferOp::bufferOp(this, distance, quadrantSegments, endCapStyle);
510 Geometry*
511 Geometry::convexHull() const
513 return ConvexHull(this).getConvexHull();
516 Geometry*
517 Geometry::intersection(const Geometry *other) const
520 * TODO: MD - add optimization for P-A case using Point-In-Polygon
523 // special case: if one input is empty ==> empty
524 if (isEmpty() || other->isEmpty() )
526 return getFactory()->createGeometryCollection();
529 return BinaryOp(this, other, overlayOp(OverlayOp::opINTERSECTION)).release();
532 Geometry*
533 Geometry::Union(const Geometry *other) const
534 //throw(TopologyException *, IllegalArgumentException *)
537 // special case: if one input is empty ==> other input
538 if ( isEmpty() ) return other->clone();
539 if ( other->isEmpty() ) return clone();
541 Geometry *out = NULL;
543 #ifdef SHORTCIRCUIT_PREDICATES
544 // if envelopes are disjoint return a MULTI geom or
545 // a geometrycollection
546 if ( ! getEnvelopeInternal()->intersects(other->getEnvelopeInternal()) )
548 //cerr<<"SHORTCIRCUITED-UNION engaged"<<endl;
549 const GeometryCollection *coll;
551 size_t ngeomsThis = getNumGeometries();
552 size_t ngeomsOther = other->getNumGeometries();
554 // Allocated for ownership transfer
555 vector<Geometry *> *v = new vector<Geometry *>();
556 v->reserve(ngeomsThis+ngeomsOther);
559 if ( NULL != (coll = dynamic_cast<const GeometryCollection *>(this)) )
561 for (size_t i=0; i<ngeomsThis; ++i)
562 v->push_back(coll->getGeometryN(i)->clone());
563 } else {
564 v->push_back(this->clone());
567 if ( NULL != (coll = dynamic_cast<const GeometryCollection *>(other)) )
569 for (size_t i=0; i<ngeomsOther; ++i)
570 v->push_back(coll->getGeometryN(i)->clone());
571 } else {
572 v->push_back(other->clone());
575 out = factory->buildGeometry(v);
576 return out;
578 #endif
580 return BinaryOp(this, other, overlayOp(OverlayOp::opUNION)).release();
583 /* public */
584 Geometry::AutoPtr
585 Geometry::Union() const
587 using geos::operation::geounion::UnaryUnionOp;
588 return UnaryUnionOp::Union(*this);
591 Geometry*
592 Geometry::difference(const Geometry *other) const
593 //throw(IllegalArgumentException *)
595 // special case: if A.isEmpty ==> empty; if B.isEmpty ==> A
596 if (isEmpty()) return getFactory()->createGeometryCollection();
597 if (other->isEmpty()) return clone();
599 return BinaryOp(this, other, overlayOp(OverlayOp::opDIFFERENCE)).release();
602 Geometry*
603 Geometry::symDifference(const Geometry *other) const
605 // special case: if either input is empty ==> other input
606 if ( isEmpty() ) return other->clone();
607 if ( other->isEmpty() ) return clone();
609 return BinaryOp(this, other, overlayOp(OverlayOp::opSYMDIFFERENCE)).release();
613 Geometry::compareTo(const Geometry *geom) const
615 // compare to self
616 if ( this == geom ) return 0;
618 if (getClassSortIndex()!=geom->getClassSortIndex()) {
619 return getClassSortIndex()-geom->getClassSortIndex();
621 if (isEmpty() && geom->isEmpty()) {
622 return 0;
624 if (isEmpty()) {
625 return -1;
627 if (geom->isEmpty()) {
628 return 1;
630 return compareToSameClass(geom);
633 bool
634 Geometry::isEquivalentClass(const Geometry *other) const
636 if (typeid(*this)==typeid(*other))
637 return true;
638 else
639 return false;
642 void
643 Geometry::checkNotGeometryCollection(const Geometry *g)
644 //throw(IllegalArgumentException *)
646 if ((typeid(*g)==typeid(GeometryCollection))) {
647 throw geos::util::IllegalArgumentException("This method does not support GeometryCollection arguments\n");
652 Geometry::getClassSortIndex() const
654 //const type_info &t=typeid(*this);
656 if ( typeid(*this) == typeid(Point) ) return 0;
657 else if ( typeid(*this) == typeid(MultiPoint) ) return 1;
658 else if ( typeid(*this) == typeid(LineString) ) return 2;
659 else if ( typeid(*this) == typeid(LinearRing) ) return 3;
660 else if ( typeid(*this) == typeid(MultiLineString) ) return 4;
661 else if ( typeid(*this) == typeid(Polygon) ) return 5;
662 else if ( typeid(*this) == typeid(MultiPolygon) ) return 6;
663 else
665 assert(typeid(*this) == typeid(GeometryCollection)); // unsupported class
666 return 7;
669 #if 0
670 string str="Class not supported: ";
671 str.append(typeid(*this).name());
672 str.append("");
673 Assert::shouldNeverReachHere(str);
674 return -1;
675 #endif
679 Geometry::compare(vector<Coordinate> a, vector<Coordinate> b) const
681 size_t i=0;
682 size_t j=0;
683 while (i<a.size() && j<b.size()) {
684 Coordinate& aCoord=a[i];
685 Coordinate& bCoord=b[j];
686 int comparison=aCoord.compareTo(bCoord);
687 if (comparison!=0) {
688 return comparison;
690 i++;
691 j++;
693 if (i<a.size()) {
694 return 1;
696 if (j<b.size()) {
697 return -1;
699 return 0;
703 Geometry::compare(vector<Geometry *> a, vector<Geometry *> b) const
705 size_t i=0;
706 size_t j=0;
707 while (i<a.size() && j<b.size()) {
708 Geometry *aGeom=a[i];
709 Geometry *bGeom=b[j];
710 int comparison=aGeom->compareTo(bGeom);
711 if (comparison!=0) {
712 return comparison;
714 i++;
715 j++;
717 if (i<a.size()) {
718 return 1;
720 if (j<b.size()) {
721 return -1;
723 return 0;
727 * Returns the minimum distance between this Geometry
728 * and the other Geometry
730 * @param other the Geometry from which to compute the distance
732 double
733 Geometry::distance(const Geometry *other) const
735 return DistanceOp::distance(this, other);
739 * Returns the area of this <code>Geometry</code>.
740 * Areal Geometries have a non-zero area.
741 * They override this function to compute the area.
742 * Others return 0.0
744 * @return the area of the Geometry
746 double
747 Geometry::getArea() const
749 return 0.0;
753 * Returns the length of this <code>Geometry</code>.
754 * Linear geometries return their length.
755 * Areal geometries return their perimeter.
756 * They override this function to compute the area.
757 * Others return 0.0
759 * @return the length of the Geometry
761 double
762 Geometry::getLength() const
764 return 0.0;
767 Geometry::~Geometry()
769 //delete envelope;
772 bool
773 GeometryGreaterThen::operator()(const Geometry *first, const Geometry *second)
775 if (first->compareTo(second)>0)
776 return true;
777 else
778 return false;
781 bool
782 Geometry::equal(const Coordinate& a, const Coordinate& b,
783 double tolerance) const
785 if (tolerance==0)
787 return a == b; // 2D only !!!
789 //double dist=a.distance(b);
790 return a.distance(b)<=tolerance;
793 void
794 Geometry::apply_ro(GeometryFilter *filter) const
796 filter->filter_ro(this);
799 void
800 Geometry::apply_rw(GeometryFilter *filter)
802 filter->filter_rw(this);
805 void
806 Geometry::apply_ro(GeometryComponentFilter *filter) const
808 filter->filter_ro(this);
811 void
812 Geometry::apply_rw(GeometryComponentFilter *filter)
814 filter->filter_rw(this);
817 bool
818 Geometry::isSimple() const
820 checkNotGeometryCollection(this);
821 operation::IsSimpleOp op(*this);
822 return op.isSimple();
825 /* public */
826 const PrecisionModel*
827 Geometry::getPrecisionModel() const
829 return factory->getPrecisionModel();
832 } // namespace geos::geom
833 } // namespace geos