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