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