Line data Source code
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 42194 : IndexedArc RPolygon::newArc(bool bFollowRighthand)
23 : {
24 42194 : const std::size_t iArcIndex = oArcs.size();
25 : const auto &oNewArc =
26 42194 : oArcs.emplace_back(static_cast<unsigned>(iArcIndex), bFollowRighthand);
27 42194 : return IndexedArc{oNewArc.poArc.get(), iArcIndex};
28 : }
29 :
30 42194 : void RPolygon::setArcConnection(const IndexedArc &oArc,
31 : const IndexedArc &oNextArc)
32 : {
33 42194 : oArcs[oArc.iIndex].nConnection = static_cast<unsigned>(oNextArc.iIndex);
34 42194 : }
35 :
36 432305 : void RPolygon::updateBottomRightPos(IndexType iRow, IndexType iCol)
37 : {
38 432305 : iBottomRightRow = iRow;
39 432305 : iBottomRightCol = iCol;
40 432305 : }
41 :
42 : /**
43 : * Process different kinds of Arm connections.
44 : */
45 432305 : static void ProcessArmConnections(TwoArm *poCurrent, TwoArm *poAbove,
46 : TwoArm *poLeft)
47 : {
48 432305 : poCurrent->poPolyInside->updateBottomRightPos(poCurrent->iRow,
49 : poCurrent->iCol);
50 432305 : poCurrent->bSolidVertical = poCurrent->poPolyInside != poLeft->poPolyInside;
51 432305 : poCurrent->bSolidHorizontal =
52 432305 : poCurrent->poPolyInside != poAbove->poPolyInside;
53 432305 : poCurrent->poPolyAbove = poAbove->poPolyInside;
54 432305 : poCurrent->poPolyLeft = poLeft->poPolyInside;
55 :
56 432305 : constexpr int BIT_CUR_HORIZ = 0;
57 432305 : constexpr int BIT_CUR_VERT = 1;
58 432305 : constexpr int BIT_LEFT = 2;
59 432305 : constexpr int BIT_ABOVE = 3;
60 :
61 432305 : const int nArmConnectionType =
62 432305 : (static_cast<int>(poAbove->bSolidVertical) << BIT_ABOVE) |
63 432305 : (static_cast<int>(poLeft->bSolidHorizontal) << BIT_LEFT) |
64 432305 : (static_cast<int>(poCurrent->bSolidVertical) << BIT_CUR_VERT) |
65 432305 : (static_cast<int>(poCurrent->bSolidHorizontal) << BIT_CUR_HORIZ);
66 :
67 432305 : constexpr int VIRTUAL = 0;
68 432305 : constexpr int SOLID = 1;
69 :
70 432305 : constexpr int ABOVE_VIRTUAL = VIRTUAL << BIT_ABOVE;
71 432305 : constexpr int ABOVE_SOLID = SOLID << BIT_ABOVE;
72 :
73 432305 : constexpr int LEFT_VIRTUAL = VIRTUAL << BIT_LEFT;
74 432305 : constexpr int LEFT_SOLID = SOLID << BIT_LEFT;
75 :
76 432305 : constexpr int CUR_VERT_VIRTUAL = VIRTUAL << BIT_CUR_VERT;
77 432305 : constexpr int CUR_VERT_SOLID = SOLID << BIT_CUR_VERT;
78 :
79 432305 : constexpr int CUR_HORIZ_VIRTUAL = VIRTUAL << BIT_CUR_HORIZ;
80 432305 : 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 432305 : switch (nArmConnectionType)
109 : {
110 362247 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
111 : CUR_HORIZ_VIRTUAL: // 0
112 : // nothing to do
113 362247 : break;
114 :
115 7305 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
116 : CUR_HORIZ_SOLID: // 3
117 : // add inner arcs
118 7305 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
119 7305 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
120 7305 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
121 7305 : poCurrent->oArcVerInner);
122 7305 : poCurrent->oArcVerInner.poArc->emplace_back(
123 7305 : Point{poCurrent->iRow, poCurrent->iCol});
124 :
125 : // add outer arcs
126 7305 : poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
127 7305 : poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
128 7305 : poAbove->poPolyInside->setArcConnection(poCurrent->oArcVerOuter,
129 7305 : poCurrent->oArcHorOuter);
130 7305 : poCurrent->oArcHorOuter.poArc->push_back(
131 7305 : Point{poCurrent->iRow, poCurrent->iCol});
132 :
133 7305 : break;
134 16428 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
135 : CUR_HORIZ_SOLID: // 5
136 : // pass arcs
137 16428 : poCurrent->oArcHorInner = poLeft->oArcHorInner;
138 16428 : poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
139 :
140 16428 : break;
141 8814 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
142 : CUR_HORIZ_VIRTUAL: // 6
143 : // pass arcs
144 8814 : poCurrent->oArcVerInner = poLeft->oArcHorOuter;
145 8814 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
146 8814 : poCurrent->oArcVerInner.poArc->push_back(
147 8814 : Point{poCurrent->iRow, poCurrent->iCol});
148 8814 : poCurrent->oArcVerOuter.poArc->push_back(
149 8814 : Point{poCurrent->iRow, poCurrent->iCol});
150 :
151 8814 : break;
152 1370 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
153 : CUR_HORIZ_SOLID: // 7
154 : // pass arcs
155 1370 : poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
156 1370 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
157 1370 : poLeft->oArcHorInner.poArc->push_back(
158 1370 : Point{poCurrent->iRow, poCurrent->iCol});
159 :
160 : // add inner arcs
161 1370 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
162 1370 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
163 1370 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
164 1370 : poCurrent->oArcVerInner);
165 1370 : poCurrent->oArcVerInner.poArc->push_back(
166 1370 : Point{poCurrent->iRow, poCurrent->iCol});
167 :
168 1370 : break;
169 8776 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
170 : CUR_HORIZ_SOLID: // 9
171 : // pass arcs
172 8776 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
173 8776 : poCurrent->oArcHorInner = poAbove->oArcVerOuter;
174 8776 : poCurrent->oArcHorOuter.poArc->push_back(
175 8776 : Point{poCurrent->iRow, poCurrent->iCol});
176 8776 : poCurrent->oArcHorInner.poArc->push_back(
177 8776 : Point{poCurrent->iRow, poCurrent->iCol});
178 :
179 8776 : break;
180 12104 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
181 : CUR_HORIZ_VIRTUAL: // 10
182 : // pass arcs
183 12104 : poCurrent->oArcVerInner = poAbove->oArcVerInner;
184 12104 : poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
185 :
186 12104 : break;
187 1541 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
188 : CUR_HORIZ_SOLID: // 11
189 : // pass arcs
190 1541 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
191 1541 : poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
192 1541 : poCurrent->oArcHorOuter.poArc->push_back(
193 1541 : Point{poCurrent->iRow, poCurrent->iCol});
194 : // add inner arcs
195 1541 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
196 1541 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
197 1541 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
198 1541 : poCurrent->oArcVerInner);
199 1541 : poCurrent->oArcVerInner.poArc->push_back(
200 1541 : Point{poCurrent->iRow, poCurrent->iCol});
201 :
202 1541 : break;
203 7335 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
204 : CUR_HORIZ_VIRTUAL: // 12
205 : // close arcs
206 7335 : poLeft->oArcHorOuter.poArc->push_back(
207 7335 : Point{poCurrent->iRow, poCurrent->iCol});
208 7335 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
209 7335 : poAbove->oArcVerOuter);
210 : // close arcs
211 7335 : poAbove->oArcVerInner.poArc->push_back(
212 7335 : Point{poCurrent->iRow, poCurrent->iCol});
213 7335 : poCurrent->poPolyInside->setArcConnection(poAbove->oArcVerInner,
214 7335 : poLeft->oArcHorInner);
215 :
216 7335 : break;
217 1378 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
218 : CUR_HORIZ_SOLID: // 13
219 : // close arcs
220 1378 : poLeft->oArcHorOuter.poArc->push_back(
221 1378 : Point{poCurrent->iRow, poCurrent->iCol});
222 1378 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
223 1378 : poAbove->oArcVerOuter);
224 : // pass arcs
225 1378 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
226 1378 : poCurrent->oArcHorInner = poLeft->oArcHorInner;
227 1378 : poCurrent->oArcHorOuter.poArc->push_back(
228 1378 : Point{poCurrent->iRow, poCurrent->iCol});
229 :
230 1378 : break;
231 1473 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID |
232 : CUR_HORIZ_VIRTUAL: // 14
233 : // close arcs
234 1473 : poLeft->oArcHorOuter.poArc->push_back(
235 1473 : Point{poCurrent->iRow, poCurrent->iCol});
236 1473 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
237 1473 : poAbove->oArcVerOuter);
238 : // pass arcs
239 1473 : poCurrent->oArcVerInner = poAbove->oArcVerInner;
240 1473 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
241 1473 : poCurrent->oArcVerOuter.poArc->push_back(
242 1473 : Point{poCurrent->iRow, poCurrent->iCol});
243 :
244 1473 : break;
245 3534 : 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 3534 : if (poAbove->poPolyLeft == poCurrent->poPolyInside)
248 : {
249 : // pass arcs
250 62 : poCurrent->oArcVerInner = poLeft->oArcHorOuter;
251 62 : poCurrent->oArcHorInner = poAbove->oArcVerOuter;
252 62 : poCurrent->oArcVerInner.poArc->push_back(
253 62 : Point{poCurrent->iRow, poCurrent->iCol});
254 62 : poCurrent->oArcHorInner.poArc->push_back(
255 62 : Point{poCurrent->iRow, poCurrent->iCol});
256 : }
257 : else
258 : {
259 : // close arcs
260 3472 : poLeft->oArcHorOuter.poArc->push_back(
261 3472 : Point{poCurrent->iRow, poCurrent->iCol});
262 3472 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
263 3472 : poAbove->oArcVerOuter);
264 : // add inner arcs
265 3472 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
266 : poCurrent->oArcHorInner =
267 3472 : poCurrent->poPolyInside->newArc(false);
268 3472 : poCurrent->poPolyInside->setArcConnection(
269 3472 : poCurrent->oArcHorInner, poCurrent->oArcVerInner);
270 3472 : poCurrent->oArcVerInner.poArc->push_back(
271 3472 : Point{poCurrent->iRow, poCurrent->iCol});
272 : }
273 :
274 : // Tow pixels of the secondary diagonal belong to the same polygon
275 3534 : if (poAbove->poPolyInside == poLeft->poPolyInside)
276 : {
277 : // close arcs
278 104 : poAbove->poPolyInside->setArcConnection(poAbove->oArcVerInner,
279 104 : poLeft->oArcHorInner);
280 104 : poAbove->oArcVerInner.poArc->push_back(
281 104 : Point{poCurrent->iRow, poCurrent->iCol});
282 : // add outer arcs
283 104 : poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
284 104 : poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
285 104 : poCurrent->oArcHorOuter.poArc->push_back(
286 104 : Point{poCurrent->iRow, poCurrent->iCol});
287 104 : poAbove->poPolyInside->setArcConnection(
288 104 : poCurrent->oArcVerOuter, poCurrent->oArcHorOuter);
289 : }
290 : else
291 : {
292 : // pass arcs
293 3430 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
294 3430 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
295 3430 : poCurrent->oArcHorOuter.poArc->push_back(
296 3430 : Point{poCurrent->iRow, poCurrent->iCol});
297 3430 : poCurrent->oArcVerOuter.poArc->push_back(
298 3430 : Point{poCurrent->iRow, poCurrent->iCol});
299 : }
300 :
301 3534 : break;
302 :
303 0 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
304 : CUR_HORIZ_SOLID: // 1
305 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
306 : CUR_HORIZ_VIRTUAL: // 2
307 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
308 : CUR_HORIZ_VIRTUAL: // 4
309 : default:
310 : // Impossible case
311 0 : CPLAssert(false);
312 : break;
313 : }
314 432305 : }
315 :
316 : template <typename PolyIdType, typename DataType>
317 92 : Polygonizer<PolyIdType, DataType>::Polygonizer(
318 : PolyIdType nInvalidPolyId, PolygonReceiver<DataType> *poPolygonReceiver)
319 92 : : nInvalidPolyId_(nInvalidPolyId), poPolygonReceiver_(poPolygonReceiver)
320 : {
321 92 : poTheOuterPolygon_ = createPolygon(THE_OUTER_POLYGON_ID);
322 92 : }
323 :
324 : template <typename PolyIdType, typename DataType>
325 92 : Polygonizer<PolyIdType, DataType>::~Polygonizer()
326 : {
327 : // cppcheck-suppress constVariableReference
328 184 : for (auto &pair : oPolygonMap_)
329 : {
330 92 : delete pair.second;
331 : }
332 92 : }
333 :
334 : template <typename PolyIdType, typename DataType>
335 430343 : RPolygon *Polygonizer<PolyIdType, DataType>::getPolygon(PolyIdType nPolygonId)
336 : {
337 430343 : const auto oIter = oPolygonMap_.find(nPolygonId);
338 430343 : if (oIter == oPolygonMap_.end())
339 : {
340 6386 : return createPolygon(nPolygonId);
341 : }
342 : else
343 : {
344 423957 : return oIter->second;
345 : }
346 : }
347 :
348 : template <typename PolyIdType, typename DataType>
349 : RPolygon *
350 6478 : Polygonizer<PolyIdType, DataType>::createPolygon(PolyIdType nPolygonId)
351 : {
352 6478 : auto polygon = new RPolygon();
353 6478 : oPolygonMap_[nPolygonId] = polygon;
354 6478 : return polygon;
355 : }
356 :
357 : template <typename PolyIdType, typename DataType>
358 6386 : void Polygonizer<PolyIdType, DataType>::destroyPolygon(PolyIdType nPolygonId)
359 : {
360 6386 : const auto oIter = oPolygonMap_.find(nPolygonId);
361 6386 : CPLAssert(oIter != oPolygonMap_.end());
362 6386 : delete oIter->second;
363 6386 : oPolygonMap_.erase(oIter);
364 6386 : }
365 :
366 : template <typename PolyIdType, typename DataType>
367 1962 : 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 : {
372 : TwoArm *poCurrent, *poAbove, *poLeft;
373 :
374 : try
375 : {
376 1962 : poCurrent = poThisLineArm + 1;
377 1962 : poCurrent->iRow = nCurrentRow;
378 1962 : poCurrent->iCol = 0;
379 1962 : poCurrent->poPolyInside = getPolygon(panThisLineId[0]);
380 1962 : poAbove = poLastLineArm + 1;
381 1962 : poLeft = poThisLineArm;
382 1962 : poLeft->poPolyInside = poTheOuterPolygon_;
383 1962 : ProcessArmConnections(poCurrent, poAbove, poLeft);
384 430343 : for (IndexType col = 1; col < nCols; ++col)
385 : {
386 428381 : IndexType iArmIndex = col + 1;
387 428381 : poCurrent = poThisLineArm + iArmIndex;
388 428381 : poCurrent->iRow = nCurrentRow;
389 428381 : poCurrent->iCol = col;
390 428381 : poCurrent->poPolyInside = getPolygon(panThisLineId[col]);
391 428381 : poAbove = poLastLineArm + iArmIndex;
392 428381 : poLeft = poThisLineArm + iArmIndex - 1;
393 428381 : ProcessArmConnections(poCurrent, poAbove, poLeft);
394 : }
395 1962 : poCurrent = poThisLineArm + nCols + 1;
396 1962 : poCurrent->iRow = nCurrentRow;
397 1962 : poCurrent->iCol = nCols;
398 1962 : poCurrent->poPolyInside = poTheOuterPolygon_;
399 1962 : poAbove = poLastLineArm + nCols + 1;
400 1962 : poAbove->poPolyInside = poTheOuterPolygon_;
401 1962 : poLeft = poThisLineArm + nCols;
402 1962 : 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 1962 : std::vector<PolygonMapEntry> oCompletedPolygons;
410 41489 : for (auto &entry : oPolygonMap_)
411 : {
412 39527 : RPolygon *poPolygon = entry.second;
413 :
414 39527 : if (poPolygon->iBottomRightRow + 1 == nCurrentRow)
415 : {
416 6386 : oCompletedPolygons.push_back(entry);
417 : }
418 : }
419 : // cppcheck-suppress constVariableReference
420 8348 : for (auto &entry : oCompletedPolygons)
421 : {
422 6386 : PolyIdType nPolyId = entry.first;
423 6386 : RPolygon *poPolygon = entry.second;
424 :
425 : // emit valid polygon only
426 6386 : if (nPolyId != nInvalidPolyId_)
427 : {
428 6357 : poPolygonReceiver_->receive(
429 6357 : poPolygon, panLastLineVal[poPolygon->iBottomRightCol]);
430 : }
431 :
432 6386 : destroyPolygon(nPolyId);
433 : }
434 1962 : return true;
435 : }
436 0 : catch (const std::bad_alloc &)
437 : {
438 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
439 : "Out of memory in Polygonizer::processLine");
440 0 : return false;
441 : }
442 : }
443 :
444 : template <typename DataType>
445 92 : OGRPolygonWriter<DataType>::OGRPolygonWriter(OGRLayerH hOutLayer,
446 : int iPixValField,
447 : double *padfGeoTransform)
448 92 : : PolygonReceiver<DataType>(), poOutLayer_(OGRLayer::FromHandle(hOutLayer)),
449 92 : iPixValField_(iPixValField), padfGeoTransform_(padfGeoTransform)
450 : {
451 92 : poFeature_ = std::make_unique<OGRFeature>(poOutLayer_->GetLayerDefn());
452 92 : poPolygon_ = new OGRPolygon();
453 92 : poFeature_->SetGeometryDirectly(poPolygon_);
454 92 : }
455 :
456 : template <typename DataType>
457 6357 : void OGRPolygonWriter<DataType>::receive(RPolygon *poPolygon,
458 : DataType nPolygonCellValue)
459 : {
460 6357 : std::vector<bool> oAccessedArc(poPolygon->oArcs.size(), false);
461 6357 : double *padfGeoTransform = padfGeoTransform_;
462 :
463 6357 : OGRLinearRing *poFirstRing = poPolygon_->getExteriorRing();
464 6357 : if (poFirstRing && poPolygon_->getNumInteriorRings() == 0)
465 : {
466 6254 : poFirstRing->empty();
467 : }
468 : else
469 : {
470 103 : poFirstRing = nullptr;
471 103 : poPolygon_->empty();
472 : }
473 :
474 6357 : auto AddRingToPolygon =
475 92073 : [this, &poPolygon, &oAccessedArc,
476 : padfGeoTransform](std::size_t iFirstArcIndex, OGRLinearRing *poRing)
477 : {
478 6381 : std::unique_ptr<OGRLinearRing> poNewRing;
479 6381 : if (!poRing)
480 : {
481 127 : poNewRing = std::make_unique<OGRLinearRing>();
482 127 : poRing = poNewRing.get();
483 : }
484 :
485 6381 : auto AddArcToRing =
486 583388 : [&poPolygon, poRing, padfGeoTransform](std::size_t iArcIndex)
487 : {
488 39592 : const auto &oArc = poPolygon->oArcs[iArcIndex];
489 39592 : const bool bArcFollowRighthand = oArc.bFollowRighthand;
490 39592 : const int nArcPointCount = static_cast<int>(oArc.poArc->size());
491 39592 : int nDstPointIdx = poRing->getNumPoints();
492 39592 : poRing->setNumPoints(nDstPointIdx + nArcPointCount,
493 : /* bZeroizeNewContent = */ false);
494 39592 : if (poRing->getNumPoints() < nDstPointIdx + nArcPointCount)
495 : {
496 0 : return false;
497 : }
498 124596 : for (int i = 0; i < nArcPointCount; ++i)
499 : {
500 107581 : const Point &oPixel =
501 85004 : (*oArc.poArc)[bArcFollowRighthand
502 : ? i
503 22577 : : (nArcPointCount - i - 1)];
504 :
505 255012 : const double dfX = padfGeoTransform[0] +
506 85004 : oPixel[1] * padfGeoTransform[1] +
507 85004 : oPixel[0] * padfGeoTransform[2];
508 255012 : const double dfY = padfGeoTransform[3] +
509 85004 : oPixel[1] * padfGeoTransform[4] +
510 85004 : oPixel[0] * padfGeoTransform[5];
511 :
512 85004 : poRing->setPoint(nDstPointIdx, dfX, dfY);
513 85004 : ++nDstPointIdx;
514 : }
515 39592 : return true;
516 : };
517 :
518 6381 : if (!AddArcToRing(iFirstArcIndex))
519 : {
520 0 : return false;
521 : }
522 :
523 6381 : std::size_t iArcIndex = iFirstArcIndex;
524 6381 : std::size_t iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
525 6381 : oAccessedArc[iArcIndex] = true;
526 39592 : while (iNextArcIndex != iFirstArcIndex)
527 : {
528 33211 : if (!AddArcToRing(iNextArcIndex))
529 : {
530 0 : return false;
531 : }
532 33211 : iArcIndex = iNextArcIndex;
533 33211 : iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
534 33211 : oAccessedArc[iArcIndex] = true;
535 : }
536 :
537 : // close ring manually
538 6381 : poRing->closeRings();
539 :
540 6381 : if (poNewRing)
541 127 : poPolygon_->addRingDirectly(poNewRing.release());
542 6381 : return true;
543 : };
544 :
545 45949 : for (size_t i = 0; i < oAccessedArc.size(); ++i)
546 : {
547 39592 : if (!oAccessedArc[i])
548 : {
549 6381 : if (!AddRingToPolygon(i, poFirstRing))
550 : {
551 0 : eErr_ = CE_Failure;
552 0 : return;
553 : }
554 6381 : poFirstRing = nullptr;
555 : }
556 : }
557 :
558 : // Create the feature object
559 6357 : poFeature_->SetFID(OGRNullFID);
560 6357 : if (iPixValField_ >= 0)
561 5733 : poFeature_->SetField(iPixValField_,
562 : static_cast<double>(nPolygonCellValue));
563 :
564 : // Write the to the layer.
565 6357 : if (poOutLayer_->CreateFeature(poFeature_.get()) != OGRERR_NONE)
566 0 : eErr_ = CE_Failure;
567 :
568 : // Shouldn't happen for well behaved drivers, but better check...
569 6357 : else if (poFeature_->GetGeometryRef() != poPolygon_)
570 : {
571 0 : poPolygon_ = new OGRPolygon();
572 0 : poFeature_->SetGeometryDirectly(poPolygon_);
573 : }
574 : }
575 :
576 : } // namespace polygonizer
577 : } // namespace gdal
578 :
579 : /*! @endcond */
|