LCOV - code coverage report
Current view: top level - alg - polygonize_polygonizer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 282 285 98.9 %
Date: 2024-05-04 12:52:34 Functions: 27 27 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      10             :  * copy of this software and associated documentation files (the "Software"),
      11             :  * to deal in the Software without restriction, including without limitation
      12             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      13             :  * and/or sell copies of the Software, and to permit persons to whom the
      14             :  * Software is furnished to do so, subject to the following conditions:
      15             :  *
      16             :  * The above copyright notice and this permission notice shall be included
      17             :  * in all copies or substantial portions of the Software.
      18             :  *
      19             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      20             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      22             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      24             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      25             :  * DEALINGS IN THE SOFTWARE.
      26             :  ****************************************************************************/
      27             : 
      28             : /*! @cond Doxygen_Suppress */
      29             : 
      30             : #include "polygonize_polygonizer.h"
      31             : 
      32             : #include <algorithm>
      33             : 
      34             : namespace gdal
      35             : {
      36             : namespace polygonizer
      37             : {
      38             : 
      39        3639 : RPolygon::~RPolygon()
      40             : {
      41       39629 :     for (auto &arc : oArcs)
      42             :     {
      43       35990 :         delete arc;
      44             :     }
      45        3639 : }
      46             : 
      47       35990 : IndexedArc RPolygon::newArc(bool bFollowRighthand)
      48             : {
      49       35990 :     Arc *poArc = new Arc();
      50       35990 :     std::size_t iArcIndex = oArcs.size();
      51       35990 :     oArcs.push_back(poArc);
      52       35990 :     oArcRighthandFollow.push_back(bFollowRighthand);
      53       35990 :     oArcConnections.push_back(iArcIndex);
      54       35990 :     return IndexedArc{poArc, iArcIndex};
      55             : }
      56             : 
      57       35990 : void RPolygon::setArcConnection(const IndexedArc &oArc,
      58             :                                 const IndexedArc &oNextArc)
      59             : {
      60       35990 :     oArcConnections[oArc.iIndex] = oNextArc.iIndex;
      61       35990 : }
      62             : 
      63      423251 : void RPolygon::updateBottomRightPos(IndexType iRow, IndexType iCol)
      64             : {
      65      423251 :     iBottomRightRow = iRow;
      66      423251 :     iBottomRightCol = iCol;
      67      423251 : }
      68             : 
      69             : /**
      70             :  * Process different kinds of Arm connections.
      71             :  */
      72      423251 : static void ProcessArmConnections(TwoArm *poCurrent, TwoArm *poAbove,
      73             :                                   TwoArm *poLeft)
      74             : {
      75      423251 :     poCurrent->poPolyInside->updateBottomRightPos(poCurrent->iRow,
      76             :                                                   poCurrent->iCol);
      77      423251 :     poCurrent->bSolidVertical = poCurrent->poPolyInside != poLeft->poPolyInside;
      78      423251 :     poCurrent->bSolidHorizontal =
      79      423251 :         poCurrent->poPolyInside != poAbove->poPolyInside;
      80      423251 :     poCurrent->poPolyAbove = poAbove->poPolyInside;
      81      423251 :     poCurrent->poPolyLeft = poLeft->poPolyInside;
      82             : 
      83      423251 :     constexpr int BIT_CUR_HORIZ = 0;
      84      423251 :     constexpr int BIT_CUR_VERT = 1;
      85      423251 :     constexpr int BIT_LEFT = 2;
      86      423251 :     constexpr int BIT_ABOVE = 3;
      87             : 
      88      423251 :     const int nArmConnectionType =
      89      423251 :         (static_cast<int>(poAbove->bSolidVertical) << BIT_ABOVE) |
      90      423251 :         (static_cast<int>(poLeft->bSolidHorizontal) << BIT_LEFT) |
      91      423251 :         (static_cast<int>(poCurrent->bSolidVertical) << BIT_CUR_VERT) |
      92      423251 :         (static_cast<int>(poCurrent->bSolidHorizontal) << BIT_CUR_HORIZ);
      93             : 
      94      423251 :     constexpr int VIRTUAL = 0;
      95      423251 :     constexpr int SOLID = 1;
      96             : 
      97      423251 :     constexpr int ABOVE_VIRTUAL = VIRTUAL << BIT_ABOVE;
      98      423251 :     constexpr int ABOVE_SOLID = SOLID << BIT_ABOVE;
      99             : 
     100      423251 :     constexpr int LEFT_VIRTUAL = VIRTUAL << BIT_LEFT;
     101      423251 :     constexpr int LEFT_SOLID = SOLID << BIT_LEFT;
     102             : 
     103      423251 :     constexpr int CUR_VERT_VIRTUAL = VIRTUAL << BIT_CUR_VERT;
     104      423251 :     constexpr int CUR_VERT_SOLID = SOLID << BIT_CUR_VERT;
     105             : 
     106      423251 :     constexpr int CUR_HORIZ_VIRTUAL = VIRTUAL << BIT_CUR_HORIZ;
     107      423251 :     constexpr int CUR_HORIZ_SOLID = SOLID << BIT_CUR_HORIZ;
     108             : 
     109             :     /**
     110             :      * There are 12 valid connection types depending on the arm types(virtual or solid)
     111             :      * The following diagram illustrates these kinds of connection types, ⇢⇣ means virtual arm, →↓ means solid arm.
     112             :      *     ⇣        ⇣          ⇣         ⇣        ↓
     113             :      *    ⇢ →      → →        → ⇢       → →      ⇢ →
     114             :      *     ↓        ⇣          ↓         ↓        ⇣
     115             :      *   type=3    type=5    type=6    type=7    type=9
     116             :      *
     117             :      *     ↓        ↓          ↓         ↓          ↓
     118             :      *    ⇢ ⇢      ⇢ →        → ⇢       → →        → ⇢
     119             :      *     ↓        ↓          ⇣         ⇣          ↓
     120             :      *   type=10  type=11    type=12    type=13   type=14
     121             :      *
     122             :      *     ↓        ⇣
     123             :      *    → →      ⇢ ⇢
     124             :      *     ↓        ⇣
     125             :      *   type=15  type=0
     126             :      *
     127             :      *   For each connection type, we may create new arc, ,
     128             :      *   Depending on the connection type, we may do the following things:
     129             :      *       1. Create new arc. If the arc is closed to the inner polygon, it is called "Inner Arc", otherwise "Outer Arc"
     130             :      *       2. Pass an arc to the next arm.
     131             :      *       3. "Close" two arcs. If two arcs meet at the bottom right corner of a cell, close them by recording the arc connection.
     132             :      *       4. Add grid position(row, col) to an arc.
     133             :      */
     134             : 
     135      423251 :     switch (nArmConnectionType)
     136             :     {
     137      358585 :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
     138             :             CUR_HORIZ_VIRTUAL:  // 0
     139             :             // nothing to do
     140      358585 :             break;
     141             : 
     142        7175 :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
     143             :             CUR_HORIZ_SOLID:  // 3
     144             :             // add inner arcs
     145        7175 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     146        7175 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     147        7175 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     148        7175 :                                                       poCurrent->oArcVerInner);
     149        7175 :             poCurrent->oArcVerInner.poArc->emplace_back(
     150        7175 :                 Point{poCurrent->iRow, poCurrent->iCol});
     151             : 
     152             :             // add outer arcs
     153        7175 :             poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
     154        7175 :             poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
     155        7175 :             poAbove->poPolyInside->setArcConnection(poCurrent->oArcVerOuter,
     156        7175 :                                                     poCurrent->oArcHorOuter);
     157        7175 :             poCurrent->oArcHorOuter.poArc->push_back(
     158        7175 :                 Point{poCurrent->iRow, poCurrent->iCol});
     159             : 
     160        7175 :             break;
     161       15831 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
     162             :             CUR_HORIZ_SOLID:  // 5
     163             :             // pass arcs
     164       15831 :             poCurrent->oArcHorInner = poLeft->oArcHorInner;
     165       15831 :             poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
     166             : 
     167       15831 :             break;
     168        8688 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
     169             :             CUR_HORIZ_VIRTUAL:  // 6
     170             :             // pass arcs
     171        8688 :             poCurrent->oArcVerInner = poLeft->oArcHorOuter;
     172        8688 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     173        8688 :             poCurrent->oArcVerInner.poArc->push_back(
     174        8688 :                 Point{poCurrent->iRow, poCurrent->iCol});
     175        8688 :             poCurrent->oArcVerOuter.poArc->push_back(
     176        8688 :                 Point{poCurrent->iRow, poCurrent->iCol});
     177             : 
     178        8688 :             break;
     179         942 :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_SOLID |
     180             :             CUR_HORIZ_SOLID:  // 7
     181             :             // pass arcs
     182         942 :             poCurrent->oArcHorOuter = poLeft->oArcHorOuter;
     183         942 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     184         942 :             poLeft->oArcHorInner.poArc->push_back(
     185         942 :                 Point{poCurrent->iRow, poCurrent->iCol});
     186             : 
     187             :             // add inner arcs
     188         942 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     189         942 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     190         942 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     191         942 :                                                       poCurrent->oArcVerInner);
     192         942 :             poCurrent->oArcVerInner.poArc->push_back(
     193         942 :                 Point{poCurrent->iRow, poCurrent->iCol});
     194             : 
     195         942 :             break;
     196        8671 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
     197             :             CUR_HORIZ_SOLID:  // 9
     198             :             // pass arcs
     199        8671 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     200        8671 :             poCurrent->oArcHorInner = poAbove->oArcVerOuter;
     201        8671 :             poCurrent->oArcHorOuter.poArc->push_back(
     202        8671 :                 Point{poCurrent->iRow, poCurrent->iCol});
     203        8671 :             poCurrent->oArcHorInner.poArc->push_back(
     204        8671 :                 Point{poCurrent->iRow, poCurrent->iCol});
     205             : 
     206        8671 :             break;
     207       11609 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
     208             :             CUR_HORIZ_VIRTUAL:  // 10
     209             :             // pass arcs
     210       11609 :             poCurrent->oArcVerInner = poAbove->oArcVerInner;
     211       11609 :             poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
     212             : 
     213       11609 :             break;
     214         976 :         case ABOVE_SOLID | LEFT_VIRTUAL | CUR_VERT_SOLID |
     215             :             CUR_HORIZ_SOLID:  // 11
     216             :             // pass arcs
     217         976 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     218         976 :             poCurrent->oArcVerOuter = poAbove->oArcVerOuter;
     219         976 :             poCurrent->oArcHorOuter.poArc->push_back(
     220         976 :                 Point{poCurrent->iRow, poCurrent->iCol});
     221             :             // add inner arcs
     222         976 :             poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     223         976 :             poCurrent->oArcHorInner = poCurrent->poPolyInside->newArc(false);
     224         976 :             poCurrent->poPolyInside->setArcConnection(poCurrent->oArcHorInner,
     225         976 :                                                       poCurrent->oArcVerInner);
     226         976 :             poCurrent->oArcVerInner.poArc->push_back(
     227         976 :                 Point{poCurrent->iRow, poCurrent->iCol});
     228             : 
     229         976 :             break;
     230        7195 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
     231             :             CUR_HORIZ_VIRTUAL:  // 12
     232             :             // close arcs
     233        7195 :             poLeft->oArcHorOuter.poArc->push_back(
     234        7195 :                 Point{poCurrent->iRow, poCurrent->iCol});
     235        7195 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     236        7195 :                                                   poAbove->oArcVerOuter);
     237             :             // close arcs
     238        7195 :             poAbove->oArcVerInner.poArc->push_back(
     239        7195 :                 Point{poCurrent->iRow, poCurrent->iCol});
     240        7195 :             poCurrent->poPolyInside->setArcConnection(poAbove->oArcVerInner,
     241        7195 :                                                       poLeft->oArcHorInner);
     242             : 
     243        7195 :             break;
     244         939 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_VIRTUAL |
     245             :             CUR_HORIZ_SOLID:  // 13
     246             :             // close arcs
     247         939 :             poLeft->oArcHorOuter.poArc->push_back(
     248         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     249         939 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     250         939 :                                                   poAbove->oArcVerOuter);
     251             :             // pass arcs
     252         939 :             poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     253         939 :             poCurrent->oArcHorInner = poLeft->oArcHorInner;
     254         939 :             poCurrent->oArcHorOuter.poArc->push_back(
     255         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     256             : 
     257         939 :             break;
     258         939 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID |
     259             :             CUR_HORIZ_VIRTUAL:  // 14
     260             :             // close arcs
     261         939 :             poLeft->oArcHorOuter.poArc->push_back(
     262         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     263         939 :             poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     264         939 :                                                   poAbove->oArcVerOuter);
     265             :             // pass arcs
     266         939 :             poCurrent->oArcVerInner = poAbove->oArcVerInner;
     267         939 :             poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     268         939 :             poCurrent->oArcVerOuter.poArc->push_back(
     269         939 :                 Point{poCurrent->iRow, poCurrent->iCol});
     270             : 
     271         939 :             break;
     272        1701 :         case ABOVE_SOLID | LEFT_SOLID | CUR_VERT_SOLID | CUR_HORIZ_SOLID:  // 15
     273             :             // Tow pixels of the main diagonal belong to the same polygon
     274        1701 :             if (poAbove->poPolyLeft == poCurrent->poPolyInside)
     275             :             {
     276             :                 // pass arcs
     277          42 :                 poCurrent->oArcVerInner = poLeft->oArcHorOuter;
     278          42 :                 poCurrent->oArcHorInner = poAbove->oArcVerOuter;
     279          42 :                 poCurrent->oArcVerInner.poArc->push_back(
     280          42 :                     Point{poCurrent->iRow, poCurrent->iCol});
     281          42 :                 poCurrent->oArcHorInner.poArc->push_back(
     282          42 :                     Point{poCurrent->iRow, poCurrent->iCol});
     283             :             }
     284             :             else
     285             :             {
     286             :                 // close arcs
     287        1659 :                 poLeft->oArcHorOuter.poArc->push_back(
     288        1659 :                     Point{poCurrent->iRow, poCurrent->iCol});
     289        1659 :                 poLeft->poPolyAbove->setArcConnection(poLeft->oArcHorOuter,
     290        1659 :                                                       poAbove->oArcVerOuter);
     291             :                 // add inner arcs
     292        1659 :                 poCurrent->oArcVerInner = poCurrent->poPolyInside->newArc(true);
     293             :                 poCurrent->oArcHorInner =
     294        1659 :                     poCurrent->poPolyInside->newArc(false);
     295        1659 :                 poCurrent->poPolyInside->setArcConnection(
     296        1659 :                     poCurrent->oArcHorInner, poCurrent->oArcVerInner);
     297        1659 :                 poCurrent->oArcVerInner.poArc->push_back(
     298        1659 :                     Point{poCurrent->iRow, poCurrent->iCol});
     299             :             }
     300             : 
     301             :             // Tow pixels of the secondary diagonal belong to the same polygon
     302        1701 :             if (poAbove->poPolyInside == poLeft->poPolyInside)
     303             :             {
     304             :                 // close arcs
     305          68 :                 poAbove->poPolyInside->setArcConnection(poAbove->oArcVerInner,
     306          68 :                                                         poLeft->oArcHorInner);
     307          68 :                 poAbove->oArcVerInner.poArc->push_back(
     308          68 :                     Point{poCurrent->iRow, poCurrent->iCol});
     309             :                 // add outer arcs
     310          68 :                 poCurrent->oArcHorOuter = poAbove->poPolyInside->newArc(true);
     311          68 :                 poCurrent->oArcVerOuter = poAbove->poPolyInside->newArc(false);
     312          68 :                 poCurrent->oArcHorOuter.poArc->push_back(
     313          68 :                     Point{poCurrent->iRow, poCurrent->iCol});
     314          68 :                 poAbove->poPolyInside->setArcConnection(
     315          68 :                     poCurrent->oArcVerOuter, poCurrent->oArcHorOuter);
     316             :             }
     317             :             else
     318             :             {
     319             :                 // pass arcs
     320        1633 :                 poCurrent->oArcHorOuter = poAbove->oArcVerInner;
     321        1633 :                 poCurrent->oArcVerOuter = poLeft->oArcHorInner;
     322        1633 :                 poCurrent->oArcHorOuter.poArc->push_back(
     323        1633 :                     Point{poCurrent->iRow, poCurrent->iCol});
     324        1633 :                 poCurrent->oArcVerOuter.poArc->push_back(
     325        1633 :                     Point{poCurrent->iRow, poCurrent->iCol});
     326             :             }
     327             : 
     328        1701 :             break;
     329             : 
     330           0 :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_VIRTUAL |
     331             :             CUR_HORIZ_SOLID:  // 1
     332             :         case ABOVE_VIRTUAL | LEFT_VIRTUAL | CUR_VERT_SOLID |
     333             :             CUR_HORIZ_VIRTUAL:  // 2
     334             :         case ABOVE_VIRTUAL | LEFT_SOLID | CUR_VERT_VIRTUAL |
     335             :             CUR_HORIZ_VIRTUAL:  // 4
     336             :         default:
     337             :             // Impossible case
     338           0 :             CPLAssert(false);
     339             :             break;
     340             :     }
     341      423251 : }
     342             : 
     343             : template <typename PolyIdType, typename DataType>
     344          52 : Polygonizer<PolyIdType, DataType>::Polygonizer(
     345             :     PolyIdType nInvalidPolyId, PolygonReceiver<DataType> *poPolygonReceiver)
     346          52 :     : nInvalidPolyId_(nInvalidPolyId), poPolygonReceiver_(poPolygonReceiver)
     347             : {
     348          52 :     poTheOuterPolygon_ = createPolygon(THE_OUTER_POLYGON_ID);
     349          52 : }
     350             : 
     351             : template <typename PolyIdType, typename DataType>
     352          52 : Polygonizer<PolyIdType, DataType>::~Polygonizer()
     353             : {
     354             :     // cppcheck-suppress constVariableReference
     355         104 :     for (auto &pair : oPolygonMap_)
     356             :     {
     357          52 :         delete pair.second;
     358             :     }
     359          52 : }
     360             : 
     361             : template <typename PolyIdType, typename DataType>
     362      421761 : RPolygon *Polygonizer<PolyIdType, DataType>::getPolygon(PolyIdType nPolygonId)
     363             : {
     364      421761 :     if (oPolygonMap_.count(nPolygonId) == 0)
     365             :     {
     366        3587 :         return createPolygon(nPolygonId);
     367             :     }
     368             :     else
     369             :     {
     370      418174 :         return oPolygonMap_[nPolygonId];
     371             :     }
     372             : }
     373             : 
     374             : template <typename PolyIdType, typename DataType>
     375             : RPolygon *
     376        3639 : Polygonizer<PolyIdType, DataType>::createPolygon(PolyIdType nPolygonId)
     377             : {
     378        3639 :     auto polygon = new RPolygon();
     379        3639 :     oPolygonMap_[nPolygonId] = polygon;
     380        3639 :     return polygon;
     381             : }
     382             : 
     383             : template <typename PolyIdType, typename DataType>
     384        3587 : void Polygonizer<PolyIdType, DataType>::destroyPolygon(PolyIdType nPolygonId)
     385             : {
     386        3587 :     delete oPolygonMap_[nPolygonId];
     387        3587 :     oPolygonMap_.erase(nPolygonId);
     388        3587 : }
     389             : 
     390             : template <typename PolyIdType, typename DataType>
     391        1490 : void Polygonizer<PolyIdType, DataType>::processLine(
     392             :     const PolyIdType *panThisLineId, const DataType *panLastLineVal,
     393             :     TwoArm *poThisLineArm, TwoArm *poLastLineArm, const IndexType nCurrentRow,
     394             :     const IndexType nCols)
     395             : {
     396             :     TwoArm *poCurrent, *poAbove, *poLeft;
     397             : 
     398        1490 :     poCurrent = poThisLineArm + 1;
     399        1490 :     poCurrent->iRow = nCurrentRow;
     400        1490 :     poCurrent->iCol = 0;
     401        1490 :     poCurrent->poPolyInside = getPolygon(panThisLineId[0]);
     402        1490 :     poAbove = poLastLineArm + 1;
     403        1490 :     poLeft = poThisLineArm;
     404        1490 :     poLeft->poPolyInside = poTheOuterPolygon_;
     405        1490 :     ProcessArmConnections(poCurrent, poAbove, poLeft);
     406      421761 :     for (IndexType col = 1; col < nCols; ++col)
     407             :     {
     408      420271 :         IndexType iArmIndex = col + 1;
     409      420271 :         poCurrent = poThisLineArm + iArmIndex;
     410      420271 :         poCurrent->iRow = nCurrentRow;
     411      420271 :         poCurrent->iCol = col;
     412      420271 :         poCurrent->poPolyInside = getPolygon(panThisLineId[col]);
     413      420271 :         poAbove = poLastLineArm + iArmIndex;
     414      420271 :         poLeft = poThisLineArm + iArmIndex - 1;
     415      420271 :         ProcessArmConnections(poCurrent, poAbove, poLeft);
     416             :     }
     417        1490 :     poCurrent = poThisLineArm + nCols + 1;
     418        1490 :     poCurrent->iRow = nCurrentRow;
     419        1490 :     poCurrent->iCol = nCols;
     420        1490 :     poCurrent->poPolyInside = poTheOuterPolygon_;
     421        1490 :     poAbove = poLastLineArm + nCols + 1;
     422        1490 :     poAbove->poPolyInside = poTheOuterPolygon_;
     423        1490 :     poLeft = poThisLineArm + nCols;
     424        1490 :     ProcessArmConnections(poCurrent, poAbove, poLeft);
     425             : 
     426             :     /**
     427             :      *
     428             :      * Find those polygons haven't been processed on this line as we can be sure they are completed
     429             :      *
     430             :      */
     431        2980 :     std::vector<PolygonMapEntry> oCompletedPolygons;
     432       34097 :     for (auto &entry : oPolygonMap_)
     433             :     {
     434       32607 :         RPolygon *poPolygon = entry.second;
     435             : 
     436       32607 :         if (poPolygon->iBottomRightRow + 1 == nCurrentRow)
     437             :         {
     438        3587 :             oCompletedPolygons.push_back(entry);
     439             :         }
     440             :     }
     441             :     // cppcheck-suppress constVariableReference
     442        5077 :     for (auto &entry : oCompletedPolygons)
     443             :     {
     444        3587 :         PolyIdType nPolyId = entry.first;
     445        3587 :         RPolygon *poPolygon = entry.second;
     446             : 
     447             :         // emit valid polygon only
     448        3587 :         if (nPolyId != nInvalidPolyId_)
     449             :         {
     450        3568 :             poPolygonReceiver_->receive(
     451        3568 :                 poPolygon, panLastLineVal[poPolygon->iBottomRightCol]);
     452             :         }
     453             : 
     454        3587 :         destroyPolygon(nPolyId);
     455             :     }
     456        1490 : }
     457             : 
     458             : template <typename DataType>
     459          52 : OGRPolygonWriter<DataType>::OGRPolygonWriter(OGRLayerH hOutLayer,
     460             :                                              int iPixValField,
     461             :                                              double *padfGeoTransform)
     462             :     : PolygonReceiver<DataType>(), hOutLayer_(hOutLayer),
     463          52 :       iPixValField_(iPixValField), padfGeoTransform_(padfGeoTransform)
     464             : {
     465          52 : }
     466             : 
     467             : template <typename DataType>
     468        3568 : void OGRPolygonWriter<DataType>::receive(RPolygon *poPolygon,
     469             :                                          DataType nPolygonCellValue)
     470             : {
     471        7136 :     std::vector<bool> oAccessedArc(poPolygon->oArcConnections.size(), false);
     472        3568 :     double *padfGeoTransform = padfGeoTransform_;
     473             : 
     474        3568 :     OGRGeometryH hPolygon = OGR_G_CreateGeometry(wkbPolygon);
     475             : 
     476        7159 :     auto AddRingToPolygon = [&poPolygon, &oAccessedArc, &hPolygon,
     477             :                              padfGeoTransform](std::size_t iFirstArcIndex)
     478             :     {
     479        3591 :         OGRGeometryH hRing = OGR_G_CreateGeometry(wkbLinearRing);
     480             : 
     481        3591 :         auto AddArcToRing =
     482      465442 :             [&poPolygon, &hRing, padfGeoTransform](std::size_t iArcIndex)
     483             :         {
     484       33504 :             auto oArc = poPolygon->oArcs[iArcIndex];
     485       33504 :             bool bArcFollowRighthand =
     486       33504 :                 poPolygon->oArcRighthandFollow[iArcIndex];
     487      106490 :             for (std::size_t i = 0; i < oArc->size(); ++i)
     488             :             {
     489       92619 :                 const Point &oPixel =
     490       19633 :                     (*oArc)[bArcFollowRighthand ? i : (oArc->size() - i - 1)];
     491             : 
     492      218958 :                 const double dfX = padfGeoTransform[0] +
     493       72986 :                                    oPixel[1] * padfGeoTransform[1] +
     494       72986 :                                    oPixel[0] * padfGeoTransform[2];
     495      218958 :                 const double dfY = padfGeoTransform[3] +
     496       72986 :                                    oPixel[1] * padfGeoTransform[4] +
     497       72986 :                                    oPixel[0] * padfGeoTransform[5];
     498             : 
     499       72986 :                 OGR_G_AddPoint_2D(hRing, dfX, dfY);
     500             :             }
     501             :         };
     502             : 
     503        3591 :         AddArcToRing(iFirstArcIndex);
     504             : 
     505        3591 :         std::size_t iArcIndex = iFirstArcIndex;
     506        3591 :         std::size_t iNextArcIndex = poPolygon->oArcConnections[iArcIndex];
     507        3591 :         oAccessedArc[iArcIndex] = true;
     508       33504 :         while (iNextArcIndex != iFirstArcIndex)
     509             :         {
     510       29913 :             AddArcToRing(iNextArcIndex);
     511       29913 :             iArcIndex = iNextArcIndex;
     512       29913 :             iNextArcIndex = poPolygon->oArcConnections[iArcIndex];
     513       29913 :             oAccessedArc[iArcIndex] = true;
     514             :         }
     515             : 
     516             :         // close ring manually
     517        3591 :         OGR_G_AddPoint_2D(hRing, OGR_G_GetX(hRing, 0), OGR_G_GetY(hRing, 0));
     518             : 
     519        3591 :         OGR_G_AddGeometryDirectly(hPolygon, hRing);
     520             :     };
     521             : 
     522        3568 :     std::vector<bool>::iterator ite;
     523        7159 :     while ((ite = std::find_if_not(oAccessedArc.begin(), oAccessedArc.end(),
     524       44394 :                                    [](bool accessed) { return accessed; })) !=
     525       14318 :            oAccessedArc.end())
     526             :     {
     527        3591 :         AddRingToPolygon(ite - oAccessedArc.begin());
     528             :     }
     529             : 
     530             :     // Create the feature object
     531        3568 :     OGRFeatureH hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hOutLayer_));
     532             : 
     533        3568 :     OGR_F_SetGeometryDirectly(hFeat, hPolygon);
     534             : 
     535        3568 :     if (iPixValField_ >= 0)
     536        2975 :         OGR_F_SetFieldDouble(hFeat, iPixValField_,
     537             :                              static_cast<double>(nPolygonCellValue));
     538             : 
     539             :     // Write the to the layer.
     540        3568 :     if (OGR_L_CreateFeature(hOutLayer_, hFeat) != OGRERR_NONE)
     541           0 :         eErr_ = CE_Failure;
     542             : 
     543        3568 :     OGR_F_Destroy(hFeat);
     544        3568 : }
     545             : 
     546             : }  // namespace polygonizer
     547             : }  // namespace gdal
     548             : 
     549             : /*! @endcond */

Generated by: LCOV version 1.14