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
|