LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_rasterize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 188 192 97.9 %
Date: 2026-02-06 20:12:57 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "vector rasterize" subcommand
       5             :  * Author:   Alessandro Pasotti <elpaso at itopen dot it>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Alessandro Pasotti <elpaso at itopen dot it>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include <cmath>
      14             : 
      15             : #include "gdalalg_vector_rasterize.h"
      16             : #include "gdalalg_raster_write.h"
      17             : 
      18             : #include "cpl_conv.h"
      19             : #include "gdal_priv.h"
      20             : #include "gdal_utils.h"
      21             : 
      22             : //! @cond Doxygen_Suppress
      23             : 
      24             : #ifndef _
      25             : #define _(x) (x)
      26             : #endif
      27             : 
      28             : /************************************************************************/
      29             : /*     GDALVectorRasterizeAlgorithm::GDALVectorRasterizeAlgorithm()     */
      30             : /************************************************************************/
      31             : 
      32          75 : GDALVectorRasterizeAlgorithm::GDALVectorRasterizeAlgorithm(bool bStandaloneStep)
      33             :     : GDALPipelineStepAlgorithm(
      34             :           NAME, DESCRIPTION, HELP_URL,
      35           0 :           ConstructorOptions()
      36          75 :               .SetStandaloneStep(bStandaloneStep)
      37         150 :               .SetOutputFormatCreateCapability(GDAL_DCAP_CREATE))
      38             : {
      39          75 :     AddProgressArg();
      40          75 :     if (bStandaloneStep)
      41             :     {
      42          60 :         AddOutputFormatArg(&m_format)
      43             :             .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      44         240 :                              {GDAL_DCAP_RASTER, GDAL_DCAP_CREATE})
      45         120 :             .AddMetadataItem(GAAMDI_VRT_COMPATIBLE, {"false"});
      46          60 :         AddOpenOptionsArg(&m_openOptions);
      47          60 :         AddInputFormatsArg(&m_inputFormats)
      48         120 :             .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR});
      49          60 :         AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR)
      50          60 :             .SetMinCount(1)
      51          60 :             .SetMaxCount(1);
      52          60 :         AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER)
      53          60 :             .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
      54          60 :         AddCreationOptionsArg(&m_creationOptions);
      55          60 :         AddOverwriteArg(&m_overwrite);
      56             :     }
      57             : 
      58          75 :     AddBandArg(&m_bands, _("The band(s) to burn values into (1-based index)"));
      59         150 :     AddArg("invert", 0, _("Invert the rasterization"), &m_invert)
      60          75 :         .SetDefault(false);
      61             :     AddArg("all-touched", 0, _("Enables the ALL_TOUCHED rasterization option"),
      62          75 :            &m_allTouched);
      63          75 :     AddArg("burn", 0, _("Burn value"), &m_burnValues);
      64          75 :     AddArg("attribute-name", 'a', _("Attribute name"), &m_attributeName);
      65             :     AddArg("3d", 0,
      66             :            _("Indicates that a burn value should be extracted from the Z"
      67             :              " values of the feature"),
      68          75 :            &m_3d);
      69          75 :     AddLayerNameArg(&m_layerName).SetMutualExclusionGroup("layer-name-or-sql");
      70          75 :     AddArg("where", 0, _("SQL where clause"), &m_where);
      71         150 :     AddArg("sql", 0, _("SQL select statement"), &m_sql)
      72          75 :         .SetMutualExclusionGroup("layer-name-or-sql");
      73          75 :     AddArg("dialect", 0, _("SQL dialect"), &m_dialect);
      74             :     AddArg("nodata", 0, _("Assign a specified nodata value to output bands"),
      75          75 :            &m_nodata);
      76             :     AddArg("init", 0, _("Pre-initialize output bands with specified value"),
      77          75 :            &m_initValues);
      78         150 :     AddArg("crs", 0, _("Override the projection for the output file"), &m_srs)
      79         150 :         .AddHiddenAlias("srs")
      80          75 :         .SetIsCRSArg(/*noneAllowed=*/false);
      81             :     AddArg("transformer-option", 0,
      82             :            _("Set a transformer option suitable to pass to "
      83             :              "GDALCreateGenImgProjTransformer2"),
      84         150 :            &m_transformerOption)
      85          75 :         .SetMetaVar("<NAME>=<VALUE>");
      86             :     AddArg("extent", 0, _("Set the target georeferenced extent"),
      87         150 :            &m_targetExtent)
      88          75 :         .SetMinCount(4)
      89          75 :         .SetMaxCount(4)
      90          75 :         .SetRepeatedArgAllowed(false)
      91          75 :         .SetMetaVar("<xmin>,<ymin>,<xmax>,<ymax>");
      92         150 :     AddArg("resolution", 0, _("Set the target resolution"), &m_targetResolution)
      93          75 :         .SetMinCount(2)
      94          75 :         .SetMaxCount(2)
      95          75 :         .SetRepeatedArgAllowed(false)
      96         150 :         .SetMetaVar("<xres>,<yres>")
      97          75 :         .SetMutualExclusionGroup("size-or-resolution");
      98             :     AddArg("target-aligned-pixels", 0,
      99             :            _("(target aligned pixels) Align the coordinates of the extent of "
     100             :              "the output file to the values of the resolution"),
     101         150 :            &m_tap)
     102          75 :         .AddAlias("tap");
     103             :     AddArg("size", 0, _("Set the target size in pixels and lines"),
     104         150 :            &m_targetSize)
     105          75 :         .SetMinCount(2)
     106          75 :         .SetMaxCount(2)
     107          75 :         .SetRepeatedArgAllowed(false)
     108         150 :         .SetMetaVar("<xsize>,<ysize>")
     109          75 :         .SetMutualExclusionGroup("size-or-resolution");
     110          75 :     AddOutputDataTypeArg(&m_outputType);
     111             :     AddArg("optimization", 0,
     112             :            _("Force the algorithm used (results are identical)"),
     113         150 :            &m_optimization)
     114          75 :         .SetChoices("AUTO", "RASTER", "VECTOR")
     115          75 :         .SetDefault("AUTO");
     116             : 
     117          75 :     if (bStandaloneStep)
     118             :     {
     119         120 :         auto &addArg = AddArg("add", 0, _("Add to existing raster"), &m_add)
     120          60 :                            .SetDefault(false);
     121          60 :         auto &updateArg = AddUpdateArg(&m_update);
     122             :         addArg.AddValidationAction(
     123           3 :             [&updateArg]()
     124             :             {
     125           3 :                 updateArg.Set(true);
     126           3 :                 return true;
     127          60 :             });
     128             :     }
     129          75 : }
     130             : 
     131             : /************************************************************************/
     132             : /*               GDALVectorRasterizeAlgorithm::RunStep()                */
     133             : /************************************************************************/
     134             : 
     135          48 : bool GDALVectorRasterizeAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     136             : {
     137          48 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     138          48 :     CPLAssert(poSrcDS);
     139             : 
     140          96 :     CPLStringList aosOptions;
     141             : 
     142          48 :     if (m_bands.size())
     143             :     {
     144          72 :         for (int band : m_bands)
     145             :         {
     146          54 :             aosOptions.AddString("-b");
     147          54 :             aosOptions.AddString(CPLSPrintf("%d", band));
     148             :         }
     149             :     }
     150             : 
     151          48 :     if (m_invert)
     152             :     {
     153           1 :         aosOptions.AddString("-i");
     154             :     }
     155             : 
     156          48 :     if (m_allTouched)
     157             :     {
     158          31 :         aosOptions.AddString("-at");
     159             :     }
     160             : 
     161          48 :     if (m_burnValues.size())
     162             :     {
     163         138 :         for (double burnValue : m_burnValues)
     164             :         {
     165          98 :             aosOptions.AddString("-burn");
     166          98 :             aosOptions.AddString(CPLSPrintf("%.17g", burnValue));
     167             :         }
     168             :     }
     169             : 
     170          48 :     if (!m_attributeName.empty())
     171             :     {
     172           5 :         aosOptions.AddString("-a");
     173           5 :         aosOptions.AddString(m_attributeName.c_str());
     174             :     }
     175             : 
     176          48 :     if (m_3d)
     177             :     {
     178           2 :         aosOptions.AddString("-3d");
     179             :     }
     180             : 
     181          48 :     if (m_add)
     182             :     {
     183           1 :         aosOptions.AddString("-add");
     184             :         // Implies update
     185           1 :         m_update = true;
     186             :     }
     187             : 
     188          48 :     if (!m_layerName.empty())
     189             :     {
     190          22 :         aosOptions.AddString("-l");
     191          22 :         aosOptions.AddString(m_layerName.c_str());
     192             :     }
     193             : 
     194          48 :     if (!m_where.empty())
     195             :     {
     196           1 :         aosOptions.AddString("-where");
     197           1 :         aosOptions.AddString(m_where.c_str());
     198             :     }
     199             : 
     200          48 :     if (!m_sql.empty())
     201             :     {
     202           7 :         aosOptions.AddString("-sql");
     203           7 :         aosOptions.AddString(m_sql.c_str());
     204             :     }
     205             : 
     206          48 :     if (!m_dialect.empty())
     207             :     {
     208           3 :         aosOptions.AddString("-dialect");
     209           3 :         aosOptions.AddString(m_dialect.c_str());
     210             :     }
     211             : 
     212          96 :     std::string outputFilename;
     213          48 :     if (m_standaloneStep)
     214             :     {
     215          47 :         outputFilename = m_outputDataset.GetName();
     216          47 :         if (!m_format.empty())
     217             :         {
     218           5 :             aosOptions.AddString("-of");
     219           5 :             aosOptions.AddString(m_format.c_str());
     220             :         }
     221             : 
     222          48 :         for (const std::string &co : m_creationOptions)
     223             :         {
     224           1 :             aosOptions.AddString("-co");
     225           1 :             aosOptions.AddString(co.c_str());
     226             :         }
     227             :     }
     228             :     else
     229             :     {
     230           1 :         outputFilename = CPLGenerateTempFilenameSafe("_rasterize.tif");
     231             : 
     232           1 :         aosOptions.AddString("-of");
     233           1 :         aosOptions.AddString("GTiff");
     234             : 
     235           1 :         aosOptions.AddString("-co");
     236           1 :         aosOptions.AddString("TILED=YES");
     237             :     }
     238             : 
     239          48 :     if (!std::isnan(m_nodata))
     240             :     {
     241           2 :         if (m_update)
     242             :         {
     243           1 :             ReportError(
     244             :                 CE_Failure, CPLE_AppDefined,
     245             :                 "Cannot specify --nodata when updating an existing raster.");
     246           1 :             return false;
     247             :         }
     248           1 :         aosOptions.AddString("-a_nodata");
     249           1 :         aosOptions.AddString(CPLSPrintf("%.17g", m_nodata));
     250             :     }
     251             : 
     252          47 :     if (m_initValues.size())
     253             :     {
     254          36 :         for (double initValue : m_initValues)
     255             :         {
     256          27 :             aosOptions.AddString("-init");
     257          27 :             aosOptions.AddString(CPLSPrintf("%.17g", initValue));
     258             :         }
     259             :     }
     260             : 
     261          47 :     if (!m_srs.empty())
     262             :     {
     263           2 :         if (m_update)
     264             :         {
     265           1 :             ReportError(
     266             :                 CE_Failure, CPLE_AppDefined,
     267             :                 "Cannot specify --crs when updating an existing raster.");
     268           1 :             return false;
     269             :         }
     270           1 :         aosOptions.AddString("-a_srs");
     271           1 :         aosOptions.AddString(m_srs.c_str());
     272             :     }
     273             : 
     274          46 :     if (m_transformerOption.size())
     275             :     {
     276           0 :         for (const auto &to : m_transformerOption)
     277             :         {
     278           0 :             aosOptions.AddString("-to");
     279           0 :             aosOptions.AddString(to.c_str());
     280             :         }
     281             :     }
     282             : 
     283          46 :     if (m_targetExtent.size())
     284             :     {
     285           1 :         aosOptions.AddString("-te");
     286           5 :         for (double targetExtent : m_targetExtent)
     287             :         {
     288           4 :             aosOptions.AddString(CPLSPrintf("%.17g", targetExtent));
     289             :         }
     290             :     }
     291             : 
     292          46 :     if (m_tap)
     293             :     {
     294           1 :         aosOptions.AddString("-tap");
     295             :     }
     296             : 
     297          46 :     if (m_targetResolution.size())
     298             :     {
     299           7 :         if (m_update)
     300             :         {
     301           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     302             :                         "Cannot specify --resolution when updating an existing "
     303             :                         "raster.");
     304           1 :             return false;
     305             :         }
     306           6 :         aosOptions.AddString("-tr");
     307          18 :         for (double targetResolution : m_targetResolution)
     308             :         {
     309          12 :             aosOptions.AddString(CPLSPrintf("%.17g", targetResolution));
     310             :         }
     311             :     }
     312          39 :     else if (m_targetSize.size())
     313             :     {
     314          20 :         if (m_update)
     315             :         {
     316           1 :             ReportError(
     317             :                 CE_Failure, CPLE_AppDefined,
     318             :                 "Cannot specify --size when updating an existing raster.");
     319           1 :             return false;
     320             :         }
     321          19 :         aosOptions.AddString("-ts");
     322          57 :         for (int targetSize : m_targetSize)
     323             :         {
     324          38 :             aosOptions.AddString(CPLSPrintf("%d", targetSize));
     325             :         }
     326             :     }
     327          19 :     else if (m_outputDataset.GetDatasetRef() == nullptr)
     328             :     {
     329           3 :         ReportError(
     330             :             CE_Failure, CPLE_AppDefined,
     331             :             "Must specify output resolution (--resolution) or size (--size) "
     332             :             "when writing rasterized features to a new dataset.");
     333           3 :         return false;
     334             :     }
     335             : 
     336          41 :     if (!m_outputType.empty())
     337             :     {
     338           2 :         if (m_update)
     339             :         {
     340           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     341             :                         "Cannot specify --output-data-type when updating an "
     342             :                         "existing raster.");
     343           1 :             return false;
     344             :         }
     345           1 :         aosOptions.AddString("-ot");
     346           1 :         aosOptions.AddString(m_outputType.c_str());
     347             :     }
     348             : 
     349          40 :     if (!m_optimization.empty())
     350             :     {
     351          40 :         aosOptions.AddString("-optim");
     352          40 :         aosOptions.AddString(m_optimization.c_str());
     353             :     }
     354             : 
     355          40 :     bool bOK = false;
     356             :     std::unique_ptr<GDALRasterizeOptions, decltype(&GDALRasterizeOptionsFree)>
     357             :         psOptions{GDALRasterizeOptionsNew(aosOptions.List(), nullptr),
     358          40 :                   GDALRasterizeOptionsFree};
     359          40 :     if (psOptions)
     360             :     {
     361          37 :         GDALRasterizeOptionsSetProgress(psOptions.get(), ctxt.m_pfnProgress,
     362             :                                         ctxt.m_pProgressData);
     363             : 
     364             :         GDALDatasetH hDstDS =
     365          37 :             GDALDataset::ToHandle(m_outputDataset.GetDatasetRef());
     366             : 
     367          37 :         GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
     368             : 
     369          37 :         auto poRetDS = GDALDataset::FromHandle(GDALRasterize(
     370          37 :             outputFilename.c_str(), hDstDS, hSrcDS, psOptions.get(), nullptr));
     371          37 :         bOK = poRetDS != nullptr;
     372             : 
     373          37 :         if (!hDstDS)
     374             :         {
     375          24 :             if (!m_standaloneStep && poRetDS)
     376             :             {
     377           1 :                 VSIUnlink(outputFilename.c_str());
     378           1 :                 poRetDS->MarkSuppressOnClose();
     379             :             }
     380             : 
     381          24 :             m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
     382             :         }
     383             :     }
     384             : 
     385          40 :     return bOK;
     386             : }
     387             : 
     388             : /************************************************************************/
     389             : /*               GDALVectorRasterizeAlgorithm::RunImpl()                */
     390             : /************************************************************************/
     391             : 
     392          47 : bool GDALVectorRasterizeAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
     393             :                                            void *pProgressData)
     394             : {
     395          47 :     GDALPipelineStepRunContext stepCtxt;
     396          47 :     stepCtxt.m_pfnProgress = pfnProgress;
     397          47 :     stepCtxt.m_pProgressData = pProgressData;
     398          47 :     return RunPreStepPipelineValidations() && RunStep(stepCtxt);
     399             : }
     400             : 
     401             : GDALVectorRasterizeAlgorithmStandalone::
     402             :     ~GDALVectorRasterizeAlgorithmStandalone() = default;
     403             : 
     404             : //! @endcond

Generated by: LCOV version 1.14