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