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

Generated by: LCOV version 1.14