LCOV - code coverage report
Current view: top level - alg - polygonize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 130 154 84.4 %
Date: 2025-10-22 13:51:22 Functions: 7 7 100.0 %

          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_Byte, 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          97 : 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          97 :     VALIDATE_POINTER1(hSrcBand, "GDALPolygonize", CE_Failure);
      81          97 :     VALIDATE_POINTER1(hOutLayer, "GDALPolygonize", CE_Failure);
      82             : 
      83          97 :     if (pfnProgress == nullptr)
      84          29 :         pfnProgress = GDALDummyProgress;
      85             : 
      86          97 :     const int nConnectedness =
      87          97 :         CSLFetchNameValue(papszOptions, "8CONNECTED") ? 8 : 4;
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Confirm our output layer will support feature creation.         */
      91             :     /* -------------------------------------------------------------------- */
      92          97 :     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          97 :     const int nXSize = GDALGetRasterBandXSize(hSrcBand);
     104          97 :     const int nYSize = GDALGetRasterBandYSize(hSrcBand);
     105          97 :     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          97 :     DataType *panLastLineVal =
     112          97 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     113          97 :     DataType *panThisLineVal =
     114          97 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     115          97 :     GInt32 *panLastLineId =
     116          97 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     117          97 :     GInt32 *panThisLineId =
     118          97 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     119             : 
     120          97 :     GByte *pabyMaskLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     121             : 
     122          97 :     if (panLastLineVal == nullptr || panThisLineVal == nullptr ||
     123          97 :         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          97 :     GDALGeoTransform gt;
     139          97 :     bool bGotGeoTransform = false;
     140             :     const char *pszDatasetForGeoRef =
     141          97 :         CSLFetchNameValue(papszOptions, "DATASET_FOR_GEOREF");
     142          97 :     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          95 :         auto poSrcDS = GDALRasterBand::FromHandle(hSrcBand)->GetDataset();
     154          95 :         if (poSrcDS)
     155             :         {
     156          35 :             bGotGeoTransform = poSrcDS->GetGeoTransform(gt) == CE_None;
     157             :         }
     158             :     }
     159          97 :     if (!bGotGeoTransform)
     160             :     {
     161          60 :         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         194 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oFirstEnum(
     170             :         nConnectedness);
     171             : 
     172          97 :     CPLErr eErr = CE_None;
     173             : 
     174        2067 :     for (int iY = 0; eErr == CE_None && iY < nYSize; iY++)
     175             :     {
     176        1970 :         eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1, panThisLineVal,
     177             :                             nXSize, 1, eDT, 0, 0);
     178             : 
     179        1970 :         if (eErr == CE_None && hMaskBand != nullptr)
     180        1892 :             eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     181             :                                    panThisLineVal);
     182             : 
     183        1970 :         if (eErr != CE_None)
     184           0 :             break;
     185             : 
     186        1970 :         if (iY == 0)
     187          97 :             eErr = oFirstEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     188             :                                           panThisLineId, nXSize)
     189          97 :                        ? CE_None
     190             :                        : CE_Failure;
     191             :         else
     192        1873 :             eErr = oFirstEnum.ProcessLine(panLastLineVal, panThisLineVal,
     193             :                                           panLastLineId, panThisLineId, nXSize)
     194        1873 :                        ? CE_None
     195             :                        : CE_Failure;
     196             : 
     197        1970 :         if (eErr != CE_None)
     198           0 :             break;
     199             : 
     200             :         // Swap lines.
     201        1970 :         std::swap(panLastLineVal, panThisLineVal);
     202        1970 :         std::swap(panLastLineId, panThisLineId);
     203             : 
     204             :         /* --------------------------------------------------------------------
     205             :          */
     206             :         /*      Report progress, and support interrupts. */
     207             :         /* --------------------------------------------------------------------
     208             :          */
     209        1970 :         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          97 :     if (eErr == CE_None)
     223          97 :         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         194 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oSecondEnum(
     230             :         nConnectedness);
     231             : 
     232         194 :     OGRPolygonWriter<DataType> oPolygonWriter{
     233             :         hOutLayer, iPixValField, gt,
     234             :         atoi(CSLFetchNameValueDef(papszOptions, "COMMIT_INTERVAL", "100000"))};
     235          97 :     Polygonizer<GInt32, DataType> oPolygonizer{-1, &oPolygonWriter};
     236          97 :     TwoArm *paoLastLineArm =
     237          97 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     238          97 :     TwoArm *paoThisLineArm =
     239          97 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     240             : 
     241          97 :     if (paoThisLineArm == nullptr || paoLastLineArm == nullptr)
     242             :     {
     243           0 :         eErr = CE_Failure;
     244             :     }
     245             :     else
     246             :     {
     247        1934 :         for (int i = 0; i < nXSize + 2; ++i)
     248             :         {
     249        1837 :             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        2164 :     for (int iY = 0; eErr == CE_None && iY < nYSize + 1; iY++)
     258             :     {
     259             :         /* --------------------------------------------------------------------
     260             :          */
     261             :         /*      Read the image data. */
     262             :         /* --------------------------------------------------------------------
     263             :          */
     264        2067 :         if (iY < nYSize)
     265             :         {
     266        1970 :             eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1,
     267             :                                 panThisLineVal, nXSize, 1, eDT, 0, 0);
     268        1970 :             if (eErr == CE_None && hMaskBand != nullptr)
     269        1892 :                 eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     270             :                                        panThisLineVal);
     271             :         }
     272             : 
     273        2067 :         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        2067 :         if (iY == nYSize)
     283             :         {
     284        1740 :             for (int iX = 0; iX < nXSize; iX++)
     285        1643 :                 panThisLineId[iX] =
     286             :                     decltype(oPolygonizer)::THE_OUTER_POLYGON_ID;
     287             :         }
     288        1970 :         else if (iY == 0)
     289             :         {
     290          97 :             eErr = oSecondEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     291             :                                            panThisLineId, nXSize)
     292          97 :                        ? CE_None
     293             :                        : CE_Failure;
     294             :         }
     295             :         else
     296             :         {
     297        1873 :             eErr = oSecondEnum.ProcessLine(panLastLineVal, panThisLineVal,
     298             :                                            panLastLineId, panThisLineId, nXSize)
     299        1873 :                        ? CE_None
     300             :                        : CE_Failure;
     301             :         }
     302             : 
     303        2067 :         if (eErr != CE_None)
     304           0 :             continue;
     305             : 
     306        2067 :         if (iY < nYSize)
     307             :         {
     308      432770 :             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      430800 :                 panLastLineId[iX] =
     314      430800 :                     panThisLineId[iX] == -1
     315      430800 :                         ? -1
     316      377864 :                         : oFirstEnum.panPolyIdMap[panThisLineId[iX]];
     317             :             }
     318             : 
     319        1970 :             if (!oPolygonizer.processLine(panLastLineId, panLastLineVal,
     320             :                                           paoThisLineArm, paoLastLineArm, iY,
     321             :                                           nXSize))
     322             :             {
     323           0 :                 eErr = CE_Failure;
     324             :             }
     325             :             else
     326             :             {
     327        1970 :                 eErr = oPolygonWriter.getErr();
     328             :             }
     329             :         }
     330             :         else
     331             :         {
     332          97 :             if (!oPolygonizer.processLine(panThisLineId, panLastLineVal,
     333             :                                           paoThisLineArm, paoLastLineArm, iY,
     334             :                                           nXSize))
     335             :             {
     336           0 :                 eErr = CE_Failure;
     337             :             }
     338             :             else
     339             :             {
     340          97 :                 eErr = oPolygonWriter.getErr();
     341             :             }
     342             :         }
     343             : 
     344        2067 :         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        2067 :         std::swap(panLastLineVal, panThisLineVal);
     354        2067 :         std::swap(panLastLineId, panThisLineId);
     355        2067 :         std::swap(paoThisLineArm, paoLastLineArm);
     356             : 
     357             :         /* --------------------------------------------------------------------
     358             :          */
     359             :         /*      Report progress, and support interrupts. */
     360             :         /* --------------------------------------------------------------------
     361             :          */
     362        2067 :         if (!pfnProgress(
     363        2067 :                 std::min(1.0, 0.10 + 0.90 * ((iY + 1) /
     364        2067 :                                              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          97 :     if (!oPolygonWriter.Finalize())
     373           0 :         eErr = CE_Failure;
     374             : 
     375             :     /* -------------------------------------------------------------------- */
     376             :     /*      Cleanup                                                         */
     377             :     /* -------------------------------------------------------------------- */
     378          97 :     CPLFree(panThisLineId);
     379          97 :     CPLFree(panLastLineId);
     380          97 :     CPLFree(panThisLineVal);
     381          97 :     CPLFree(panLastLineVal);
     382          97 :     CPLFree(paoThisLineArm);
     383          97 :     CPLFree(paoLastLineArm);
     384          97 :     CPLFree(pabyMaskLine);
     385             : 
     386          97 :     return eErr;
     387             : }
     388             : 
     389             : /******************************************************************************/
     390             : /*                          GDALFloatEquals()                                 */
     391             : /* Code from:                                                                 */
     392             : /* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm  */
     393             : /******************************************************************************/
     394        1608 : GBool GDALFloatEquals(float A, float B)
     395             : {
     396             :     // This function will allow maxUlps-1 floats between A and B.
     397        1608 :     const int maxUlps = MAX_ULPS;
     398             : 
     399             :     // Make sure maxUlps is non-negative and small enough that the default NAN
     400             :     // won't compare as equal to anything.
     401             : #if MAX_ULPS <= 0 || MAX_ULPS >= 4 * 1024 * 1024
     402             : #error "Invalid MAX_ULPS"
     403             : #endif
     404             : 
     405             :     // This assignation could violate strict aliasing. It causes a warning with
     406             :     // gcc -O2. Use of memcpy preferred. Credits for Even Rouault. Further info
     407             :     // at http://trac.osgeo.org/gdal/ticket/4005#comment:6
     408        1608 :     int aInt = 0;
     409        1608 :     memcpy(&aInt, &A, 4);
     410             : 
     411             :     // Make aInt lexicographically ordered as a twos-complement int.
     412        1608 :     if (aInt < 0)
     413          10 :         aInt = INT_MIN - aInt;
     414             : 
     415             :     // Make bInt lexicographically ordered as a twos-complement int.
     416        1608 :     int bInt = 0;
     417        1608 :     memcpy(&bInt, &B, 4);
     418             : 
     419        1608 :     if (bInt < 0)
     420          10 :         bInt = INT_MIN - bInt;
     421             : #ifdef COMPAT_WITH_ICC_CONVERSION_CHECK
     422             :     const int intDiff =
     423             :         abs(static_cast<int>(static_cast<GUIntBig>(static_cast<GIntBig>(aInt) -
     424             :                                                    static_cast<GIntBig>(bInt)) &
     425             :                              0xFFFFFFFFU));
     426             : #else
     427             :     // To make -ftrapv happy we compute the diff on larger type and
     428             :     // cast down later.
     429        1608 :     const int intDiff = abs(static_cast<int>(static_cast<GIntBig>(aInt) -
     430             :                                              static_cast<GIntBig>(bInt)));
     431             : #endif
     432        1608 :     if (intDiff <= maxUlps)
     433         270 :         return true;
     434        1338 :     return false;
     435             : }
     436             : 
     437             : /************************************************************************/
     438             : /*                           GDALPolygonize()                           */
     439             : /************************************************************************/
     440             : 
     441             : /**
     442             :  * Create polygon coverage from raster data.
     443             :  *
     444             :  * This function creates vector polygons for all connected regions of pixels in
     445             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     446             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     447             :  * can be provided to determine which pixels are eligible for processing.
     448             :  *
     449             :  * Note that currently the source pixel band values are read into a
     450             :  * signed 64bit integer buffer (Int64), so floating point or complex
     451             :  * bands will be implicitly truncated before processing. If you want to use a
     452             :  * version using 32bit float buffers, see GDALFPolygonize().
     453             :  *
     454             :  * Polygon features will be created on the output layer, with polygon
     455             :  * geometries representing the polygons.  The polygon geometries will be
     456             :  * in the georeferenced coordinate system of the image (based on the
     457             :  * geotransform of the source dataset).  It is acceptable for the output
     458             :  * layer to already have features.  Note that GDALPolygonize() does not
     459             :  * set the coordinate system on the output layer.  Application code should
     460             :  * do this when the layer is created, presumably matching the raster
     461             :  * coordinate system.
     462             :  *
     463             :  * The algorithm used attempts to minimize memory use so that very large
     464             :  * rasters can be processed.  However, if the raster has many polygons
     465             :  * or very large/complex polygons, the memory use for holding polygon
     466             :  * enumerations and active polygon geometries may grow to be quite large.
     467             :  *
     468             :  * The algorithm will generally produce very dense polygon geometries, with
     469             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     470             :  * For non-thematic raster data (such as satellite images) the result will
     471             :  * essentially be one small polygon per pixel, and memory and output layer
     472             :  * sizes will be substantial.  The algorithm is primarily intended for
     473             :  * relatively simple thematic imagery, masks, and classification results.
     474             :  *
     475             :  * @param hSrcBand the source raster band to be processed.
     476             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     477             :  * value other than zero will be considered suitable for collection as
     478             :  * polygons.
     479             :  * @param hOutLayer the vector feature layer to which the polygons should
     480             :  * be written.
     481             :  * @param iPixValField the attribute field index indicating the feature
     482             :  * attribute into which the pixel value of the polygon should be written. Or
     483             :  * -1 to indicate that the pixel value must not be written.
     484             :  * @param papszOptions a name/value list of additional options
     485             :  * <ul>
     486             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     487             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     488             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     489             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     490             :  * typical for mask bands.</li>
     491             :  * <li>COMMIT_INTERVAL=num:
     492             :  * (GDAL >= 3.12) Interval in number of features at which transactions must be
     493             :  * flushed. A value of 0 means that no transactions are opened.
     494             :  * A negative value means a single transaction.
     495             :  * The default value is 100000.
     496             :  * The function takes care of issuing the starting transaction and committing
     497             :  * the final one.
     498             :  * </li>
     499             :  * </ul>
     500             :  * @param pfnProgress callback for reporting algorithm progress matching the
     501             :  * GDALProgressFunc() semantics.  May be NULL.
     502             :  * @param pProgressArg callback argument passed to pfnProgress.
     503             :  *
     504             :  * @return CE_None on success or CE_Failure on a failure.
     505             :  */
     506             : 
     507          95 : CPLErr CPL_STDCALL GDALPolygonize(GDALRasterBandH hSrcBand,
     508             :                                   GDALRasterBandH hMaskBand,
     509             :                                   OGRLayerH hOutLayer, int iPixValField,
     510             :                                   char **papszOptions,
     511             :                                   GDALProgressFunc pfnProgress,
     512             :                                   void *pProgressArg)
     513             : 
     514             : {
     515          95 :     return GDALPolygonizeT<std::int64_t, IntEqualityTest>(
     516             :         hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
     517          95 :         pProgressArg, GDT_Int64);
     518             : }
     519             : 
     520             : /************************************************************************/
     521             : /*                           GDALFPolygonize()                           */
     522             : /************************************************************************/
     523             : 
     524             : /**
     525             :  * Create polygon coverage from raster data.
     526             :  *
     527             :  * This function creates vector polygons for all connected regions of pixels in
     528             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     529             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     530             :  * can be provided to determine which pixels are eligible for processing.
     531             :  *
     532             :  * The source pixel band values are read into a 32bit float buffer. If you want
     533             :  * to use a (probably faster) version using signed 32bit integer buffer, see
     534             :  * GDALPolygonize().
     535             :  *
     536             :  * Polygon features will be created on the output layer, with polygon
     537             :  * geometries representing the polygons.  The polygon geometries will be
     538             :  * in the georeferenced coordinate system of the image (based on the
     539             :  * geotransform of the source dataset).  It is acceptable for the output
     540             :  * layer to already have features.  Note that GDALFPolygonize() does not
     541             :  * set the coordinate system on the output layer.  Application code should
     542             :  * do this when the layer is created, presumably matching the raster
     543             :  * coordinate system.
     544             :  *
     545             :  * The algorithm used attempts to minimize memory use so that very large
     546             :  * rasters can be processed.  However, if the raster has many polygons
     547             :  * or very large/complex polygons, the memory use for holding polygon
     548             :  * enumerations and active polygon geometries may grow to be quite large.
     549             :  *
     550             :  * The algorithm will generally produce very dense polygon geometries, with
     551             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     552             :  * For non-thematic raster data (such as satellite images) the result will
     553             :  * essentially be one small polygon per pixel, and memory and output layer
     554             :  * sizes will be substantial.  The algorithm is primarily intended for
     555             :  * relatively simple thematic imagery, masks, and classification results.
     556             :  *
     557             :  * @param hSrcBand the source raster band to be processed.
     558             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     559             :  * value other than zero will be considered suitable for collection as
     560             :  * polygons.
     561             :  * @param hOutLayer the vector feature layer to which the polygons should
     562             :  * be written.
     563             :  * @param iPixValField the attribute field index indicating the feature
     564             :  * attribute into which the pixel value of the polygon should be written. Or
     565             :  * -1 to indicate that the pixel value must not be written.
     566             :  * @param papszOptions a name/value list of additional options
     567             :  * <ul>
     568             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     569             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     570             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     571             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     572             :  * typical for mask bands.</li>
     573             :  * <li>COMMIT_INTERVAL=num:
     574             :  * (GDAL >= 3.12) Interval in number of features at which transactions must be
     575             :  * flushed. A value of 0 means that no transactions are opened.
     576             :  * A negative value means a single transaction.
     577             :  * The default value is 100000.
     578             :  * The function takes care of issuing the starting transaction and committing
     579             :  * the final one.
     580             :  * </li>
     581             :  * </ul>
     582             :  * @param pfnProgress callback for reporting algorithm progress matching the
     583             :  * GDALProgressFunc() semantics.  May be NULL.
     584             :  * @param pProgressArg callback argument passed to pfnProgress.
     585             :  *
     586             :  * @return CE_None on success or CE_Failure on a failure.
     587             :  *
     588             :  */
     589             : 
     590           2 : CPLErr CPL_STDCALL GDALFPolygonize(GDALRasterBandH hSrcBand,
     591             :                                    GDALRasterBandH hMaskBand,
     592             :                                    OGRLayerH hOutLayer, int iPixValField,
     593             :                                    char **papszOptions,
     594             :                                    GDALProgressFunc pfnProgress,
     595             :                                    void *pProgressArg)
     596             : 
     597             : {
     598           2 :     return GDALPolygonizeT<float, FloatEqualityTest>(
     599             :         hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
     600           2 :         pProgressArg, GDT_Float32);
     601             : }

Generated by: LCOV version 1.14