Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 &gt,
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) const
Unexecuted 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) const
Unexecuted 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*) const
Unexecuted instantiation: gdal::polygonizer::OGRPolygonWriter<float>::receive(gdal::polygonizer::RPolygon*, float)::{lambda(unsigned long, OGRLinearRing*)#1}::operator()(unsigned long, OGRLinearRing*) const
Unexecuted 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 */