Coverage Report

Created: 2026-02-14 06:52

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
    AddProgressArg();
40
0
    if (bStandaloneStep)
41
0
    {
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
    AddArg("resolution", 0, _("Set the target resolution"), &m_targetResolution)
97
0
        .SetMinCount(2)
98
0
        .SetMaxCount(2)
99
0
        .SetRepeatedArgAllowed(false)
100
0
        .SetMetaVar("<xres>,<yres>")
101
0
        .SetMutualExclusionGroup("size-or-resolution");
102
0
    AddArg("target-aligned-pixels", 0,
103
0
           _("(target aligned pixels) Align the coordinates of the extent of "
104
0
             "the output file to the values of the resolution"),
105
0
           &m_tap)
106
0
        .AddAlias("tap");
107
0
    AddArg("size", 0, _("Set the target size in pixels and lines"),
108
0
           &m_targetSize)
109
0
        .SetMinCount(2)
110
0
        .SetMaxCount(2)
111
0
        .SetRepeatedArgAllowed(false)
112
0
        .SetMetaVar("<xsize>,<ysize>")
113
0
        .SetMutualExclusionGroup("size-or-resolution");
114
0
    AddOutputDataTypeArg(&m_outputType);
115
0
    AddArg("optimization", 0,
116
0
           _("Force the algorithm used (results are identical)"),
117
0
           &m_optimization)
118
0
        .SetChoices("AUTO", "RASTER", "VECTOR")
119
0
        .SetDefault("AUTO");
120
121
0
    if (bStandaloneStep)
122
0
    {
123
0
        auto &addArg = AddArg("add", 0, _("Add to existing raster"), &m_add)
124
0
                           .SetDefault(false);
125
0
        auto &updateArg = AddUpdateArg(&m_update);
126
0
        addArg.AddValidationAction(
127
0
            [&updateArg]()
128
0
            {
129
0
                updateArg.Set(true);
130
0
                return true;
131
0
            });
132
0
    }
133
0
}
134
135
/************************************************************************/
136
/*               GDALVectorRasterizeAlgorithm::RunStep()                */
137
/************************************************************************/
138
139
bool GDALVectorRasterizeAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
140
0
{
141
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
142
0
    CPLAssert(poSrcDS);
143
144
0
    CPLStringList aosOptions;
145
146
0
    if (m_bands.size())
147
0
    {
148
0
        for (int band : m_bands)
149
0
        {
150
0
            aosOptions.AddString("-b");
151
0
            aosOptions.AddString(CPLSPrintf("%d", band));
152
0
        }
153
0
    }
154
155
0
    if (m_invert)
156
0
    {
157
0
        aosOptions.AddString("-i");
158
0
    }
159
160
0
    if (m_allTouched)
161
0
    {
162
0
        aosOptions.AddString("-at");
163
0
    }
164
165
0
    if (m_burnValues.size())
166
0
    {
167
0
        for (double burnValue : m_burnValues)
168
0
        {
169
0
            aosOptions.AddString("-burn");
170
0
            aosOptions.AddString(CPLSPrintf("%.17g", burnValue));
171
0
        }
172
0
    }
173
174
0
    if (!m_attributeName.empty())
175
0
    {
176
0
        aosOptions.AddString("-a");
177
0
        aosOptions.AddString(m_attributeName.c_str());
178
0
    }
179
180
0
    if (m_3d)
181
0
    {
182
0
        aosOptions.AddString("-3d");
183
0
    }
184
185
0
    if (m_add)
186
0
    {
187
0
        aosOptions.AddString("-add");
188
        // Implies update
189
0
        m_update = true;
190
0
    }
191
192
0
    if (!m_layerName.empty())
193
0
    {
194
0
        aosOptions.AddString("-l");
195
0
        aosOptions.AddString(m_layerName.c_str());
196
0
    }
197
198
0
    if (!m_where.empty())
199
0
    {
200
0
        aosOptions.AddString("-where");
201
0
        aosOptions.AddString(m_where.c_str());
202
0
    }
203
204
0
    if (!m_sql.empty())
205
0
    {
206
0
        aosOptions.AddString("-sql");
207
0
        aosOptions.AddString(m_sql.c_str());
208
0
    }
209
210
0
    if (!m_dialect.empty())
211
0
    {
212
0
        aosOptions.AddString("-dialect");
213
0
        aosOptions.AddString(m_dialect.c_str());
214
0
    }
215
216
0
    std::string outputFilename;
217
0
    if (m_standaloneStep)
218
0
    {
219
0
        outputFilename = m_outputDataset.GetName();
220
0
        if (!m_format.empty())
221
0
        {
222
0
            aosOptions.AddString("-of");
223
0
            aosOptions.AddString(m_format.c_str());
224
0
        }
225
226
0
        for (const std::string &co : m_creationOptions)
227
0
        {
228
0
            aosOptions.AddString("-co");
229
0
            aosOptions.AddString(co.c_str());
230
0
        }
231
0
    }
232
0
    else
233
0
    {
234
0
        outputFilename = CPLGenerateTempFilenameSafe("_rasterize.tif");
235
236
0
        aosOptions.AddString("-of");
237
0
        aosOptions.AddString("GTiff");
238
239
0
        aosOptions.AddString("-co");
240
0
        aosOptions.AddString("TILED=YES");
241
0
    }
242
243
0
    if (!std::isnan(m_nodata))
244
0
    {
245
0
        if (m_update)
246
0
        {
247
0
            ReportError(
248
0
                CE_Failure, CPLE_AppDefined,
249
0
                "Cannot specify --nodata when updating an existing raster.");
250
0
            return false;
251
0
        }
252
0
        aosOptions.AddString("-a_nodata");
253
0
        aosOptions.AddString(CPLSPrintf("%.17g", m_nodata));
254
0
    }
255
256
0
    if (m_initValues.size())
257
0
    {
258
0
        for (double initValue : m_initValues)
259
0
        {
260
0
            aosOptions.AddString("-init");
261
0
            aosOptions.AddString(CPLSPrintf("%.17g", initValue));
262
0
        }
263
0
    }
264
265
0
    if (!m_srs.empty())
266
0
    {
267
0
        if (m_update)
268
0
        {
269
0
            ReportError(
270
0
                CE_Failure, CPLE_AppDefined,
271
0
                "Cannot specify --crs when updating an existing raster.");
272
0
            return false;
273
0
        }
274
0
        aosOptions.AddString("-a_srs");
275
0
        aosOptions.AddString(m_srs.c_str());
276
0
    }
277
278
0
    if (m_transformerOption.size())
279
0
    {
280
0
        for (const auto &to : m_transformerOption)
281
0
        {
282
0
            aosOptions.AddString("-to");
283
0
            aosOptions.AddString(to.c_str());
284
0
        }
285
0
    }
286
287
0
    if (m_targetExtent.size())
288
0
    {
289
0
        aosOptions.AddString("-te");
290
0
        for (double targetExtent : m_targetExtent)
291
0
        {
292
0
            aosOptions.AddString(CPLSPrintf("%.17g", targetExtent));
293
0
        }
294
0
    }
295
296
0
    if (m_tap)
297
0
    {
298
0
        aosOptions.AddString("-tap");
299
0
    }
300
301
0
    if (m_targetResolution.size())
302
0
    {
303
0
        if (m_update)
304
0
        {
305
0
            ReportError(CE_Failure, CPLE_AppDefined,
306
0
                        "Cannot specify --resolution when updating an existing "
307
0
                        "raster.");
308
0
            return false;
309
0
        }
310
0
        aosOptions.AddString("-tr");
311
0
        for (double targetResolution : m_targetResolution)
312
0
        {
313
0
            aosOptions.AddString(CPLSPrintf("%.17g", targetResolution));
314
0
        }
315
0
    }
316
0
    else if (m_targetSize.size())
317
0
    {
318
0
        if (m_update)
319
0
        {
320
0
            ReportError(
321
0
                CE_Failure, CPLE_AppDefined,
322
0
                "Cannot specify --size when updating an existing raster.");
323
0
            return false;
324
0
        }
325
0
        aosOptions.AddString("-ts");
326
0
        for (int targetSize : m_targetSize)
327
0
        {
328
0
            aosOptions.AddString(CPLSPrintf("%d", targetSize));
329
0
        }
330
0
    }
331
0
    else if (m_outputDataset.GetDatasetRef() == nullptr)
332
0
    {
333
0
        ReportError(
334
0
            CE_Failure, CPLE_AppDefined,
335
0
            "Must specify output resolution (--resolution) or size (--size) "
336
0
            "when writing rasterized features to a new dataset.");
337
0
        return false;
338
0
    }
339
340
0
    if (!m_outputType.empty())
341
0
    {
342
0
        if (m_update)
343
0
        {
344
0
            ReportError(CE_Failure, CPLE_AppDefined,
345
0
                        "Cannot specify --output-data-type when updating an "
346
0
                        "existing raster.");
347
0
            return false;
348
0
        }
349
0
        aosOptions.AddString("-ot");
350
0
        aosOptions.AddString(m_outputType.c_str());
351
0
    }
352
353
0
    if (!m_optimization.empty())
354
0
    {
355
0
        aosOptions.AddString("-optim");
356
0
        aosOptions.AddString(m_optimization.c_str());
357
0
    }
358
359
0
    bool bOK = false;
360
0
    std::unique_ptr<GDALRasterizeOptions, decltype(&GDALRasterizeOptionsFree)>
361
0
        psOptions{GDALRasterizeOptionsNew(aosOptions.List(), nullptr),
362
0
                  GDALRasterizeOptionsFree};
363
0
    if (psOptions)
364
0
    {
365
0
        GDALRasterizeOptionsSetProgress(psOptions.get(), ctxt.m_pfnProgress,
366
0
                                        ctxt.m_pProgressData);
367
368
0
        GDALDatasetH hDstDS =
369
0
            GDALDataset::ToHandle(m_outputDataset.GetDatasetRef());
370
371
0
        GDALDatasetH hSrcDS = GDALDataset::ToHandle(poSrcDS);
372
373
0
        auto poRetDS = GDALDataset::FromHandle(GDALRasterize(
374
0
            outputFilename.c_str(), hDstDS, hSrcDS, psOptions.get(), nullptr));
375
0
        bOK = poRetDS != nullptr;
376
377
0
        if (!hDstDS)
378
0
        {
379
0
            if (!m_standaloneStep && poRetDS)
380
0
            {
381
0
                VSIUnlink(outputFilename.c_str());
382
0
                poRetDS->MarkSuppressOnClose();
383
0
            }
384
385
0
            m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
386
0
        }
387
0
    }
388
389
0
    return bOK;
390
0
}
391
392
/************************************************************************/
393
/*               GDALVectorRasterizeAlgorithm::RunImpl()                */
394
/************************************************************************/
395
396
bool GDALVectorRasterizeAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
397
                                           void *pProgressData)
398
0
{
399
0
    GDALPipelineStepRunContext stepCtxt;
400
0
    stepCtxt.m_pfnProgress = pfnProgress;
401
0
    stepCtxt.m_pProgressData = pProgressData;
402
0
    return RunPreStepPipelineValidations() && RunStep(stepCtxt);
403
0
}
404
405
GDALVectorRasterizeAlgorithmStandalone::
406
0
    ~GDALVectorRasterizeAlgorithmStandalone() = default;
407
408
//! @endcond