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 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "cpl_port.h"
30 : #include "gdal_alg.h"
31 :
32 : #include <stddef.h>
33 : #include <stdio.h>
34 : #include <cstdlib>
35 : #include <string.h>
36 :
37 : #include <algorithm>
38 : #include <limits>
39 : #include <map>
40 : #include <memory>
41 : #include <utility>
42 : #include <vector>
43 :
44 : #include "gdal_alg_priv.h"
45 : #include "gdal.h"
46 : #include "ogr_api.h"
47 : #include "ogr_core.h"
48 : #include "cpl_conv.h"
49 : #include "cpl_error.h"
50 : #include "cpl_progress.h"
51 : #include "cpl_string.h"
52 : #include "cpl_vsi.h"
53 :
54 : #include "polygonize_polygonizer.h"
55 :
56 : using namespace gdal::polygonizer;
57 :
58 : /************************************************************************/
59 : /* GPMaskImageData() */
60 : /* */
61 : /* Mask out image pixels to a special nodata value if the mask */
62 : /* band is zero. */
63 : /************************************************************************/
64 :
65 : template <class DataType>
66 2720 : static CPLErr GPMaskImageData(GDALRasterBandH hMaskBand, GByte *pabyMaskLine,
67 : int iY, int nXSize, DataType *panImageLine)
68 :
69 : {
70 2720 : const CPLErr eErr = GDALRasterIO(hMaskBand, GF_Read, 0, iY, nXSize, 1,
71 : pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0);
72 2720 : if (eErr != CE_None)
73 0 : return eErr;
74 :
75 840682 : for (int i = 0; i < nXSize; i++)
76 : {
77 837962 : if (pabyMaskLine[i] == 0)
78 105692 : panImageLine[i] = GP_NODATA_MARKER;
79 : }
80 :
81 2720 : return CE_None;
82 : }
83 :
84 : /************************************************************************/
85 : /* GDALPolygonizeT() */
86 : /************************************************************************/
87 :
88 : template <class DataType, class EqualityTest>
89 52 : static CPLErr GDALPolygonizeT(GDALRasterBandH hSrcBand,
90 : GDALRasterBandH hMaskBand, OGRLayerH hOutLayer,
91 : int iPixValField, char **papszOptions,
92 : GDALProgressFunc pfnProgress, void *pProgressArg,
93 : GDALDataType eDT)
94 :
95 : {
96 52 : VALIDATE_POINTER1(hSrcBand, "GDALPolygonize", CE_Failure);
97 52 : VALIDATE_POINTER1(hOutLayer, "GDALPolygonize", CE_Failure);
98 :
99 52 : if (pfnProgress == nullptr)
100 15 : pfnProgress = GDALDummyProgress;
101 :
102 52 : const int nConnectedness =
103 52 : CSLFetchNameValue(papszOptions, "8CONNECTED") ? 8 : 4;
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Confirm our output layer will support feature creation. */
107 : /* -------------------------------------------------------------------- */
108 52 : if (!OGR_L_TestCapability(hOutLayer, OLCSequentialWrite))
109 : {
110 0 : CPLError(CE_Failure, CPLE_AppDefined,
111 : "Output feature layer does not appear to support creation "
112 : "of features in GDALPolygonize().");
113 0 : return CE_Failure;
114 : }
115 :
116 : /* -------------------------------------------------------------------- */
117 : /* Allocate working buffers. */
118 : /* -------------------------------------------------------------------- */
119 52 : const int nXSize = GDALGetRasterBandXSize(hSrcBand);
120 52 : const int nYSize = GDALGetRasterBandYSize(hSrcBand);
121 52 : if (nXSize > std::numeric_limits<int>::max() - 2)
122 : {
123 0 : CPLError(CE_Failure, CPLE_AppDefined, "Too wide raster");
124 0 : return CE_Failure;
125 : }
126 :
127 52 : DataType *panLastLineVal =
128 52 : static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
129 52 : DataType *panThisLineVal =
130 52 : static_cast<DataType *>(VSI_MALLOC2_VERBOSE(sizeof(DataType), nXSize));
131 52 : GInt32 *panLastLineId =
132 52 : static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
133 52 : GInt32 *panThisLineId =
134 52 : static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
135 :
136 52 : GByte *pabyMaskLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
137 :
138 52 : if (panLastLineVal == nullptr || panThisLineVal == nullptr ||
139 52 : panLastLineId == nullptr || panThisLineId == nullptr ||
140 : pabyMaskLine == nullptr)
141 : {
142 0 : CPLFree(panThisLineId);
143 0 : CPLFree(panLastLineId);
144 0 : CPLFree(panThisLineVal);
145 0 : CPLFree(panLastLineVal);
146 0 : CPLFree(pabyMaskLine);
147 0 : return CE_Failure;
148 : }
149 :
150 : /* -------------------------------------------------------------------- */
151 : /* Get the geotransform, if there is one, so we can convert the */
152 : /* vectors into georeferenced coordinates. */
153 : /* -------------------------------------------------------------------- */
154 52 : double adfGeoTransform[6] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
155 52 : bool bGotGeoTransform = false;
156 : const char *pszDatasetForGeoRef =
157 52 : CSLFetchNameValue(papszOptions, "DATASET_FOR_GEOREF");
158 52 : if (pszDatasetForGeoRef)
159 : {
160 2 : GDALDatasetH hSrcDS = GDALOpen(pszDatasetForGeoRef, GA_ReadOnly);
161 2 : if (hSrcDS)
162 : {
163 2 : bGotGeoTransform =
164 2 : GDALGetGeoTransform(hSrcDS, adfGeoTransform) == CE_None;
165 2 : GDALClose(hSrcDS);
166 : }
167 : }
168 : else
169 : {
170 50 : GDALDatasetH hSrcDS = GDALGetBandDataset(hSrcBand);
171 50 : if (hSrcDS)
172 20 : bGotGeoTransform =
173 20 : GDALGetGeoTransform(hSrcDS, adfGeoTransform) == CE_None;
174 : }
175 52 : if (!bGotGeoTransform)
176 : {
177 30 : adfGeoTransform[0] = 0;
178 30 : adfGeoTransform[1] = 1;
179 30 : adfGeoTransform[2] = 0;
180 30 : adfGeoTransform[3] = 0;
181 30 : adfGeoTransform[4] = 0;
182 30 : adfGeoTransform[5] = 1;
183 : }
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* The first pass over the raster is only used to build up the */
187 : /* polygon id map so we will know in advance what polygons are */
188 : /* what on the second pass. */
189 : /* -------------------------------------------------------------------- */
190 104 : GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oFirstEnum(
191 : nConnectedness);
192 :
193 52 : CPLErr eErr = CE_None;
194 :
195 1490 : for (int iY = 0; eErr == CE_None && iY < nYSize; iY++)
196 : {
197 1438 : eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1, panThisLineVal,
198 : nXSize, 1, eDT, 0, 0);
199 :
200 1438 : if (eErr == CE_None && hMaskBand != nullptr)
201 1360 : eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
202 : panThisLineVal);
203 :
204 1438 : if (eErr != CE_None)
205 0 : break;
206 :
207 1438 : if (iY == 0)
208 52 : eErr = oFirstEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
209 : panThisLineId, nXSize)
210 52 : ? CE_None
211 : : CE_Failure;
212 : else
213 1386 : eErr = oFirstEnum.ProcessLine(panLastLineVal, panThisLineVal,
214 : panLastLineId, panThisLineId, nXSize)
215 1386 : ? CE_None
216 : : CE_Failure;
217 :
218 1438 : if (eErr != CE_None)
219 0 : break;
220 :
221 : // Swap lines.
222 1438 : std::swap(panLastLineVal, panThisLineVal);
223 1438 : std::swap(panLastLineId, panThisLineId);
224 :
225 : /* --------------------------------------------------------------------
226 : */
227 : /* Report progress, and support interrupts. */
228 : /* --------------------------------------------------------------------
229 : */
230 1438 : if (!pfnProgress(0.10 * ((iY + 1) / static_cast<double>(nYSize)), "",
231 : pProgressArg))
232 : {
233 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
234 0 : eErr = CE_Failure;
235 : }
236 : }
237 :
238 : /* -------------------------------------------------------------------- */
239 : /* Make a pass through the maps, ensuring every polygon id */
240 : /* points to the final id it should use, not an intermediate */
241 : /* value. */
242 : /* -------------------------------------------------------------------- */
243 52 : if (eErr == CE_None)
244 52 : oFirstEnum.CompleteMerges();
245 :
246 : /* -------------------------------------------------------------------- */
247 : /* We will use a new enumerator for the second pass primarily */
248 : /* so we can preserve the first pass map. */
249 : /* -------------------------------------------------------------------- */
250 104 : GDALRasterPolygonEnumeratorT<DataType, EqualityTest> oSecondEnum(
251 : nConnectedness);
252 :
253 104 : OGRPolygonWriter<DataType> oPolygonWriter{hOutLayer, iPixValField,
254 : adfGeoTransform};
255 52 : Polygonizer<GInt32, DataType> oPolygonizer{-1, &oPolygonWriter};
256 52 : TwoArm *paoLastLineArm =
257 52 : static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
258 52 : TwoArm *paoThisLineArm =
259 52 : static_cast<TwoArm *>(VSI_CALLOC_VERBOSE(sizeof(TwoArm), nXSize + 2));
260 :
261 52 : if (paoThisLineArm == nullptr || paoLastLineArm == nullptr)
262 : {
263 0 : eErr = CE_Failure;
264 : }
265 : else
266 : {
267 1252 : for (int i = 0; i < nXSize + 2; ++i)
268 : {
269 1200 : paoLastLineArm[i].poPolyInside = oPolygonizer.getTheOuterPolygon();
270 : }
271 : }
272 :
273 : /* ==================================================================== */
274 : /* Second pass during which we will actually collect polygon */
275 : /* edges as geometries. */
276 : /* ==================================================================== */
277 1542 : for (int iY = 0; eErr == CE_None && iY < nYSize + 1; iY++)
278 : {
279 : /* --------------------------------------------------------------------
280 : */
281 : /* Read the image data. */
282 : /* --------------------------------------------------------------------
283 : */
284 1490 : if (iY < nYSize)
285 : {
286 1438 : eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iY, nXSize, 1,
287 : panThisLineVal, nXSize, 1, eDT, 0, 0);
288 1438 : if (eErr == CE_None && hMaskBand != nullptr)
289 1360 : eErr = GPMaskImageData(hMaskBand, pabyMaskLine, iY, nXSize,
290 : panThisLineVal);
291 : }
292 :
293 1490 : if (eErr != CE_None)
294 0 : continue;
295 :
296 : /* --------------------------------------------------------------------
297 : */
298 : /* Determine what polygon the various pixels belong to (redoing */
299 : /* the same thing done in the first pass above). */
300 : /* --------------------------------------------------------------------
301 : */
302 1490 : if (iY == nYSize)
303 : {
304 1148 : for (int iX = 0; iX < nXSize; iX++)
305 1096 : panThisLineId[iX] =
306 : decltype(oPolygonizer)::THE_OUTER_POLYGON_ID;
307 : }
308 1438 : else if (iY == 0)
309 : {
310 52 : eErr = oSecondEnum.ProcessLine(nullptr, panThisLineVal, nullptr,
311 : panThisLineId, nXSize)
312 52 : ? CE_None
313 : : CE_Failure;
314 : }
315 : else
316 : {
317 1386 : eErr = oSecondEnum.ProcessLine(panLastLineVal, panThisLineVal,
318 : panLastLineId, panThisLineId, nXSize)
319 1386 : ? CE_None
320 : : CE_Failure;
321 : }
322 :
323 1490 : if (eErr != CE_None)
324 0 : continue;
325 :
326 1490 : if (iY < nYSize)
327 : {
328 422103 : for (int iX = 0; iX < nXSize; iX++)
329 : {
330 : // TODO: maybe we can reserve -1 as the lookup result for -1 polygon id in the panPolyIdMap,
331 : // so the this expression becomes: panLastLineId[iX] = *(oFirstEnum.panPolyIdMap + panThisLineId[iX]).
332 : // This would eliminate the condition checking.
333 420665 : panLastLineId[iX] =
334 420665 : panThisLineId[iX] == -1
335 420665 : ? -1
336 367819 : : oFirstEnum.panPolyIdMap[panThisLineId[iX]];
337 : }
338 :
339 1438 : oPolygonizer.processLine(panLastLineId, panLastLineVal,
340 : paoThisLineArm, paoLastLineArm, iY,
341 : nXSize);
342 1438 : eErr = oPolygonWriter.getErr();
343 : }
344 : else
345 : {
346 52 : oPolygonizer.processLine(panThisLineId, panLastLineVal,
347 : paoThisLineArm, paoLastLineArm, iY,
348 : nXSize);
349 52 : eErr = oPolygonWriter.getErr();
350 : }
351 :
352 1490 : if (eErr != CE_None)
353 0 : continue;
354 :
355 : /* --------------------------------------------------------------------
356 : */
357 : /* Swap pixel value, and polygon id lines to be ready for the */
358 : /* next line. */
359 : /* --------------------------------------------------------------------
360 : */
361 1490 : std::swap(panLastLineVal, panThisLineVal);
362 1490 : std::swap(panLastLineId, panThisLineId);
363 1490 : std::swap(paoThisLineArm, paoLastLineArm);
364 :
365 : /* --------------------------------------------------------------------
366 : */
367 : /* Report progress, and support interrupts. */
368 : /* --------------------------------------------------------------------
369 : */
370 1490 : if (!pfnProgress(0.10 + 0.90 * ((iY + 1) / static_cast<double>(nYSize)),
371 : "", pProgressArg))
372 : {
373 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
374 0 : eErr = CE_Failure;
375 : }
376 : }
377 :
378 : /* -------------------------------------------------------------------- */
379 : /* Cleanup */
380 : /* -------------------------------------------------------------------- */
381 52 : CPLFree(panThisLineId);
382 52 : CPLFree(panLastLineId);
383 52 : CPLFree(panThisLineVal);
384 52 : CPLFree(panLastLineVal);
385 52 : CPLFree(paoThisLineArm);
386 52 : CPLFree(paoLastLineArm);
387 52 : CPLFree(pabyMaskLine);
388 :
389 52 : return eErr;
390 : }
391 :
392 : /******************************************************************************/
393 : /* GDALFloatEquals() */
394 : /* Code from: */
395 : /* http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm */
396 : /******************************************************************************/
397 88 : GBool GDALFloatEquals(float A, float B)
398 : {
399 : // This function will allow maxUlps-1 floats between A and B.
400 88 : const int maxUlps = MAX_ULPS;
401 :
402 : // Make sure maxUlps is non-negative and small enough that the default NAN
403 : // won't compare as equal to anything.
404 : #if MAX_ULPS <= 0 || MAX_ULPS >= 4 * 1024 * 1024
405 : #error "Invalid MAX_ULPS"
406 : #endif
407 :
408 : // This assignation could violate strict aliasing. It causes a warning with
409 : // gcc -O2. Use of memcpy preferred. Credits for Even Rouault. Further info
410 : // at http://trac.osgeo.org/gdal/ticket/4005#comment:6
411 88 : int aInt = 0;
412 88 : memcpy(&aInt, &A, 4);
413 :
414 : // Make aInt lexicographically ordered as a twos-complement int.
415 88 : if (aInt < 0)
416 10 : aInt = INT_MIN - aInt;
417 :
418 : // Make bInt lexicographically ordered as a twos-complement int.
419 88 : int bInt = 0;
420 88 : memcpy(&bInt, &B, 4);
421 :
422 88 : if (bInt < 0)
423 10 : bInt = INT_MIN - bInt;
424 : #ifdef COMPAT_WITH_ICC_CONVERSION_CHECK
425 : const int intDiff =
426 : abs(static_cast<int>(static_cast<GUIntBig>(static_cast<GIntBig>(aInt) -
427 : static_cast<GIntBig>(bInt)) &
428 : 0xFFFFFFFFU));
429 : #else
430 : // To make -ftrapv happy we compute the diff on larger type and
431 : // cast down later.
432 88 : const int intDiff = abs(static_cast<int>(static_cast<GIntBig>(aInt) -
433 : static_cast<GIntBig>(bInt)));
434 : #endif
435 88 : if (intDiff <= maxUlps)
436 30 : return true;
437 58 : return false;
438 : }
439 :
440 : /************************************************************************/
441 : /* GDALPolygonize() */
442 : /************************************************************************/
443 :
444 : /**
445 : * Create polygon coverage from raster data.
446 : *
447 : * This function creates vector polygons for all connected regions of pixels in
448 : * the raster sharing a common pixel value. Optionally each polygon may be
449 : * labeled with the pixel value in an attribute. Optionally a mask band
450 : * can be provided to determine which pixels are eligible for processing.
451 : *
452 : * Note that currently the source pixel band values are read into a
453 : * signed 64bit integer buffer (Int64), so floating point or complex
454 : * bands will be implicitly truncated before processing. If you want to use a
455 : * version using 32bit float buffers, see GDALFPolygonize().
456 : *
457 : * Polygon features will be created on the output layer, with polygon
458 : * geometries representing the polygons. The polygon geometries will be
459 : * in the georeferenced coordinate system of the image (based on the
460 : * geotransform of the source dataset). It is acceptable for the output
461 : * layer to already have features. Note that GDALPolygonize() does not
462 : * set the coordinate system on the output layer. Application code should
463 : * do this when the layer is created, presumably matching the raster
464 : * coordinate system.
465 : *
466 : * The algorithm used attempts to minimize memory use so that very large
467 : * rasters can be processed. However, if the raster has many polygons
468 : * or very large/complex polygons, the memory use for holding polygon
469 : * enumerations and active polygon geometries may grow to be quite large.
470 : *
471 : * The algorithm will generally produce very dense polygon geometries, with
472 : * edges that follow exactly on pixel boundaries for all non-interior pixels.
473 : * For non-thematic raster data (such as satellite images) the result will
474 : * essentially be one small polygon per pixel, and memory and output layer
475 : * sizes will be substantial. The algorithm is primarily intended for
476 : * relatively simple thematic imagery, masks, and classification results.
477 : *
478 : * @param hSrcBand the source raster band to be processed.
479 : * @param hMaskBand an optional mask band. All pixels in the mask band with a
480 : * value other than zero will be considered suitable for collection as
481 : * polygons.
482 : * @param hOutLayer the vector feature layer to which the polygons should
483 : * be written.
484 : * @param iPixValField the attribute field index indicating the feature
485 : * attribute into which the pixel value of the polygon should be written. Or
486 : * -1 to indicate that the pixel value must not be written.
487 : * @param papszOptions a name/value list of additional options
488 : * <ul>
489 : * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
490 : * Otherwise 4 connectedness will be applied to the algorithm</li>
491 : * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
492 : * the geotransform. This useful if hSrcBand has no related dataset, which is
493 : * typical for mask bands.</li>
494 : * </ul>
495 : * @param pfnProgress callback for reporting algorithm progress matching the
496 : * GDALProgressFunc() semantics. May be NULL.
497 : * @param pProgressArg callback argument passed to pfnProgress.
498 : *
499 : * @return CE_None on success or CE_Failure on a failure.
500 : */
501 :
502 51 : CPLErr CPL_STDCALL GDALPolygonize(GDALRasterBandH hSrcBand,
503 : GDALRasterBandH hMaskBand,
504 : OGRLayerH hOutLayer, int iPixValField,
505 : char **papszOptions,
506 : GDALProgressFunc pfnProgress,
507 : void *pProgressArg)
508 :
509 : {
510 51 : return GDALPolygonizeT<std::int64_t, IntEqualityTest>(
511 : hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
512 51 : pProgressArg, GDT_Int64);
513 : }
514 :
515 : /************************************************************************/
516 : /* GDALFPolygonize() */
517 : /************************************************************************/
518 :
519 : /**
520 : * Create polygon coverage from raster data.
521 : *
522 : * This function creates vector polygons for all connected regions of pixels in
523 : * the raster sharing a common pixel value. Optionally each polygon may be
524 : * labeled with the pixel value in an attribute. Optionally a mask band
525 : * can be provided to determine which pixels are eligible for processing.
526 : *
527 : * The source pixel band values are read into a 32bit float buffer. If you want
528 : * to use a (probably faster) version using signed 32bit integer buffer, see
529 : * GDALPolygonize().
530 : *
531 : * Polygon features will be created on the output layer, with polygon
532 : * geometries representing the polygons. The polygon geometries will be
533 : * in the georeferenced coordinate system of the image (based on the
534 : * geotransform of the source dataset). It is acceptable for the output
535 : * layer to already have features. Note that GDALFPolygonize() does not
536 : * set the coordinate system on the output layer. Application code should
537 : * do this when the layer is created, presumably matching the raster
538 : * coordinate system.
539 : *
540 : * The algorithm used attempts to minimize memory use so that very large
541 : * rasters can be processed. However, if the raster has many polygons
542 : * or very large/complex polygons, the memory use for holding polygon
543 : * enumerations and active polygon geometries may grow to be quite large.
544 : *
545 : * The algorithm will generally produce very dense polygon geometries, with
546 : * edges that follow exactly on pixel boundaries for all non-interior pixels.
547 : * For non-thematic raster data (such as satellite images) the result will
548 : * essentially be one small polygon per pixel, and memory and output layer
549 : * sizes will be substantial. The algorithm is primarily intended for
550 : * relatively simple thematic imagery, masks, and classification results.
551 : *
552 : * @param hSrcBand the source raster band to be processed.
553 : * @param hMaskBand an optional mask band. All pixels in the mask band with a
554 : * value other than zero will be considered suitable for collection as
555 : * polygons.
556 : * @param hOutLayer the vector feature layer to which the polygons should
557 : * be written.
558 : * @param iPixValField the attribute field index indicating the feature
559 : * attribute into which the pixel value of the polygon should be written. Or
560 : * -1 to indicate that the pixel value must not be written.
561 : * @param papszOptions a name/value list of additional options
562 : * <ul>
563 : * <li>8CONNECTED=8: May be set to "8" to use 8 connectedness.
564 : * Otherwise 4 connectedness will be applied to the algorithm</li>
565 : * <li>DATASET_FOR_GEOREF=dataset_name: Name of a dataset from which to read
566 : * the geotransform. This useful if hSrcBand has no related dataset, which is
567 : * typical for mask bands.</li>
568 : * </ul>
569 : * @param pfnProgress callback for reporting algorithm progress matching the
570 : * GDALProgressFunc() semantics. May be NULL.
571 : * @param pProgressArg callback argument passed to pfnProgress.
572 : *
573 : * @return CE_None on success or CE_Failure on a failure.
574 : *
575 : * @since GDAL 1.9.0
576 : */
577 :
578 1 : CPLErr CPL_STDCALL GDALFPolygonize(GDALRasterBandH hSrcBand,
579 : GDALRasterBandH hMaskBand,
580 : OGRLayerH hOutLayer, int iPixValField,
581 : char **papszOptions,
582 : GDALProgressFunc pfnProgress,
583 : void *pProgressArg)
584 :
585 : {
586 1 : return GDALPolygonizeT<float, FloatEqualityTest>(
587 : hSrcBand, hMaskBand, hOutLayer, iPixValField, papszOptions, pfnProgress,
588 1 : pProgressArg, GDT_Float32);
589 : }
|