LCOV - code coverage report
Current view: top level - apps - gdal_rasterize_lib.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 626 759 82.5 %
Date: 2025-12-13 23:48:27 Functions: 22 26 84.6 %

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

Generated by: LCOV version 1.14