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