Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Utilities
4 : * Purpose: Rasterize OGR shapes into a GDAL raster.
5 : * Author: Frank Warmerdam <warmerdam@pobox.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2005, Frank Warmerdam <warmerdam@pobox.com>
9 : * Copyright (c) 2008-2015, Even Rouault <even dot rouault at spatialys dot com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "gdal_utils.h"
16 : #include "gdal_utils_priv.h"
17 :
18 : #include <cinttypes>
19 : #include <cmath>
20 : #include <cstdio>
21 : #include <cstdlib>
22 : #include <cstring>
23 : #include <algorithm>
24 : #include <limits>
25 : #include <vector>
26 :
27 : #include "commonutils.h"
28 : #include "cpl_conv.h"
29 : #include "cpl_error.h"
30 : #include "cpl_progress.h"
31 : #include "cpl_string.h"
32 : #include "gdal.h"
33 : #include "gdal_alg.h"
34 : #include "gdal_priv.h"
35 : #include "ogr_api.h"
36 : #include "ogr_core.h"
37 : #include "ogr_srs_api.h"
38 : #include "gdalargumentparser.h"
39 :
40 : /************************************************************************/
41 : /* GDALRasterizeOptions() */
42 : /************************************************************************/
43 :
44 : struct GDALRasterizeOptions
45 : {
46 : std::vector<int> anBandList{};
47 : std::vector<double> adfBurnValues{};
48 : bool bInverse = false;
49 : std::string osFormat{};
50 : bool b3D = false;
51 : GDALProgressFunc pfnProgress = GDALDummyProgress;
52 : void *pProgressData = nullptr;
53 : std::vector<std::string> aosLayers{};
54 : std::string osSQL{};
55 : std::string osDialect{};
56 : std::string osBurnAttribute{};
57 : std::string osWHERE{};
58 : CPLStringList aosRasterizeOptions{};
59 : CPLStringList aosTO{};
60 : double dfXRes = 0;
61 : double dfYRes = 0;
62 : CPLStringList aosCreationOptions{};
63 : GDALDataType eOutputType = GDT_Unknown;
64 : std::vector<double> adfInitVals{};
65 : std::string osNoData{};
66 : OGREnvelope sEnvelop{};
67 : int nXSize = 0;
68 : int nYSize = 0;
69 : OGRSpatialReference oOutputSRS{};
70 :
71 : bool bTargetAlignedPixels = false;
72 : bool bCreateOutput = false;
73 : };
74 :
75 : /************************************************************************/
76 : /* GDALRasterizeOptionsGetParser() */
77 : /************************************************************************/
78 :
79 : static std::unique_ptr<GDALArgumentParser>
80 74 : GDALRasterizeOptionsGetParser(GDALRasterizeOptions *psOptions,
81 : GDALRasterizeOptionsForBinary *psOptionsForBinary)
82 : {
83 : auto argParser = std::make_unique<GDALArgumentParser>(
84 74 : "gdal_rasterize", /* bForBinary=*/psOptionsForBinary != nullptr);
85 :
86 74 : argParser->add_description(_("Burns vector geometries into a raster."));
87 :
88 74 : argParser->add_epilog(
89 : _("This program burns vector geometries (points, lines, and polygons) "
90 74 : "into the raster band(s) of a raster image."));
91 :
92 : // Dealt manually as argparse::nargs_pattern::at_least_one is problematic
93 74 : argParser->add_argument("-b")
94 148 : .metavar("<band>")
95 74 : .append()
96 74 : .scan<'i', int>()
97 : //.nargs(argparse::nargs_pattern::at_least_one)
98 74 : .help(_("The band(s) to burn values into."));
99 :
100 74 : argParser->add_argument("-i")
101 74 : .flag()
102 74 : .store_into(psOptions->bInverse)
103 74 : .help(_("Invert rasterization."));
104 :
105 74 : argParser->add_argument("-at")
106 74 : .flag()
107 : .action(
108 32 : [psOptions](const std::string &)
109 : {
110 : psOptions->aosRasterizeOptions.SetNameValue("ALL_TOUCHED",
111 32 : "TRUE");
112 74 : })
113 74 : .help(_("Enables the ALL_TOUCHED rasterization option."));
114 :
115 : // Mutually exclusive options: -burn, -3d, -a
116 : {
117 : // Required if options for binary
118 74 : auto &group = argParser->add_mutually_exclusive_group(
119 74 : psOptionsForBinary != nullptr);
120 :
121 : // Dealt manually as argparse::nargs_pattern::at_least_one is problematic
122 74 : group.add_argument("-burn")
123 148 : .metavar("<value>")
124 74 : .scan<'g', double>()
125 74 : .append()
126 : //.nargs(argparse::nargs_pattern::at_least_one)
127 74 : .help(_("A fixed value to burn into the raster band(s)."));
128 :
129 74 : group.add_argument("-a")
130 148 : .metavar("<attribute_name>")
131 74 : .store_into(psOptions->osBurnAttribute)
132 : .help(_("Name of the field in the input layer to get the burn "
133 74 : "values from."));
134 :
135 74 : group.add_argument("-3d")
136 74 : .flag()
137 74 : .store_into(psOptions->b3D)
138 : .action(
139 5 : [psOptions](const std::string &)
140 : {
141 : psOptions->aosRasterizeOptions.SetNameValue(
142 5 : "BURN_VALUE_FROM", "Z");
143 74 : })
144 : .help(_("Indicates that a burn value should be extracted from the "
145 74 : "\"Z\" values of the feature."));
146 : }
147 :
148 74 : argParser->add_argument("-add")
149 74 : .flag()
150 : .action(
151 1 : [psOptions](const std::string &)
152 : {
153 1 : psOptions->aosRasterizeOptions.SetNameValue("MERGE_ALG", "ADD");
154 74 : })
155 : .help(_("Instead of burning a new value, this adds the new value to "
156 74 : "the existing raster."));
157 :
158 : // Undocumented
159 74 : argParser->add_argument("-chunkysize")
160 74 : .flag()
161 74 : .hidden()
162 : .action(
163 0 : [psOptions](const std::string &s)
164 : {
165 : psOptions->aosRasterizeOptions.SetNameValue("CHUNKYSIZE",
166 0 : s.c_str());
167 74 : });
168 :
169 : // Mutually exclusive -l, -sql
170 : {
171 74 : auto &group = argParser->add_mutually_exclusive_group(false);
172 :
173 74 : group.add_argument("-l")
174 148 : .metavar("<layer_name>")
175 74 : .append()
176 74 : .store_into(psOptions->aosLayers)
177 74 : .help(_("Name of the layer(s) to process."));
178 :
179 74 : group.add_argument("-sql")
180 148 : .metavar("<sql_statement>")
181 74 : .store_into(psOptions->osSQL)
182 : .action(
183 10 : [psOptions](const std::string &sql)
184 : {
185 9 : GByte *pabyRet = nullptr;
186 10 : if (!sql.empty() && sql.at(0) == '@' &&
187 10 : VSIIngestFile(nullptr, sql.substr(1).c_str(), &pabyRet,
188 : nullptr, 10 * 1024 * 1024))
189 : {
190 1 : GDALRemoveBOM(pabyRet);
191 1 : char *pszSQLStatement =
192 : reinterpret_cast<char *>(pabyRet);
193 : psOptions->osSQL =
194 1 : CPLRemoveSQLComments(pszSQLStatement);
195 1 : VSIFree(pszSQLStatement);
196 : }
197 83 : })
198 : .help(
199 : _("An SQL statement to be evaluated against the datasource to "
200 74 : "produce a virtual layer of features to be burned in."));
201 : }
202 :
203 74 : argParser->add_argument("-where")
204 148 : .metavar("<expression>")
205 74 : .store_into(psOptions->osWHERE)
206 : .help(_("An optional SQL WHERE style query expression to be applied to "
207 : "select features "
208 74 : "to burn in from the input layer(s)."));
209 :
210 74 : argParser->add_argument("-dialect")
211 148 : .metavar("<sql_dialect>")
212 74 : .store_into(psOptions->osDialect)
213 74 : .help(_("The SQL dialect to use for the SQL expression."));
214 :
215 : // Store later
216 74 : argParser->add_argument("-a_nodata")
217 148 : .metavar("<value>")
218 74 : .help(_("Assign a specified nodata value to output bands."));
219 :
220 : // Dealt manually as argparse::nargs_pattern::at_least_one is problematic
221 74 : argParser->add_argument("-init")
222 148 : .metavar("<value>")
223 74 : .append()
224 : //.nargs(argparse::nargs_pattern::at_least_one)
225 74 : .scan<'g', double>()
226 74 : .help(_("Initialize the output bands to the specified value."));
227 :
228 74 : argParser->add_argument("-a_srs")
229 148 : .metavar("<srs_def>")
230 : .action(
231 4 : [psOptions](const std::string &osOutputSRSDef)
232 : {
233 2 : if (psOptions->oOutputSRS.SetFromUserInput(
234 2 : osOutputSRSDef.c_str()) != OGRERR_NONE)
235 : {
236 : throw std::invalid_argument(
237 0 : std::string("Failed to process SRS definition: ")
238 0 : .append(osOutputSRSDef));
239 : }
240 2 : psOptions->bCreateOutput = true;
241 76 : })
242 74 : .help(_("The spatial reference system to use for the output raster."));
243 :
244 74 : argParser->add_argument("-to")
245 148 : .metavar("<NAME>=<VALUE>")
246 74 : .append()
247 1 : .action([psOptions](const std::string &s)
248 75 : { psOptions->aosTO.AddString(s.c_str()); })
249 74 : .help(_("Set a transformer option."));
250 :
251 : // Store later
252 74 : argParser->add_argument("-te")
253 148 : .metavar("<xmin> <ymin> <xmax> <ymax>")
254 74 : .nargs(4)
255 74 : .scan<'g', double>()
256 74 : .help(_("Set georeferenced extents of output file to be created."));
257 :
258 : // Mutex with tr
259 : {
260 74 : auto &group = argParser->add_mutually_exclusive_group(false);
261 :
262 : // Store later
263 74 : group.add_argument("-tr")
264 148 : .metavar("<xres> <yres>")
265 74 : .nargs(2)
266 74 : .scan<'g', double>()
267 : .help(
268 74 : _("Set output file resolution in target georeferenced units."));
269 :
270 : // Store later
271 : // Note: this is supposed to be int but for backward compatibility, we
272 : // use double
273 74 : auto &arg = group.add_argument("-ts")
274 148 : .metavar("<width> <height>")
275 74 : .nargs(2)
276 74 : .scan<'g', double>()
277 74 : .help(_("Set output file size in pixels and lines."));
278 :
279 74 : argParser->add_hidden_alias_for(arg, "-outsize");
280 : }
281 :
282 74 : argParser->add_argument("-tap")
283 74 : .flag()
284 74 : .store_into(psOptions->bTargetAlignedPixels)
285 1 : .action([psOptions](const std::string &)
286 74 : { psOptions->bCreateOutput = true; })
287 : .help(_("Align the coordinates of the extent to the values of the "
288 74 : "output raster."));
289 :
290 74 : argParser->add_argument("-optim")
291 148 : .metavar("AUTO|VECTOR|RASTER")
292 : .action(
293 43 : [psOptions](const std::string &s)
294 : {
295 43 : psOptions->aosRasterizeOptions.SetNameValue("OPTIM", s.c_str());
296 74 : })
297 74 : .help(_("Force the algorithm used."));
298 :
299 74 : argParser->add_creation_options_argument(psOptions->aosCreationOptions)
300 2 : .action([psOptions](const std::string &)
301 74 : { psOptions->bCreateOutput = true; });
302 :
303 74 : argParser->add_output_type_argument(psOptions->eOutputType)
304 3 : .action([psOptions](const std::string &)
305 74 : { psOptions->bCreateOutput = true; });
306 :
307 74 : argParser->add_output_format_argument(psOptions->osFormat)
308 14 : .action([psOptions](const std::string &)
309 74 : { psOptions->bCreateOutput = true; });
310 :
311 : // Written that way so that in library mode, users can still use the -q
312 : // switch, even if it has no effect
313 : argParser->add_quiet_argument(
314 74 : psOptionsForBinary ? &(psOptionsForBinary->bQuiet) : nullptr);
315 :
316 74 : if (psOptionsForBinary)
317 : {
318 :
319 : argParser->add_open_options_argument(
320 11 : psOptionsForBinary->aosOpenOptions);
321 :
322 11 : argParser->add_argument("src_datasource")
323 22 : .metavar("<src_datasource>")
324 11 : .store_into(psOptionsForBinary->osSource)
325 11 : .help(_("Any vector supported readable datasource."));
326 :
327 11 : argParser->add_argument("dst_filename")
328 22 : .metavar("<dst_filename>")
329 11 : .store_into(psOptionsForBinary->osDest)
330 11 : .help(_("The GDAL raster supported output file."));
331 : }
332 :
333 74 : return argParser;
334 : }
335 :
336 : /************************************************************************/
337 : /* GDALRasterizeAppGetParserUsage() */
338 : /************************************************************************/
339 :
340 0 : std::string GDALRasterizeAppGetParserUsage()
341 : {
342 : try
343 : {
344 0 : GDALRasterizeOptions sOptions;
345 0 : GDALRasterizeOptionsForBinary sOptionsForBinary;
346 : auto argParser =
347 0 : GDALRasterizeOptionsGetParser(&sOptions, &sOptionsForBinary);
348 0 : return argParser->usage();
349 : }
350 0 : catch (const std::exception &err)
351 : {
352 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception: %s",
353 0 : err.what());
354 0 : return std::string();
355 : }
356 : }
357 :
358 : /************************************************************************/
359 : /* InvertGeometries() */
360 : /************************************************************************/
361 :
362 3 : static void InvertGeometries(GDALDatasetH hDstDS,
363 : std::vector<OGRGeometryH> &ahGeometries)
364 :
365 : {
366 3 : OGRMultiPolygon *poInvertMP = new OGRMultiPolygon();
367 :
368 : /* -------------------------------------------------------------------- */
369 : /* Create a ring that is a bit outside the raster dataset. */
370 : /* -------------------------------------------------------------------- */
371 3 : const int brx = GDALGetRasterXSize(hDstDS) + 2;
372 3 : const int bry = GDALGetRasterYSize(hDstDS) + 2;
373 :
374 3 : double adfGeoTransform[6] = {};
375 3 : GDALGetGeoTransform(hDstDS, adfGeoTransform);
376 :
377 3 : auto poUniverseRing = std::make_unique<OGRLinearRing>();
378 :
379 3 : poUniverseRing->addPoint(
380 3 : adfGeoTransform[0] + -2 * adfGeoTransform[1] + -2 * adfGeoTransform[2],
381 3 : adfGeoTransform[3] + -2 * adfGeoTransform[4] + -2 * adfGeoTransform[5]);
382 :
383 3 : poUniverseRing->addPoint(adfGeoTransform[0] + brx * adfGeoTransform[1] +
384 3 : -2 * adfGeoTransform[2],
385 3 : adfGeoTransform[3] + brx * adfGeoTransform[4] +
386 3 : -2 * adfGeoTransform[5]);
387 :
388 3 : poUniverseRing->addPoint(adfGeoTransform[0] + brx * adfGeoTransform[1] +
389 3 : bry * adfGeoTransform[2],
390 3 : adfGeoTransform[3] + brx * adfGeoTransform[4] +
391 3 : bry * adfGeoTransform[5]);
392 :
393 3 : poUniverseRing->addPoint(adfGeoTransform[0] + -2 * adfGeoTransform[1] +
394 3 : bry * adfGeoTransform[2],
395 3 : adfGeoTransform[3] + -2 * adfGeoTransform[4] +
396 3 : bry * adfGeoTransform[5]);
397 :
398 3 : poUniverseRing->addPoint(
399 3 : adfGeoTransform[0] + -2 * adfGeoTransform[1] + -2 * adfGeoTransform[2],
400 3 : adfGeoTransform[3] + -2 * adfGeoTransform[4] + -2 * adfGeoTransform[5]);
401 :
402 3 : auto poUniversePoly = std::make_unique<OGRPolygon>();
403 3 : poUniversePoly->addRing(std::move(poUniverseRing));
404 3 : poInvertMP->addGeometry(std::move(poUniversePoly));
405 :
406 3 : bool bFoundNonPoly = false;
407 : // If we have GEOS, use it to "subtract" each polygon from the universe
408 : // multipolygon
409 3 : if (OGRGeometryFactory::haveGEOS())
410 : {
411 3 : OGRGeometry *poInvertMPAsGeom = poInvertMP;
412 3 : poInvertMP = nullptr;
413 3 : CPL_IGNORE_RET_VAL(poInvertMP);
414 10 : for (unsigned int iGeom = 0; iGeom < ahGeometries.size(); iGeom++)
415 : {
416 7 : auto poGeom = OGRGeometry::FromHandle(ahGeometries[iGeom]);
417 7 : const auto eGType = OGR_GT_Flatten(poGeom->getGeometryType());
418 7 : if (eGType != wkbPolygon && eGType != wkbMultiPolygon)
419 : {
420 1 : if (!bFoundNonPoly)
421 : {
422 1 : bFoundNonPoly = true;
423 1 : CPLError(CE_Warning, CPLE_AppDefined,
424 : "Ignoring non-polygon geometries in -i mode");
425 : }
426 : }
427 : else
428 : {
429 6 : auto poNewGeom = poInvertMPAsGeom->Difference(poGeom);
430 6 : if (poNewGeom)
431 : {
432 6 : delete poInvertMPAsGeom;
433 6 : poInvertMPAsGeom = poNewGeom;
434 : }
435 : }
436 :
437 7 : delete poGeom;
438 : }
439 :
440 3 : ahGeometries.resize(1);
441 3 : ahGeometries[0] = OGRGeometry::ToHandle(poInvertMPAsGeom);
442 3 : return;
443 : }
444 :
445 : OGRPolygon &hUniversePoly =
446 0 : *poInvertMP->getGeometryRef(poInvertMP->getNumGeometries() - 1);
447 :
448 : /* -------------------------------------------------------------------- */
449 : /* If we don't have GEOS, add outer rings of polygons as inner */
450 : /* rings of poUniversePoly and inner rings as sub-polygons. Note */
451 : /* that this only works properly if the polygons are disjoint, in */
452 : /* the sense that the outer ring of any polygon is not inside the */
453 : /* outer ring of another one. So the scenario of */
454 : /* https://github.com/OSGeo/gdal/issues/8689 with an "island" in */
455 : /* the middle of a hole will not work properly. */
456 : /* -------------------------------------------------------------------- */
457 0 : for (unsigned int iGeom = 0; iGeom < ahGeometries.size(); iGeom++)
458 : {
459 : const auto eGType =
460 0 : OGR_GT_Flatten(OGR_G_GetGeometryType(ahGeometries[iGeom]));
461 0 : if (eGType != wkbPolygon && eGType != wkbMultiPolygon)
462 : {
463 0 : if (!bFoundNonPoly)
464 : {
465 0 : bFoundNonPoly = true;
466 0 : CPLError(CE_Warning, CPLE_AppDefined,
467 : "Ignoring non-polygon geometries in -i mode");
468 : }
469 0 : OGR_G_DestroyGeometry(ahGeometries[iGeom]);
470 0 : continue;
471 : }
472 :
473 : const auto ProcessPoly =
474 0 : [&hUniversePoly, poInvertMP](OGRPolygon *poPoly)
475 : {
476 0 : for (int i = poPoly->getNumInteriorRings() - 1; i >= 0; --i)
477 : {
478 0 : auto poNewPoly = std::make_unique<OGRPolygon>();
479 : std::unique_ptr<OGRLinearRing> poRing(
480 0 : poPoly->stealInteriorRing(i));
481 0 : poNewPoly->addRing(std::move(poRing));
482 0 : poInvertMP->addGeometry(std::move(poNewPoly));
483 : }
484 0 : std::unique_ptr<OGRLinearRing> poShell(poPoly->stealExteriorRing());
485 0 : hUniversePoly.addRing(std::move(poShell));
486 0 : };
487 :
488 0 : if (eGType == wkbPolygon)
489 : {
490 : auto poPoly =
491 0 : OGRGeometry::FromHandle(ahGeometries[iGeom])->toPolygon();
492 0 : ProcessPoly(poPoly);
493 0 : delete poPoly;
494 : }
495 : else
496 : {
497 : auto poMulti =
498 0 : OGRGeometry::FromHandle(ahGeometries[iGeom])->toMultiPolygon();
499 0 : for (auto *poPoly : *poMulti)
500 : {
501 0 : ProcessPoly(poPoly);
502 : }
503 0 : delete poMulti;
504 : }
505 : }
506 :
507 0 : ahGeometries.resize(1);
508 0 : ahGeometries[0] = OGRGeometry::ToHandle(poInvertMP);
509 : }
510 :
511 : /************************************************************************/
512 : /* ProcessLayer() */
513 : /* */
514 : /* Process all the features in a layer selection, collecting */
515 : /* geometries and burn values. */
516 : /************************************************************************/
517 :
518 62 : static CPLErr ProcessLayer(OGRLayerH hSrcLayer, bool bSRSIsSet,
519 : GDALDataset *poDstDS,
520 : const std::vector<int> &anBandList,
521 : const std::vector<double> &adfBurnValues, bool b3D,
522 : bool bInverse, const std::string &osBurnAttribute,
523 : CSLConstList papszRasterizeOptions,
524 : CSLConstList papszTO, GDALProgressFunc pfnProgress,
525 : void *pProgressData)
526 :
527 : {
528 62 : GDALDatasetH hDstDS = GDALDataset::ToHandle(poDstDS);
529 :
530 : /* -------------------------------------------------------------------- */
531 : /* Checkout that SRS are the same. */
532 : /* If -a_srs is specified, skip the test */
533 : /* -------------------------------------------------------------------- */
534 62 : OGRCoordinateTransformationH hCT = nullptr;
535 62 : if (!bSRSIsSet)
536 : {
537 60 : OGRSpatialReferenceH hDstSRS = GDALGetSpatialRef(hDstDS);
538 :
539 60 : if (hDstSRS)
540 21 : hDstSRS = OSRClone(hDstSRS);
541 39 : else if (GDALGetMetadata(hDstDS, "RPC") != nullptr)
542 : {
543 2 : hDstSRS = OSRNewSpatialReference(nullptr);
544 2 : CPL_IGNORE_RET_VAL(
545 2 : OSRSetFromUserInput(hDstSRS, SRS_WKT_WGS84_LAT_LONG));
546 2 : OSRSetAxisMappingStrategy(hDstSRS, OAMS_TRADITIONAL_GIS_ORDER);
547 : }
548 :
549 60 : OGRSpatialReferenceH hSrcSRS = OGR_L_GetSpatialRef(hSrcLayer);
550 60 : if (hDstSRS != nullptr && hSrcSRS != nullptr)
551 : {
552 23 : if (OSRIsSame(hSrcSRS, hDstSRS) == FALSE)
553 : {
554 1 : hCT = OCTNewCoordinateTransformation(hSrcSRS, hDstSRS);
555 1 : if (hCT == nullptr)
556 : {
557 0 : CPLError(CE_Warning, CPLE_AppDefined,
558 : "The output raster dataset and the input vector "
559 : "layer do not have the same SRS.\n"
560 : "And reprojection of input data did not work. "
561 : "Results might be incorrect.");
562 : }
563 : }
564 : }
565 37 : else if (hDstSRS != nullptr && hSrcSRS == nullptr)
566 : {
567 0 : CPLError(CE_Warning, CPLE_AppDefined,
568 : "The output raster dataset has a SRS, but the input "
569 : "vector layer SRS is unknown.\n"
570 : "Ensure input vector has the same SRS, otherwise results "
571 : "might be incorrect.");
572 : }
573 37 : else if (hDstSRS == nullptr && hSrcSRS != nullptr)
574 : {
575 1 : CPLError(CE_Warning, CPLE_AppDefined,
576 : "The input vector layer has a SRS, but the output raster "
577 : "dataset SRS is unknown.\n"
578 : "Ensure output raster dataset has the same SRS, otherwise "
579 : "results might be incorrect.");
580 : }
581 :
582 60 : if (hDstSRS != nullptr)
583 : {
584 23 : OSRDestroySpatialReference(hDstSRS);
585 : }
586 : }
587 :
588 : /* -------------------------------------------------------------------- */
589 : /* Get field index, and check. */
590 : /* -------------------------------------------------------------------- */
591 62 : int iBurnField = -1;
592 62 : bool bUseInt64 = false;
593 62 : OGRFieldType eBurnAttributeType = OFTInteger;
594 62 : if (!osBurnAttribute.empty())
595 : {
596 7 : OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hSrcLayer);
597 7 : iBurnField = OGR_FD_GetFieldIndex(hLayerDefn, osBurnAttribute.c_str());
598 7 : if (iBurnField == -1)
599 : {
600 1 : CPLError(CE_Failure, CPLE_AppDefined,
601 : "Failed to find field %s on layer %s.",
602 : osBurnAttribute.c_str(),
603 : OGR_FD_GetName(OGR_L_GetLayerDefn(hSrcLayer)));
604 1 : if (hCT != nullptr)
605 0 : OCTDestroyCoordinateTransformation(hCT);
606 1 : return CE_Failure;
607 : }
608 :
609 : eBurnAttributeType =
610 6 : OGR_Fld_GetType(OGR_FD_GetFieldDefn(hLayerDefn, iBurnField));
611 :
612 6 : if (eBurnAttributeType == OFTInteger64)
613 : {
614 1 : GDALRasterBandH hBand = GDALGetRasterBand(hDstDS, anBandList[0]);
615 1 : if (hBand && GDALGetRasterDataType(hBand) == GDT_Int64)
616 : {
617 1 : bUseInt64 = true;
618 : }
619 : }
620 : }
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Collect the geometries from this layer, and build list of */
624 : /* burn values. */
625 : /* -------------------------------------------------------------------- */
626 61 : OGRFeatureH hFeat = nullptr;
627 122 : std::vector<OGRGeometryH> ahGeometries;
628 122 : std::vector<double> adfFullBurnValues;
629 61 : std::vector<int64_t> anFullBurnValues;
630 :
631 61 : OGR_L_ResetReading(hSrcLayer);
632 :
633 2134 : while ((hFeat = OGR_L_GetNextFeature(hSrcLayer)) != nullptr)
634 : {
635 2073 : OGRGeometryH hGeom = OGR_F_StealGeometry(hFeat);
636 2073 : if (hGeom == nullptr)
637 : {
638 5 : OGR_F_Destroy(hFeat);
639 5 : continue;
640 : }
641 :
642 2068 : if (hCT != nullptr)
643 : {
644 1 : if (OGR_G_Transform(hGeom, hCT) != OGRERR_NONE)
645 : {
646 0 : OGR_F_Destroy(hFeat);
647 0 : OGR_G_DestroyGeometry(hGeom);
648 0 : continue;
649 : }
650 : }
651 2068 : ahGeometries.push_back(hGeom);
652 :
653 4292 : for (unsigned int iBand = 0; iBand < anBandList.size(); iBand++)
654 : {
655 : GDALRasterBandH hBand =
656 2224 : GDALGetRasterBand(hDstDS, anBandList[iBand]);
657 2224 : GDALDataType eDT = GDALGetRasterDataType(hBand);
658 :
659 2224 : if (!adfBurnValues.empty())
660 325 : adfFullBurnValues.push_back(adfBurnValues[std::min(
661 : iBand,
662 650 : static_cast<unsigned int>(adfBurnValues.size()) - 1)]);
663 1899 : else if (!osBurnAttribute.empty())
664 : {
665 36 : if (bUseInt64)
666 1 : anFullBurnValues.push_back(
667 1 : OGR_F_GetFieldAsInteger64(hFeat, iBurnField));
668 : else
669 : {
670 : double dfBurnValue;
671 :
672 35 : if (eBurnAttributeType == OFTInteger ||
673 : eBurnAttributeType == OFTReal)
674 : {
675 0 : dfBurnValue = OGR_F_GetFieldAsDouble(hFeat, iBurnField);
676 : }
677 : else
678 : {
679 : const char *pszAttribute =
680 35 : OGR_F_GetFieldAsString(hFeat, iBurnField);
681 : char *end;
682 35 : dfBurnValue = CPLStrtod(pszAttribute, &end);
683 :
684 35 : while (isspace(*end) && *end != '\0')
685 : {
686 0 : end++;
687 : }
688 :
689 35 : if (*end != '\0')
690 : {
691 10 : CPLErrorOnce(
692 : CE_Warning, CPLE_AppDefined,
693 : "Failed to parse attribute value %s of feature "
694 : "%" PRId64 " as a number. A value of zero will "
695 : "be burned for this feature.",
696 : pszAttribute,
697 : static_cast<int64_t>(OGR_F_GetFID(hFeat)));
698 : }
699 : }
700 :
701 35 : if (!GDALIsValueExactAs(dfBurnValue, eDT))
702 : {
703 : const char *pszAttribute =
704 10 : OGR_F_GetFieldAsString(hFeat, iBurnField);
705 10 : CPLErrorOnce(CE_Warning, CPLE_AppDefined,
706 : "Attribute value %s of feature %" PRId64
707 : " cannot be exactly burned to an output "
708 : "band of type %s.",
709 : pszAttribute,
710 : static_cast<int64_t>(OGR_F_GetFID(hFeat)),
711 : GDALGetDataTypeName(eDT));
712 : }
713 :
714 35 : adfFullBurnValues.push_back(dfBurnValue);
715 : }
716 : }
717 1863 : else if (b3D)
718 : {
719 : /* Points and Lines will have their "z" values collected at the
720 : point and line levels respectively. Not implemented for
721 : polygons */
722 1863 : adfFullBurnValues.push_back(0.0);
723 : }
724 : }
725 :
726 2068 : OGR_F_Destroy(hFeat);
727 : }
728 :
729 61 : if (hCT != nullptr)
730 1 : OCTDestroyCoordinateTransformation(hCT);
731 :
732 : /* -------------------------------------------------------------------- */
733 : /* If we are in inverse mode, we add one extra ring around the */
734 : /* whole dataset to invert the concept of insideness and then */
735 : /* merge everything into one geometry collection. */
736 : /* -------------------------------------------------------------------- */
737 61 : if (bInverse)
738 : {
739 3 : if (ahGeometries.empty())
740 : {
741 0 : for (unsigned int iBand = 0; iBand < anBandList.size(); iBand++)
742 : {
743 0 : if (!adfBurnValues.empty())
744 0 : adfFullBurnValues.push_back(adfBurnValues[std::min(
745 : iBand,
746 0 : static_cast<unsigned int>(adfBurnValues.size()) - 1)]);
747 : else /* FIXME? Not sure what to do exactly in the else case, but
748 : we must insert a value */
749 : {
750 0 : adfFullBurnValues.push_back(0.0);
751 0 : anFullBurnValues.push_back(0);
752 : }
753 : }
754 : }
755 :
756 3 : InvertGeometries(hDstDS, ahGeometries);
757 : }
758 :
759 : /* -------------------------------------------------------------------- */
760 : /* If we have transformer options, create the transformer here */
761 : /* Coordinate transformation to the target SRS has already been */
762 : /* done, so we just need to convert to target raster space. */
763 : /* Note: this is somewhat identical to what is done in */
764 : /* GDALRasterizeGeometries() itself, except we can pass transformer*/
765 : /* options. */
766 : /* -------------------------------------------------------------------- */
767 :
768 61 : void *pTransformArg = nullptr;
769 61 : GDALTransformerFunc pfnTransformer = nullptr;
770 61 : CPLErr eErr = CE_None;
771 61 : if (papszTO != nullptr)
772 : {
773 1 : GDALDataset *poDS = GDALDataset::FromHandle(hDstDS);
774 1 : char **papszTransformerOptions = CSLDuplicate(papszTO);
775 1 : GDALGeoTransform gt;
776 2 : if (poDS->GetGeoTransform(gt) != CE_None && poDS->GetGCPCount() == 0 &&
777 1 : poDS->GetMetadata("RPC") == nullptr)
778 : {
779 0 : papszTransformerOptions = CSLSetNameValue(
780 : papszTransformerOptions, "DST_METHOD", "NO_GEOTRANSFORM");
781 : }
782 :
783 1 : pTransformArg = GDALCreateGenImgProjTransformer2(
784 : nullptr, hDstDS, papszTransformerOptions);
785 1 : CSLDestroy(papszTransformerOptions);
786 :
787 1 : pfnTransformer = GDALGenImgProjTransform;
788 1 : if (pTransformArg == nullptr)
789 : {
790 0 : eErr = CE_Failure;
791 : }
792 : }
793 :
794 : /* -------------------------------------------------------------------- */
795 : /* Perform the burn. */
796 : /* -------------------------------------------------------------------- */
797 61 : if (eErr == CE_None)
798 : {
799 61 : if (bUseInt64)
800 : {
801 2 : eErr = GDALRasterizeGeometriesInt64(
802 1 : hDstDS, static_cast<int>(anBandList.size()), anBandList.data(),
803 1 : static_cast<int>(ahGeometries.size()), ahGeometries.data(),
804 1 : pfnTransformer, pTransformArg, anFullBurnValues.data(),
805 : papszRasterizeOptions, pfnProgress, pProgressData);
806 : }
807 : else
808 : {
809 120 : eErr = GDALRasterizeGeometries(
810 60 : hDstDS, static_cast<int>(anBandList.size()), anBandList.data(),
811 60 : static_cast<int>(ahGeometries.size()), ahGeometries.data(),
812 60 : pfnTransformer, pTransformArg, adfFullBurnValues.data(),
813 : papszRasterizeOptions, pfnProgress, pProgressData);
814 : }
815 : }
816 :
817 : /* -------------------------------------------------------------------- */
818 : /* Cleanup */
819 : /* -------------------------------------------------------------------- */
820 :
821 61 : if (pTransformArg)
822 1 : GDALDestroyTransformer(pTransformArg);
823 :
824 2125 : for (int iGeom = static_cast<int>(ahGeometries.size()) - 1; iGeom >= 0;
825 : iGeom--)
826 2064 : OGR_G_DestroyGeometry(ahGeometries[iGeom]);
827 :
828 61 : return eErr;
829 : }
830 :
831 : /************************************************************************/
832 : /* CreateOutputDataset() */
833 : /************************************************************************/
834 :
835 37 : static std::unique_ptr<GDALDataset> CreateOutputDataset(
836 : const std::vector<OGRLayerH> &ahLayers, OGRSpatialReferenceH hSRS,
837 : OGREnvelope sEnvelop, GDALDriverH hDriver, const char *pszDest, int nXSize,
838 : int nYSize, double dfXRes, double dfYRes, bool bTargetAlignedPixels,
839 : int nBandCount, GDALDataType eOutputType, CSLConstList papszCreationOptions,
840 : const std::vector<double> &adfInitVals, const char *pszNoData)
841 : {
842 37 : bool bFirstLayer = true;
843 37 : const bool bBoundsSpecifiedByUser = sEnvelop.IsInit();
844 :
845 73 : for (unsigned int i = 0; i < ahLayers.size(); i++)
846 : {
847 37 : OGRLayerH hLayer = ahLayers[i];
848 :
849 37 : if (!bBoundsSpecifiedByUser)
850 : {
851 34 : OGREnvelope sLayerEnvelop;
852 :
853 34 : if (OGR_L_GetExtent(hLayer, &sLayerEnvelop, TRUE) != OGRERR_NONE)
854 : {
855 1 : CPLError(CE_Failure, CPLE_AppDefined,
856 : "Cannot get layer extent");
857 1 : return nullptr;
858 : }
859 :
860 : /* Voluntarily increase the extent by a half-pixel size to avoid */
861 : /* missing points on the border */
862 33 : if (!bTargetAlignedPixels && dfXRes != 0 && dfYRes != 0)
863 : {
864 9 : sLayerEnvelop.MinX -= dfXRes / 2;
865 9 : sLayerEnvelop.MaxX += dfXRes / 2;
866 9 : sLayerEnvelop.MinY -= dfYRes / 2;
867 9 : sLayerEnvelop.MaxY += dfYRes / 2;
868 : }
869 :
870 33 : sEnvelop.Merge(sLayerEnvelop);
871 : }
872 :
873 36 : if (bFirstLayer)
874 : {
875 36 : if (hSRS == nullptr)
876 34 : hSRS = OGR_L_GetSpatialRef(hLayer);
877 :
878 36 : bFirstLayer = false;
879 : }
880 : }
881 :
882 36 : if (!sEnvelop.IsInit())
883 : {
884 0 : CPLError(CE_Failure, CPLE_AppDefined, "Could not determine bounds");
885 0 : return nullptr;
886 : }
887 :
888 36 : if (dfXRes == 0 && dfYRes == 0)
889 : {
890 23 : if (nXSize == 0 || nYSize == 0)
891 : {
892 1 : CPLError(CE_Failure, CPLE_AppDefined,
893 : "Size and resolution are missing");
894 1 : return nullptr;
895 : }
896 22 : dfXRes = (sEnvelop.MaxX - sEnvelop.MinX) / nXSize;
897 22 : dfYRes = (sEnvelop.MaxY - sEnvelop.MinY) / nYSize;
898 : }
899 13 : else if (bTargetAlignedPixels && dfXRes != 0 && dfYRes != 0)
900 : {
901 1 : sEnvelop.MinX = floor(sEnvelop.MinX / dfXRes) * dfXRes;
902 1 : sEnvelop.MaxX = ceil(sEnvelop.MaxX / dfXRes) * dfXRes;
903 1 : sEnvelop.MinY = floor(sEnvelop.MinY / dfYRes) * dfYRes;
904 1 : sEnvelop.MaxY = ceil(sEnvelop.MaxY / dfYRes) * dfYRes;
905 : }
906 :
907 35 : if (dfXRes == 0 || dfYRes == 0)
908 : {
909 0 : CPLError(CE_Failure, CPLE_AppDefined, "Could not determine bounds");
910 0 : return nullptr;
911 : }
912 :
913 35 : if (nXSize == 0 && nYSize == 0)
914 : {
915 : // coverity[divide_by_zero]
916 13 : const double dfXSize = 0.5 + (sEnvelop.MaxX - sEnvelop.MinX) / dfXRes;
917 : // coverity[divide_by_zero]
918 13 : const double dfYSize = 0.5 + (sEnvelop.MaxY - sEnvelop.MinY) / dfYRes;
919 13 : if (dfXSize > std::numeric_limits<int>::max() ||
920 12 : dfXSize < std::numeric_limits<int>::min() ||
921 36 : dfYSize > std::numeric_limits<int>::max() ||
922 11 : dfYSize < std::numeric_limits<int>::min())
923 : {
924 2 : CPLError(CE_Failure, CPLE_AppDefined,
925 : "Invalid computed output raster size: %f x %f", dfXSize,
926 : dfYSize);
927 2 : return nullptr;
928 : }
929 11 : nXSize = static_cast<int>(dfXSize);
930 11 : nYSize = static_cast<int>(dfYSize);
931 : }
932 :
933 : auto poDstDS =
934 : std::unique_ptr<GDALDataset>(GDALDriver::FromHandle(hDriver)->Create(
935 : pszDest, nXSize, nYSize, nBandCount, eOutputType,
936 66 : papszCreationOptions));
937 33 : if (poDstDS == nullptr)
938 : {
939 0 : CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s", pszDest);
940 0 : return nullptr;
941 : }
942 :
943 : GDALGeoTransform gt = {sEnvelop.MinX, dfXRes, 0.0,
944 33 : sEnvelop.MaxY, 0.0, -dfYRes};
945 33 : poDstDS->SetGeoTransform(gt);
946 :
947 33 : if (hSRS)
948 14 : poDstDS->SetSpatialRef(OGRSpatialReference::FromHandle(hSRS));
949 :
950 33 : if (pszNoData)
951 : {
952 92 : for (int iBand = 0; iBand < nBandCount; iBand++)
953 : {
954 59 : auto poBand = poDstDS->GetRasterBand(iBand + 1);
955 59 : if (poBand->GetRasterDataType() == GDT_Int64)
956 1 : poBand->SetNoDataValueAsInt64(CPLAtoGIntBig(pszNoData));
957 : else
958 58 : poBand->SetNoDataValue(CPLAtof(pszNoData));
959 : }
960 : }
961 :
962 33 : if (!adfInitVals.empty())
963 : {
964 30 : for (int iBand = 0;
965 30 : iBand < std::min(nBandCount, static_cast<int>(adfInitVals.size()));
966 : iBand++)
967 : {
968 21 : auto poBand = poDstDS->GetRasterBand(iBand + 1);
969 21 : poBand->Fill(adfInitVals[iBand]);
970 : }
971 : }
972 :
973 33 : return poDstDS;
974 : }
975 :
976 : /************************************************************************/
977 : /* GDALRasterize() */
978 : /************************************************************************/
979 :
980 : /* clang-format off */
981 : /**
982 : * Burns vector geometries into a raster
983 : *
984 : * This is the equivalent of the
985 : * <a href="/programs/gdal_rasterize.html">gdal_rasterize</a> utility.
986 : *
987 : * GDALRasterizeOptions* must be allocated and freed with
988 : * GDALRasterizeOptionsNew() and GDALRasterizeOptionsFree() respectively.
989 : * pszDest and hDstDS cannot be used at the same time.
990 : *
991 : * @param pszDest the destination dataset path or NULL.
992 : * @param hDstDS the destination dataset or NULL.
993 : * @param hSrcDataset the source dataset handle.
994 : * @param psOptionsIn the options struct returned by GDALRasterizeOptionsNew()
995 : * or NULL.
996 : * @param pbUsageError pointer to an integer output variable to store if any
997 : * usage error has occurred or NULL.
998 : * @return the output dataset (new dataset that must be closed using
999 : * GDALClose(), or hDstDS is not NULL) or NULL in case of error.
1000 : *
1001 : * @since GDAL 2.1
1002 : */
1003 : /* clang-format on */
1004 :
1005 71 : GDALDatasetH GDALRasterize(const char *pszDest, GDALDatasetH hDstDS,
1006 : GDALDatasetH hSrcDataset,
1007 : const GDALRasterizeOptions *psOptionsIn,
1008 : int *pbUsageError)
1009 : {
1010 71 : GDALDataset *poOutDS = GDALDataset::FromHandle(hDstDS);
1011 : #define hDstDS no_longer_use_hDstDS
1012 71 : if (pszDest == nullptr && poOutDS == nullptr)
1013 : {
1014 0 : CPLError(CE_Failure, CPLE_AppDefined,
1015 : "pszDest == NULL && hDstDS == NULL");
1016 :
1017 0 : if (pbUsageError)
1018 0 : *pbUsageError = TRUE;
1019 0 : return nullptr;
1020 : }
1021 71 : if (hSrcDataset == nullptr)
1022 : {
1023 0 : CPLError(CE_Failure, CPLE_AppDefined, "hSrcDataset== NULL");
1024 :
1025 0 : if (pbUsageError)
1026 0 : *pbUsageError = TRUE;
1027 0 : return nullptr;
1028 : }
1029 71 : if (poOutDS != nullptr && psOptionsIn && psOptionsIn->bCreateOutput)
1030 : {
1031 0 : CPLError(CE_Failure, CPLE_AppDefined,
1032 : "hDstDS != NULL but options that imply creating a new dataset "
1033 : "have been set.");
1034 :
1035 0 : if (pbUsageError)
1036 0 : *pbUsageError = TRUE;
1037 0 : return nullptr;
1038 : }
1039 :
1040 : std::unique_ptr<GDALRasterizeOptions, decltype(&GDALRasterizeOptionsFree)>
1041 142 : psOptionsToFree(nullptr, GDALRasterizeOptionsFree);
1042 142 : GDALRasterizeOptions sOptions;
1043 71 : if (psOptionsIn)
1044 71 : sOptions = *psOptionsIn;
1045 :
1046 71 : std::unique_ptr<GDALDataset> poNewOutDS;
1047 71 : if (pszDest == nullptr)
1048 13 : pszDest = poOutDS->GetDescription();
1049 :
1050 104 : if (sOptions.osSQL.empty() && sOptions.aosLayers.empty() &&
1051 33 : GDALDatasetGetLayerCount(hSrcDataset) != 1)
1052 : {
1053 0 : CPLError(CE_Failure, CPLE_NotSupported,
1054 : "Neither -sql nor -l are specified, but the source dataset "
1055 : "has not one single layer.");
1056 0 : if (pbUsageError)
1057 0 : *pbUsageError = TRUE;
1058 0 : return nullptr;
1059 : }
1060 :
1061 : /* -------------------------------------------------------------------- */
1062 : /* Open target raster file. Eventually we will add optional */
1063 : /* creation. */
1064 : /* -------------------------------------------------------------------- */
1065 71 : const bool bCreateOutput = sOptions.bCreateOutput || poOutDS == nullptr;
1066 :
1067 71 : GDALDriverH hDriver = nullptr;
1068 71 : if (bCreateOutput)
1069 : {
1070 42 : CPLString osFormat;
1071 42 : if (sOptions.osFormat.empty())
1072 : {
1073 28 : osFormat = GetOutputDriverForRaster(pszDest);
1074 28 : if (osFormat.empty())
1075 : {
1076 0 : return nullptr;
1077 : }
1078 : }
1079 : else
1080 : {
1081 14 : osFormat = sOptions.osFormat;
1082 : }
1083 :
1084 : /* ------------------------------------------------------------------ */
1085 : /* Find the output driver. */
1086 : /* ------------------------------------------------------------------ */
1087 42 : hDriver = GDALGetDriverByName(osFormat);
1088 : CSLConstList papszDriverMD =
1089 42 : hDriver ? GDALGetMetadata(hDriver, nullptr) : nullptr;
1090 42 : if (hDriver == nullptr)
1091 : {
1092 1 : CPLError(CE_Failure, CPLE_NotSupported,
1093 : "Output driver `%s' not recognised.", osFormat.c_str());
1094 1 : return nullptr;
1095 : }
1096 41 : if (!CPLTestBool(
1097 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_RASTER, "FALSE")))
1098 : {
1099 1 : CPLError(CE_Failure, CPLE_NotSupported,
1100 : "Output driver `%s' is not a raster driver.",
1101 : osFormat.c_str());
1102 1 : return nullptr;
1103 : }
1104 40 : if (!CPLTestBool(
1105 : CSLFetchNameValueDef(papszDriverMD, GDAL_DCAP_CREATE, "FALSE")))
1106 : {
1107 1 : CPLError(CE_Failure, CPLE_NotSupported,
1108 : "Output driver `%s' does not support direct output file "
1109 : "creation. "
1110 : "To write a file to this format, first write to a "
1111 : "different format such as "
1112 : "GeoTIFF and then convert the output.",
1113 : osFormat.c_str());
1114 1 : return nullptr;
1115 : }
1116 : }
1117 :
1118 4 : auto calculateSize = [&](const OGREnvelope &sEnvelope) -> bool
1119 : {
1120 4 : const double width{sEnvelope.MaxX - sEnvelope.MinX};
1121 4 : if (std::isnan(width))
1122 : {
1123 0 : return false;
1124 : }
1125 :
1126 4 : const double height{sEnvelope.MaxY - sEnvelope.MinY};
1127 4 : if (std::isnan(height))
1128 : {
1129 0 : return false;
1130 : }
1131 :
1132 4 : if (height == 0 || width == 0)
1133 : {
1134 0 : return false;
1135 : }
1136 :
1137 4 : if (sOptions.nXSize == 0)
1138 : {
1139 2 : const double xSize{
1140 2 : (sEnvelope.MaxX - sEnvelope.MinX) /
1141 2 : ((sEnvelope.MaxY - sEnvelope.MinY) / sOptions.nYSize)};
1142 4 : if (std::isnan(xSize) || xSize > std::numeric_limits<int>::max() ||
1143 2 : xSize < std::numeric_limits<int>::min())
1144 : {
1145 0 : return false;
1146 : }
1147 2 : sOptions.nXSize = static_cast<int>(xSize);
1148 : }
1149 : else
1150 : {
1151 2 : const double ySize{
1152 2 : (sEnvelope.MaxY - sEnvelope.MinY) /
1153 2 : ((sEnvelope.MaxX - sEnvelope.MinX) / sOptions.nXSize)};
1154 4 : if (std::isnan(ySize) || ySize > std::numeric_limits<int>::max() ||
1155 2 : ySize < std::numeric_limits<int>::min())
1156 : {
1157 0 : return false;
1158 : }
1159 2 : sOptions.nYSize = static_cast<int>(ySize);
1160 : }
1161 4 : return sOptions.nXSize > 0 && sOptions.nYSize > 0;
1162 68 : };
1163 :
1164 : const int nLayerCount =
1165 127 : (sOptions.osSQL.empty() && sOptions.aosLayers.empty())
1166 136 : ? 1
1167 38 : : static_cast<int>(sOptions.aosLayers.size());
1168 :
1169 68 : const bool bOneSizeNeedsCalculation{
1170 68 : static_cast<bool>((sOptions.nXSize == 0) ^ (sOptions.nYSize == 0))};
1171 :
1172 : // Calculate the size if either nXSize or nYSize is 0
1173 68 : if (sOptions.osSQL.empty() && bOneSizeNeedsCalculation)
1174 : {
1175 2 : CPLErr eErr = CE_None;
1176 : // Get the extent of the source dataset
1177 2 : OGREnvelope sEnvelope;
1178 2 : bool bFirstLayer = true;
1179 4 : for (int i = 0; i < nLayerCount; i++)
1180 : {
1181 : OGRLayerH hLayer;
1182 2 : if (sOptions.aosLayers.size() > static_cast<size_t>(i))
1183 2 : hLayer = GDALDatasetGetLayerByName(
1184 2 : hSrcDataset, sOptions.aosLayers[i].c_str());
1185 : else
1186 0 : hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
1187 2 : if (hLayer == nullptr)
1188 : {
1189 0 : CPLError(CE_Failure, CPLE_AppDefined,
1190 : "Unable to find layer \"%s\".",
1191 0 : sOptions.aosLayers.size() > static_cast<size_t>(i)
1192 0 : ? sOptions.aosLayers[i].c_str()
1193 : : "0");
1194 0 : eErr = CE_Failure;
1195 0 : break;
1196 : }
1197 2 : OGREnvelope sLayerEnvelop;
1198 2 : if (OGR_L_GetExtent(hLayer, &sLayerEnvelop, TRUE) != OGRERR_NONE)
1199 : {
1200 0 : CPLError(CE_Failure, CPLE_AppDefined,
1201 : "Cannot get layer extent");
1202 0 : eErr = CE_Failure;
1203 0 : break;
1204 : }
1205 2 : if (bFirstLayer)
1206 : {
1207 2 : sEnvelope = sLayerEnvelop;
1208 2 : bFirstLayer = false;
1209 : }
1210 : else
1211 : {
1212 0 : sEnvelope.Merge(sLayerEnvelop);
1213 : }
1214 : }
1215 :
1216 2 : if (!calculateSize(sEnvelope))
1217 : {
1218 0 : CPLError(CE_Failure, CPLE_AppDefined,
1219 : "Cannot calculate size from layer extent");
1220 0 : eErr = CE_Failure;
1221 : }
1222 :
1223 2 : if (eErr == CE_Failure)
1224 : {
1225 0 : return nullptr;
1226 : }
1227 : }
1228 :
1229 34 : const auto GetOutputDataType = [&](OGRLayerH hLayer)
1230 : {
1231 34 : CPLAssert(bCreateOutput);
1232 34 : CPLAssert(hDriver);
1233 70 : GDALDataType eOutputType = sOptions.eOutputType;
1234 34 : if (eOutputType == GDT_Unknown && !sOptions.osBurnAttribute.empty())
1235 : {
1236 2 : OGRFeatureDefnH hLayerDefn = OGR_L_GetLayerDefn(hLayer);
1237 2 : const int iBurnField = OGR_FD_GetFieldIndex(
1238 : hLayerDefn, sOptions.osBurnAttribute.c_str());
1239 2 : if (iBurnField >= 0 && OGR_Fld_GetType(OGR_FD_GetFieldDefn(
1240 : hLayerDefn, iBurnField)) == OFTInteger64)
1241 : {
1242 1 : const char *pszMD = GDALGetMetadataItem(
1243 : hDriver, GDAL_DMD_CREATIONDATATYPES, nullptr);
1244 2 : if (pszMD && CPLStringList(CSLTokenizeString2(pszMD, " ", 0))
1245 1 : .FindString("Int64") >= 0)
1246 : {
1247 1 : eOutputType = GDT_Int64;
1248 : }
1249 : }
1250 : }
1251 34 : if (eOutputType == GDT_Unknown)
1252 : {
1253 33 : eOutputType = GDT_Float64;
1254 : }
1255 34 : return eOutputType;
1256 68 : };
1257 :
1258 : // Store SRS handle
1259 : OGRSpatialReferenceH hSRS =
1260 68 : sOptions.oOutputSRS.IsEmpty()
1261 68 : ? nullptr
1262 2 : : OGRSpatialReference::ToHandle(
1263 68 : const_cast<OGRSpatialReference *>(&sOptions.oOutputSRS));
1264 :
1265 : /* -------------------------------------------------------------------- */
1266 : /* Process SQL request. */
1267 : /* -------------------------------------------------------------------- */
1268 68 : CPLErr eErr = CE_Failure;
1269 :
1270 68 : if (!sOptions.osSQL.empty())
1271 : {
1272 : OGRLayerH hLayer =
1273 9 : GDALDatasetExecuteSQL(hSrcDataset, sOptions.osSQL.c_str(), nullptr,
1274 9 : sOptions.osDialect.c_str());
1275 9 : if (hLayer != nullptr)
1276 : {
1277 :
1278 9 : if (bOneSizeNeedsCalculation)
1279 : {
1280 3 : OGREnvelope sEnvelope;
1281 : bool bSizeCalculationError{
1282 3 : OGR_L_GetExtent(hLayer, &sEnvelope, TRUE) != OGRERR_NONE};
1283 3 : if (!bSizeCalculationError)
1284 : {
1285 2 : bSizeCalculationError = !calculateSize(sEnvelope);
1286 : }
1287 :
1288 3 : if (bSizeCalculationError)
1289 : {
1290 1 : CPLError(CE_Failure, CPLE_AppDefined,
1291 : "Cannot get layer extent");
1292 1 : GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
1293 1 : return nullptr;
1294 : }
1295 : }
1296 :
1297 8 : if (bCreateOutput)
1298 : {
1299 4 : std::vector<OGRLayerH> ahLayers;
1300 4 : ahLayers.push_back(hLayer);
1301 :
1302 4 : const GDALDataType eOutputType = GetOutputDataType(hLayer);
1303 12 : poNewOutDS = CreateOutputDataset(
1304 : ahLayers, hSRS, sOptions.sEnvelop, hDriver, pszDest,
1305 : sOptions.nXSize, sOptions.nYSize, sOptions.dfXRes,
1306 4 : sOptions.dfYRes, sOptions.bTargetAlignedPixels,
1307 4 : static_cast<int>(sOptions.anBandList.size()), eOutputType,
1308 : sOptions.aosCreationOptions, sOptions.adfInitVals,
1309 8 : sOptions.osNoData.c_str());
1310 4 : if (poNewOutDS == nullptr)
1311 : {
1312 0 : GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
1313 0 : return nullptr;
1314 : }
1315 4 : poOutDS = poNewOutDS.get();
1316 : }
1317 :
1318 : const bool bCloseReportsProgress =
1319 8 : bCreateOutput && poOutDS->GetCloseReportsProgress();
1320 :
1321 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
1322 : pScaledProgressArg(GDALCreateScaledProgress(
1323 : 0.0, bCloseReportsProgress ? 0.5 : 1.0,
1324 : sOptions.pfnProgress,
1325 : sOptions.pProgressData),
1326 16 : GDALDestroyScaledProgress);
1327 :
1328 24 : eErr = ProcessLayer(
1329 : hLayer, hSRS != nullptr, poOutDS, sOptions.anBandList,
1330 8 : sOptions.adfBurnValues, sOptions.b3D, sOptions.bInverse,
1331 : sOptions.osBurnAttribute.c_str(), sOptions.aosRasterizeOptions,
1332 8 : sOptions.aosTO, GDALScaledProgress, pScaledProgressArg.get());
1333 :
1334 8 : GDALDatasetReleaseResultSet(hSrcDataset, hLayer);
1335 : }
1336 : }
1337 :
1338 : /* -------------------------------------------------------------------- */
1339 : /* Create output file if necessary. */
1340 : /* -------------------------------------------------------------------- */
1341 :
1342 67 : if (bCreateOutput && poOutDS == nullptr)
1343 : {
1344 34 : std::vector<OGRLayerH> ahLayers;
1345 :
1346 34 : GDALDataType eOutputType = sOptions.eOutputType;
1347 :
1348 67 : for (int i = 0; i < nLayerCount; i++)
1349 : {
1350 : OGRLayerH hLayer;
1351 34 : if (sOptions.aosLayers.size() > static_cast<size_t>(i))
1352 15 : hLayer = GDALDatasetGetLayerByName(
1353 15 : hSrcDataset, sOptions.aosLayers[i].c_str());
1354 : else
1355 19 : hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
1356 34 : if (hLayer == nullptr)
1357 : {
1358 1 : CPLError(CE_Failure, CPLE_AppDefined,
1359 : "Unable to find layer \"%s\".",
1360 1 : sOptions.aosLayers.size() > static_cast<size_t>(i)
1361 1 : ? sOptions.aosLayers[i].c_str()
1362 : : "0");
1363 1 : return nullptr;
1364 : }
1365 33 : if (eOutputType == GDT_Unknown)
1366 : {
1367 30 : if (GetOutputDataType(hLayer) == GDT_Int64)
1368 1 : eOutputType = GDT_Int64;
1369 : }
1370 :
1371 33 : ahLayers.push_back(hLayer);
1372 : }
1373 :
1374 33 : if (eOutputType == GDT_Unknown)
1375 : {
1376 29 : eOutputType = GDT_Float64;
1377 : }
1378 :
1379 99 : poNewOutDS = CreateOutputDataset(
1380 : ahLayers, hSRS, sOptions.sEnvelop, hDriver, pszDest,
1381 : sOptions.nXSize, sOptions.nYSize, sOptions.dfXRes, sOptions.dfYRes,
1382 33 : sOptions.bTargetAlignedPixels,
1383 33 : static_cast<int>(sOptions.anBandList.size()), eOutputType,
1384 : sOptions.aosCreationOptions, sOptions.adfInitVals,
1385 66 : sOptions.osNoData.c_str());
1386 33 : if (poNewOutDS == nullptr)
1387 : {
1388 4 : return nullptr;
1389 : }
1390 29 : poOutDS = poNewOutDS.get();
1391 : }
1392 :
1393 : const bool bCloseReportsProgress =
1394 62 : bCreateOutput && poOutDS->GetCloseReportsProgress();
1395 :
1396 : /* -------------------------------------------------------------------- */
1397 : /* Process each layer. */
1398 : /* -------------------------------------------------------------------- */
1399 :
1400 115 : for (int i = 0; i < nLayerCount; i++)
1401 : {
1402 : OGRLayerH hLayer;
1403 54 : if (sOptions.aosLayers.size() > static_cast<size_t>(i))
1404 28 : hLayer = GDALDatasetGetLayerByName(hSrcDataset,
1405 28 : sOptions.aosLayers[i].c_str());
1406 : else
1407 26 : hLayer = GDALDatasetGetLayer(hSrcDataset, 0);
1408 54 : if (hLayer == nullptr)
1409 : {
1410 0 : CPLError(CE_Failure, CPLE_AppDefined,
1411 : "Unable to find layer \"%s\".",
1412 0 : sOptions.aosLayers.size() > static_cast<size_t>(i)
1413 0 : ? sOptions.aosLayers[i].c_str()
1414 : : "0");
1415 0 : eErr = CE_Failure;
1416 1 : break;
1417 : }
1418 :
1419 54 : if (!sOptions.osWHERE.empty())
1420 : {
1421 1 : if (OGR_L_SetAttributeFilter(hLayer, sOptions.osWHERE.c_str()) !=
1422 : OGRERR_NONE)
1423 : {
1424 0 : eErr = CE_Failure;
1425 0 : break;
1426 : }
1427 : }
1428 :
1429 54 : const double dfFactor = bCloseReportsProgress ? 0.5 : 1.0;
1430 :
1431 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
1432 : pScaledProgressArg(
1433 54 : GDALCreateScaledProgress(dfFactor * i / nLayerCount,
1434 54 : dfFactor * (i + 1) / nLayerCount,
1435 : sOptions.pfnProgress,
1436 : sOptions.pProgressData),
1437 54 : GDALDestroyScaledProgress);
1438 :
1439 162 : eErr = ProcessLayer(hLayer, !sOptions.oOutputSRS.IsEmpty(), poOutDS,
1440 : sOptions.anBandList, sOptions.adfBurnValues,
1441 54 : sOptions.b3D, sOptions.bInverse,
1442 : sOptions.osBurnAttribute.c_str(),
1443 : sOptions.aosRasterizeOptions, sOptions.aosTO,
1444 54 : GDALScaledProgress, pScaledProgressArg.get());
1445 54 : if (eErr != CE_None)
1446 1 : break;
1447 : }
1448 :
1449 62 : if (eErr != CE_None)
1450 : {
1451 1 : return nullptr;
1452 : }
1453 :
1454 61 : if (bCloseReportsProgress)
1455 : {
1456 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
1457 : pScaledProgressArg(GDALCreateScaledProgress(0.5, 1.0,
1458 : sOptions.pfnProgress,
1459 : sOptions.pProgressData),
1460 1 : GDALDestroyScaledProgress);
1461 :
1462 : const bool bCanReopenWithCurrentDescription =
1463 1 : poOutDS->CanReopenWithCurrentDescription();
1464 :
1465 1 : eErr = poOutDS->Close(GDALScaledProgress, pScaledProgressArg.get());
1466 1 : poOutDS = nullptr;
1467 1 : if (eErr != CE_None)
1468 0 : return nullptr;
1469 :
1470 1 : if (bCanReopenWithCurrentDescription)
1471 : {
1472 : {
1473 2 : CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
1474 1 : poNewOutDS.reset(
1475 : GDALDataset::Open(pszDest, GDAL_OF_RASTER | GDAL_OF_UPDATE,
1476 : nullptr, nullptr, nullptr));
1477 : }
1478 1 : if (!poNewOutDS)
1479 : {
1480 1 : poNewOutDS.reset(GDALDataset::Open(
1481 : pszDest, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, nullptr,
1482 : nullptr, nullptr));
1483 : }
1484 : }
1485 : else
1486 : {
1487 : struct DummyDataset final : public GDALDataset
1488 : {
1489 0 : DummyDataset() = default;
1490 : };
1491 :
1492 0 : poNewOutDS = std::make_unique<DummyDataset>();
1493 : }
1494 : }
1495 :
1496 61 : return poNewOutDS ? poNewOutDS.release() : poOutDS;
1497 : }
1498 :
1499 : /************************************************************************/
1500 : /* ArgIsNumericRasterize() */
1501 : /************************************************************************/
1502 :
1503 411 : static bool ArgIsNumericRasterize(const char *pszArg)
1504 :
1505 : {
1506 411 : char *pszEnd = nullptr;
1507 411 : CPLStrtod(pszArg, &pszEnd);
1508 411 : return pszEnd != nullptr && pszEnd[0] == '\0';
1509 : }
1510 :
1511 : /************************************************************************/
1512 : /* GDALRasterizeOptionsNew() */
1513 : /************************************************************************/
1514 :
1515 : /**
1516 : * Allocates a GDALRasterizeOptions struct.
1517 : *
1518 : * @param papszArgv NULL terminated list of options (potentially including
1519 : * filename and open options too), or NULL. The accepted options are the ones of
1520 : * the <a href="/programs/gdal_rasterize.html">gdal_rasterize</a> utility.
1521 : * @param psOptionsForBinary (output) may be NULL (and should generally be
1522 : * NULL), otherwise (gdal_translate_bin.cpp use case) must be allocated with
1523 : * GDALRasterizeOptionsForBinaryNew() prior to this
1524 : * function. Will be filled with potentially present filename, open options,...
1525 : * @return pointer to the allocated GDALRasterizeOptions struct. Must be freed
1526 : * with GDALRasterizeOptionsFree().
1527 : *
1528 : * @since GDAL 2.1
1529 : */
1530 :
1531 : GDALRasterizeOptions *
1532 74 : GDALRasterizeOptionsNew(char **papszArgv,
1533 : GDALRasterizeOptionsForBinary *psOptionsForBinary)
1534 : {
1535 :
1536 148 : auto psOptions = std::make_unique<GDALRasterizeOptions>();
1537 :
1538 : /*-------------------------------------------------------------------- */
1539 : /* Parse arguments. */
1540 : /*-------------------------------------------------------------------- */
1541 :
1542 148 : CPLStringList aosArgv;
1543 :
1544 : /* -------------------------------------------------------------------- */
1545 : /* Pre-processing for custom syntax that ArgumentParser does not */
1546 : /* support. */
1547 : /* -------------------------------------------------------------------- */
1548 74 : const int argc = CSLCount(papszArgv);
1549 739 : for (int i = 0; i < argc && papszArgv != nullptr && papszArgv[i] != nullptr;
1550 : i++)
1551 : {
1552 : // argparser will be confused if the value of a string argument
1553 : // starts with a negative sign.
1554 665 : if (EQUAL(papszArgv[i], "-a_nodata") && papszArgv[i + 1])
1555 : {
1556 5 : ++i;
1557 5 : psOptions->osNoData = papszArgv[i];
1558 5 : psOptions->bCreateOutput = true;
1559 : }
1560 :
1561 : // argparser is confused by arguments that have at_least_one
1562 : // cardinality, if they immediately precede positional arguments.
1563 660 : else if (EQUAL(papszArgv[i], "-burn") && papszArgv[i + 1])
1564 : {
1565 117 : if (strchr(papszArgv[i + 1], ' '))
1566 : {
1567 : const CPLStringList aosTokens(
1568 0 : CSLTokenizeString(papszArgv[i + 1]));
1569 0 : for (const char *pszToken : aosTokens)
1570 : {
1571 0 : psOptions->adfBurnValues.push_back(CPLAtof(pszToken));
1572 : }
1573 0 : i += 1;
1574 : }
1575 : else
1576 : {
1577 234 : while (i < argc - 1 && ArgIsNumericRasterize(papszArgv[i + 1]))
1578 : {
1579 117 : psOptions->adfBurnValues.push_back(
1580 117 : CPLAtof(papszArgv[i + 1]));
1581 117 : i += 1;
1582 : }
1583 : }
1584 :
1585 : // Dummy value to make argparse happy, as at least one of
1586 : // -burn, -a or -3d is required
1587 117 : aosArgv.AddString("-burn");
1588 117 : aosArgv.AddString("0");
1589 : }
1590 543 : else if (EQUAL(papszArgv[i], "-init") && papszArgv[i + 1])
1591 : {
1592 27 : if (strchr(papszArgv[i + 1], ' '))
1593 : {
1594 : const CPLStringList aosTokens(
1595 0 : CSLTokenizeString(papszArgv[i + 1]));
1596 0 : for (const char *pszToken : aosTokens)
1597 : {
1598 0 : psOptions->adfInitVals.push_back(CPLAtof(pszToken));
1599 : }
1600 0 : i += 1;
1601 : }
1602 : else
1603 : {
1604 54 : while (i < argc - 1 && ArgIsNumericRasterize(papszArgv[i + 1]))
1605 : {
1606 27 : psOptions->adfInitVals.push_back(CPLAtof(papszArgv[i + 1]));
1607 27 : i += 1;
1608 : }
1609 : }
1610 27 : psOptions->bCreateOutput = true;
1611 : }
1612 516 : else if (EQUAL(papszArgv[i], "-b") && papszArgv[i + 1])
1613 : {
1614 66 : if (strchr(papszArgv[i + 1], ' '))
1615 : {
1616 : const CPLStringList aosTokens(
1617 0 : CSLTokenizeString(papszArgv[i + 1]));
1618 0 : for (const char *pszToken : aosTokens)
1619 : {
1620 0 : psOptions->anBandList.push_back(atoi(pszToken));
1621 : }
1622 0 : i += 1;
1623 : }
1624 : else
1625 : {
1626 132 : while (i < argc - 1 && ArgIsNumericRasterize(papszArgv[i + 1]))
1627 : {
1628 66 : psOptions->anBandList.push_back(atoi(papszArgv[i + 1]));
1629 66 : i += 1;
1630 : }
1631 66 : }
1632 : }
1633 : else
1634 : {
1635 450 : aosArgv.AddString(papszArgv[i]);
1636 : }
1637 : }
1638 :
1639 : try
1640 : {
1641 : auto argParser =
1642 76 : GDALRasterizeOptionsGetParser(psOptions.get(), psOptionsForBinary);
1643 74 : argParser->parse_args_without_binary_name(aosArgv.List());
1644 :
1645 : // Check all no store_into args
1646 75 : if (auto oTe = argParser->present<std::vector<double>>("-te"))
1647 : {
1648 3 : psOptions->sEnvelop.MinX = oTe.value()[0];
1649 3 : psOptions->sEnvelop.MinY = oTe.value()[1];
1650 3 : psOptions->sEnvelop.MaxX = oTe.value()[2];
1651 3 : psOptions->sEnvelop.MaxY = oTe.value()[3];
1652 3 : psOptions->bCreateOutput = true;
1653 : }
1654 :
1655 72 : if (auto oTr = argParser->present<std::vector<double>>("-tr"))
1656 : {
1657 13 : psOptions->dfXRes = oTr.value()[0];
1658 13 : psOptions->dfYRes = oTr.value()[1];
1659 :
1660 13 : if (psOptions->dfXRes <= 0 || psOptions->dfYRes <= 0)
1661 : {
1662 0 : CPLError(CE_Failure, CPLE_AppDefined,
1663 : "Wrong value for -tr parameter.");
1664 0 : return nullptr;
1665 : }
1666 :
1667 13 : psOptions->bCreateOutput = true;
1668 : }
1669 :
1670 72 : if (auto oTs = argParser->present<std::vector<double>>("-ts"))
1671 : {
1672 29 : const int nXSize = static_cast<int>(oTs.value()[0]);
1673 29 : const int nYSize = static_cast<int>(oTs.value()[1]);
1674 :
1675 : // Warn the user if the conversion to int looses precision
1676 29 : if (nXSize != oTs.value()[0] || nYSize != oTs.value()[1])
1677 : {
1678 1 : CPLError(CE_Warning, CPLE_AppDefined,
1679 : "-ts values parsed as %d %d.", nXSize, nYSize);
1680 : }
1681 :
1682 29 : psOptions->nXSize = nXSize;
1683 29 : psOptions->nYSize = nYSize;
1684 :
1685 29 : if (!(psOptions->nXSize > 0 || psOptions->nYSize > 0))
1686 : {
1687 0 : CPLError(CE_Failure, CPLE_AppDefined,
1688 : "Wrong value for -ts parameter: at least one of the "
1689 : "arguments must be greater than zero.");
1690 0 : return nullptr;
1691 : }
1692 :
1693 29 : psOptions->bCreateOutput = true;
1694 : }
1695 :
1696 72 : if (psOptions->bCreateOutput)
1697 : {
1698 71 : if (psOptions->dfXRes == 0 && psOptions->dfYRes == 0 &&
1699 71 : psOptions->nXSize == 0 && psOptions->nYSize == 0)
1700 : {
1701 0 : CPLError(CE_Failure, CPLE_NotSupported,
1702 : "'-tr xres yres' or '-ts xsize ysize' is required.");
1703 0 : return nullptr;
1704 : }
1705 :
1706 42 : if (psOptions->bTargetAlignedPixels && psOptions->dfXRes == 0 &&
1707 0 : psOptions->dfYRes == 0)
1708 : {
1709 0 : CPLError(CE_Failure, CPLE_NotSupported,
1710 : "-tap option cannot be used without using -tr.");
1711 0 : return nullptr;
1712 : }
1713 :
1714 42 : if (!psOptions->anBandList.empty())
1715 : {
1716 1 : CPLError(
1717 : CE_Failure, CPLE_NotSupported,
1718 : "-b option cannot be used when creating a GDAL dataset.");
1719 1 : return nullptr;
1720 : }
1721 :
1722 41 : int nBandCount = 1;
1723 :
1724 41 : if (!psOptions->adfBurnValues.empty())
1725 24 : nBandCount = static_cast<int>(psOptions->adfBurnValues.size());
1726 :
1727 41 : if (static_cast<int>(psOptions->adfInitVals.size()) > nBandCount)
1728 0 : nBandCount = static_cast<int>(psOptions->adfInitVals.size());
1729 :
1730 41 : if (psOptions->adfInitVals.size() == 1)
1731 : {
1732 3 : for (int i = 1; i <= nBandCount - 1; i++)
1733 0 : psOptions->adfInitVals.push_back(psOptions->adfInitVals[0]);
1734 : }
1735 :
1736 110 : for (int i = 1; i <= nBandCount; i++)
1737 69 : psOptions->anBandList.push_back(i);
1738 : }
1739 : else
1740 : {
1741 30 : if (psOptions->anBandList.empty())
1742 11 : psOptions->anBandList.push_back(1);
1743 : }
1744 :
1745 71 : if (!psOptions->osDialect.empty() && !psOptions->osWHERE.empty() &&
1746 0 : !psOptions->osSQL.empty())
1747 : {
1748 0 : CPLError(CE_Warning, CPLE_AppDefined,
1749 : "-dialect is ignored with -where. Use -sql instead");
1750 : }
1751 :
1752 71 : if (psOptionsForBinary)
1753 : {
1754 11 : psOptionsForBinary->bCreateOutput = psOptions->bCreateOutput;
1755 11 : if (!psOptions->osFormat.empty())
1756 0 : psOptionsForBinary->osFormat = psOptions->osFormat;
1757 : }
1758 79 : else if (psOptions->adfBurnValues.empty() &&
1759 79 : psOptions->osBurnAttribute.empty() && !psOptions->b3D)
1760 : {
1761 12 : psOptions->adfBurnValues.push_back(255);
1762 : }
1763 : }
1764 2 : catch (const std::exception &e)
1765 : {
1766 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
1767 2 : return nullptr;
1768 : }
1769 :
1770 71 : return psOptions.release();
1771 : }
1772 :
1773 : /************************************************************************/
1774 : /* GDALRasterizeOptionsFree() */
1775 : /************************************************************************/
1776 :
1777 : /**
1778 : * Frees the GDALRasterizeOptions struct.
1779 : *
1780 : * @param psOptions the options struct for GDALRasterize().
1781 : *
1782 : * @since GDAL 2.1
1783 : */
1784 :
1785 71 : void GDALRasterizeOptionsFree(GDALRasterizeOptions *psOptions)
1786 : {
1787 71 : delete psOptions;
1788 71 : }
1789 :
1790 : /************************************************************************/
1791 : /* GDALRasterizeOptionsSetProgress() */
1792 : /************************************************************************/
1793 :
1794 : /**
1795 : * Set a progress function.
1796 : *
1797 : * @param psOptions the options struct for GDALRasterize().
1798 : * @param pfnProgress the progress callback.
1799 : * @param pProgressData the user data for the progress callback.
1800 : *
1801 : * @since GDAL 2.1
1802 : */
1803 :
1804 47 : void GDALRasterizeOptionsSetProgress(GDALRasterizeOptions *psOptions,
1805 : GDALProgressFunc pfnProgress,
1806 : void *pProgressData)
1807 : {
1808 47 : psOptions->pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
1809 47 : psOptions->pProgressData = pProgressData;
1810 47 : }
|