/src/geos/include/geos/operation/buffer/OffsetSegmentString.h
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * GEOS - Geometry Engine Open Source |
4 | | * http://geos.osgeo.org |
5 | | * |
6 | | * Copyright (C) 2011 Sandro Santilli <strk@kbt.io> |
7 | | * Copyright (C) 2007 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/buffer/OffsetSegmentString.java r378 (JTS-1.12) |
17 | | * |
18 | | **********************************************************************/ |
19 | | |
20 | | #pragma once |
21 | | |
22 | | #include <geos/geom/Coordinate.h> // for inlines |
23 | | #include <geos/geom/CoordinateSequence.h> // for inlines |
24 | | #include <geos/geom/PrecisionModel.h> // for inlines |
25 | | |
26 | | #include <vector> |
27 | | #include <memory> |
28 | | #include <cassert> |
29 | | |
30 | | namespace geos { |
31 | | namespace operation { // geos.operation |
32 | | namespace buffer { // geos.operation.buffer |
33 | | |
34 | | /// A dynamic list of the vertices in a constructed offset curve. |
35 | | /// |
36 | | /// Automatically removes close vertices |
37 | | /// which are closer than a given tolerance. |
38 | | /// |
39 | | /// @author Martin Davis |
40 | | /// |
41 | | class OffsetSegmentString { |
42 | | |
43 | | private: |
44 | | |
45 | | geom::CoordinateSequence* ptList; |
46 | | |
47 | | const geom::PrecisionModel* precisionModel; |
48 | | |
49 | | /** \brief |
50 | | * The distance below which two adjacent points on the curve |
51 | | * are considered to be coincident. |
52 | | * |
53 | | * This is chosen to be a small fraction of the offset distance. |
54 | | */ |
55 | | double minimumVertexDistance; |
56 | | |
57 | | /** \brief |
58 | | * Tests whether the given point is redundant relative to the previous |
59 | | * point in the list (up to tolerance) |
60 | | * |
61 | | * @param pt |
62 | | * @return true if the point is redundant |
63 | | */ |
64 | | bool |
65 | | isRedundant(const geom::Coordinate& pt) const |
66 | 0 | { |
67 | 0 | if(ptList->size() < 1) { |
68 | 0 | return false; |
69 | 0 | } |
70 | 0 | const geom::Coordinate& lastPt = ptList->back(); |
71 | 0 | double ptDist = pt.distance(lastPt); |
72 | 0 | if(ptDist < minimumVertexDistance) { |
73 | 0 | return true; |
74 | 0 | } |
75 | 0 | return false; |
76 | 0 | } |
77 | | |
78 | | OffsetSegmentString(const OffsetSegmentString&) = delete; |
79 | | OffsetSegmentString& operator=(const OffsetSegmentString&) = delete; |
80 | | |
81 | | public: |
82 | | |
83 | | friend std::ostream& operator<< (std::ostream& os, const OffsetSegmentString& node); |
84 | | |
85 | | OffsetSegmentString() |
86 | | : |
87 | 0 | ptList(new geom::CoordinateSequence()), |
88 | 0 | precisionModel(nullptr), |
89 | 0 | minimumVertexDistance(0.0) |
90 | 0 | { |
91 | 0 | } |
92 | | |
93 | | ~OffsetSegmentString() |
94 | 0 | { |
95 | 0 | delete ptList; |
96 | 0 | } |
97 | | |
98 | | void |
99 | | reset() |
100 | 0 | { |
101 | 0 | if(ptList) { |
102 | 0 | ptList->clear(); |
103 | 0 | } |
104 | 0 | else { |
105 | 0 | ptList = new geom::CoordinateSequence(); |
106 | 0 | } |
107 | |
|
108 | 0 | precisionModel = nullptr; |
109 | 0 | minimumVertexDistance = 0.0; |
110 | 0 | } |
111 | | |
112 | | void |
113 | | setPrecisionModel(const geom::PrecisionModel* nPrecisionModel) |
114 | 0 | { |
115 | 0 | precisionModel = nPrecisionModel; |
116 | 0 | } |
117 | | |
118 | | void |
119 | | setMinimumVertexDistance(double nMinVertexDistance) |
120 | 0 | { |
121 | 0 | minimumVertexDistance = nMinVertexDistance; |
122 | 0 | } |
123 | | |
124 | | void |
125 | | addPt(const geom::Coordinate& pt) |
126 | 0 | { |
127 | 0 | assert(precisionModel); |
128 | |
|
129 | 0 | geom::Coordinate bufPt = pt; |
130 | 0 | precisionModel->makePrecise(bufPt); |
131 | | // don't add duplicate (or near-duplicate) points |
132 | 0 | if(isRedundant(bufPt)) { |
133 | 0 | return; |
134 | 0 | } |
135 | | // we ask to allow repeated as we checked this ourself |
136 | | // (JTS uses a vector for ptList, not a CoordinateSequence, |
137 | | // we should do the same) |
138 | 0 | ptList->add(bufPt, true); |
139 | 0 | } |
140 | | |
141 | | void |
142 | | addPts(const geom::CoordinateSequence& pts, bool isForward) |
143 | 0 | { |
144 | 0 | if(isForward) { |
145 | 0 | for(std::size_t i = 0, n = pts.size(); i < n; ++i) { |
146 | 0 | addPt(pts[i]); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | else { |
150 | 0 | for(std::size_t i = pts.size(); i > 0; --i) { |
151 | 0 | addPt(pts[i - 1]); |
152 | 0 | } |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | | /// Check that points are a ring |
157 | | /// |
158 | | /// add the startpoint again if they are not |
159 | | void |
160 | | closeRing() |
161 | 0 | { |
162 | 0 | if(ptList->size() < 1) { |
163 | 0 | return; |
164 | 0 | } |
165 | 0 | const geom::Coordinate& startPt = ptList->front(); |
166 | 0 | const geom::Coordinate& lastPt = ptList->back(); |
167 | 0 | if(startPt.equals(lastPt)) { |
168 | 0 | return; |
169 | 0 | } |
170 | | // we ask to allow repeated as we checked this ourself |
171 | 0 | ptList->add(startPt, true); |
172 | 0 | } |
173 | | |
174 | | /// Get coordinates by taking ownership of them |
175 | | /// |
176 | | /// After this call, the coordinates reference in |
177 | | /// this object are dropped. Calling twice will |
178 | | /// segfault... |
179 | | /// |
180 | | /// FIXME: refactor memory management of this |
181 | | /// |
182 | | geom::CoordinateSequence* |
183 | | getCoordinates() |
184 | 0 | { |
185 | 0 | closeRing(); |
186 | 0 | geom::CoordinateSequence* ret = ptList; |
187 | 0 | ptList = nullptr; |
188 | 0 | return ret; |
189 | 0 | } |
190 | | |
191 | | inline size_t |
192 | | size() const |
193 | 0 | { |
194 | 0 | return ptList ? ptList->size() : 0 ; |
195 | 0 | } |
196 | | |
197 | | }; |
198 | | |
199 | | inline std::ostream& |
200 | | operator<< (std::ostream& os, |
201 | | const OffsetSegmentString& lst) |
202 | 0 | { |
203 | 0 | if(lst.ptList) { |
204 | 0 | os << *(lst.ptList); |
205 | 0 | } |
206 | 0 | else { |
207 | 0 | os << "empty (consumed?)"; |
208 | 0 | } |
209 | 0 | return os; |
210 | 0 | } |
211 | | |
212 | | } // namespace geos.operation.buffer |
213 | | } // namespace geos.operation |
214 | | } // namespace geos |
215 | | |