Coverage Report

Created: 2026-06-30 08:33

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