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