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