LCOV - code coverage report
Current view: top level - alg - polygonize_polygonizer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 309 324 95.4 %
Date: 2026-06-18 03:37:25 Functions: 40 43 93.0 %

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

Generated by: LCOV version 1.14