/src/geos/src/operation/overlay/snap/GeometrySnapper.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2009-2010 Sandro Santilli <strk@kbt.io> |
7 | | * Copyright (C) 2006 Refractions Research Inc. |
8 | | * |
9 | | * This is free software; you can redistribute and/or modify it under |
10 | | * the terms of the GNU Lesser General Public Licence as published |
11 | | * by the Free Software Foundation. |
12 | | * See the COPYING file for more information. |
13 | | * |
14 | | *********************************************************************** |
15 | | * |
16 | | * Last port: operation/overlay/snap/GeometrySnapper.java r320 (JTS-1.12) |
17 | | * |
18 | | **********************************************************************/ |
19 | | |
20 | | #include <geos/operation/overlay/snap/GeometrySnapper.h> |
21 | | #include <geos/operation/overlay/snap/LineStringSnapper.h> |
22 | | #include <geos/geom/util/GeometryTransformer.h> // inherit. of SnapTransformer |
23 | | #include <geos/geom/util/GeometryFixer.h> |
24 | | #include <geos/geom/CoordinateSequence.h> |
25 | | #include <geos/geom/Polygon.h> |
26 | | #include <geos/geom/MultiPolygon.h> |
27 | | #include <geos/geom/Coordinate.h> |
28 | | #include <geos/geom/GeometryFactory.h> |
29 | | #include <geos/geom/PrecisionModel.h> |
30 | | #include <geos/util/UniqueCoordinateArrayFilter.h> |
31 | | #include <geos/util.h> |
32 | | |
33 | | #include <vector> |
34 | | #include <memory> |
35 | | #include <algorithm> |
36 | | |
37 | | // |
38 | | using namespace geos::geom; |
39 | | |
40 | | namespace geos { |
41 | | namespace operation { // geos.operation |
42 | | namespace overlay { // geos.operation.overlay |
43 | | namespace snap { // geos.operation.overlay.snap |
44 | | |
45 | | const double GeometrySnapper::snapPrecisionFactor = 1e-9; |
46 | | |
47 | | class SnapTransformer: public geos::geom::util::GeometryTransformer { |
48 | | |
49 | | private: |
50 | | |
51 | | double snapTol; |
52 | | |
53 | | const Coordinate::ConstVect& snapPts; |
54 | | |
55 | | CoordinateSequence::Ptr |
56 | | snapLine( |
57 | | const CoordinateSequence* srcPts) |
58 | 0 | { |
59 | 0 | using std::unique_ptr; |
60 | |
|
61 | 0 | assert(srcPts); |
62 | 0 | auto coords = detail::make_unique<CoordinateSequence>(); |
63 | 0 | coords->add(*srcPts); |
64 | 0 | LineStringSnapper snapper(*coords, snapTol); |
65 | 0 | return snapper.snapTo(snapPts); |
66 | 0 | } |
67 | | |
68 | | public: |
69 | | |
70 | | SnapTransformer(double nSnapTol, |
71 | | const Coordinate::ConstVect& nSnapPts) |
72 | | : |
73 | 0 | snapTol(nSnapTol), |
74 | 0 | snapPts(nSnapPts) |
75 | 0 | { |
76 | 0 | } |
77 | | |
78 | | CoordinateSequence::Ptr |
79 | | transformCoordinates( |
80 | | const CoordinateSequence* coords, |
81 | | const Geometry* parent) override |
82 | 0 | { |
83 | 0 | ::geos::ignore_unused_variable_warning(parent); |
84 | 0 | return snapLine(coords); |
85 | 0 | } |
86 | | |
87 | | |
88 | | }; |
89 | | |
90 | | GeometrySnapper::GeometrySnapper(const Geometry& g) |
91 | 0 | : srcGeom(g) |
92 | 0 | { |
93 | 0 | util::ensureNoCurvedComponents(g); |
94 | 0 | } |
95 | | |
96 | | /*private*/ |
97 | | std::unique_ptr<Coordinate::ConstVect> |
98 | | GeometrySnapper::extractTargetCoordinates(const Geometry& g) |
99 | 0 | { |
100 | 0 | auto snapPts = detail::make_unique<Coordinate::ConstVect>(); |
101 | 0 | util::UniqueCoordinateArrayFilter filter(*snapPts); |
102 | 0 | g.apply_ro(&filter); |
103 | | // integrity check |
104 | 0 | assert(snapPts->size() <= g.getNumPoints()); |
105 | 0 | return snapPts; |
106 | 0 | } |
107 | | |
108 | | /*public*/ |
109 | | std::unique_ptr<geom::Geometry> |
110 | | GeometrySnapper::snapTo(const geom::Geometry& g, double snapTolerance) |
111 | 0 | { |
112 | |
|
113 | 0 | using std::unique_ptr; |
114 | 0 | using geom::util::GeometryTransformer; |
115 | | |
116 | | // Get snap points |
117 | 0 | std::unique_ptr<Coordinate::ConstVect> snapPts = extractTargetCoordinates(g); |
118 | | |
119 | | // Apply a SnapTransformer to source geometry |
120 | | // (we need a pointer for dynamic polymorphism) |
121 | 0 | std::unique_ptr<GeometryTransformer> snapTrans(new SnapTransformer(snapTolerance, *snapPts)); |
122 | 0 | return snapTrans->transform(&srcGeom); |
123 | 0 | } |
124 | | |
125 | | /*public*/ |
126 | | std::unique_ptr<geom::Geometry> |
127 | | GeometrySnapper::snapToSelf(double snapTolerance, bool cleanResult) |
128 | 0 | { |
129 | |
|
130 | 0 | using std::unique_ptr; |
131 | 0 | using geom::util::GeometryTransformer; |
132 | | |
133 | | // Get snap points |
134 | 0 | std::unique_ptr<Coordinate::ConstVect> snapPts = extractTargetCoordinates(srcGeom); |
135 | | |
136 | | // Apply a SnapTransformer to source geometry |
137 | | // (we need a pointer for dynamic polymorphism) |
138 | 0 | std::unique_ptr<GeometryTransformer> snapTrans(new SnapTransformer(snapTolerance, *snapPts)); |
139 | |
|
140 | 0 | std::unique_ptr<Geometry> result = snapTrans->transform(&srcGeom); |
141 | |
|
142 | 0 | if (cleanResult && (result->getGeometryTypeId() == GEOS_POLYGON || |
143 | 0 | result->getGeometryTypeId() == GEOS_MULTIPOLYGON)) { |
144 | 0 | result = geom::util::GeometryFixer::fix(result.get()); |
145 | 0 | } |
146 | |
|
147 | 0 | return result; |
148 | 0 | } |
149 | | |
150 | | /*public static*/ |
151 | | double |
152 | | GeometrySnapper::computeSizeBasedSnapTolerance(const geom::Geometry& g) |
153 | 0 | { |
154 | 0 | const Envelope* env = g.getEnvelopeInternal(); |
155 | 0 | double minDimension = std::min(env->getHeight(), env->getWidth()); |
156 | 0 | double snapTol = minDimension * snapPrecisionFactor; |
157 | 0 | return snapTol; |
158 | 0 | } |
159 | | |
160 | | /*public static*/ |
161 | | double |
162 | | GeometrySnapper::computeOverlaySnapTolerance(const geom::Geometry& g) |
163 | 0 | { |
164 | 0 | double snapTolerance = computeSizeBasedSnapTolerance(g); |
165 | | |
166 | | /* |
167 | | * Overlay is carried out in the precision model |
168 | | * of the two inputs. |
169 | | * If this precision model is of type FIXED, then the snap tolerance |
170 | | * must reflect the precision grid size. |
171 | | * Specifically, the snap tolerance should be at least |
172 | | * the distance from a corner of a precision grid cell |
173 | | * to the centre point of the cell. |
174 | | */ |
175 | 0 | assert(g.getPrecisionModel()); |
176 | 0 | const PrecisionModel& pm = *(g.getPrecisionModel()); |
177 | 0 | if(pm.getType() == PrecisionModel::FIXED) { |
178 | 0 | double fixedSnapTol = (1 / pm.getScale()) * 2 / 1.415; |
179 | 0 | if(fixedSnapTol > snapTolerance) { |
180 | 0 | snapTolerance = fixedSnapTol; |
181 | 0 | } |
182 | 0 | } |
183 | 0 | return snapTolerance; |
184 | 0 | } |
185 | | |
186 | | /*public static*/ |
187 | | double |
188 | | GeometrySnapper::computeOverlaySnapTolerance(const geom::Geometry& g1, |
189 | | const geom::Geometry& g2) |
190 | 0 | { |
191 | 0 | return std::min(computeOverlaySnapTolerance(g1), computeOverlaySnapTolerance(g2)); |
192 | 0 | } |
193 | | |
194 | | /* public static */ |
195 | | void |
196 | | GeometrySnapper::snap(const geom::Geometry& g0, |
197 | | const geom::Geometry& g1, |
198 | | double snapTolerance, |
199 | | geom::GeomPtrPair& snapGeom) |
200 | 0 | { |
201 | 0 | GeometrySnapper snapper0(g0); |
202 | 0 | snapGeom.first = snapper0.snapTo(g1, snapTolerance); |
203 | | |
204 | | /* |
205 | | * Snap the second geometry to the snapped first geometry |
206 | | * (this strategy minimizes the number of possible different |
207 | | * points in the result) |
208 | | */ |
209 | 0 | GeometrySnapper snapper1(g1); |
210 | 0 | snapGeom.second = snapper1.snapTo(*snapGeom.first, snapTolerance); |
211 | | |
212 | | // std::cout << *snapGeom.first << std::endl; |
213 | | // std::cout << *snapGeom.second << std::endl; |
214 | |
|
215 | 0 | } |
216 | | |
217 | | /* public static */ |
218 | | GeometrySnapper::GeomPtr |
219 | | GeometrySnapper::snapToSelf(const geom::Geometry& g, |
220 | | double snapTolerance, |
221 | | bool cleanResult) |
222 | 0 | { |
223 | 0 | GeometrySnapper snapper0(g); |
224 | 0 | return snapper0.snapToSelf(snapTolerance, cleanResult); |
225 | 0 | } |
226 | | |
227 | | } // namespace geos.operation.snap |
228 | | } // namespace geos.operation.overlay |
229 | | } // namespace geos.operation |
230 | | } // namespace geos |