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 : }
|