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

Generated by: LCOV version 1.14