/src/gdal/alg/polygonize_polygonizer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * Project: GDAL |
3 | | * Purpose: Implements The Two-Arm Chains EdgeTracing Algorithm |
4 | | * Author: kikitte.lee |
5 | | * |
6 | | ****************************************************************************** |
7 | | * Copyright (c) 2023, kikitte.lee <kikitte.lee@gmail.com> |
8 | | * |
9 | | * SPDX-License-Identifier: MIT |
10 | | ****************************************************************************/ |
11 | | |
12 | | /*! @cond Doxygen_Suppress */ |
13 | | |
14 | | #include "polygonize_polygonizer.h" |
15 | | |
16 | | #include <algorithm> |
17 | | |
18 | | namespace gdal |
19 | | { |
20 | | namespace polygonizer |
21 | | { |
22 | | IndexedArc RPolygon::newArc(bool bFollowRighthand) |
23 | 0 | { |
24 | 0 | const std::size_t iArcIndex = oArcs.size(); |
25 | 0 | const auto &oNewArc = |
26 | 0 | oArcs.emplace_back(static_cast<unsigned>(iArcIndex), bFollowRighthand); |
27 | 0 | return IndexedArc{oNewArc.poArc.get(), iArcIndex}; |
28 | 0 | } |
29 | | |
30 | | void RPolygon::setArcConnection(const IndexedArc &oArc, |
31 | | const IndexedArc &oNextArc) |
32 | 0 | { |
33 | 0 | oArcs[oArc.iIndex].nConnection = static_cast<unsigned>(oNextArc.iIndex); |
34 | 0 | } |
35 | | |
36 | | void RPolygon::updateBottomRightPos(IndexType iRow, IndexType iCol) |
37 | 0 | { |
38 | 0 | iBottomRightRow = iRow; |
39 | 0 | iBottomRightCol = iCol; |
40 | 0 | } |
41 | | |
42 | | /** |
43 | | * Process different kinds of Arm connections. |
44 | | */ |
45 | | static void ProcessArmConnections(TwoArm *poCurrent, TwoArm *poAbove, |
46 | | TwoArm *poLeft) |
47 | 0 | { |
48 | 0 | poCurrent->poPolyInside->updateBottomRightPos(poCurrent->iRow, |
49 | 0 | poCurrent->iCol); |
50 | 0 | poCurrent->bSolidVertical = poCurrent->poPolyInside != poLeft->poPolyInside; |
51 | 0 | poCurrent->bSolidHorizontal = |
52 | 0 | poCurrent->poPolyInside != poAbove->poPolyInside; |
53 | 0 | poCurrent->poPolyAbove = poAbove->poPolyInside; |
54 | 0 | poCurrent->poPolyLeft = poLeft->poPolyInside; |
55 | |
|
56 | 0 | constexpr int BIT_CUR_HORIZ = 0; |
57 | 0 | constexpr int BIT_CUR_VERT = 1; |
58 | 0 | constexpr int BIT_LEFT = 2; |
59 | 0 | constexpr int BIT_ABOVE = 3; |
60 | |
|
61 | 0 | const int nArmConnectionType = |
62 | 0 | (static_cast<int>(poAbove->bSolidVertical) << BIT_ABOVE) | |
63 | 0 | (static_cast<int>(poLeft->bSolidHorizontal) << BIT_LEFT) | |
64 | 0 | (static_cast<int>(poCurrent->bSolidVertical) << BIT_CUR_VERT) | |
65 | 0 | (static_cast<int>(poCurrent->bSolidHorizontal) << BIT_CUR_HORIZ); |
66 | |
|
67 | 0 | constexpr int VIRTUAL = 0; |
68 | 0 | constexpr int SOLID = 1; |
69 | |
|
70 | 0 | constexpr int ABOVE_VIRTUAL = VIRTUAL << BIT_ABOVE; |
71 | 0 | constexpr int ABOVE_SOLID = SOLID << BIT_ABOVE; |
72 | |
|
73 | 0 | constexpr int LEFT_VIRTUAL = VIRTUAL << BIT_LEFT; |
74 | 0 | constexpr int LEFT_SOLID = SOLID << BIT_LEFT; |
75 | |
|
76 | 0 | constexpr int CUR_VERT_VIRTUAL = VIRTUAL << BIT_CUR_VERT; |
77 | 0 | constexpr int CUR_VERT_SOLID = SOLID << BIT_CUR_VERT; |
78 | |
|
79 | 0 | constexpr int CUR_HORIZ_VIRTUAL = VIRTUAL << BIT_CUR_HORIZ; |
80 | 0 | constexpr int CUR_HORIZ_SOLID = SOLID << BIT_CUR_HORIZ; |
81 | | |
82 | | /** |
83 | | * There are 12 valid connection types depending on the arm types(virtual or solid) |
84 | | * The following diagram illustrates these kinds of connection types, ⇢⇣ means virtual arm, →↓ means solid arm. |
85 | | * ⇣ ⇣ ⇣ ⇣ ↓ |
86 | | * ⇢ → → → → ⇢ → → ⇢ → |
87 | | * ↓ ⇣ ↓ ↓ ⇣ |
88 | | * type=3 type=5 type=6 type=7 type=9 |
89 | | * |
90 | | * ↓ ↓ ↓ ↓ ↓ |
91 | | * ⇢ ⇢ ⇢ → → ⇢ → → → ⇢ |
92 | | * ↓ ↓ ⇣ ⇣ ↓ |
93 | | * type=10 type=11 type=12 type=13 type=14 |
94 | | * |
95 | | * ↓ ⇣ |
96 | | * → → ⇢ ⇢ |
97 | | * ↓ ⇣ |
98 | | * type=15 type=0 |
99 | | * |
100 | | * For each connection type, we may create new arc, , |
101 | | * Depending on the connection type, we may do the following things: |
102 | | * 1. Create new arc. If the arc is closed to the inner polygon, it is called "Inner Arc", otherwise "Outer Arc" |
103 | | * 2. Pass an arc to the next arm. |
104 | | * 3. "Close" two arcs. If two arcs meet at the bottom right corner of a cell, close them by recording the arc connection. |
105 | | * 4. Add grid position(row, col) to an arc. |
106 | | */ |
107 | |
|
108 | 0 | switch (nArmConnectionType) |
109 | 0 | { |
110 | 0 | case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL | |
111 | 0 | CUR_HORIZ_VIRTUAL: // 0 |
112 | | // nothing to do |
113 | 0 | break; |
114 | | |
115 | 0 | case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID | |
116 | 0 | CUR_HORIZ_SOLID: // 3 |
117 | | // add inner arcs |
118 | 0 | poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true); |
119 | 0 | poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false); |
120 | 0 | poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner, |
121 | 0 | poCurrent->oArcVerInner); |
122 | 0 | poCurrent->oArcVerInner.poArc->emplace_back( |
123 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
124 | | |
125 | | // add outer arcs |
126 | 0 | poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true); |
127 | 0 | poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false); |
128 | 0 | poAbove->poPolyInside->setArcConnection(poCurrent->oArcVerOuter, |
129 | 0 | poCurrent->oArcHorOuter); |
130 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
131 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
132 | |
|
133 | 0 | break; |
134 | 0 | case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL | |
135 | 0 | CUR_HORIZ_SOLID: // 5 |
136 | | // pass arcs |
137 | 0 | poCurrent->oArcHorInner = poLeft->oArcHorInner; |
138 | 0 | poCurrent->oArcHorOuter = poLeft->oArcHorOuter; |
139 | |
|
140 | 0 | break; |
141 | 0 | case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID | |
142 | 0 | CUR_HORIZ_VIRTUAL: // 6 |
143 | | // pass arcs |
144 | 0 | poCurrent->oArcVerInner = poLeft->oArcHorOuter; |
145 | 0 | poCurrent->oArcVerOuter = poLeft->oArcHorInner; |
146 | 0 | poCurrent->oArcVerInner.poArc->push_back( |
147 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
148 | 0 | poCurrent->oArcVerOuter.poArc->push_back( |
149 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
150 | |
|
151 | 0 | break; |
152 | 0 | case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID | |
153 | 0 | CUR_HORIZ_SOLID: // 7 |
154 | | // pass arcs |
155 | 0 | poCurrent->oArcHorOuter = poLeft->oArcHorOuter; |
156 | 0 | poCurrent->oArcVerOuter = poLeft->oArcHorInner; |
157 | 0 | poLeft->oArcHorInner.poArc->push_back( |
158 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
159 | | |
160 | | // add inner arcs |
161 | 0 | poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true); |
162 | 0 | poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false); |
163 | 0 | poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner, |
164 | 0 | poCurrent->oArcVerInner); |
165 | 0 | poCurrent->oArcVerInner.poArc->push_back( |
166 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
167 | |
|
168 | 0 | break; |
169 | 0 | case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_VIRTUAL | |
170 | 0 | CUR_HORIZ_SOLID: // 9 |
171 | | // pass arcs |
172 | 0 | poCurrent->oArcHorOuter = poAbove->oArcVerInner; |
173 | 0 | poCurrent->oArcHorInner = poAbove->oArcVerOuter; |
174 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
175 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
176 | 0 | poCurrent->oArcHorInner.poArc->push_back( |
177 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
178 | |
|
179 | 0 | break; |
180 | 0 | case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID | |
181 | 0 | CUR_HORIZ_VIRTUAL: // 10 |
182 | | // pass arcs |
183 | 0 | poCurrent->oArcVerInner = poAbove->oArcVerInner; |
184 | 0 | poCurrent->oArcVerOuter = poAbove->oArcVerOuter; |
185 | |
|
186 | 0 | break; |
187 | 0 | case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID | |
188 | 0 | CUR_HORIZ_SOLID: // 11 |
189 | | // pass arcs |
190 | 0 | poCurrent->oArcHorOuter = poAbove->oArcVerInner; |
191 | 0 | poCurrent->oArcVerOuter = poAbove->oArcVerOuter; |
192 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
193 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
194 | | // add inner arcs |
195 | 0 | poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true); |
196 | 0 | poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false); |
197 | 0 | poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner, |
198 | 0 | poCurrent->oArcVerInner); |
199 | 0 | poCurrent->oArcVerInner.poArc->push_back( |
200 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
201 | |
|
202 | 0 | break; |
203 | 0 | case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL | |
204 | 0 | CUR_HORIZ_VIRTUAL: // 12 |
205 | | // close arcs |
206 | 0 | poLeft->oArcHorOuter.poArc->push_back( |
207 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
208 | 0 | poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter, |
209 | 0 | poAbove->oArcVerOuter); |
210 | | // close arcs |
211 | 0 | poAbove->oArcVerInner.poArc->push_back( |
212 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
213 | 0 | poCurrent->poPolyInside->setArcConnection(poAbove->oArcVerInner, |
214 | 0 | poLeft->oArcHorInner); |
215 | |
|
216 | 0 | break; |
217 | 0 | case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL | |
218 | 0 | CUR_HORIZ_SOLID: // 13 |
219 | | // close arcs |
220 | 0 | poLeft->oArcHorOuter.poArc->push_back( |
221 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
222 | 0 | poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter, |
223 | 0 | poAbove->oArcVerOuter); |
224 | | // pass arcs |
225 | 0 | poCurrent->oArcHorOuter = poAbove->oArcVerInner; |
226 | 0 | poCurrent->oArcHorInner = poLeft->oArcHorInner; |
227 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
228 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
229 | |
|
230 | 0 | break; |
231 | 0 | case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID | |
232 | 0 | CUR_HORIZ_VIRTUAL: // 14 |
233 | | // close arcs |
234 | 0 | poLeft->oArcHorOuter.poArc->push_back( |
235 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
236 | 0 | poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter, |
237 | 0 | poAbove->oArcVerOuter); |
238 | | // pass arcs |
239 | 0 | poCurrent->oArcVerInner = poAbove->oArcVerInner; |
240 | 0 | poCurrent->oArcVerOuter = poLeft->oArcHorInner; |
241 | 0 | poCurrent->oArcVerOuter.poArc->push_back( |
242 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
243 | |
|
244 | 0 | break; |
245 | 0 | case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID | CUR_HORIZ_SOLID: // 15 |
246 | | // Tow pixels of the main diagonal belong to the same polygon |
247 | 0 | if (poAbove->poPolyLeft == poCurrent->poPolyInside) |
248 | 0 | { |
249 | | // pass arcs |
250 | 0 | poCurrent->oArcVerInner = poLeft->oArcHorOuter; |
251 | 0 | poCurrent->oArcHorInner = poAbove->oArcVerOuter; |
252 | 0 | poCurrent->oArcVerInner.poArc->push_back( |
253 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
254 | 0 | poCurrent->oArcHorInner.poArc->push_back( |
255 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
256 | 0 | } |
257 | 0 | else |
258 | 0 | { |
259 | | // close arcs |
260 | 0 | poLeft->oArcHorOuter.poArc->push_back( |
261 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
262 | 0 | poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter, |
263 | 0 | poAbove->oArcVerOuter); |
264 | | // add inner arcs |
265 | 0 | poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true); |
266 | 0 | poCurrent->oArcHorInner = |
267 | 0 | poCurrent->poPolyInside->newArc(false); |
268 | 0 | poCurrent->poPolyInside->setArcConnection( |
269 | 0 | poCurrent->oArcHorInner, poCurrent->oArcVerInner); |
270 | 0 | poCurrent->oArcVerInner.poArc->push_back( |
271 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
272 | 0 | } |
273 | | |
274 | | // Tow pixels of the secondary diagonal belong to the same polygon |
275 | 0 | if (poAbove->poPolyInside == poLeft->poPolyInside) |
276 | 0 | { |
277 | | // close arcs |
278 | 0 | poAbove->poPolyInside->setArcConnection(poAbove->oArcVerInner, |
279 | 0 | poLeft->oArcHorInner); |
280 | 0 | poAbove->oArcVerInner.poArc->push_back( |
281 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
282 | | // add outer arcs |
283 | 0 | poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true); |
284 | 0 | poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false); |
285 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
286 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
287 | 0 | poAbove->poPolyInside->setArcConnection( |
288 | 0 | poCurrent->oArcVerOuter, poCurrent->oArcHorOuter); |
289 | 0 | } |
290 | 0 | else |
291 | 0 | { |
292 | | // pass arcs |
293 | 0 | poCurrent->oArcHorOuter = poAbove->oArcVerInner; |
294 | 0 | poCurrent->oArcVerOuter = poLeft->oArcHorInner; |
295 | 0 | poCurrent->oArcHorOuter.poArc->push_back( |
296 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
297 | 0 | poCurrent->oArcVerOuter.poArc->push_back( |
298 | 0 | Point{poCurrent->iRow, poCurrent->iCol}); |
299 | 0 | } |
300 | |
|
301 | 0 | break; |
302 | | |
303 | 0 | case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL | |
304 | 0 | CUR_HORIZ_SOLID: // 1 |
305 | 0 | case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID | |
306 | 0 | CUR_HORIZ_VIRTUAL: // 2 |
307 | 0 | case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL | |
308 | 0 | CUR_HORIZ_VIRTUAL: // 4 |
309 | 0 | default: |
310 | | // Impossible case |
311 | 0 | CPLAssert(false); |
312 | 0 | break; |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | | template <typename PolyIdType, typename DataType> |
317 | | Polygonizer<PolyIdType, DataType>::Polygonizer( |
318 | | PolyIdType nInvalidPolyId, PolygonReceiver<DataType> *poPolygonReceiver) |
319 | 0 | : nInvalidPolyId_(nInvalidPolyId), poPolygonReceiver_(poPolygonReceiver) |
320 | 0 | { |
321 | 0 | poTheOuterPolygon_ = createPolygon(THE_OUTER_POLYGON_ID); |
322 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::Polygonizer(int, gdal::polygonizer::PolygonReceiver<long>*) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::Polygonizer(int, gdal::polygonizer::PolygonReceiver<float>*) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::Polygonizer(int, gdal::polygonizer::PolygonReceiver<double>*) |
323 | | |
324 | | template <typename PolyIdType, typename DataType> |
325 | | Polygonizer<PolyIdType, DataType>::~Polygonizer() |
326 | 0 | { |
327 | | // cppcheck-suppress constVariableReference |
328 | 0 | for (auto &pair : oPolygonMap_) |
329 | 0 | { |
330 | 0 | delete pair.second; |
331 | 0 | } |
332 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::~Polygonizer() Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::~Polygonizer() Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::~Polygonizer() |
333 | | |
334 | | template <typename PolyIdType, typename DataType> |
335 | | RPolygon *Polygonizer<PolyIdType, DataType>::getPolygon(PolyIdType nPolygonId) |
336 | 0 | { |
337 | 0 | const auto oIter = oPolygonMap_.find(nPolygonId); |
338 | 0 | if (oIter == oPolygonMap_.end()) |
339 | 0 | { |
340 | 0 | return createPolygon(nPolygonId); |
341 | 0 | } |
342 | 0 | else |
343 | 0 | { |
344 | 0 | return oIter->second; |
345 | 0 | } |
346 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::getPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::getPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::getPolygon(int) |
347 | | |
348 | | template <typename PolyIdType, typename DataType> |
349 | | RPolygon * |
350 | | Polygonizer<PolyIdType, DataType>::createPolygon(PolyIdType nPolygonId) |
351 | 0 | { |
352 | 0 | auto polygon = new RPolygon(); |
353 | 0 | oPolygonMap_[nPolygonId] = polygon; |
354 | 0 | return polygon; |
355 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::createPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::createPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::createPolygon(int) |
356 | | |
357 | | template <typename PolyIdType, typename DataType> |
358 | | void Polygonizer<PolyIdType, DataType>::destroyPolygon(PolyIdType nPolygonId) |
359 | 0 | { |
360 | 0 | const auto oIter = oPolygonMap_.find(nPolygonId); |
361 | 0 | CPLAssert(oIter != oPolygonMap_.end()); |
362 | 0 | delete oIter->second; |
363 | 0 | oPolygonMap_.erase(oIter); |
364 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::destroyPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::destroyPolygon(int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::destroyPolygon(int) |
365 | | |
366 | | template <typename PolyIdType, typename DataType> |
367 | | bool Polygonizer<PolyIdType, DataType>::processLine( |
368 | | const PolyIdType *panThisLineId, const DataType *panLastLineVal, |
369 | | TwoArm *poThisLineArm, TwoArm *poLastLineArm, const IndexType nCurrentRow, |
370 | | const IndexType nCols) |
371 | 0 | { |
372 | 0 | TwoArm *poCurrent, *poAbove, *poLeft; |
373 | |
|
374 | 0 | try |
375 | 0 | { |
376 | 0 | poCurrent = poThisLineArm + 1; |
377 | 0 | poCurrent->iRow = nCurrentRow; |
378 | 0 | poCurrent->iCol = 0; |
379 | 0 | poCurrent->poPolyInside = getPolygon(panThisLineId[0]); |
380 | 0 | poAbove = poLastLineArm + 1; |
381 | 0 | poLeft = poThisLineArm; |
382 | 0 | poLeft->poPolyInside = poTheOuterPolygon_; |
383 | 0 | ProcessArmConnections(poCurrent, poAbove, poLeft); |
384 | 0 | for (IndexType col = 1; col < nCols; ++col) |
385 | 0 | { |
386 | 0 | IndexType iArmIndex = col + 1; |
387 | 0 | poCurrent = poThisLineArm + iArmIndex; |
388 | 0 | poCurrent->iRow = nCurrentRow; |
389 | 0 | poCurrent->iCol = col; |
390 | 0 | poCurrent->poPolyInside = getPolygon(panThisLineId[col]); |
391 | 0 | poAbove = poLastLineArm + iArmIndex; |
392 | 0 | poLeft = poThisLineArm + iArmIndex - 1; |
393 | 0 | ProcessArmConnections(poCurrent, poAbove, poLeft); |
394 | 0 | } |
395 | 0 | poCurrent = poThisLineArm + nCols + 1; |
396 | 0 | poCurrent->iRow = nCurrentRow; |
397 | 0 | poCurrent->iCol = nCols; |
398 | 0 | poCurrent->poPolyInside = poTheOuterPolygon_; |
399 | 0 | poAbove = poLastLineArm + nCols + 1; |
400 | 0 | poAbove->poPolyInside = poTheOuterPolygon_; |
401 | 0 | poLeft = poThisLineArm + nCols; |
402 | 0 | ProcessArmConnections(poCurrent, poAbove, poLeft); |
403 | | |
404 | | /** |
405 | | * |
406 | | * Find those polygons haven't been processed on this line as we can be sure they are completed |
407 | | * |
408 | | */ |
409 | 0 | std::vector<PolygonMapEntry> oCompletedPolygons; |
410 | 0 | for (auto &entry : oPolygonMap_) |
411 | 0 | { |
412 | 0 | RPolygon *poPolygon = entry.second; |
413 | |
|
414 | 0 | if (poPolygon->iBottomRightRow + 1 == nCurrentRow) |
415 | 0 | { |
416 | 0 | oCompletedPolygons.push_back(entry); |
417 | 0 | } |
418 | 0 | } |
419 | | // cppcheck-suppress constVariableReference |
420 | 0 | for (auto &entry : oCompletedPolygons) |
421 | 0 | { |
422 | 0 | PolyIdType nPolyId = entry.first; |
423 | 0 | RPolygon *poPolygon = entry.second; |
424 | | |
425 | | // emit valid polygon only |
426 | 0 | if (nPolyId != nInvalidPolyId_) |
427 | 0 | { |
428 | 0 | poPolygonReceiver_->receive( |
429 | 0 | poPolygon, panLastLineVal[poPolygon->iBottomRightCol]); |
430 | 0 | } |
431 | |
|
432 | 0 | destroyPolygon(nPolyId); |
433 | 0 | } |
434 | 0 | return true; |
435 | 0 | } |
436 | 0 | catch (const std::bad_alloc &) |
437 | 0 | { |
438 | 0 | CPLError(CE_Failure, CPLE_OutOfMemory, |
439 | 0 | "Out of memory in Polygonizer::processLine"); |
440 | 0 | return false; |
441 | 0 | } |
442 | 0 | } Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, long>::processLine(int const*, long const*, gdal::polygonizer::TwoArm*, gdal::polygonizer::TwoArm*, unsigned int, unsigned int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, float>::processLine(int const*, float const*, gdal::polygonizer::TwoArm*, gdal::polygonizer::TwoArm*, unsigned int, unsigned int) Unexecuted instantiation: gdal::polygonizer::Polygonizer<int, double>::processLine(int const*, double const*, gdal::polygonizer::TwoArm*, gdal::polygonizer::TwoArm*, unsigned int, unsigned int) |
443 | | |
444 | | template <typename DataType> |
445 | | OGRPolygonWriter<DataType>::OGRPolygonWriter(OGRLayerH hOutLayer, |
446 | | int iPixValField, |
447 | | const GDALGeoTransform >, |
448 | | int nCommitInterval) |
449 | 0 | : PolygonReceiver<DataType>(), poOutLayer_(OGRLayer::FromHandle(hOutLayer)), |
450 | 0 | poOutDS_(poOutLayer_->GetDataset()), iPixValField_(iPixValField), gt_(gt), |
451 | 0 | nCommitInterval_(nCommitInterval) |
452 | 0 | { |
453 | 0 | if (nCommitInterval_ != 0) |
454 | 0 | { |
455 | 0 | CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler); |
456 | 0 | if (!(poOutDS_ && poOutDS_->TestCapability(ODsCTransactions) && |
457 | 0 | poOutDS_->StartTransaction(false) == OGRERR_NONE)) |
458 | 0 | { |
459 | 0 | nCommitInterval_ = 0; |
460 | 0 | } |
461 | 0 | } |
462 | 0 | poFeature_ = std::make_unique<OGRFeature>(poOutLayer_->GetLayerDefn()); |
463 | 0 | poPolygon_ = new OGRPolygon(); |
464 | 0 | poFeature_->SetGeometryDirectly(poPolygon_); |
465 | 0 | } Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::OGRPolygonWriter(OGRLayerHS*, int, GDALGeoTransform const&, int) Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::OGRPolygonWriter(OGRLayerHS*, int, GDALGeoTransform const&, int) Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::OGRPolygonWriter(OGRLayerHS*, int, GDALGeoTransform const&, int) |
466 | | |
467 | | template <typename DataType> OGRPolygonWriter<DataType>::~OGRPolygonWriter() |
468 | 0 | { |
469 | 0 | OGRPolygonWriter::Finalize(); |
470 | 0 | } Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::~OGRPolygonWriter() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::~OGRPolygonWriter() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::~OGRPolygonWriter() |
471 | | |
472 | | template <typename DataType> bool OGRPolygonWriter<DataType>::Finalize() |
473 | 0 | { |
474 | 0 | if (nFeaturesWrittenInTransaction_) |
475 | 0 | { |
476 | 0 | nFeaturesWrittenInTransaction_ = 0; |
477 | 0 | if (poOutDS_->CommitTransaction() != OGRERR_NONE) |
478 | 0 | { |
479 | 0 | return false; |
480 | 0 | } |
481 | 0 | } |
482 | 0 | return true; |
483 | 0 | } Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::Finalize() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::Finalize() Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::Finalize() |
484 | | |
485 | | template <typename DataType> |
486 | | void OGRPolygonWriter<DataType>::receive(RPolygon *poPolygon, |
487 | | DataType nPolygonCellValue) |
488 | 0 | { |
489 | 0 | std::vector<bool> oAccessedArc(poPolygon->oArcs.size(), false); |
490 | |
|
491 | 0 | OGRLinearRing *poFirstRing = poPolygon_->getExteriorRing(); |
492 | 0 | if (poFirstRing && poPolygon_->getNumInteriorRings() == 0) |
493 | 0 | { |
494 | 0 | poFirstRing->empty(); |
495 | 0 | } |
496 | 0 | else |
497 | 0 | { |
498 | 0 | poFirstRing = nullptr; |
499 | 0 | poPolygon_->empty(); |
500 | 0 | } |
501 | |
|
502 | 0 | auto AddRingToPolygon = |
503 | 0 | [this, &poPolygon, &oAccessedArc](std::size_t iFirstArcIndex, |
504 | 0 | OGRLinearRing *poRing) |
505 | 0 | { |
506 | 0 | std::unique_ptr<OGRLinearRing> poNewRing; |
507 | 0 | if (!poRing) |
508 | 0 | { |
509 | 0 | poNewRing = std::make_unique<OGRLinearRing>(); |
510 | 0 | poRing = poNewRing.get(); |
511 | 0 | } |
512 | |
|
513 | 0 | auto AddArcToRing = [this, &poPolygon, poRing](std::size_t iArcIndex) |
514 | 0 | { |
515 | 0 | const auto &oArc = poPolygon->oArcs[iArcIndex]; |
516 | 0 | const bool bArcFollowRighthand = oArc.bFollowRighthand; |
517 | 0 | const int nArcPointCount = static_cast<int>(oArc.poArc->size()); |
518 | 0 | int nDstPointIdx = poRing->getNumPoints(); |
519 | 0 | poRing->setNumPoints(nDstPointIdx + nArcPointCount, |
520 | 0 | /* bZeroizeNewContent = */ false); |
521 | 0 | if (poRing->getNumPoints() < nDstPointIdx + nArcPointCount) |
522 | 0 | { |
523 | 0 | return false; |
524 | 0 | } |
525 | 0 | for (int i = 0; i < nArcPointCount; ++i) |
526 | 0 | { |
527 | 0 | const Point &oPixel = |
528 | 0 | (*oArc.poArc)[bArcFollowRighthand |
529 | 0 | ? i |
530 | 0 | : (nArcPointCount - i - 1)]; |
531 | |
|
532 | 0 | const auto oGeoreferenced = gt_.Apply(oPixel[1], oPixel[0]); |
533 | 0 | poRing->setPoint(nDstPointIdx, oGeoreferenced.first, |
534 | 0 | oGeoreferenced.second); |
535 | 0 | ++nDstPointIdx; |
536 | 0 | } |
537 | 0 | return true; |
538 | 0 | }; Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::receive(gdal::polygonizer::RPolygon*, long)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) const::{lambda(unsigned long)#1}::operator()(unsigned long) constUnexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::receive(gdal::polygonizer::RPolygon*, float)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) const::{lambda(unsigned long)#1}::operator()(unsigned long) constUnexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::receive(gdal::polygonizer::RPolygon*, double)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) const::{lambda(unsigned long)#1}::operator()(unsigned long) const |
539 | |
|
540 | 0 | if (!AddArcToRing(iFirstArcIndex)) |
541 | 0 | { |
542 | 0 | return false; |
543 | 0 | } |
544 | | |
545 | 0 | std::size_t iArcIndex = iFirstArcIndex; |
546 | 0 | std::size_t iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection; |
547 | 0 | oAccessedArc[iArcIndex] = true; |
548 | 0 | while (iNextArcIndex != iFirstArcIndex) |
549 | 0 | { |
550 | 0 | if (!AddArcToRing(iNextArcIndex)) |
551 | 0 | { |
552 | 0 | return false; |
553 | 0 | } |
554 | 0 | iArcIndex = iNextArcIndex; |
555 | 0 | iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection; |
556 | 0 | oAccessedArc[iArcIndex] = true; |
557 | 0 | } |
558 | | |
559 | | // close ring manually |
560 | 0 | poRing->closeRings(); |
561 | |
|
562 | 0 | if (poNewRing) |
563 | 0 | poPolygon_->addRingDirectly(poNewRing.release()); |
564 | 0 | return true; |
565 | 0 | }; Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::receive(gdal::polygonizer::RPolygon*, long)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) constUnexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::receive(gdal::polygonizer::RPolygon*, float)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) constUnexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::receive(gdal::polygonizer::RPolygon*, double)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) const |
566 | |
|
567 | 0 | for (size_t i = 0; i < oAccessedArc.size(); ++i) |
568 | 0 | { |
569 | 0 | if (!oAccessedArc[i]) |
570 | 0 | { |
571 | 0 | if (!AddRingToPolygon(i, poFirstRing)) |
572 | 0 | { |
573 | 0 | eErr_ = CE_Failure; |
574 | 0 | return; |
575 | 0 | } |
576 | 0 | poFirstRing = nullptr; |
577 | 0 | } |
578 | 0 | } |
579 | | |
580 | | // Create the feature object |
581 | 0 | poFeature_->SetFID(OGRNullFID); |
582 | 0 | if (iPixValField_ >= 0) |
583 | 0 | poFeature_->SetField(iPixValField_, |
584 | 0 | static_cast<double>(nPolygonCellValue)); |
585 | | |
586 | | // Write the to the layer. |
587 | 0 | if (poOutLayer_->CreateFeature(poFeature_.get()) != OGRERR_NONE) |
588 | 0 | eErr_ = CE_Failure; |
589 | | |
590 | 0 | else |
591 | 0 | { |
592 | 0 | if (nCommitInterval_ != 0) |
593 | 0 | { |
594 | 0 | ++nFeaturesWrittenInTransaction_; |
595 | 0 | if (nFeaturesWrittenInTransaction_ == nCommitInterval_) |
596 | 0 | { |
597 | 0 | if (poOutDS_->CommitTransaction() != OGRERR_NONE || |
598 | 0 | poOutDS_->StartTransaction(false) != OGRERR_NONE) |
599 | 0 | { |
600 | 0 | eErr_ = CE_Failure; |
601 | 0 | } |
602 | 0 | nFeaturesWrittenInTransaction_ = 0; |
603 | 0 | } |
604 | 0 | } |
605 | | |
606 | | // Shouldn't happen for well behaved drivers, but better check... |
607 | 0 | if (poFeature_->GetGeometryRef() != poPolygon_) |
608 | 0 | { |
609 | 0 | poPolygon_ = new OGRPolygon(); |
610 | 0 | poFeature_->SetGeometryDirectly(poPolygon_); |
611 | 0 | } |
612 | 0 | } |
613 | 0 | } Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<long>::receive(gdal::polygonizer::RPolygon*, long) Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::receive(gdal::polygonizer::RPolygon*, float) Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<double>::receive(gdal::polygonizer::RPolygon*, double) |
614 | | |
615 | | } // namespace polygonizer |
616 | | } // namespace gdal |
617 | | |
618 | | /*! @endcond */ |