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

Generated by: LCOV version 1.14