LCOV - code coverage report
Current view: top level - alg - polygonize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 137 163 84.0 %
Date: 2025-12-28 05:19:56 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Project:  GDAL
       3             :  * Purpose:  Raster to Polygon Converter
       4             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       5             :  *
       6             :  ******************************************************************************
       7             :  * Copyright (c) 2008, Frank Warmerdam
       8             :  * Copyright (c) 2009-2020, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "cpl_port.h"
      14             : #include "gdal_alg.h"
      15             : 
      16             : #include <stddef.h>
      17             : #include <stdio.h>
      18             : #include <cstdlib>
      19             : #include <string.h>
      20             : 
      21             : #include <algorithm>
      22             : #include <limits>
      23             : #include <map>
      24             : #include <memory>
      25             : #include <utility>
      26             : #include <vector>
      27             : 
      28             : #include "gdal_alg_priv.h"
      29             : #include "gdal.h"
      30             : #include "ogr_api.h"
      31             : #include "ogr_core.h"
      32             : #include "cpl_conv.h"
      33             : #include "cpl_error.h"
      34             : #include "cpl_progress.h"
      35             : #include "cpl_string.h"
      36             : #include "cpl_vsi.h"
      37             : 
      38             : #include "polygonize_polygonizer.h"
      39             : 
      40             : using namespace gdal::polygonizer;
      41             : 
      42             : /************************************************************************/
      43             : /*                          GPMaskImageData()                           */
      44             : /*                                                                      */
      45             : /*      Mask out image pixels to a special nodata value if the mask     */
      46             : /*      band is zero.                                                   */
      47             : /************************************************************************/
      48             : 
      49             : template <class DataType>
      50        3784 : static CPLErr GPMaskImageData(GDALRasterBandH hMaskBand, GByte *pabyMaskLine,
      51             :                               int iY, int nXSize, DataType *panImageLine)
      52             : 
      53             : {
      54        3784 :     const CPLErr eErr = GDALRasterIO(hMaskBand, GF_Read, 0, iY, nXSize, 1,
      55             :                                      pabyMaskLine, nXSize, 1, GDT_UInt8, 0, 0);
      56        3784 :     if (eErr != CE_None)
      57           0 :         return eErr;
      58             : 
      59      862016 :     for (int i = 0; i < nXSize; i++)
      60             :     {
      61      858232 :         if (pabyMaskLine[i] == 0)
      62      105872 :             panImageLine[i] = GP_NODATA_MARKER;
      63             :     }
      64             : 
      65        3784 :     return CE_None;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                           GDALPolygonizeT()                          */
      70             : /************************************************************************/
      71             : 
      72             : template <class DataType, class EqualityTest>
      73          98 : static CPLErr GDALPolygonizeT(GDALRasterBandH hSrcBand,
      74             :                               GDALRasterBandH hMaskBand, OGRLayerH hOutLayer,
      75             :                               int iPixValField, CSLConstList papszOptions,
      76             :                               GDALProgressFunc pfnProgress, void *pProgressArg,
      77             :                               GDALDataType eDT)
      78             : 
      79             : {
      80          98 :     VALIDATE_POINTER1(hSrcBand, "GDALPolygonize", CE_Failure);
      81          98 :     VALIDATE_POINTER1(hOutLayer, "GDALPolygonize", CE_Failure);
      82             : 
      83          98 :     if (pfnProgress == nullptr)
      84          30 :         pfnProgress = GDALDummyProgress;
      85             : 
      86          98 :     const int nConnectedness =
      87          98 :         CSLFetchNameValue(papszOptions, "8CONNECTED") ? 8 : 4;
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Confirm our output layer will support feature creation.         */
      91             :     /* -------------------------------------------------------------------- */
      92          98 :     if (!OGR_L_TestCapability(hOutLayer, OLCSequentialWrite))
      93             :     {
      94           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      95             :                  "Output feature layer does not appear to support creation "
      96             :                  "of features in GDALPolygonize().");
      97           0 :         return CE_Failure;
      98             :     }
      99             : 
     100             :     /* -------------------------------------------------------------------- */
     101             :     /*      Allocate working buffers.                                       */
     102             :     /* -------------------------------------------------------------------- */
     103          98 :     const int nXSize = GDALGetRasterBandXSize(hSrcBand);
     104          98 :     const int nYSize = GDALGetRasterBandYSize(hSrcBand);
     105          98 :     if (nXSize > std::numeric_limits<int>::max() - 2)
     106             :     {
     107           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Too wide raster");
     108           0 :         return CE_Failure;
     109             :     }
     110             : 
     111          98 :     DataType *panLastLineVal =
     112          98 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     113          98 :     DataType *panThisLineVal =
     114          98 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     115          98 :     GInt32 *panLastLineId =
     116          98 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     117          98 :     GInt32 *panThisLineId =
     118          98 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     119             : 
     120          98 :     GByte *pabyMaskLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     121             : 
     122          98 :     if (panLastLineVal == nullptr || panThisLineVal == nullptr ||
     123          98 :         panLastLineId == nullptr || panThisLineId == nullptr ||
     124             :         pabyMaskLine == nullptr)
     125             :     {
     126           0 :         CPLFree(panThisLineId);
     127           0 :         CPLFree(panLastLineId);
     128           0 :         CPLFree(panThisLineVal);
     129           0 :         CPLFree(panLastLineVal);
     130           0 :         CPLFree(pabyMaskLine);
     131           0 :         return CE_Failure;
     132             :     }
     133             : 
     134             :     /* -------------------------------------------------------------------- */
     135             :     /*      Get the geotransform, if there is one, so we can convert the    */
     136             :     /*      vectors into georeferenced coordinates.                         */
     137             :     /* -------------------------------------------------------------------- */
     138          98 :     GDALGeoTransform gt;
     139          98 :     bool bGotGeoTransform = false;
     140             :     const char *pszDatasetForGeoRef =
     141          98 :         CSLFetchNameValue(papszOptions, "DATASET_FOR_GEOREF");
     142          98 :     if (pszDatasetForGeoRef)
     143             :     {
     144           4 :         auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
     145             :             pszDatasetForGeoRef, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR));
     146           2 :         if (poSrcDS)
     147             :         {
     148           2 :             bGotGeoTransform = poSrcDS->GetGeoTransform(gt) == CE_None;
     149             :         }
     150             :     }
     151             :     else
     152             :     {
     153          96 :         auto poSrcDS = GDALRasterBand::FromHandle(hSrcBand)->GetDataset();
     154          96 :         if (poSrcDS)
     155             :         {
     156          36 :             bGotGeoTransform = poSrcDS->GetGeoTransform(gt) == CE_None;
     157             :         }
     158             :     }
     159          98 :     if (!bGotGeoTransform)
     160             :     {
     161          61 :         gt = GDALGeoTransform();
     162             :     }
     163             : 
     164             :     /* -------------------------------------------------------------------- */
     165             :     /*      The first pass over the raster is only used to build up the     */
     166             :     /*      polygon id map so we will know in advance what polygons are     */
     167             :     /*      what on the second pass.                                        */
     168             :     /* -------------------------------------------------------------------- */
     169         196 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oFirstEnum(
     170             :         nConnectedness);
     171             : 
     172          98 :     CPLErr eErr = CE_None;
     173             : 
     174        2071 :     for (int iY = 0; eErr == CE_None && iY < nYSize; iY++)
     175             :     {
     176        1973 :         eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1, panThisLineVal,
     177             :                             nXSize, 1, eDT, 0, 0);
     178             : 
     179        1973 :         if (eErr == CE_None && hMaskBand != nullptr)
     180        1892 :             eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     181             :                                    panThisLineVal);
     182             : 
     183        1973 :         if (eErr != CE_None)
     184           0 :             break;
     185             : 
     186        1973 :         if (iY == 0)
     187          98 :             eErr = oFirstEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     188             :                                           panThisLineId, nXSize)
     189          98 :                        ? CE_None
     190             :                        : CE_Failure;
     191             :         else
     192        1875 :             eErr = oFirstEnum.ProcessLine(panLastLineVal, panThisLineVal,
     193             :                                           panLastLineId, panThisLineId, nXSize)
     194        1875 :                        ? CE_None
     195             :                        : CE_Failure;
     196             : 
     197        1973 :         if (eErr != CE_None)
     198           0 :             break;
     199             : 
     200             :         // Swap lines.
     201        1973 :         std::swap(panLastLineVal, panThisLineVal);
     202        1973 :         std::swap(panLastLineId, panThisLineId);
     203             : 
     204             :         /* --------------------------------------------------------------------
     205             :          */
     206             :         /*      Report progress, and support interrupts. */
     207             :         /* --------------------------------------------------------------------
     208             :          */
     209        1973 :         if (!pfnProgress(0.10 * ((iY + 1) / static_cast<double>(nYSize)), "",
     210             :                          pProgressArg))
     211             :         {
     212           0 :             CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
     213           0 :             eErr = CE_Failure;
     214             :         }
     215             :     }
     216             : 
     217             :     /* -------------------------------------------------------------------- */
     218             :     /*      Make a pass through the maps, ensuring every polygon id         */
     219             :     /*      points to the final id it should use, not an intermediate       */
     220             :     /*      value.                                                          */
     221             :     /* -------------------------------------------------------------------- */
     222          98 :     if (eErr == CE_None)
     223          98 :         oFirstEnum.CompleteMerges();
     224             : 
     225             :     /* -------------------------------------------------------------------- */
     226             :     /*      We will use a new enumerator for the second pass primarily      */
     227             :     /*      so we can preserve the first pass map.                          */
     228             :     /* -------------------------------------------------------------------- */
     229         196 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oSecondEnum(
     230             :         nConnectedness);
     231             : 
     232         196 :     OGRPolygonWriter<DataType> oPolygonWriter{
     233             :         hOutLayer, iPixValField, gt,
     234             :         atoi(CSLFetchNameValueDef(papszOptions, "COMMIT_INTERVAL", "100000"))};
     235          98 :     Polygonizer<GInt32, DataType> oPolygonizer{-1, &oPolygonWriter};
     236          98 :     TwoArm *paoLastLineArm =
     237          98 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     238          98 :     TwoArm *paoThisLineArm =
     239          98 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     240             : 
     241          98 :     if (paoThisLineArm == nullptr || paoLastLineArm == nullptr)
     242             :     {
     243           0 :         eErr = CE_Failure;
     244             :     }
     245             :     else
     246             :     {
     247        1940 :         for (int i = 0; i < nXSize + 2; ++i)
     248             :         {
     249        1842 :             paoLastLineArm[i].poPolyInside = oPolygonizer.getTheOuterPolygon();
     250             :         }
     251             :     }
     252             : 
     253             :     /* ==================================================================== */
     254             :     /*      Second pass during which we will actually collect polygon       */
     255             :     /*      edges as geometries.                                            */
     256             :     /* ==================================================================== */
     257        2169 :     for (int iY = 0; eErr == CE_None && iY < nYSize + 1; iY++)
     258             :     {
     259             :         /* --------------------------------------------------------------------
     260             :          */
     261             :         /*      Read the image data. */
     262             :         /* --------------------------------------------------------------------
     263             :          */
     264        2071 :         if (iY < nYSize)
     265             :         {
     266        1973 :             eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1,
     267             :                                 panThisLineVal, nXSize, 1, eDT, 0, 0);
     268        1973 :             if (eErr == CE_None && hMaskBand != nullptr)
     269        1892 :                 eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     270             :                                        panThisLineVal);
     271             :         }
     272             : 
     273        2071 :         if (eErr != CE_None)
     274           0 :             continue;
     275             : 
     276             :         /* --------------------------------------------------------------------
     277             :          */
     278             :         /*      Determine what polygon the various pixels belong to (redoing */
     279             :         /*      the same thing done in the first pass above). */
     280             :         /* --------------------------------------------------------------------
     281             :          */
     282        2071 :         if (iY == nYSize)
     283             :         {
     284        1744 :             for (int iX = 0; iX < nXSize; iX++)
     285        1646 :                 panThisLineId[iX] =
     286             :                     decltype(oPolygonizer)::THE_OUTER_POLYGON_ID;
     287             :         }
     288        1973 :         else if (iY == 0)
     289             :         {
     290          98 :             eErr = oSecondEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     291             :                                            panThisLineId, nXSize)
     292          98 :                        ? CE_None
     293             :                        : CE_Failure;
     294             :         }
     295             :         else
     296             :         {
     297        1875 :             eErr = oSecondEnum.ProcessLine(panLastLineVal, panThisLineVal,
     298             :                                            panLastLineId, panThisLineId, nXSize)
     299        1875 :                        ? CE_None
     300             :                        : CE_Failure;
     301             :         }
     302             : 
     303        2071 :         if (eErr != CE_None)
     304           0 :             continue;
     305             : 
     306        2071 :         if (iY < nYSize)
     307             :         {
     308      432782 :             for (int iX = 0; iX < nXSize; iX++)
     309             :             {
     310             :                 // TODO: maybe we can reserve -1 as the lookup result for -1 polygon id in the panPolyIdMap,
     311             :                 //       so the this expression becomes: panLastLineId[iX] = *(oFirstEnum.panPolyIdMap + panThisLineId[iX]).
     312             :                 //       This would eliminate the condition checking.
     313      430809 :                 panLastLineId[iX] =
     314      430809 :                     panThisLineId[iX] == -1
     315      430809 :                         ? -1
     316      377873 :                         : oFirstEnum.panPolyIdMap[panThisLineId[iX]];
     317             :             }
     318             : 
     319        1973 :             if (!oPolygonizer.processLine(panLastLineId, panLastLineVal,
     320             :                                           paoThisLineArm, paoLastLineArm, iY,
     321             :                                           nXSize))
     322             :             {
     323           0 :                 eErr = CE_Failure;
     324             :             }
     325             :             else
     326             :             {
     327        1973 :                 eErr = oPolygonWriter.getErr();
     328             :             }
     329             :         }
     330             :         else
     331             :         {
     332          98 :             if (!oPolygonizer.processLine(panThisLineId, panLastLineVal,
     333             :                                           paoThisLineArm, paoLastLineArm, iY,
     334             :                                           nXSize))
     335             :             {
     336           0 :                 eErr = CE_Failure;
     337             :             }
     338             :             else
     339             :             {
     340          98 :                 eErr = oPolygonWriter.getErr();
     341             :             }
     342             :         }
     343             : 
     344        2071 :         if (eErr != CE_None)
     345           0 :             continue;
     346             : 
     347             :         /* --------------------------------------------------------------------
     348             :          */
     349             :         /*      Swap pixel value, and polygon id lines to be ready for the */
     350             :         /*      next line. */
     351             :         /* --------------------------------------------------------------------
     352             :          */
     353        2071 :         std::swap(panLastLineVal, panThisLineVal);
     354        2071 :         std::swap(panLastLineId, panThisLineId);
     355        2071 :         std::swap(paoThisLineArm, paoLastLineArm);
     356             : 
     357             :         /* --------------------------------------------------------------------
     358             :          */
     359             :         /*      Report progress, and support interrupts. */
     360             :         /* --------------------------------------------------------------------
     361             :          */
     362        2071 :         if (!pfnProgress(
     363        2071 :                 std::min(1.0, 0.10 + 0.90 * ((iY + 1) /
     364        2071 :                                              static_cast<double>(nYSize))),
     365             :                 "", pProgressArg))
     366             :         {
     367           0 :             CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
     368           0 :             eErr = CE_Failure;
     369             :         }
     370             :     }
     371             : 
     372          98 :     if (!oPolygonWriter.Finalize())
     373           0 :         eErr = CE_Failure;
     374             : 
     375             :     /* -------------------------------------------------------------------- */
     376             :     /*      Cleanup                                                         */
     377             :     /* -------------------------------------------------------------------- */
     378          98 :     CPLFree(panThisLineId);
     379          98 :     CPLFree(panLastLineId);
     380          98 :     CPLFree(panThisLineVal);
     381          98 :     CPLFree(panLastLineVal);
     382          98 :     CPLFree(paoThisLineArm);
     383          98 :     CPLFree(paoLastLineArm);
     384          98 :     CPLFree(pabyMaskLine);
     385             : 
     386          98 :     return eErr;
     387             : }
     388             : 
     389             : /******************************************************************************/
     390             : /*                       GDALFloatAlmostEquals()                              */
     391             : /* Code (originally) from:                                                    */
     392             : /* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm  */
     393             : /******************************************************************************/
     394             : 
     395             : template <typename FloatType, typename IntType>
     396        1654 : static inline bool GDALFloatAlmostEquals(FloatType A, FloatType B,
     397             :                                          unsigned maxUlps)
     398             : {
     399             :     static_assert(sizeof(FloatType) == sizeof(IntType));
     400             :     // This function will allow maxUlps-1 floats between A and B.
     401             : 
     402             :     // Make sure maxUlps is non-negative and small enough that the default NAN
     403             :     // won't compare as equal to anything.
     404        1654 :     if (maxUlps >= 4 * 1024 * 1024)
     405             :     {
     406           0 :         CPLError(CE_Failure, CPLE_IllegalArg, "Invalid maxUlps");
     407           0 :         return false;
     408             :     }
     409             : 
     410        3308 :     const auto MapToInteger = [](FloatType x)
     411             :     {
     412        3308 :         IntType i = 0;
     413        3308 :         memcpy(&i, &x, sizeof(i));
     414             : 
     415        3308 :         constexpr int NBITS = 8 * static_cast<int>(sizeof(i)) - 1;
     416        3308 :         constexpr IntType SHIFT = (static_cast<IntType>(1) << NBITS);
     417             : 
     418             :         // Make i lexicographically ordered with negative values
     419             :         // remapped to the [0, SHIFT[ range and positive values in the
     420             :         // [SHIFT, UINT_MAX[ range
     421        3308 :         if ((i >> NBITS) != 0)
     422          36 :             i = SHIFT - (i & ~SHIFT);
     423             :         else
     424        3272 :             i += SHIFT;
     425        3308 :         return i;
     426             :     };
     427             : 
     428        1654 :     const auto aInt = MapToInteger(A);
     429        1654 :     const auto bInt = MapToInteger(B);
     430             : 
     431        1654 :     return ((aInt > bInt) ? aInt - bInt : bInt - aInt) <= maxUlps;
     432             : }
     433             : 
     434        1619 : bool GDALFloatAlmostEquals(float A, float B, unsigned maxUlps)
     435             : {
     436        1619 :     return GDALFloatAlmostEquals<float, uint32_t>(A, B, maxUlps);
     437             : }
     438             : 
     439             : /******************************************************************************/
     440             : /*                         GDALDoubleAlmostEquals()                           */
     441             : /******************************************************************************/
     442             : 
     443          35 : bool GDALDoubleAlmostEquals(double A, double B, unsigned maxUlps)
     444             : {
     445          35 :     return GDALFloatAlmostEquals<double, uint64_t>(A, B, maxUlps);
     446             : }
     447             : 
     448             : /************************************************************************/
     449             : /*                           GDALPolygonize()                           */
     450             : /************************************************************************/
     451             : 
     452             : /**
     453             :  * Create polygon coverage from raster data.
     454             :  *
     455             :  * This function creates vector polygons for all connected regions of pixels in
     456             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     457             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     458             :  * can be provided to determine which pixels are eligible for processing.
     459             :  *
     460             :  * Note that currently the source pixel band values are read into a
     461             :  * signed 64bit integer buffer (Int64), so floating point or complex
     462             :  * bands will be implicitly truncated before processing. If you want to use a
     463             :  * version using 32bit or 64bit float buffers, see GDALFPolygonize().
     464             :  *
     465             :  * Polygon features will be created on the output layer, with polygon
     466             :  * geometries representing the polygons.  The polygon geometries will be
     467             :  * in the georeferenced coordinate system of the image (based on the
     468             :  * geotransform of the source dataset).  It is acceptable for the output
     469             :  * layer to already have features.  Note that GDALPolygonize() does not
     470             :  * set the coordinate system on the output layer.  Application code should
     471             :  * do this when the layer is created, presumably matching the raster
     472             :  * coordinate system.
     473             :  *
     474             :  * The algorithm used attempts to minimize memory use so that very large
     475             :  * rasters can be processed.  However, if the raster has many polygons
     476             :  * or very large/complex polygons, the memory use for holding polygon
     477             :  * enumerations and active polygon geometries may grow to be quite large.
     478             :  *
     479             :  * The algorithm will generally produce very dense polygon geometries, with
     480             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     481             :  * For non-thematic raster data (such as satellite images) the result will
     482             :  * essentially be one small polygon per pixel, and memory and output layer
     483             :  * sizes will be substantial.  The algorithm is primarily intended for
     484             :  * relatively simple thematic imagery, masks, and classification results.
     485             :  *
     486             :  * @param hSrcBand the source raster band to be processed.
     487             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     488             :  * value other than zero will be considered suitable for collection as
     489             :  * polygons.
     490             :  * @param hOutLayer the vector feature layer to which the polygons should
     491             :  * be written.
     492             :  * @param iPixValField the attribute field index indicating the feature
     493             :  * attribute into which the pixel value of the polygon should be written. Or
     494             :  * -1 to indicate that the pixel value must not be written.
     495             :  * @param papszOptions a name/value list of additional options
     496             :  * <ul>
     497             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     498             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     499             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     500             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     501             :  * typical for mask bands.</li>
     502             :  * <li>COMMIT_INTERVAL=num:
     503             :  * (GDAL >= 3.12) Interval in number of features at which transactions must be
     504             :  * flushed. A value of 0 means that no transactions are opened.
     505             :  * A negative value means a single transaction.
     506             :  * The default value is 100000.
     507             :  * The function takes care of issuing the starting transaction and committing
     508             :  * the final one.
     509             :  * </li>
     510             :  * </ul>
     511             :  * @param pfnProgress callback for reporting algorithm progress matching the
     512             :  * GDALProgressFunc() semantics.  May be NULL.
     513             :  * @param pProgressArg callback argument passed to pfnProgress.
     514             :  *
     515             :  * @return CE_None on success or CE_Failure on a failure.
     516             :  */
     517             : 
     518          95 : CPLErr CPL_STDCALL GDALPolygonize(GDALRasterBandH hSrcBand,
     519             :                                   GDALRasterBandH hMaskBand,
     520             :                                   OGRLayerH hOutLayer, int iPixValField,
     521             :                                   char **papszOptions,
     522             :                                   GDALProgressFunc pfnProgress,
     523             :                                   void *pProgressArg)
     524             : 
     525             : {
     526          95 :     return GDALPolygonizeT<std::int64_t, IntEqualityTest>(
     527             :         hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
     528          95 :         pProgressArg, GDT_Int64);
     529             : }
     530             : 
     531             : /************************************************************************/
     532             : /*                           GDALFPolygonize()                           */
     533             : /************************************************************************/
     534             : 
     535             : /**
     536             :  * Create polygon coverage from raster data.
     537             :  *
     538             :  * This function creates vector polygons for all connected regions of pixels in
     539             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     540             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     541             :  * can be provided to determine which pixels are eligible for processing.
     542             :  *
     543             :  * The source pixel band values are read into a 32-bit float buffer, or 64-bit
     544             :  * float if the source band is 64-bit float itself. If you want
     545             :  * to use a (probably faster) version using signed 32bit integer buffer, see
     546             :  * GDALPolygonize().
     547             :  *
     548             :  * Polygon features will be created on the output layer, with polygon
     549             :  * geometries representing the polygons.  The polygon geometries will be
     550             :  * in the georeferenced coordinate system of the image (based on the
     551             :  * geotransform of the source dataset).  It is acceptable for the output
     552             :  * layer to already have features.  Note that GDALFPolygonize() does not
     553             :  * set the coordinate system on the output layer.  Application code should
     554             :  * do this when the layer is created, presumably matching the raster
     555             :  * coordinate system.
     556             :  *
     557             :  * The algorithm used attempts to minimize memory use so that very large
     558             :  * rasters can be processed.  However, if the raster has many polygons
     559             :  * or very large/complex polygons, the memory use for holding polygon
     560             :  * enumerations and active polygon geometries may grow to be quite large.
     561             :  *
     562             :  * The algorithm will generally produce very dense polygon geometries, with
     563             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     564             :  * For non-thematic raster data (such as satellite images) the result will
     565             :  * essentially be one small polygon per pixel, and memory and output layer
     566             :  * sizes will be substantial.  The algorithm is primarily intended for
     567             :  * relatively simple thematic imagery, masks, and classification results.
     568             :  *
     569             :  * @param hSrcBand the source raster band to be processed.
     570             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     571             :  * value other than zero will be considered suitable for collection as
     572             :  * polygons.
     573             :  * @param hOutLayer the vector feature layer to which the polygons should
     574             :  * be written.
     575             :  * @param iPixValField the attribute field index indicating the feature
     576             :  * attribute into which the pixel value of the polygon should be written. Or
     577             :  * -1 to indicate that the pixel value must not be written.
     578             :  * @param papszOptions a name/value list of additional options
     579             :  * <ul>
     580             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     581             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     582             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     583             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     584             :  * typical for mask bands.</li>
     585             :  * <li>COMMIT_INTERVAL=num:
     586             :  * (GDAL >= 3.12) Interval in number of features at which transactions must be
     587             :  * flushed. A value of 0 means that no transactions are opened.
     588             :  * A negative value means a single transaction.
     589             :  * The default value is 100000.
     590             :  * The function takes care of issuing the starting transaction and committing
     591             :  * the final one.
     592             :  * </li>
     593             :  * </ul>
     594             :  * @param pfnProgress callback for reporting algorithm progress matching the
     595             :  * GDALProgressFunc() semantics.  May be NULL.
     596             :  * @param pProgressArg callback argument passed to pfnProgress.
     597             :  *
     598             :  * @return CE_None on success or CE_Failure on a failure.
     599             :  *
     600             :  */
     601             : 
     602           3 : CPLErr CPL_STDCALL GDALFPolygonize(GDALRasterBandH hSrcBand,
     603             :                                    GDALRasterBandH hMaskBand,
     604             :                                    OGRLayerH hOutLayer, int iPixValField,
     605             :                                    char **papszOptions,
     606             :                                    GDALProgressFunc pfnProgress,
     607             :                                    void *pProgressArg)
     608             : 
     609             : {
     610           3 :     if (GDALGetRasterDataType(hSrcBand) == GDT_Float64)
     611             :     {
     612           1 :         return GDALPolygonizeT<double, DoubleEqualityTest>(
     613             :             hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions,
     614           1 :             pfnProgress, pProgressArg, GDT_Float64);
     615             :     }
     616             :     else
     617             :     {
     618           2 :         return GDALPolygonizeT<float, FloatEqualityTest>(
     619             :             hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions,
     620           2 :             pfnProgress, pProgressArg, GDT_Float32);
     621             :     }
     622             : }

Generated by: LCOV version 1.14