Complete Note#1 in the http://wiki.osgeo.org/wiki/GEOS_Provenance_Review to get out...
[geos.git] / src / geom / GeometryFactory.cpp
blob20e2a946076e43ed79cdca7267356fd13e94b5ed
1 /**********************************************************************
3 * GEOS - Geometry Engine Open Source
4 * http://geos.osgeo.org
6 * Copyright (C) 2011 Sandro Santilli <strk@keybit.net>
7 * Copyright (C) 2001-2002 Vivid Solutions Inc.
8 * Copyright (C) 2005 Refractions Research 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/GeometryFactory.java r320 (JTS-1.12)
19 **********************************************************************/
21 #include <geos/geom/Coordinate.h>
22 #include <geos/geom/CoordinateArraySequenceFactory.h>
23 #include <geos/geom/CoordinateSequence.h>
24 #include <geos/geom/GeometryFactory.h>
25 #include <geos/geom/Point.h>
26 #include <geos/geom/LineString.h>
27 #include <geos/geom/LinearRing.h>
28 #include <geos/geom/Polygon.h>
29 #include <geos/geom/MultiPoint.h>
30 #include <geos/geom/MultiLineString.h>
31 #include <geos/geom/MultiPolygon.h>
32 #include <geos/geom/GeometryCollection.h>
33 #include <geos/geom/PrecisionModel.h>
34 #include <geos/geom/Envelope.h>
35 #include <geos/util/IllegalArgumentException.h>
37 #include <cassert>
38 #include <vector>
39 #include <typeinfo>
40 #include <cmath>
42 #ifndef GEOS_DEBUG
43 #define GEOS_DEBUG 0
44 #endif
46 #ifdef GEOS_DEBUG
47 #include <iostream>
48 #endif
50 #ifndef GEOS_INLINE
51 # include <geos/geom/GeometryFactory.inl>
52 #endif
54 using namespace std;
56 namespace geos {
57 namespace geom { // geos::geom
59 //namespace {
60 // class gfCoordinateOperation: public CoordinateOperation {
61 // using CoordinateOperation::edit;
62 // public:
63 // virtual CoordinateSequence* edit(const CoordinateSequence *coordinates,
64 // const Geometry *geometry);
65 // };
66 //}
70 /*public*/
71 GeometryFactory::GeometryFactory()
73 precisionModel(new PrecisionModel()),
74 SRID(0),
75 coordinateListFactory(CoordinateArraySequenceFactory::instance())
77 #if GEOS_DEBUG
78 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::GeometryFactory()" << std::endl;
79 std::cerr << "\tcreate PrecisionModel["<<precisionModel<<"]" << std::endl;
80 #endif
83 /*public*/
84 GeometryFactory::GeometryFactory(const PrecisionModel* pm, int newSRID,
85 CoordinateSequenceFactory* nCoordinateSequenceFactory)
87 SRID(newSRID)
89 #if GEOS_DEBUG
90 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::GeometryFactory(PrecisionModel["<<pm<<"], SRID)" << std::endl;
91 #endif
92 if ( ! pm ) {
93 precisionModel=new PrecisionModel();
94 } else {
95 precisionModel=new PrecisionModel(*pm);
98 if ( ! nCoordinateSequenceFactory ) {
99 coordinateListFactory=CoordinateArraySequenceFactory::instance();
100 } else {
101 coordinateListFactory=nCoordinateSequenceFactory;
105 /*public*/
106 GeometryFactory::GeometryFactory(
107 CoordinateSequenceFactory* nCoordinateSequenceFactory)
109 precisionModel(new PrecisionModel()),
110 SRID(0)
112 #if GEOS_DEBUG
113 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::GeometryFactory(CoordinateSequenceFactory["<<nCoordinateSequenceFactory<<"])" << std::endl;
114 #endif
115 if ( ! nCoordinateSequenceFactory ) {
116 coordinateListFactory=CoordinateArraySequenceFactory::instance();
117 } else {
118 coordinateListFactory=nCoordinateSequenceFactory;
122 /*public*/
123 GeometryFactory::GeometryFactory(const PrecisionModel *pm)
125 SRID(0),
126 coordinateListFactory(CoordinateArraySequenceFactory::instance())
128 #if GEOS_DEBUG
129 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::GeometryFactory(PrecisionModel["<<pm<<"])" << std::endl;
130 #endif
131 if ( ! pm ) {
132 precisionModel=new PrecisionModel();
133 } else {
134 precisionModel=new PrecisionModel(*pm);
138 /*public*/
139 GeometryFactory::GeometryFactory(const PrecisionModel* pm, int newSRID)
141 SRID(newSRID),
142 coordinateListFactory(CoordinateArraySequenceFactory::instance())
144 #if GEOS_DEBUG
145 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::GeometryFactory(PrecisionModel["<<pm<<"], SRID)" << std::endl;
146 #endif
147 if ( ! pm ) {
148 precisionModel=new PrecisionModel();
149 } else {
150 precisionModel=new PrecisionModel(*pm);
154 /*public*/
155 GeometryFactory::GeometryFactory(const GeometryFactory &gf)
157 assert(gf.precisionModel);
158 precisionModel=new PrecisionModel(*(gf.precisionModel));
159 SRID=gf.SRID;
160 coordinateListFactory=gf.coordinateListFactory;
163 /*public*/
164 GeometryFactory::~GeometryFactory(){
165 #if GEOS_DEBUG
166 std::cerr << "GEOS_DEBUG: GeometryFactory["<<this<<"]::~GeometryFactory()" << std::endl;
167 #endif
168 delete precisionModel;
171 /*public*/
172 Point*
173 GeometryFactory::createPointFromInternalCoord(const Coordinate* coord,
174 const Geometry *exemplar) const
176 assert(coord);
177 Coordinate newcoord = *coord;
178 exemplar->getPrecisionModel()->makePrecise(&newcoord);
179 return exemplar->getFactory()->createPoint(newcoord);
183 /*public*/
184 Geometry*
185 GeometryFactory::toGeometry(const Envelope* envelope) const
187 Coordinate coord;
189 if (envelope->isNull()) {
190 return createPoint();
192 if (envelope->getMinX()==envelope->getMaxX() && envelope->getMinY()==envelope->getMaxY()) {
193 coord.x = envelope->getMinX();
194 coord.y = envelope->getMinY();
195 return createPoint(coord);
197 CoordinateSequence *cl=CoordinateArraySequenceFactory::instance()->
198 create((size_t) 0, 2);
199 coord.x = envelope->getMinX();
200 coord.y = envelope->getMinY();
201 cl->add(coord);
202 coord.x = envelope->getMaxX();
203 coord.y = envelope->getMinY();
204 cl->add(coord);
205 coord.x = envelope->getMaxX();
206 coord.y = envelope->getMaxY();
207 cl->add(coord);
208 coord.x = envelope->getMinX();
209 coord.y = envelope->getMaxY();
210 cl->add(coord);
211 coord.x = envelope->getMinX();
212 coord.y = envelope->getMinY();
213 cl->add(coord);
215 Polygon *p = createPolygon(createLinearRing(cl), NULL);
216 return p;
219 /*public*/
220 const PrecisionModel*
221 GeometryFactory::getPrecisionModel() const
223 return precisionModel;
226 /*public*/
227 Point*
228 GeometryFactory::createPoint() const
230 return new Point(NULL, this);
233 /*public*/
234 Point*
235 GeometryFactory::createPoint(const Coordinate& coordinate) const
237 if (coordinate.isNull()) {
238 return createPoint();
239 } else {
240 std::size_t dim = ISNAN(coordinate.z) ? 2 : 3;
241 CoordinateSequence *cl = coordinateListFactory->create(new vector<Coordinate>(1, coordinate), dim);
242 //cl->setAt(coordinate, 0);
243 Point *ret = createPoint(cl);
244 return ret;
248 /*public*/
249 Point*
250 GeometryFactory::createPoint(CoordinateSequence *newCoords) const
252 return new Point(newCoords,this);
255 /*public*/
256 Point*
257 GeometryFactory::createPoint(const CoordinateSequence &fromCoords) const
259 CoordinateSequence *newCoords = fromCoords.clone();
260 Point *g = NULL;
261 try {
262 g = new Point(newCoords,this);
263 } catch (...) {
264 delete newCoords;
265 throw;
267 return g;
271 /*public*/
272 MultiLineString*
273 GeometryFactory::createMultiLineString() const
275 return new MultiLineString(NULL,this);
278 /*public*/
279 MultiLineString*
280 GeometryFactory::createMultiLineString(vector<Geometry *> *newLines)
281 const
283 return new MultiLineString(newLines,this);
286 /*public*/
287 MultiLineString*
288 GeometryFactory::createMultiLineString(const vector<Geometry *> &fromLines)
289 const
291 vector<Geometry *>*newGeoms = new vector<Geometry *>(fromLines.size());
292 for (size_t i=0; i<fromLines.size(); i++)
294 const LineString *line = dynamic_cast<const LineString *>(fromLines[i]);
295 if ( ! line ) throw geos::util::IllegalArgumentException("createMultiLineString called with a vector containing non-LineStrings");
296 (*newGeoms)[i] = new LineString(*line);
298 MultiLineString *g = NULL;
299 try {
300 g = new MultiLineString(newGeoms,this);
301 } catch (...) {
302 for (size_t i=0; i<newGeoms->size(); i++) {
303 delete (*newGeoms)[i];
305 delete newGeoms;
306 throw;
308 return g;
311 /*public*/
312 GeometryCollection*
313 GeometryFactory::createGeometryCollection() const
315 return new GeometryCollection(NULL,this);
318 /*public*/
319 Geometry*
320 GeometryFactory::createEmptyGeometry() const
322 return new GeometryCollection(NULL,this);
325 /*public*/
326 GeometryCollection*
327 GeometryFactory::createGeometryCollection(vector<Geometry *> *newGeoms) const
329 return new GeometryCollection(newGeoms,this);
332 /*public*/
333 GeometryCollection*
334 GeometryFactory::createGeometryCollection(const vector<Geometry *> &fromGeoms) const
336 vector<Geometry *> *newGeoms = new vector<Geometry *>(fromGeoms.size());
337 for (size_t i=0; i<fromGeoms.size(); i++) {
338 (*newGeoms)[i] = fromGeoms[i]->clone();
340 GeometryCollection *g = NULL;
341 try {
342 g = new GeometryCollection(newGeoms,this);
343 } catch (...) {
344 for (size_t i=0; i<newGeoms->size(); i++) {
345 delete (*newGeoms)[i];
347 delete newGeoms;
348 throw;
350 return g;
353 /*public*/
354 MultiPolygon*
355 GeometryFactory::createMultiPolygon() const
357 return new MultiPolygon(NULL,this);
360 /*public*/
361 MultiPolygon*
362 GeometryFactory::createMultiPolygon(vector<Geometry *> *newPolys) const
364 return new MultiPolygon(newPolys,this);
367 /*public*/
368 MultiPolygon*
369 GeometryFactory::createMultiPolygon(const vector<Geometry *> &fromPolys) const
371 vector<Geometry *>*newGeoms = new vector<Geometry *>(fromPolys.size());
372 for (size_t i=0; i<fromPolys.size(); i++)
374 (*newGeoms)[i] = fromPolys[i]->clone();
376 MultiPolygon *g = NULL;
377 try {
378 g = new MultiPolygon(newGeoms,this);
379 } catch (...) {
380 for (size_t i=0; i<newGeoms->size(); i++) {
381 delete (*newGeoms)[i];
383 delete newGeoms;
384 throw;
386 return g;
389 /*public*/
390 LinearRing*
391 GeometryFactory::createLinearRing() const
393 return new LinearRing(NULL,this);
396 /*public*/
397 LinearRing*
398 GeometryFactory::createLinearRing(CoordinateSequence* newCoords) const
400 return new LinearRing(newCoords,this);
403 /*public*/
404 Geometry::AutoPtr
405 GeometryFactory::createLinearRing(CoordinateSequence::AutoPtr newCoords) const
407 return Geometry::AutoPtr(new LinearRing(newCoords, this));
410 /*public*/
411 LinearRing*
412 GeometryFactory::createLinearRing(const CoordinateSequence& fromCoords) const
414 CoordinateSequence *newCoords = fromCoords.clone();
415 LinearRing *g = NULL;
416 // construction failure will delete newCoords
417 g = new LinearRing(newCoords, this);
418 return g;
421 /*public*/
422 MultiPoint*
423 GeometryFactory::createMultiPoint(vector<Geometry *> *newPoints) const
425 return new MultiPoint(newPoints,this);
428 /*public*/
429 MultiPoint*
430 GeometryFactory::createMultiPoint(const vector<Geometry *> &fromPoints) const
432 vector<Geometry *>*newGeoms = new vector<Geometry *>(fromPoints.size());
433 for (size_t i=0; i<fromPoints.size(); i++)
435 (*newGeoms)[i] = fromPoints[i]->clone();
438 MultiPoint *g = NULL;
439 try {
440 g = new MultiPoint(newGeoms,this);
441 } catch (...) {
442 for (size_t i=0; i<newGeoms->size(); i++) {
443 delete (*newGeoms)[i];
445 delete newGeoms;
446 throw;
448 return g;
451 /*public*/
452 MultiPoint*
453 GeometryFactory::createMultiPoint() const
455 return new MultiPoint(NULL, this);
458 /*public*/
459 MultiPoint*
460 GeometryFactory::createMultiPoint(const CoordinateSequence &fromCoords) const
462 size_t npts=fromCoords.getSize();
463 vector<Geometry *> *pts=new vector<Geometry *>;
464 pts->reserve(npts);
465 for (size_t i=0; i<npts; ++i) {
466 Point *pt=createPoint(fromCoords.getAt(i));
467 pts->push_back(pt);
469 MultiPoint *mp = NULL;
470 try {
471 mp = createMultiPoint(pts);
472 } catch (...) {
473 for (size_t i=0; i<npts; ++i) delete (*pts)[i];
474 delete pts;
475 throw;
477 return mp;
480 /*public*/
481 MultiPoint*
482 GeometryFactory::createMultiPoint(const std::vector<Coordinate> &fromCoords) const
484 size_t npts=fromCoords.size();
485 vector<Geometry *> *pts=new vector<Geometry *>;
486 pts->reserve(npts);
487 for (size_t i=0; i<npts; ++i) {
488 Point *pt=createPoint(fromCoords[i]);
489 pts->push_back(pt);
491 MultiPoint *mp = NULL;
492 try {
493 mp = createMultiPoint(pts);
494 } catch (...) {
495 for (size_t i=0; i<npts; ++i) delete (*pts)[i];
496 delete pts;
497 throw;
499 return mp;
502 /*public*/
503 Polygon*
504 GeometryFactory::createPolygon() const
506 return new Polygon(NULL, NULL, this);
509 /*public*/
510 Polygon*
511 GeometryFactory::createPolygon(LinearRing *shell, vector<Geometry *> *holes)
512 const
514 return new Polygon(shell, holes, this);
517 /*public*/
518 Polygon*
519 GeometryFactory::createPolygon(const LinearRing &shell, const vector<Geometry *> &holes)
520 const
522 LinearRing *newRing = dynamic_cast<LinearRing *>(shell.clone());
523 vector<Geometry *>*newHoles = new vector<Geometry *>(holes.size());
524 for (size_t i=0; i<holes.size(); i++)
526 (*newHoles)[i] = holes[i]->clone();
528 Polygon *g = NULL;
529 try {
530 g = new Polygon(newRing, newHoles, this);
531 } catch (...) {
532 delete newRing;
533 for (size_t i=0; i<holes.size(); i++)
534 delete (*newHoles)[i];
535 delete newHoles;
536 throw;
538 return g;
541 /*public*/
542 LineString *
543 GeometryFactory::createLineString() const
545 return new LineString(NULL, this);
548 /*public*/
549 std::auto_ptr<LineString>
550 GeometryFactory::createLineString(const LineString& ls) const
552 return std::auto_ptr<LineString>(new LineString(ls));
555 /*public*/
556 LineString*
557 GeometryFactory::createLineString(CoordinateSequence *newCoords)
558 const
560 return new LineString(newCoords, this);
563 /*public*/
564 Geometry::AutoPtr
565 GeometryFactory::createLineString(CoordinateSequence::AutoPtr newCoords)
566 const
568 return Geometry::AutoPtr(new LineString(newCoords, this));
571 /*public*/
572 LineString*
573 GeometryFactory::createLineString(const CoordinateSequence &fromCoords)
574 const
576 CoordinateSequence *newCoords = fromCoords.clone();
577 LineString *g = NULL;
578 // construction failure will delete newCoords
579 g = new LineString(newCoords, this);
580 return g;
583 /*public*/
584 Geometry*
585 GeometryFactory::buildGeometry(vector<Geometry *> *newGeoms) const
587 string geomClass("NULL");
588 bool isHeterogeneous=false;
589 bool hasGeometryCollection=false;
591 for (size_t i=0, n=newGeoms->size(); i<n; ++i)
593 Geometry* geom = (*newGeoms)[i];
594 string partClass(typeid(*geom).name());
595 if (geomClass=="NULL")
597 geomClass=partClass;
599 else if (geomClass!=partClass)
601 isHeterogeneous = true;
603 if ( dynamic_cast<GeometryCollection*>(geom) )
605 hasGeometryCollection=true;
609 // for the empty geometry, return an empty GeometryCollection
610 if (geomClass=="NULL")
612 // we do not need the vector anymore
613 delete newGeoms;
614 return createGeometryCollection();
616 if (isHeterogeneous || hasGeometryCollection)
618 return createGeometryCollection(newGeoms);
621 // At this point we know the collection is not hetereogenous.
622 // Determine the type of the result from the first Geometry in the
623 // list. This should always return a geometry, since otherwise
624 // an empty collection would have already been returned
625 Geometry *geom0=(*newGeoms)[0];
626 bool isCollection=newGeoms->size()>1;
627 if (isCollection)
629 if (typeid(*geom0)==typeid(Polygon)) {
630 return createMultiPolygon(newGeoms);
631 } else if (typeid(*geom0)==typeid(LineString)) {
632 return createMultiLineString(newGeoms);
633 } else if (typeid(*geom0)==typeid(LinearRing)) {
634 return createMultiLineString(newGeoms);
635 } else if (typeid(*geom0)==typeid(Point)) {
636 return createMultiPoint(newGeoms);
637 } else {
638 return createGeometryCollection(newGeoms);
642 // since this is not a collection we can delete vector
643 delete newGeoms;
644 return geom0;
647 /*public*/
648 Geometry*
649 GeometryFactory::buildGeometry(const vector<Geometry *> &fromGeoms) const
651 string geomClass("NULL");
652 bool isHeterogeneous=false;
653 bool isCollection=fromGeoms.size()>1;
654 size_t i;
656 for (i=0; i<fromGeoms.size(); i++) {
657 string partClass(typeid(*fromGeoms[i]).name());
658 if (geomClass=="NULL") {
659 geomClass=partClass;
660 } else if (geomClass!=partClass) {
661 isHeterogeneous = true;
665 // for the empty geometry, return an empty GeometryCollection
666 if (geomClass=="NULL") {
667 return createGeometryCollection();
669 if (isHeterogeneous) {
670 return createGeometryCollection(fromGeoms);
673 // At this point we know the collection is not hetereogenous.
674 // Determine the type of the result from the first Geometry in the
675 // list. This should always return a geometry, since otherwise
676 // an empty collection would have already been returned
677 Geometry *geom0=fromGeoms[0];
678 if (isCollection) {
679 if (typeid(*geom0)==typeid(Polygon)) {
680 return createMultiPolygon(fromGeoms);
681 } else if (typeid(*geom0)==typeid(LineString)) {
682 return createMultiLineString(fromGeoms);
683 } else if (typeid(*geom0)==typeid(LinearRing)) {
684 return createMultiLineString(fromGeoms);
685 } else if (typeid(*geom0)==typeid(Point)) {
686 return createMultiPoint(fromGeoms);
688 assert(0); // buildGeomtry encountered an unkwnon geometry type
691 return geom0->clone();
694 /*public*/
695 Geometry*
696 GeometryFactory::createGeometry(const Geometry *g) const
698 // could this be cached to make this more efficient? Or maybe it isn't enough overhead to bother
699 return g->clone();
700 //GeometryEditor *editor=new GeometryEditor(this);
701 //gfCoordinateOperation *coordOp = new gfCoordinateOperation();
702 //Geometry *ret=editor->edit(g, coordOp);
703 //delete coordOp;
704 //delete editor;
705 //return ret;
708 /*public*/
709 void
710 GeometryFactory::destroyGeometry(Geometry *g) const
712 delete g;
715 /*public static*/
716 const GeometryFactory*
717 GeometryFactory::getDefaultInstance()
719 static GeometryFactory defInstance;
720 return &defInstance;
723 } // namespace geos::geom
724 } // namespace geos
726 /**********************************************************************
727 * $Log$
728 * Revision 1.71 2006/07/08 00:33:54 strk
729 * * configure.in: incremented CAPI minor version, to avoid falling behind any future version from the 2.2. branch.
730 * * source/geom/Geometry.cpp, source/geom/GeometryFactory.cpp,
731 * source/geomgraph/EdgeRing.cpp,
732 * source/headers/geos/geom/Geometry.h,
733 * source/headers/geos/geom/GeometryFactory.h,
734 * source/headers/geos/geom/GeometryFactory.inl,
735 * source/headers/geos/geomgraph/EdgeRing.h:
736 * updated doxygen comments (sync with JTS head).
737 * * source/headers/geos/platform.h.in: include <inttypes.h>
738 * rather then <stdint.h>
740 * Revision 1.70 2006/06/19 21:17:23 strk
741 * port info and doxygen dox.
743 * Revision 1.69 2006/06/12 10:10:39 strk
744 * Fixed getGeometryN() to take size_t rather then int, changed unsigned int parameters to size_t.
746 * Revision 1.68 2006/04/28 11:56:52 strk
747 * * source/geom/GeometryFactory.cpp, source/headers/geos/geom/GeometryFactory.h: added LineString copy constructor.
748 * * source/geom/Polygon.cpp: fixed getBoundary method to always return a geometry composed by LineStrings (not LinearRings)
750 * Revision 1.67 2006/04/11 11:16:25 strk
751 * Added LineString and LinearRing constructors by auto_ptr
753 * Revision 1.66 2006/04/10 13:09:47 strk
754 * Added GeometryFactory::defaultInstance()
755 * Made Geometry::INTERNAL_GEOMETRY_FACTORY an alias for it
756 * removed last deletion from Unload::Release class
758 * Revision 1.65 2006/04/06 12:33:04 strk
759 * More debugging lines
761 * Revision 1.64 2006/03/31 17:51:24 strk
762 * A few assertion checking, comments cleanup, use of initialization lists
763 * in constructors, handled NULL parameters.
765 * Revision 1.63 2006/03/24 09:52:41 strk
766 * USE_INLINE => GEOS_INLINE
768 * Revision 1.62 2006/03/20 10:11:50 strk
769 * Bug #67 - Debugging helpers in GeometryFactory class
771 * Revision 1.61 2006/03/09 16:46:47 strk
772 * geos::geom namespace definition, first pass at headers split
774 * Revision 1.60 2006/03/06 19:40:46 strk
775 * geos::util namespace. New GeometryCollection::iterator interface, many cleanups.
777 * Revision 1.59 2006/03/03 10:46:21 strk
778 * Removed 'using namespace' from headers, added missing headers in .cpp files, removed useless includes in headers (bug#46)
780 * Revision 1.58 2006/03/01 18:37:08 strk
781 * Geometry::createPointFromInternalCoord dropped (it's a duplication of GeometryFactory::createPointFromInternalCoord).
782 * Fixed bugs in InteriorPoint* and getCentroid() inserted by previous commits.
784 * Revision 1.57 2006/02/23 23:17:52 strk
785 * - Coordinate::nullCoordinate made private
786 * - Simplified Coordinate inline definitions
787 * - LMGeometryComponentFilter definition moved to LineMerger.cpp file
788 * - Misc cleanups
790 * Revision 1.56 2006/02/09 15:52:47 strk
791 * GEOSException derived from std::exception; always thrown and cought by const ref.
793 **********************************************************************/