LCOV - code coverage report
Current view: top level - alg - polygonize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 137 160 85.6 %
Date: 2025-05-20 14:45:53 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        3504 : static CPLErr GPMaskImageData(GDALRasterBandH hMaskBand, GByte *pabyMaskLine,
      51             :                               int iY, int nXSize, DataType *panImageLine)
      52             : 
      53             : {
      54        3504 :     const CPLErr eErr = GDALRasterIO(hMaskBand, GF_Read, 0, iY, nXSize, 1,
      55             :                                      pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0);
      56        3504 :     if (eErr != CE_None)
      57           0 :         return eErr;
      58             : 
      59      856136 :     for (int i = 0; i < nXSize; i++)
      60             :     {
      61      852632 :         if (pabyMaskLine[i] == 0)
      62      105872 :             panImageLine[i] = GP_NODATA_MARKER;
      63             :     }
      64             : 
      65        3504 :     return CE_None;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                           GDALPolygonizeT()                          */
      70             : /************************************************************************/
      71             : 
      72             : template <class DataType, class EqualityTest>
      73          90 : static CPLErr GDALPolygonizeT(GDALRasterBandH hSrcBand,
      74             :                               GDALRasterBandH hMaskBand, OGRLayerH hOutLayer,
      75             :                               int iPixValField, char **papszOptions,
      76             :                               GDALProgressFunc pfnProgress, void *pProgressArg,
      77             :                               GDALDataType eDT)
      78             : 
      79             : {
      80          90 :     VALIDATE_POINTER1(hSrcBand, "GDALPolygonize", CE_Failure);
      81          90 :     VALIDATE_POINTER1(hOutLayer, "GDALPolygonize", CE_Failure);
      82             : 
      83          90 :     if (pfnProgress == nullptr)
      84          23 :         pfnProgress = GDALDummyProgress;
      85             : 
      86          90 :     const int nConnectedness =
      87          90 :         CSLFetchNameValue(papszOptions, "8CONNECTED") ? 8 : 4;
      88             : 
      89             :     /* -------------------------------------------------------------------- */
      90             :     /*      Confirm our output layer will support feature creation.         */
      91             :     /* -------------------------------------------------------------------- */
      92          90 :     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          90 :     const int nXSize = GDALGetRasterBandXSize(hSrcBand);
     104          90 :     const int nYSize = GDALGetRasterBandYSize(hSrcBand);
     105          90 :     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          90 :     DataType *panLastLineVal =
     112          90 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     113          90 :     DataType *panThisLineVal =
     114          90 :         static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
     115          90 :     GInt32 *panLastLineId =
     116          90 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     117          90 :     GInt32 *panThisLineId =
     118          90 :         static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
     119             : 
     120          90 :     GByte *pabyMaskLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
     121             : 
     122          90 :     if (panLastLineVal == nullptr || panThisLineVal == nullptr ||
     123          90 :         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          90 :     double adfGeoTransform[6] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
     139          90 :     bool bGotGeoTransform = false;
     140             :     const char *pszDatasetForGeoRef =
     141          90 :         CSLFetchNameValue(papszOptions, "DATASET_FOR_GEOREF");
     142          90 :     if (pszDatasetForGeoRef)
     143             :     {
     144           2 :         GDALDatasetH hSrcDS = GDALOpen(pszDatasetForGeoRef, GA_ReadOnly);
     145           2 :         if (hSrcDS)
     146             :         {
     147           2 :             bGotGeoTransform =
     148           2 :                 GDALGetGeoTransform(hSrcDS, adfGeoTransform) == CE_None;
     149           2 :             GDALClose(hSrcDS);
     150             :         }
     151             :     }
     152             :     else
     153             :     {
     154          88 :         GDALDatasetH hSrcDS = GDALGetBandDataset(hSrcBand);
     155          88 :         if (hSrcDS)
     156          29 :             bGotGeoTransform =
     157          29 :                 GDALGetGeoTransform(hSrcDS, adfGeoTransform) == CE_None;
     158             :     }
     159          90 :     if (!bGotGeoTransform)
     160             :     {
     161          59 :         adfGeoTransform[0] = 0;
     162          59 :         adfGeoTransform[1] = 1;
     163          59 :         adfGeoTransform[2] = 0;
     164          59 :         adfGeoTransform[3] = 0;
     165          59 :         adfGeoTransform[4] = 0;
     166          59 :         adfGeoTransform[5] = 1;
     167             :     }
     168             : 
     169             :     /* -------------------------------------------------------------------- */
     170             :     /*      The first pass over the raster is only used to build up the     */
     171             :     /*      polygon id map so we will know in advance what polygons are     */
     172             :     /*      what on the second pass.                                        */
     173             :     /* -------------------------------------------------------------------- */
     174         180 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oFirstEnum(
     175             :         nConnectedness);
     176             : 
     177          90 :     CPLErr eErr = CE_None;
     178             : 
     179        1920 :     for (int iY = 0; eErr == CE_None && iY < nYSize; iY++)
     180             :     {
     181        1830 :         eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1, panThisLineVal,
     182             :                             nXSize, 1, eDT, 0, 0);
     183             : 
     184        1830 :         if (eErr == CE_None && hMaskBand != nullptr)
     185        1752 :             eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     186             :                                    panThisLineVal);
     187             : 
     188        1830 :         if (eErr != CE_None)
     189           0 :             break;
     190             : 
     191        1830 :         if (iY == 0)
     192          90 :             eErr = oFirstEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     193             :                                           panThisLineId, nXSize)
     194          90 :                        ? CE_None
     195             :                        : CE_Failure;
     196             :         else
     197        1740 :             eErr = oFirstEnum.ProcessLine(panLastLineVal, panThisLineVal,
     198             :                                           panLastLineId, panThisLineId, nXSize)
     199        1740 :                        ? CE_None
     200             :                        : CE_Failure;
     201             : 
     202        1830 :         if (eErr != CE_None)
     203           0 :             break;
     204             : 
     205             :         // Swap lines.
     206        1830 :         std::swap(panLastLineVal, panThisLineVal);
     207        1830 :         std::swap(panLastLineId, panThisLineId);
     208             : 
     209             :         /* --------------------------------------------------------------------
     210             :          */
     211             :         /*      Report progress, and support interrupts. */
     212             :         /* --------------------------------------------------------------------
     213             :          */
     214        1830 :         if (!pfnProgress(0.10 * ((iY + 1) / static_cast<double>(nYSize)), "",
     215             :                          pProgressArg))
     216             :         {
     217           0 :             CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
     218           0 :             eErr = CE_Failure;
     219             :         }
     220             :     }
     221             : 
     222             :     /* -------------------------------------------------------------------- */
     223             :     /*      Make a pass through the maps, ensuring every polygon id         */
     224             :     /*      points to the final id it should use, not an intermediate       */
     225             :     /*      value.                                                          */
     226             :     /* -------------------------------------------------------------------- */
     227          90 :     if (eErr == CE_None)
     228          90 :         oFirstEnum.CompleteMerges();
     229             : 
     230             :     /* -------------------------------------------------------------------- */
     231             :     /*      We will use a new enumerator for the second pass primarily      */
     232             :     /*      so we can preserve the first pass map.                          */
     233             :     /* -------------------------------------------------------------------- */
     234         180 :     GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oSecondEnum(
     235             :         nConnectedness);
     236             : 
     237         180 :     OGRPolygonWriter<DataType> oPolygonWriter{hOutLayer, iPixValField,
     238             :                                               adfGeoTransform};
     239          90 :     Polygonizer<GInt32, DataType> oPolygonizer{-1, &oPolygonWriter};
     240          90 :     TwoArm *paoLastLineArm =
     241          90 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     242          90 :     TwoArm *paoThisLineArm =
     243          90 :         static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
     244             : 
     245          90 :     if (paoThisLineArm == nullptr || paoLastLineArm == nullptr)
     246             :     {
     247           0 :         eErr = CE_Failure;
     248             :     }
     249             :     else
     250             :     {
     251        1773 :         for (int i = 0; i < nXSize + 2; ++i)
     252             :         {
     253        1683 :             paoLastLineArm[i].poPolyInside = oPolygonizer.getTheOuterPolygon();
     254             :         }
     255             :     }
     256             : 
     257             :     /* ==================================================================== */
     258             :     /*      Second pass during which we will actually collect polygon       */
     259             :     /*      edges as geometries.                                            */
     260             :     /* ==================================================================== */
     261        2010 :     for (int iY = 0; eErr == CE_None && iY < nYSize + 1; iY++)
     262             :     {
     263             :         /* --------------------------------------------------------------------
     264             :          */
     265             :         /*      Read the image data. */
     266             :         /* --------------------------------------------------------------------
     267             :          */
     268        1920 :         if (iY < nYSize)
     269             :         {
     270        1830 :             eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1,
     271             :                                 panThisLineVal, nXSize, 1, eDT, 0, 0);
     272        1830 :             if (eErr == CE_None && hMaskBand != nullptr)
     273        1752 :                 eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
     274             :                                        panThisLineVal);
     275             :         }
     276             : 
     277        1920 :         if (eErr != CE_None)
     278           0 :             continue;
     279             : 
     280             :         /* --------------------------------------------------------------------
     281             :          */
     282             :         /*      Determine what polygon the various pixels belong to (redoing */
     283             :         /*      the same thing done in the first pass above). */
     284             :         /* --------------------------------------------------------------------
     285             :          */
     286        1920 :         if (iY == nYSize)
     287             :         {
     288        1593 :             for (int iX = 0; iX < nXSize; iX++)
     289        1503 :                 panThisLineId[iX] =
     290             :                     decltype(oPolygonizer)::THE_OUTER_POLYGON_ID;
     291             :         }
     292        1830 :         else if (iY == 0)
     293             :         {
     294          90 :             eErr = oSecondEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
     295             :                                            panThisLineId, nXSize)
     296          90 :                        ? CE_None
     297             :                        : CE_Failure;
     298             :         }
     299             :         else
     300             :         {
     301        1740 :             eErr = oSecondEnum.ProcessLine(panLastLineVal, panThisLineVal,
     302             :                                            panLastLineId, panThisLineId, nXSize)
     303        1740 :                        ? CE_None
     304             :                        : CE_Failure;
     305             :         }
     306             : 
     307        1920 :         if (eErr != CE_None)
     308           0 :             continue;
     309             : 
     310        1920 :         if (iY < nYSize)
     311             :         {
     312      429830 :             for (int iX = 0; iX < nXSize; iX++)
     313             :             {
     314             :                 // TODO: maybe we can reserve -1 as the lookup result for -1 polygon id in the panPolyIdMap,
     315             :                 //       so the this expression becomes: panLastLineId[iX] = *(oFirstEnum.panPolyIdMap + panThisLineId[iX]).
     316             :                 //       This would eliminate the condition checking.
     317      428000 :                 panLastLineId[iX] =
     318      428000 :                     panThisLineId[iX] == -1
     319      428000 :                         ? -1
     320      375064 :                         : oFirstEnum.panPolyIdMap[panThisLineId[iX]];
     321             :             }
     322             : 
     323        1830 :             if (!oPolygonizer.processLine(panLastLineId, panLastLineVal,
     324             :                                           paoThisLineArm, paoLastLineArm, iY,
     325             :                                           nXSize))
     326             :             {
     327           0 :                 eErr = CE_Failure;
     328             :             }
     329             :             else
     330             :             {
     331        1830 :                 eErr = oPolygonWriter.getErr();
     332             :             }
     333             :         }
     334             :         else
     335             :         {
     336          90 :             if (!oPolygonizer.processLine(panThisLineId, panLastLineVal,
     337             :                                           paoThisLineArm, paoLastLineArm, iY,
     338             :                                           nXSize))
     339             :             {
     340           0 :                 eErr = CE_Failure;
     341             :             }
     342             :             else
     343             :             {
     344          90 :                 eErr = oPolygonWriter.getErr();
     345             :             }
     346             :         }
     347             : 
     348        1920 :         if (eErr != CE_None)
     349           0 :             continue;
     350             : 
     351             :         /* --------------------------------------------------------------------
     352             :          */
     353             :         /*      Swap pixel value, and polygon id lines to be ready for the */
     354             :         /*      next line. */
     355             :         /* --------------------------------------------------------------------
     356             :          */
     357        1920 :         std::swap(panLastLineVal, panThisLineVal);
     358        1920 :         std::swap(panLastLineId, panThisLineId);
     359        1920 :         std::swap(paoThisLineArm, paoLastLineArm);
     360             : 
     361             :         /* --------------------------------------------------------------------
     362             :          */
     363             :         /*      Report progress, and support interrupts. */
     364             :         /* --------------------------------------------------------------------
     365             :          */
     366        1920 :         if (!pfnProgress(
     367        1920 :                 std::min(1.0, 0.10 + 0.90 * ((iY + 1) /
     368        1920 :                                              static_cast<double>(nYSize))),
     369             :                 "", pProgressArg))
     370             :         {
     371           0 :             CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
     372           0 :             eErr = CE_Failure;
     373             :         }
     374             :     }
     375             : 
     376             :     /* -------------------------------------------------------------------- */
     377             :     /*      Cleanup                                                         */
     378             :     /* -------------------------------------------------------------------- */
     379          90 :     CPLFree(panThisLineId);
     380          90 :     CPLFree(panLastLineId);
     381          90 :     CPLFree(panThisLineVal);
     382          90 :     CPLFree(panLastLineVal);
     383          90 :     CPLFree(paoThisLineArm);
     384          90 :     CPLFree(paoLastLineArm);
     385          90 :     CPLFree(pabyMaskLine);
     386             : 
     387          90 :     return eErr;
     388             : }
     389             : 
     390             : /******************************************************************************/
     391             : /*                          GDALFloatEquals()                                 */
     392             : /* Code from:                                                                 */
     393             : /* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm  */
     394             : /******************************************************************************/
     395        1608 : GBool GDALFloatEquals(float A, float B)
     396             : {
     397             :     // This function will allow maxUlps-1 floats between A and B.
     398        1608 :     const int maxUlps = MAX_ULPS;
     399             : 
     400             :     // Make sure maxUlps is non-negative and small enough that the default NAN
     401             :     // won't compare as equal to anything.
     402             : #if MAX_ULPS <= 0 || MAX_ULPS >= 4 * 1024 * 1024
     403             : #error "Invalid MAX_ULPS"
     404             : #endif
     405             : 
     406             :     // This assignation could violate strict aliasing. It causes a warning with
     407             :     // gcc -O2. Use of memcpy preferred. Credits for Even Rouault. Further info
     408             :     // at http://trac.osgeo.org/gdal/ticket/4005#comment:6
     409        1608 :     int aInt = 0;
     410        1608 :     memcpy(&aInt, &A, 4);
     411             : 
     412             :     // Make aInt lexicographically ordered as a twos-complement int.
     413        1608 :     if (aInt < 0)
     414          10 :         aInt = INT_MIN - aInt;
     415             : 
     416             :     // Make bInt lexicographically ordered as a twos-complement int.
     417        1608 :     int bInt = 0;
     418        1608 :     memcpy(&bInt, &B, 4);
     419             : 
     420        1608 :     if (bInt < 0)
     421          10 :         bInt = INT_MIN - bInt;
     422             : #ifdef COMPAT_WITH_ICC_CONVERSION_CHECK
     423             :     const int intDiff =
     424             :         abs(static_cast<int>(static_cast<GUIntBig>(static_cast<GIntBig>(aInt) -
     425             :                                                    static_cast<GIntBig>(bInt)) &
     426             :                              0xFFFFFFFFU));
     427             : #else
     428             :     // To make -ftrapv happy we compute the diff on larger type and
     429             :     // cast down later.
     430        1608 :     const int intDiff = abs(static_cast<int>(static_cast<GIntBig>(aInt) -
     431             :                                              static_cast<GIntBig>(bInt)));
     432             : #endif
     433        1608 :     if (intDiff <= maxUlps)
     434         270 :         return true;
     435        1338 :     return false;
     436             : }
     437             : 
     438             : /************************************************************************/
     439             : /*                           GDALPolygonize()                           */
     440             : /************************************************************************/
     441             : 
     442             : /**
     443             :  * Create polygon coverage from raster data.
     444             :  *
     445             :  * This function creates vector polygons for all connected regions of pixels in
     446             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     447             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     448             :  * can be provided to determine which pixels are eligible for processing.
     449             :  *
     450             :  * Note that currently the source pixel band values are read into a
     451             :  * signed 64bit integer buffer (Int64), so floating point or complex
     452             :  * bands will be implicitly truncated before processing. If you want to use a
     453             :  * version using 32bit float buffers, see GDALFPolygonize().
     454             :  *
     455             :  * Polygon features will be created on the output layer, with polygon
     456             :  * geometries representing the polygons.  The polygon geometries will be
     457             :  * in the georeferenced coordinate system of the image (based on the
     458             :  * geotransform of the source dataset).  It is acceptable for the output
     459             :  * layer to already have features.  Note that GDALPolygonize() does not
     460             :  * set the coordinate system on the output layer.  Application code should
     461             :  * do this when the layer is created, presumably matching the raster
     462             :  * coordinate system.
     463             :  *
     464             :  * The algorithm used attempts to minimize memory use so that very large
     465             :  * rasters can be processed.  However, if the raster has many polygons
     466             :  * or very large/complex polygons, the memory use for holding polygon
     467             :  * enumerations and active polygon geometries may grow to be quite large.
     468             :  *
     469             :  * The algorithm will generally produce very dense polygon geometries, with
     470             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     471             :  * For non-thematic raster data (such as satellite images) the result will
     472             :  * essentially be one small polygon per pixel, and memory and output layer
     473             :  * sizes will be substantial.  The algorithm is primarily intended for
     474             :  * relatively simple thematic imagery, masks, and classification results.
     475             :  *
     476             :  * @param hSrcBand the source raster band to be processed.
     477             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     478             :  * value other than zero will be considered suitable for collection as
     479             :  * polygons.
     480             :  * @param hOutLayer the vector feature layer to which the polygons should
     481             :  * be written.
     482             :  * @param iPixValField the attribute field index indicating the feature
     483             :  * attribute into which the pixel value of the polygon should be written. Or
     484             :  * -1 to indicate that the pixel value must not be written.
     485             :  * @param papszOptions a name/value list of additional options
     486             :  * <ul>
     487             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     488             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     489             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     490             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     491             :  * typical for mask bands.</li>
     492             :  * </ul>
     493             :  * @param pfnProgress callback for reporting algorithm progress matching the
     494             :  * GDALProgressFunc() semantics.  May be NULL.
     495             :  * @param pProgressArg callback argument passed to pfnProgress.
     496             :  *
     497             :  * @return CE_None on success or CE_Failure on a failure.
     498             :  */
     499             : 
     500          88 : CPLErr CPL_STDCALL GDALPolygonize(GDALRasterBandH hSrcBand,
     501             :                                   GDALRasterBandH hMaskBand,
     502             :                                   OGRLayerH hOutLayer, int iPixValField,
     503             :                                   char **papszOptions,
     504             :                                   GDALProgressFunc pfnProgress,
     505             :                                   void *pProgressArg)
     506             : 
     507             : {
     508          88 :     return GDALPolygonizeT<std::int64_t, IntEqualityTest>(
     509             :         hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
     510          88 :         pProgressArg, GDT_Int64);
     511             : }
     512             : 
     513             : /************************************************************************/
     514             : /*                           GDALFPolygonize()                           */
     515             : /************************************************************************/
     516             : 
     517             : /**
     518             :  * Create polygon coverage from raster data.
     519             :  *
     520             :  * This function creates vector polygons for all connected regions of pixels in
     521             :  * the raster sharing a common pixel value.  Optionally each polygon may be
     522             :  * labeled with the pixel value in an attribute.  Optionally a mask band
     523             :  * can be provided to determine which pixels are eligible for processing.
     524             :  *
     525             :  * The source pixel band values are read into a 32bit float buffer. If you want
     526             :  * to use a (probably faster) version using signed 32bit integer buffer, see
     527             :  * GDALPolygonize().
     528             :  *
     529             :  * Polygon features will be created on the output layer, with polygon
     530             :  * geometries representing the polygons.  The polygon geometries will be
     531             :  * in the georeferenced coordinate system of the image (based on the
     532             :  * geotransform of the source dataset).  It is acceptable for the output
     533             :  * layer to already have features.  Note that GDALFPolygonize() does not
     534             :  * set the coordinate system on the output layer.  Application code should
     535             :  * do this when the layer is created, presumably matching the raster
     536             :  * coordinate system.
     537             :  *
     538             :  * The algorithm used attempts to minimize memory use so that very large
     539             :  * rasters can be processed.  However, if the raster has many polygons
     540             :  * or very large/complex polygons, the memory use for holding polygon
     541             :  * enumerations and active polygon geometries may grow to be quite large.
     542             :  *
     543             :  * The algorithm will generally produce very dense polygon geometries, with
     544             :  * edges that follow exactly on pixel boundaries for all non-interior pixels.
     545             :  * For non-thematic raster data (such as satellite images) the result will
     546             :  * essentially be one small polygon per pixel, and memory and output layer
     547             :  * sizes will be substantial.  The algorithm is primarily intended for
     548             :  * relatively simple thematic imagery, masks, and classification results.
     549             :  *
     550             :  * @param hSrcBand the source raster band to be processed.
     551             :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a
     552             :  * value other than zero will be considered suitable for collection as
     553             :  * polygons.
     554             :  * @param hOutLayer the vector feature layer to which the polygons should
     555             :  * be written.
     556             :  * @param iPixValField the attribute field index indicating the feature
     557             :  * attribute into which the pixel value of the polygon should be written. Or
     558             :  * -1 to indicate that the pixel value must not be written.
     559             :  * @param papszOptions a name/value list of additional options
     560             :  * <ul>
     561             :  * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
     562             :  * Otherwise 4 connectedness will be applied to the algorithm</li>
     563             :  * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
     564             :  * the geotransform. This useful if hSrcBand has no related dataset, which is
     565             :  * typical for mask bands.</li>
     566             :  * </ul>
     567             :  * @param pfnProgress callback for reporting algorithm progress matching the
     568             :  * GDALProgressFunc() semantics.  May be NULL.
     569             :  * @param pProgressArg callback argument passed to pfnProgress.
     570             :  *
     571             :  * @return CE_None on success or CE_Failure on a failure.
     572             :  *
     573             :  * @since GDAL 1.9.0
     574             :  */
     575             : 
     576           2 : CPLErr CPL_STDCALL GDALFPolygonize(GDALRasterBandH hSrcBand,
     577             :                                    GDALRasterBandH hMaskBand,
     578             :                                    OGRLayerH hOutLayer, int iPixValField,
     579             :                                    char **papszOptions,
     580             :                                    GDALProgressFunc pfnProgress,
     581             :                                    void *pProgressArg)
     582             : 
     583             : {
     584           2 :     return GDALPolygonizeT<float, FloatEqualityTest>(
     585             :         hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
     586           2 :         pProgressArg, GDT_Float32);
     587             : }

Generated by: LCOV version 1.14