1 /**********************************************************************
2  *
3  * GEOS - Geometry Engine Open Source
4  * http://geos.osgeo.org
5  *
6  * Copyright (C) 2010 Sandro Santilli <strk@kbt.io>
7  * Copyright (C) 2005-2006 Refractions Research Inc.
8  * Copyright (C) 2001-2002 Vivid Solutions Inc.
9  *
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.
14  *
15  **********************************************************************
16  *
17  * Last port: operation/polygonize/Polygonizer.java rev. 1.6 (JTS-1.10)
18  *
19  **********************************************************************/
20 
21 #include <geos/geom/util/Densifier.h>
22 #include <geos/geom/CoordinateSequenceFactory.h>
23 #include <geos/geom/CoordinateList.h>
24 #include <geos/geom/Geometry.h>
25 #include <geos/geom/GeometryFactory.h>
26 #include <geos/geom/MultiPoint.h>
27 #include <geos/geom/MultiPolygon.h>
28 #include <geos/geom/MultiLineString.h>
29 #include <geos/geom/CoordinateSequence.h>
30 #include <geos/geom/PrecisionModel.h>
31 #include <geos/geom/Polygon.h>
32 #include <geos/geom/Point.h>
33 #include <geos/geom/LineString.h>
34 #include <geos/geom/LinearRing.h>
35 #include <geos/geom/LineSegment.h>
36 #include <geos/geom/GeometryCollection.h>
37 #include <geos/util/Interrupt.h>
38 #include <geos/util/IllegalArgumentException.h>
39 
40 #include <vector>
41 
42 using namespace geos::geom;
43 using namespace geos::geom::util;
44 
45 namespace geos {
46 namespace geom { // geos.geom
47 namespace util { // geos.geom.util
48 
49 /* geom::util::Densifier::DensifyTransformer */
DensifyTransformer(double distTol)50 Densifier::DensifyTransformer::DensifyTransformer(double distTol):
51     distanceTolerance(distTol)
52 {}
53 
54 CoordinateSequence::Ptr
transformCoordinates(const CoordinateSequence * coords,const Geometry * parent)55 Densifier::DensifyTransformer::transformCoordinates(const CoordinateSequence* coords, const Geometry* parent)
56 {
57     Coordinate::Vect emptyPts;
58     Coordinate::Vect inputPts;
59     coords->toVector(inputPts);
60     std::unique_ptr<Coordinate::Vect> newPts = Densifier::densifyPoints(inputPts, distanceTolerance,
61             parent->getPrecisionModel());
62     if(const LineString* ls = dynamic_cast<const LineString*>(parent)) {
63         if(ls->getNumPoints() <= 1) {
64             newPts->clear();
65         }
66     }
67     CoordinateSequence::Ptr csp(factory->getCoordinateSequenceFactory()->create(newPts.release()));
68     return csp;
69 }
70 
71 Geometry::Ptr
transformPolygon(const Polygon * geom,const Geometry * parent)72 Densifier::DensifyTransformer::transformPolygon(const Polygon* geom, const Geometry* parent)
73 {
74     Geometry::Ptr roughGeom = GeometryTransformer::transformPolygon(geom, parent);
75     // don't try and correct if the parent is going to do this
76     if(parent && parent->getGeometryTypeId() == GEOS_MULTIPOLYGON) {
77         return roughGeom;
78     }
79     Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
80     return validGeom;
81 }
82 
83 Geometry::Ptr
transformMultiPolygon(const MultiPolygon * geom,const Geometry * parent)84 Densifier::DensifyTransformer::transformMultiPolygon(const MultiPolygon* geom, const Geometry* parent)
85 {
86     Geometry::Ptr roughGeom = GeometryTransformer::transformMultiPolygon(geom, parent);
87     Geometry::Ptr validGeom(createValidArea(roughGeom.get()));
88     return validGeom;
89 }
90 
91 std::unique_ptr<Geometry>
createValidArea(const Geometry * roughAreaGeom)92 Densifier::DensifyTransformer::createValidArea(const Geometry* roughAreaGeom)
93 {
94     return roughAreaGeom->buffer(0.0);
95 }
96 
97 /* util::Densifier */
98 
Densifier(const Geometry * geom)99 Densifier::Densifier(const Geometry* geom):
100     inputGeom(geom)
101 {}
102 
103 std::unique_ptr<Coordinate::Vect>
densifyPoints(const Coordinate::Vect pts,double distanceTolerance,const PrecisionModel * precModel)104 Densifier::densifyPoints(const Coordinate::Vect pts, double distanceTolerance, const PrecisionModel* precModel)
105 {
106     geom::LineSegment seg;
107     geom::CoordinateList coordList;
108 
109     for(Coordinate::Vect::const_iterator it = pts.begin(), itEnd = pts.end() - 1; it < itEnd; ++it) {
110         seg.p0 = *it;
111         seg.p1 = *(it + 1);
112         coordList.insert(coordList.end(), seg.p0, false);
113         double len = seg.getLength();
114         int densifiedSegCount = (int)(len / distanceTolerance) + 1;
115         if(densifiedSegCount > 1) {
116             double densifiedSegLen = len / densifiedSegCount;
117             for(int j = 1; j < densifiedSegCount; j++) {
118                 double segFract = (j * densifiedSegLen) / len;
119                 Coordinate p;
120                 seg.pointAlong(segFract, p);
121                 precModel->makePrecise(p);
122                 coordList.insert(coordList.end(), p, false);
123             }
124         }
125     }
126     coordList.insert(coordList.end(), pts[pts.size() - 1], false);
127     return coordList.toCoordinateArray();
128 }
129 
130 /**
131  * Densifies a geometry using a given distance tolerance,
132  * and respecting the input geometry's {@link PrecisionModel}.
133  *
134  * @param geom the geometry to densify
135  * @param distanceTolerance the distance tolerance to densify
136  * @return the densified geometry
137  */
138 Geometry::Ptr
densify(const Geometry * geom,double distTol)139 Densifier::densify(const Geometry* geom, double distTol)
140 {
141     util::Densifier densifier(geom);
142     densifier.setDistanceTolerance(distTol);
143     return densifier.getResultGeometry();
144 }
145 
146 void
setDistanceTolerance(double tol)147 Densifier::setDistanceTolerance(double tol)
148 {
149     if(tol <= 0.0) {
150         throw geos::util::IllegalArgumentException("Tolerance must be positive");
151     }
152     distanceTolerance = tol;
153 }
154 
155 Geometry::Ptr
getResultGeometry() const156 Densifier::getResultGeometry() const
157 {
158     DensifyTransformer dt(distanceTolerance);
159     return dt.transform(inputGeom);
160 }
161 
162 
163 } // namespace geos.geom.util
164 } // namespace geos.geom
165 } // namespace geos
166