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

Generated by: LCOV version 1.14