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 45204 : IndexedArc RPolygon::newArc(bool bFollowRighthand)
23 : {
24 45204 : const std::size_t iArcIndex = oArcs.size();
25 : const auto &oNewArc =
26 45204 : oArcs.emplace_back(static_cast<unsigned>(iArcIndex), bFollowRighthand);
27 45204 : return IndexedArc{oNewArc.poArc.get(), iArcIndex};
28 : }
29 :
30 45204 : void RPolygon::setArcConnection(const IndexedArc &oArc,
31 : const IndexedArc &oNextArc)
32 : {
33 45204 : oArcs[oArc.iIndex].nConnection = static_cast<unsigned>(oNextArc.iIndex);
34 45204 : }
35 :
36 434510 : void RPolygon::updateBottomRightPos(IndexType iRow, IndexType iCol)
37 : {
38 434510 : iBottomRightRow = iRow;
39 434510 : iBottomRightCol = iCol;
40 434510 : }
41 :
42 : /**
43 : * Process different kinds of Arm connections.
44 : */
45 434510 : static void ProcessArmConnections(TwoArm *poCurrent, TwoArm *poAbove,
46 : TwoArm *poLeft)
47 : {
48 434510 : poCurrent->poPolyInside->updateBottomRightPos(poCurrent->iRow,
49 : poCurrent->iCol);
50 434510 : poCurrent->bSolidVertical = poCurrent->poPolyInside != poLeft->poPolyInside;
51 434510 : poCurrent->bSolidHorizontal =
52 434510 : poCurrent->poPolyInside != poAbove->poPolyInside;
53 434510 : poCurrent->poPolyAbove = poAbove->poPolyInside;
54 434510 : poCurrent->poPolyLeft = poLeft->poPolyInside;
55 :
56 434510 : constexpr int BIT_CUR_HORIZ = 0;
57 434510 : constexpr int BIT_CUR_VERT = 1;
58 434510 : constexpr int BIT_LEFT = 2;
59 434510 : constexpr int BIT_ABOVE = 3;
60 :
61 434510 : const int nArmConnectionType =
62 434510 : (static_cast<int>(poAbove->bSolidVertical) << BIT_ABOVE) |
63 434510 : (static_cast<int>(poLeft->bSolidHorizontal) << BIT_LEFT) |
64 434510 : (static_cast<int>(poCurrent->bSolidVertical) << BIT_CUR_VERT) |
65 434510 : (static_cast<int>(poCurrent->bSolidHorizontal) << BIT_CUR_HORIZ);
66 :
67 434510 : constexpr int VIRTUAL = 0;
68 434510 : constexpr int SOLID = 1;
69 :
70 434510 : constexpr int ABOVE_VIRTUAL = VIRTUAL << BIT_ABOVE;
71 434510 : constexpr int ABOVE_SOLID = SOLID << BIT_ABOVE;
72 :
73 434510 : constexpr int LEFT_VIRTUAL = VIRTUAL << BIT_LEFT;
74 434510 : constexpr int LEFT_SOLID = SOLID << BIT_LEFT;
75 :
76 434510 : constexpr int CUR_VERT_VIRTUAL = VIRTUAL << BIT_CUR_VERT;
77 434510 : constexpr int CUR_VERT_SOLID = SOLID << BIT_CUR_VERT;
78 :
79 434510 : constexpr int CUR_HORIZ_VIRTUAL = VIRTUAL << BIT_CUR_HORIZ;
80 434510 : 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 434510 : switch (nArmConnectionType)
109 : {
110 362252 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
111 : CUR_HORIZ_VIRTUAL: // 0
112 : // nothing to do
113 362252 : break;
114 :
115 7355 : case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
116 : CUR_HORIZ_SOLID: // 3
117 : // add inner arcs
118 7355 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
119 7355 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
120 7355 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
121 7355 : poCurrent->oArcVerInner);
122 7355 : poCurrent->oArcVerInner.poArc->emplace_back(
123 7355 : Point{poCurrent->iRow, poCurrent->iCol});
124 :
125 : // add outer arcs
126 7355 : poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
127 7355 : poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
128 7355 : poAbove->poPolyInside->setArcConnection(poCurrent->oArcVerOuter,
129 7355 : poCurrent->oArcHorOuter);
130 7355 : poCurrent->oArcHorOuter.poArc->push_back(
131 7355 : Point{poCurrent->iRow, poCurrent->iCol});
132 :
133 7355 : break;
134 16518 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
135 : CUR_HORIZ_SOLID: // 5
136 : // pass arcs
137 16518 : poCurrent->oArcHorInner = poLeft->oArcHorInner;
138 16518 : poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
139 :
140 16518 : break;
141 8854 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
142 : CUR_HORIZ_VIRTUAL: // 6
143 : // pass arcs
144 8854 : poCurrent->oArcVerInner = poLeft->oArcHorOuter;
145 8854 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
146 8854 : poCurrent->oArcVerInner.poArc->push_back(
147 8854 : Point{poCurrent->iRow, poCurrent->iCol});
148 8854 : poCurrent->oArcVerOuter.poArc->push_back(
149 8854 : Point{poCurrent->iRow, poCurrent->iCol});
150 :
151 8854 : break;
152 1580 : case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
153 : CUR_HORIZ_SOLID: // 7
154 : // pass arcs
155 1580 : poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
156 1580 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
157 1580 : poLeft->oArcHorInner.poArc->push_back(
158 1580 : Point{poCurrent->iRow, poCurrent->iCol});
159 :
160 : // add inner arcs
161 1580 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
162 1580 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
163 1580 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
164 1580 : poCurrent->oArcVerInner);
165 1580 : poCurrent->oArcVerInner.poArc->push_back(
166 1580 : Point{poCurrent->iRow, poCurrent->iCol});
167 :
168 1580 : break;
169 8806 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
170 : CUR_HORIZ_SOLID: // 9
171 : // pass arcs
172 8806 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
173 8806 : poCurrent->oArcHorInner = poAbove->oArcVerOuter;
174 8806 : poCurrent->oArcHorOuter.poArc->push_back(
175 8806 : Point{poCurrent->iRow, poCurrent->iCol});
176 8806 : poCurrent->oArcHorInner.poArc->push_back(
177 8806 : Point{poCurrent->iRow, poCurrent->iCol});
178 :
179 8806 : break;
180 12154 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
181 : CUR_HORIZ_VIRTUAL: // 10
182 : // pass arcs
183 12154 : poCurrent->oArcVerInner = poAbove->oArcVerInner;
184 12154 : poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
185 :
186 12154 : break;
187 1821 : case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
188 : CUR_HORIZ_SOLID: // 11
189 : // pass arcs
190 1821 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
191 1821 : poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
192 1821 : poCurrent->oArcHorOuter.poArc->push_back(
193 1821 : Point{poCurrent->iRow, poCurrent->iCol});
194 : // add inner arcs
195 1821 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
196 1821 : poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
197 1821 : poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
198 1821 : poCurrent->oArcVerInner);
199 1821 : poCurrent->oArcVerInner.poArc->push_back(
200 1821 : Point{poCurrent->iRow, poCurrent->iCol});
201 :
202 1821 : break;
203 7390 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
204 : CUR_HORIZ_VIRTUAL: // 12
205 : // close arcs
206 7390 : poLeft->oArcHorOuter.poArc->push_back(
207 7390 : Point{poCurrent->iRow, poCurrent->iCol});
208 7390 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
209 7390 : poAbove->oArcVerOuter);
210 : // close arcs
211 7390 : poAbove->oArcVerInner.poArc->push_back(
212 7390 : Point{poCurrent->iRow, poCurrent->iCol});
213 7390 : poCurrent->poPolyInside->setArcConnection(poAbove->oArcVerInner,
214 7390 : poLeft->oArcHorInner);
215 :
216 7390 : break;
217 1593 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
218 : CUR_HORIZ_SOLID: // 13
219 : // close arcs
220 1593 : poLeft->oArcHorOuter.poArc->push_back(
221 1593 : Point{poCurrent->iRow, poCurrent->iCol});
222 1593 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
223 1593 : poAbove->oArcVerOuter);
224 : // pass arcs
225 1593 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
226 1593 : poCurrent->oArcHorInner = poLeft->oArcHorInner;
227 1593 : poCurrent->oArcHorOuter.poArc->push_back(
228 1593 : Point{poCurrent->iRow, poCurrent->iCol});
229 :
230 1593 : break;
231 1738 : case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID |
232 : CUR_HORIZ_VIRTUAL: // 14
233 : // close arcs
234 1738 : poLeft->oArcHorOuter.poArc->push_back(
235 1738 : Point{poCurrent->iRow, poCurrent->iCol});
236 1738 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
237 1738 : poAbove->oArcVerOuter);
238 : // pass arcs
239 1738 : poCurrent->oArcVerInner = poAbove->oArcVerInner;
240 1738 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
241 1738 : poCurrent->oArcVerOuter.poArc->push_back(
242 1738 : Point{poCurrent->iRow, poCurrent->iCol});
243 :
244 1738 : break;
245 4449 : 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 4449 : 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 4387 : poLeft->oArcHorOuter.poArc->push_back(
261 4387 : Point{poCurrent->iRow, poCurrent->iCol});
262 4387 : poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
263 4387 : poAbove->oArcVerOuter);
264 : // add inner arcs
265 4387 : poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
266 : poCurrent->oArcHorInner =
267 4387 : poCurrent->poPolyInside->newArc(false);
268 4387 : poCurrent->poPolyInside->setArcConnection(
269 4387 : poCurrent->oArcHorInner, poCurrent->oArcVerInner);
270 4387 : poCurrent->oArcVerInner.poArc->push_back(
271 4387 : Point{poCurrent->iRow, poCurrent->iCol});
272 : }
273 :
274 : // Tow pixels of the secondary diagonal belong to the same polygon
275 4449 : 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 4345 : poCurrent->oArcHorOuter = poAbove->oArcVerInner;
294 4345 : poCurrent->oArcVerOuter = poLeft->oArcHorInner;
295 4345 : poCurrent->oArcHorOuter.poArc->push_back(
296 4345 : Point{poCurrent->iRow, poCurrent->iCol});
297 4345 : poCurrent->oArcVerOuter.poArc->push_back(
298 4345 : Point{poCurrent->iRow, poCurrent->iCol});
299 : }
300 :
301 4449 : 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 434510 : }
315 :
316 : template <typename PolyIdType, typename DataType>
317 97 : Polygonizer<PolyIdType, DataType>::Polygonizer(
318 : PolyIdType nInvalidPolyId, PolygonReceiver<DataType> *poPolygonReceiver)
319 97 : : nInvalidPolyId_(nInvalidPolyId), poPolygonReceiver_(poPolygonReceiver)
320 : {
321 97 : poTheOuterPolygon_ = createPolygon(THE_OUTER_POLYGON_ID);
322 97 : }
323 :
324 : template <typename PolyIdType, typename DataType>
325 97 : Polygonizer<PolyIdType, DataType>::~Polygonizer()
326 : {
327 : // cppcheck-suppress constVariableReference
328 194 : for (auto &pair : oPolygonMap_)
329 : {
330 97 : delete pair.second;
331 : }
332 97 : }
333 :
334 : template <typename PolyIdType, typename DataType>
335 432443 : RPolygon *Polygonizer<PolyIdType, DataType>::getPolygon(PolyIdType nPolygonId)
336 : {
337 432443 : const auto oIter = oPolygonMap_.find(nPolygonId);
338 432443 : if (oIter == oPolygonMap_.end())
339 : {
340 7791 : return createPolygon(nPolygonId);
341 : }
342 : else
343 : {
344 424652 : return oIter->second;
345 : }
346 : }
347 :
348 : template <typename PolyIdType, typename DataType>
349 : RPolygon *
350 7888 : Polygonizer<PolyIdType, DataType>::createPolygon(PolyIdType nPolygonId)
351 : {
352 7888 : auto polygon = new RPolygon();
353 7888 : oPolygonMap_[nPolygonId] = polygon;
354 7888 : return polygon;
355 : }
356 :
357 : template <typename PolyIdType, typename DataType>
358 7791 : void Polygonizer<PolyIdType, DataType>::destroyPolygon(PolyIdType nPolygonId)
359 : {
360 7791 : const auto oIter = oPolygonMap_.find(nPolygonId);
361 7791 : CPLAssert(oIter != oPolygonMap_.end());
362 7791 : delete oIter->second;
363 7791 : oPolygonMap_.erase(oIter);
364 7791 : }
365 :
366 : template <typename PolyIdType, typename DataType>
367 2067 : 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 2067 : poCurrent = poThisLineArm + 1;
377 2067 : poCurrent->iRow = nCurrentRow;
378 2067 : poCurrent->iCol = 0;
379 2067 : poCurrent->poPolyInside = getPolygon(panThisLineId[0]);
380 2067 : poAbove = poLastLineArm + 1;
381 2067 : poLeft = poThisLineArm;
382 2067 : poLeft->poPolyInside = poTheOuterPolygon_;
383 2067 : ProcessArmConnections(poCurrent, poAbove, poLeft);
384 432443 : for (IndexType col = 1; col < nCols; ++col)
385 : {
386 430376 : IndexType iArmIndex = col + 1;
387 430376 : poCurrent = poThisLineArm + iArmIndex;
388 430376 : poCurrent->iRow = nCurrentRow;
389 430376 : poCurrent->iCol = col;
390 430376 : poCurrent->poPolyInside = getPolygon(panThisLineId[col]);
391 430376 : poAbove = poLastLineArm + iArmIndex;
392 430376 : poLeft = poThisLineArm + iArmIndex - 1;
393 430376 : ProcessArmConnections(poCurrent, poAbove, poLeft);
394 : }
395 2067 : poCurrent = poThisLineArm + nCols + 1;
396 2067 : poCurrent->iRow = nCurrentRow;
397 2067 : poCurrent->iCol = nCols;
398 2067 : poCurrent->poPolyInside = poTheOuterPolygon_;
399 2067 : poAbove = poLastLineArm + nCols + 1;
400 2067 : poAbove->poPolyInside = poTheOuterPolygon_;
401 2067 : poLeft = poThisLineArm + nCols;
402 2067 : 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 2067 : std::vector<PolygonMapEntry> oCompletedPolygons;
410 44809 : for (auto &entry : oPolygonMap_)
411 : {
412 42742 : RPolygon *poPolygon = entry.second;
413 :
414 42742 : if (poPolygon->iBottomRightRow + 1 == nCurrentRow)
415 : {
416 7791 : oCompletedPolygons.push_back(entry);
417 : }
418 : }
419 : // cppcheck-suppress constVariableReference
420 9858 : for (auto &entry : oCompletedPolygons)
421 : {
422 7791 : PolyIdType nPolyId = entry.first;
423 7791 : RPolygon *poPolygon = entry.second;
424 :
425 : // emit valid polygon only
426 7791 : if (nPolyId != nInvalidPolyId_)
427 : {
428 7762 : poPolygonReceiver_->receive(
429 7762 : poPolygon, panLastLineVal[poPolygon->iBottomRightCol]);
430 : }
431 :
432 7791 : destroyPolygon(nPolyId);
433 : }
434 2067 : 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 97 : OGRPolygonWriter<DataType>::OGRPolygonWriter(OGRLayerH hOutLayer,
446 : int iPixValField,
447 : const GDALGeoTransform >,
448 : int nCommitInterval)
449 97 : : PolygonReceiver<DataType>(), poOutLayer_(OGRLayer::FromHandle(hOutLayer)),
450 194 : poOutDS_(poOutLayer_->GetDataset()), iPixValField_(iPixValField), gt_(gt),
451 97 : nCommitInterval_(nCommitInterval)
452 : {
453 97 : if (nCommitInterval_ != 0)
454 : {
455 194 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
456 107 : if (!(poOutDS_ && poOutDS_->TestCapability(ODsCTransactions) &&
457 10 : poOutDS_->StartTransaction(false) == OGRERR_NONE))
458 : {
459 91 : nCommitInterval_ = 0;
460 : }
461 : }
462 97 : poFeature_ = std::make_unique<OGRFeature>(poOutLayer_->GetLayerDefn());
463 97 : poPolygon_ = new OGRPolygon();
464 97 : poFeature_->SetGeometryDirectly(poPolygon_);
465 97 : }
466 :
467 97 : template <typename DataType> OGRPolygonWriter<DataType>::~OGRPolygonWriter()
468 : {
469 97 : OGRPolygonWriter::Finalize();
470 97 : }
471 :
472 194 : template <typename DataType> bool OGRPolygonWriter<DataType>::Finalize()
473 : {
474 194 : if (nFeaturesWrittenInTransaction_)
475 : {
476 6 : nFeaturesWrittenInTransaction_ = 0;
477 6 : if (poOutDS_->CommitTransaction() != OGRERR_NONE)
478 : {
479 0 : return false;
480 : }
481 : }
482 194 : return true;
483 : }
484 :
485 : template <typename DataType>
486 7762 : void OGRPolygonWriter<DataType>::receive(RPolygon *poPolygon,
487 : DataType nPolygonCellValue)
488 : {
489 7762 : std::vector<bool> oAccessedArc(poPolygon->oArcs.size(), false);
490 :
491 7762 : OGRLinearRing *poFirstRing = poPolygon_->getExteriorRing();
492 7762 : if (poFirstRing && poPolygon_->getNumInteriorRings() == 0)
493 : {
494 7654 : poFirstRing->empty();
495 : }
496 : else
497 : {
498 108 : poFirstRing = nullptr;
499 108 : poPolygon_->empty();
500 : }
501 :
502 7762 : auto AddRingToPolygon =
503 100888 : [this, &poPolygon, &oAccessedArc](std::size_t iFirstArcIndex,
504 : OGRLinearRing *poRing)
505 : {
506 7786 : std::unique_ptr<OGRLinearRing> poNewRing;
507 7786 : if (!poRing)
508 : {
509 132 : poNewRing = std::make_unique<OGRLinearRing>();
510 132 : poRing = poNewRing.get();
511 : }
512 :
513 360022 : auto AddArcToRing = [this, &poPolygon, poRing](std::size_t iArcIndex)
514 : {
515 42592 : const auto &oArc = poPolygon->oArcs[iArcIndex];
516 42592 : const bool bArcFollowRighthand = oArc.bFollowRighthand;
517 42592 : const int nArcPointCount = static_cast<int>(oArc.poArc->size());
518 42592 : int nDstPointIdx = poRing->getNumPoints();
519 42592 : poRing->setNumPoints(nDstPointIdx + nArcPointCount,
520 : /* bZeroizeNewContent = */ false);
521 42592 : if (poRing->getNumPoints() < nDstPointIdx + nArcPointCount)
522 : {
523 0 : return false;
524 : }
525 133526 : for (int i = 0; i < nArcPointCount; ++i)
526 : {
527 114966 : const Point &oPixel =
528 90934 : (*oArc.poArc)[bArcFollowRighthand
529 : ? i
530 24032 : : (nArcPointCount - i - 1)];
531 :
532 90934 : const auto oGeoreferenced = gt_.Apply(oPixel[1], oPixel[0]);
533 90934 : poRing->setPoint(nDstPointIdx, oGeoreferenced.first,
534 90934 : oGeoreferenced.second);
535 90934 : ++nDstPointIdx;
536 : }
537 42592 : return true;
538 : };
539 :
540 7786 : if (!AddArcToRing(iFirstArcIndex))
541 : {
542 0 : return false;
543 : }
544 :
545 7786 : std::size_t iArcIndex = iFirstArcIndex;
546 7786 : std::size_t iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
547 7786 : oAccessedArc[iArcIndex] = true;
548 42592 : while (iNextArcIndex != iFirstArcIndex)
549 : {
550 34806 : if (!AddArcToRing(iNextArcIndex))
551 : {
552 0 : return false;
553 : }
554 34806 : iArcIndex = iNextArcIndex;
555 34806 : iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
556 34806 : oAccessedArc[iArcIndex] = true;
557 : }
558 :
559 : // close ring manually
560 7786 : poRing->closeRings();
561 :
562 7786 : if (poNewRing)
563 132 : poPolygon_->addRingDirectly(poNewRing.release());
564 7786 : return true;
565 : };
566 :
567 50354 : for (size_t i = 0; i < oAccessedArc.size(); ++i)
568 : {
569 42592 : if (!oAccessedArc[i])
570 : {
571 7786 : if (!AddRingToPolygon(i, poFirstRing))
572 : {
573 0 : eErr_ = CE_Failure;
574 0 : return;
575 : }
576 7786 : poFirstRing = nullptr;
577 : }
578 : }
579 :
580 : // Create the feature object
581 7762 : poFeature_->SetFID(OGRNullFID);
582 7762 : if (iPixValField_ >= 0)
583 7138 : poFeature_->SetField(iPixValField_,
584 : static_cast<double>(nPolygonCellValue));
585 :
586 : // Write the to the layer.
587 7762 : if (poOutLayer_->CreateFeature(poFeature_.get()) != OGRERR_NONE)
588 0 : eErr_ = CE_Failure;
589 :
590 : else
591 : {
592 7762 : if (nCommitInterval_ != 0)
593 : {
594 1686 : ++nFeaturesWrittenInTransaction_;
595 1686 : if (nFeaturesWrittenInTransaction_ == nCommitInterval_)
596 : {
597 56 : if (poOutDS_->CommitTransaction() != OGRERR_NONE ||
598 28 : poOutDS_->StartTransaction(false) != OGRERR_NONE)
599 : {
600 0 : eErr_ = CE_Failure;
601 : }
602 28 : nFeaturesWrittenInTransaction_ = 0;
603 : }
604 : }
605 :
606 : // Shouldn't happen for well behaved drivers, but better check...
607 7762 : if (poFeature_->GetGeometryRef() != poPolygon_)
608 : {
609 0 : poPolygon_ = new OGRPolygon();
610 0 : poFeature_->SetGeometryDirectly(poPolygon_);
611 : }
612 : }
613 : }
614 :
615 : } // namespace polygonizer
616 : } // namespace gdal
617 :
618 : /*! @endcond */
|