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