LCOV - code coverage report
Current view: top level - alg - polygonize_polygonizer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 295 308 95.8 %
Date: 2024-11-21 22:18:42 Functions: 24 24 100.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       35990 : IndexedArc RPolygon::newArc(bool bFollowRighthand)
      23             : {
      24       35990 :     const std::size_t iArcIndex = oArcs.size();
      25             :     const auto &oNewArc =
      26       35990 :         oArcs.emplace_back(static_cast<unsigned>(iArcIndex), bFollowRighthand);
      27       35990 :     return IndexedArc{oNewArc.poArc.get(), iArcIndex};
      28             : }
      29             : 
      30       35990 : void RPolygon::setArcConnection(const IndexedArc &oArc,
      31             :                                 const IndexedArc &oNextArc)
      32             : {
      33       35990 :     oArcs[oArc.iIndex].nConnection = static_cast<unsigned>(oNextArc.iIndex);
      34       35990 : }
      35             : 
      36      423251 : void RPolygon::updateBottomRightPos(IndexType iRow, IndexType iCol)
      37             : {
      38      423251 :     iBottomRightRow = iRow;
      39      423251 :     iBottomRightCol = iCol;
      40      423251 : }
      41             : 
      42             : /**
      43             :  * Process different kinds of Arm connections.
      44             :  */
      45      423251 : static void ProcessArmConnections(TwoArm *poCurrent, TwoArm *poAbove,
      46             :                                   TwoArm *poLeft)
      47             : {
      48      423251 :     poCurrent->poPolyInside->updateBottomRightPos(poCurrent->iRow,
      49             :                                                   poCurrent->iCol);
      50      423251 :     poCurrent->bSolidVertical = poCurrent->poPolyInside != poLeft->poPolyInside;
      51      423251 :     poCurrent->bSolidHorizontal =
      52      423251 :         poCurrent->poPolyInside != poAbove->poPolyInside;
      53      423251 :     poCurrent->poPolyAbove = poAbove->poPolyInside;
      54      423251 :     poCurrent->poPolyLeft = poLeft->poPolyInside;
      55             : 
      56      423251 :     constexpr int BIT_CUR_HORIZ = 0;
      57      423251 :     constexpr int BIT_CUR_VERT = 1;
      58      423251 :     constexpr int BIT_LEFT = 2;
      59      423251 :     constexpr int BIT_ABOVE = 3;
      60             : 
      61      423251 :     const int nArmConnectionType =
      62      423251 :         (static_cast<int>(poAbove->bSolidVertical) << BIT_ABOVE) |
      63      423251 :         (static_cast<int>(poLeft->bSolidHorizontal) << BIT_LEFT) |
      64      423251 :         (static_cast<int>(poCurrent->bSolidVertical) << BIT_CUR_VERT) |
      65      423251 :         (static_cast<int>(poCurrent->bSolidHorizontal) << BIT_CUR_HORIZ);
      66             : 
      67      423251 :     constexpr int VIRTUAL = 0;
      68      423251 :     constexpr int SOLID = 1;
      69             : 
      70      423251 :     constexpr int ABOVE_VIRTUAL = VIRTUAL << BIT_ABOVE;
      71      423251 :     constexpr int ABOVE_SOLID = SOLID << BIT_ABOVE;
      72             : 
      73      423251 :     constexpr int LEFT_VIRTUAL = VIRTUAL << BIT_LEFT;
      74      423251 :     constexpr int LEFT_SOLID = SOLID << BIT_LEFT;
      75             : 
      76      423251 :     constexpr int CUR_VERT_VIRTUAL = VIRTUAL << BIT_CUR_VERT;
      77      423251 :     constexpr int CUR_VERT_SOLID = SOLID << BIT_CUR_VERT;
      78             : 
      79      423251 :     constexpr int CUR_HORIZ_VIRTUAL = VIRTUAL << BIT_CUR_HORIZ;
      80      423251 :     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      423251 :     switch (nArmConnectionType)
     109             :     {
     110      358585 :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
     111             :             CUR_HORIZ_VIRTUAL:  // 0
     112             :             // nothing to do
     113      358585 :             break;
     114             : 
     115        7175 :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
     116             :             CUR_HORIZ_SOLID:  // 3
     117             :             // add inner arcs
     118        7175 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     119        7175 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     120        7175 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     121        7175 :                                                       poCurrent->oArcVerInner);
     122        7175 :             poCurrent->oArcVerInner.poArc->emplace_back(
     123        7175 :                 Point{poCurrent->iRow, poCurrent->iCol});
     124             : 
     125             :             // add outer arcs
     126        7175 :             poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
     127        7175 :             poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
     128        7175 :             poAbove->poPolyInside->setArcConnection(poCurrent->oArcVerOuter,
     129        7175 :                                                     poCurrent->oArcHorOuter);
     130        7175 :             poCurrent->oArcHorOuter.poArc->push_back(
     131        7175 :                 Point{poCurrent->iRow, poCurrent->iCol});
     132             : 
     133        7175 :             break;
     134       15831 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
     135             :             CUR_HORIZ_SOLID:  // 5
     136             :             // pass arcs
     137       15831 :             poCurrent->oArcHorInner = poLeft->oArcHorInner;
     138       15831 :             poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
     139             : 
     140       15831 :             break;
     141        8688 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
     142             :             CUR_HORIZ_VIRTUAL:  // 6
     143             :             // pass arcs
     144        8688 :             poCurrent->oArcVerInner = poLeft->oArcHorOuter;
     145        8688 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     146        8688 :             poCurrent->oArcVerInner.poArc->push_back(
     147        8688 :                 Point{poCurrent->iRow, poCurrent->iCol});
     148        8688 :             poCurrent->oArcVerOuter.poArc->push_back(
     149        8688 :                 Point{poCurrent->iRow, poCurrent->iCol});
     150             : 
     151        8688 :             break;
     152         942 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
     153             :             CUR_HORIZ_SOLID:  // 7
     154             :             // pass arcs
     155         942 :             poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
     156         942 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     157         942 :             poLeft->oArcHorInner.poArc->push_back(
     158         942 :                 Point{poCurrent->iRow, poCurrent->iCol});
     159             : 
     160             :             // add inner arcs
     161         942 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     162         942 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     163         942 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     164         942 :                                                       poCurrent->oArcVerInner);
     165         942 :             poCurrent->oArcVerInner.poArc->push_back(
     166         942 :                 Point{poCurrent->iRow, poCurrent->iCol});
     167             : 
     168         942 :             break;
     169        8671 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
     170             :             CUR_HORIZ_SOLID:  // 9
     171             :             // pass arcs
     172        8671 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     173        8671 :             poCurrent->oArcHorInner = poAbove->oArcVerOuter;
     174        8671 :             poCurrent->oArcHorOuter.poArc->push_back(
     175        8671 :                 Point{poCurrent->iRow, poCurrent->iCol});
     176        8671 :             poCurrent->oArcHorInner.poArc->push_back(
     177        8671 :                 Point{poCurrent->iRow, poCurrent->iCol});
     178             : 
     179        8671 :             break;
     180       11609 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
     181             :             CUR_HORIZ_VIRTUAL:  // 10
     182             :             // pass arcs
     183       11609 :             poCurrent->oArcVerInner = poAbove->oArcVerInner;
     184       11609 :             poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
     185             : 
     186       11609 :             break;
     187         976 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
     188             :             CUR_HORIZ_SOLID:  // 11
     189             :             // pass arcs
     190         976 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     191         976 :             poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
     192         976 :             poCurrent->oArcHorOuter.poArc->push_back(
     193         976 :                 Point{poCurrent->iRow, poCurrent->iCol});
     194             :             // add inner arcs
     195         976 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     196         976 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     197         976 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     198         976 :                                                       poCurrent->oArcVerInner);
     199         976 :             poCurrent->oArcVerInner.poArc->push_back(
     200         976 :                 Point{poCurrent->iRow, poCurrent->iCol});
     201             : 
     202         976 :             break;
     203        7195 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
     204             :             CUR_HORIZ_VIRTUAL:  // 12
     205             :             // close arcs
     206        7195 :             poLeft->oArcHorOuter.poArc->push_back(
     207        7195 :                 Point{poCurrent->iRow, poCurrent->iCol});
     208        7195 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     209        7195 :                                                   poAbove->oArcVerOuter);
     210             :             // close arcs
     211        7195 :             poAbove->oArcVerInner.poArc->push_back(
     212        7195 :                 Point{poCurrent->iRow, poCurrent->iCol});
     213        7195 :             poCurrent->poPolyInside->setArcConnection(poAbove->oArcVerInner,
     214        7195 :                                                       poLeft->oArcHorInner);
     215             : 
     216        7195 :             break;
     217         939 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
     218             :             CUR_HORIZ_SOLID:  // 13
     219             :             // close arcs
     220         939 :             poLeft->oArcHorOuter.poArc->push_back(
     221         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     222         939 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     223         939 :                                                   poAbove->oArcVerOuter);
     224             :             // pass arcs
     225         939 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     226         939 :             poCurrent->oArcHorInner = poLeft->oArcHorInner;
     227         939 :             poCurrent->oArcHorOuter.poArc->push_back(
     228         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     229             : 
     230         939 :             break;
     231         939 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID |
     232             :             CUR_HORIZ_VIRTUAL:  // 14
     233             :             // close arcs
     234         939 :             poLeft->oArcHorOuter.poArc->push_back(
     235         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     236         939 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     237         939 :                                                   poAbove->oArcVerOuter);
     238             :             // pass arcs
     239         939 :             poCurrent->oArcVerInner = poAbove->oArcVerInner;
     240         939 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     241         939 :             poCurrent->oArcVerOuter.poArc->push_back(
     242         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     243             : 
     244         939 :             break;
     245        1701 :         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        1701 :             if (poAbove->poPolyLeft == poCurrent->poPolyInside)
     248             :             {
     249             :                 // pass arcs
     250          42 :                 poCurrent->oArcVerInner = poLeft->oArcHorOuter;
     251          42 :                 poCurrent->oArcHorInner = poAbove->oArcVerOuter;
     252          42 :                 poCurrent->oArcVerInner.poArc->push_back(
     253          42 :                     Point{poCurrent->iRow, poCurrent->iCol});
     254          42 :                 poCurrent->oArcHorInner.poArc->push_back(
     255          42 :                     Point{poCurrent->iRow, poCurrent->iCol});
     256             :             }
     257             :             else
     258             :             {
     259             :                 // close arcs
     260        1659 :                 poLeft->oArcHorOuter.poArc->push_back(
     261        1659 :                     Point{poCurrent->iRow, poCurrent->iCol});
     262        1659 :                 poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     263        1659 :                                                       poAbove->oArcVerOuter);
     264             :                 // add inner arcs
     265        1659 :                 poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     266             :                 poCurrent->oArcHorInner =
     267        1659 :                     poCurrent->poPolyInside->newArc(false);
     268        1659 :                 poCurrent->poPolyInside->setArcConnection(
     269        1659 :                     poCurrent->oArcHorInner, poCurrent->oArcVerInner);
     270        1659 :                 poCurrent->oArcVerInner.poArc->push_back(
     271        1659 :                     Point{poCurrent->iRow, poCurrent->iCol});
     272             :             }
     273             : 
     274             :             // Tow pixels of the secondary diagonal belong to the same polygon
     275        1701 :             if (poAbove->poPolyInside == poLeft->poPolyInside)
     276             :             {
     277             :                 // close arcs
     278          68 :                 poAbove->poPolyInside->setArcConnection(poAbove->oArcVerInner,
     279          68 :                                                         poLeft->oArcHorInner);
     280          68 :                 poAbove->oArcVerInner.poArc->push_back(
     281          68 :                     Point{poCurrent->iRow, poCurrent->iCol});
     282             :                 // add outer arcs
     283          68 :                 poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
     284          68 :                 poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
     285          68 :                 poCurrent->oArcHorOuter.poArc->push_back(
     286          68 :                     Point{poCurrent->iRow, poCurrent->iCol});
     287          68 :                 poAbove->poPolyInside->setArcConnection(
     288          68 :                     poCurrent->oArcVerOuter, poCurrent->oArcHorOuter);
     289             :             }
     290             :             else
     291             :             {
     292             :                 // pass arcs
     293        1633 :                 poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     294        1633 :                 poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     295        1633 :                 poCurrent->oArcHorOuter.poArc->push_back(
     296        1633 :                     Point{poCurrent->iRow, poCurrent->iCol});
     297        1633 :                 poCurrent->oArcVerOuter.poArc->push_back(
     298        1633 :                     Point{poCurrent->iRow, poCurrent->iCol});
     299             :             }
     300             : 
     301        1701 :             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      423251 : }
     315             : 
     316             : template <typename PolyIdType, typename DataType>
     317          52 : Polygonizer<PolyIdType, DataType>::Polygonizer(
     318             :     PolyIdType nInvalidPolyId, PolygonReceiver<DataType> *poPolygonReceiver)
     319          52 :     : nInvalidPolyId_(nInvalidPolyId), poPolygonReceiver_(poPolygonReceiver)
     320             : {
     321          52 :     poTheOuterPolygon_ = createPolygon(THE_OUTER_POLYGON_ID);
     322          52 : }
     323             : 
     324             : template <typename PolyIdType, typename DataType>
     325          52 : Polygonizer<PolyIdType, DataType>::~Polygonizer()
     326             : {
     327             :     // cppcheck-suppress constVariableReference
     328         104 :     for (auto &pair : oPolygonMap_)
     329             :     {
     330          52 :         delete pair.second;
     331             :     }
     332          52 : }
     333             : 
     334             : template <typename PolyIdType, typename DataType>
     335      421761 : RPolygon *Polygonizer<PolyIdType, DataType>::getPolygon(PolyIdType nPolygonId)
     336             : {
     337      421761 :     const auto oIter = oPolygonMap_.find(nPolygonId);
     338      421761 :     if (oIter == oPolygonMap_.end())
     339             :     {
     340        3587 :         return createPolygon(nPolygonId);
     341             :     }
     342             :     else
     343             :     {
     344      418174 :         return oIter->second;
     345             :     }
     346             : }
     347             : 
     348             : template <typename PolyIdType, typename DataType>
     349             : RPolygon *
     350        3639 : Polygonizer<PolyIdType, DataType>::createPolygon(PolyIdType nPolygonId)
     351             : {
     352        3639 :     auto polygon = new RPolygon();
     353        3639 :     oPolygonMap_[nPolygonId] = polygon;
     354        3639 :     return polygon;
     355             : }
     356             : 
     357             : template <typename PolyIdType, typename DataType>
     358        3587 : void Polygonizer<PolyIdType, DataType>::destroyPolygon(PolyIdType nPolygonId)
     359             : {
     360        3587 :     const auto oIter = oPolygonMap_.find(nPolygonId);
     361        3587 :     CPLAssert(oIter != oPolygonMap_.end());
     362        3587 :     delete oIter->second;
     363        3587 :     oPolygonMap_.erase(oIter);
     364        3587 : }
     365             : 
     366             : template <typename PolyIdType, typename DataType>
     367        1490 : 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        1490 :         poCurrent = poThisLineArm + 1;
     377        1490 :         poCurrent->iRow = nCurrentRow;
     378        1490 :         poCurrent->iCol = 0;
     379        1490 :         poCurrent->poPolyInside = getPolygon(panThisLineId[0]);
     380        1490 :         poAbove = poLastLineArm + 1;
     381        1490 :         poLeft = poThisLineArm;
     382        1490 :         poLeft->poPolyInside = poTheOuterPolygon_;
     383        1490 :         ProcessArmConnections(poCurrent, poAbove, poLeft);
     384      421761 :         for (IndexType col = 1; col < nCols; ++col)
     385             :         {
     386      420271 :             IndexType iArmIndex = col + 1;
     387      420271 :             poCurrent = poThisLineArm + iArmIndex;
     388      420271 :             poCurrent->iRow = nCurrentRow;
     389      420271 :             poCurrent->iCol = col;
     390      420271 :             poCurrent->poPolyInside = getPolygon(panThisLineId[col]);
     391      420271 :             poAbove = poLastLineArm + iArmIndex;
     392      420271 :             poLeft = poThisLineArm + iArmIndex - 1;
     393      420271 :             ProcessArmConnections(poCurrent, poAbove, poLeft);
     394             :         }
     395        1490 :         poCurrent = poThisLineArm + nCols + 1;
     396        1490 :         poCurrent->iRow = nCurrentRow;
     397        1490 :         poCurrent->iCol = nCols;
     398        1490 :         poCurrent->poPolyInside = poTheOuterPolygon_;
     399        1490 :         poAbove = poLastLineArm + nCols + 1;
     400        1490 :         poAbove->poPolyInside = poTheOuterPolygon_;
     401        1490 :         poLeft = poThisLineArm + nCols;
     402        1490 :         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        1490 :         std::vector<PolygonMapEntry> oCompletedPolygons;
     410       34097 :         for (auto &entry : oPolygonMap_)
     411             :         {
     412       32607 :             RPolygon *poPolygon = entry.second;
     413             : 
     414       32607 :             if (poPolygon->iBottomRightRow + 1 == nCurrentRow)
     415             :             {
     416        3587 :                 oCompletedPolygons.push_back(entry);
     417             :             }
     418             :         }
     419             :         // cppcheck-suppress constVariableReference
     420        5077 :         for (auto &entry : oCompletedPolygons)
     421             :         {
     422        3587 :             PolyIdType nPolyId = entry.first;
     423        3587 :             RPolygon *poPolygon = entry.second;
     424             : 
     425             :             // emit valid polygon only
     426        3587 :             if (nPolyId != nInvalidPolyId_)
     427             :             {
     428        3568 :                 poPolygonReceiver_->receive(
     429        3568 :                     poPolygon, panLastLineVal[poPolygon->iBottomRightCol]);
     430             :             }
     431             : 
     432        3587 :             destroyPolygon(nPolyId);
     433             :         }
     434        1490 :         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          52 : OGRPolygonWriter<DataType>::OGRPolygonWriter(OGRLayerH hOutLayer,
     446             :                                              int iPixValField,
     447             :                                              double *padfGeoTransform)
     448          52 :     : PolygonReceiver<DataType>(), poOutLayer_(OGRLayer::FromHandle(hOutLayer)),
     449          52 :       iPixValField_(iPixValField), padfGeoTransform_(padfGeoTransform)
     450             : {
     451          52 :     poFeature_ = std::make_unique<OGRFeature>(poOutLayer_->GetLayerDefn());
     452          52 :     poPolygon_ = new OGRPolygon();
     453          52 :     poFeature_->SetGeometryDirectly(poPolygon_);
     454          52 : }
     455             : 
     456             : template <typename DataType>
     457        3568 : void OGRPolygonWriter<DataType>::receive(RPolygon *poPolygon,
     458             :                                          DataType nPolygonCellValue)
     459             : {
     460        3568 :     std::vector<bool> oAccessedArc(poPolygon->oArcs.size(), false);
     461        3568 :     double *padfGeoTransform = padfGeoTransform_;
     462             : 
     463        3568 :     OGRLinearRing *poFirstRing = poPolygon_->getExteriorRing();
     464        3568 :     if (poFirstRing && poPolygon_->getNumInteriorRings() == 0)
     465             :     {
     466        3504 :         poFirstRing->empty();
     467             :     }
     468             :     else
     469             :     {
     470          64 :         poFirstRing = nullptr;
     471          64 :         poPolygon_->empty();
     472             :     }
     473             : 
     474        3568 :     auto AddRingToPolygon =
     475       74277 :         [this, &poPolygon, &oAccessedArc,
     476             :          padfGeoTransform](std::size_t iFirstArcIndex, OGRLinearRing *poRing)
     477             :     {
     478        3591 :         std::unique_ptr<OGRLinearRing> poNewRing;
     479        3591 :         if (!poRing)
     480             :         {
     481          87 :             poNewRing = std::make_unique<OGRLinearRing>();
     482          87 :             poRing = poNewRing.get();
     483             :         }
     484             : 
     485        3591 :         auto AddArcToRing =
     486      498946 :             [&poPolygon, poRing, padfGeoTransform](std::size_t iArcIndex)
     487             :         {
     488       33504 :             const auto &oArc = poPolygon->oArcs[iArcIndex];
     489       33504 :             const bool bArcFollowRighthand = oArc.bFollowRighthand;
     490       33504 :             const int nArcPointCount = static_cast<int>(oArc.poArc->size());
     491       33504 :             int nDstPointIdx = poRing->getNumPoints();
     492       33504 :             poRing->setNumPoints(nDstPointIdx + nArcPointCount,
     493             :                                  /* bZeroizeNewContent = */ false);
     494       33504 :             if (poRing->getNumPoints() < nDstPointIdx + nArcPointCount)
     495             :             {
     496           0 :                 return false;
     497             :             }
     498      106490 :             for (int i = 0; i < nArcPointCount; ++i)
     499             :             {
     500       92619 :                 const Point &oPixel =
     501       72986 :                     (*oArc.poArc)[bArcFollowRighthand
     502             :                                       ? i
     503       19633 :                                       : (nArcPointCount - i - 1)];
     504             : 
     505      218958 :                 const double dfX = padfGeoTransform[0] +
     506       72986 :                                    oPixel[1] * padfGeoTransform[1] +
     507       72986 :                                    oPixel[0] * padfGeoTransform[2];
     508      218958 :                 const double dfY = padfGeoTransform[3] +
     509       72986 :                                    oPixel[1] * padfGeoTransform[4] +
     510       72986 :                                    oPixel[0] * padfGeoTransform[5];
     511             : 
     512       72986 :                 poRing->setPoint(nDstPointIdx, dfX, dfY);
     513       72986 :                 ++nDstPointIdx;
     514             :             }
     515       33504 :             return true;
     516             :         };
     517             : 
     518        3591 :         if (!AddArcToRing(iFirstArcIndex))
     519             :         {
     520           0 :             return false;
     521             :         }
     522             : 
     523        3591 :         std::size_t iArcIndex = iFirstArcIndex;
     524        3591 :         std::size_t iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
     525        3591 :         oAccessedArc[iArcIndex] = true;
     526       33504 :         while (iNextArcIndex != iFirstArcIndex)
     527             :         {
     528       29913 :             if (!AddArcToRing(iNextArcIndex))
     529             :             {
     530           0 :                 return false;
     531             :             }
     532       29913 :             iArcIndex = iNextArcIndex;
     533       29913 :             iNextArcIndex = poPolygon->oArcs[iArcIndex].nConnection;
     534       29913 :             oAccessedArc[iArcIndex] = true;
     535             :         }
     536             : 
     537             :         // close ring manually
     538        3591 :         poRing->closeRings();
     539             : 
     540        3591 :         if (poNewRing)
     541          87 :             poPolygon_->addRingDirectly(poNewRing.release());
     542        3591 :         return true;
     543             :     };
     544             : 
     545       37072 :     for (size_t i = 0; i < oAccessedArc.size(); ++i)
     546             :     {
     547       33504 :         if (!oAccessedArc[i])
     548             :         {
     549        3591 :             if (!AddRingToPolygon(i, poFirstRing))
     550             :             {
     551           0 :                 eErr_ = CE_Failure;
     552           0 :                 return;
     553             :             }
     554        3591 :             poFirstRing = nullptr;
     555             :         }
     556             :     }
     557             : 
     558             :     // Create the feature object
     559        3568 :     poFeature_->SetFID(OGRNullFID);
     560        3568 :     if (iPixValField_ >= 0)
     561        2975 :         poFeature_->SetField(iPixValField_,
     562             :                              static_cast<double>(nPolygonCellValue));
     563             : 
     564             :     // Write the to the layer.
     565        3568 :     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        3568 :     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 */

Generated by: LCOV version 1.14