Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "raster index" subcommand
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_raster_index.h"
14 :
15 : #include "cpl_conv.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_utils_priv.h"
18 : #include "ogrsf_frmts.h"
19 :
20 : //! @cond Doxygen_Suppress
21 :
22 : #ifndef _
23 : #define _(x) (x)
24 : #endif
25 :
26 : /************************************************************************/
27 : /* GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm() */
28 : /************************************************************************/
29 :
30 21 : GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm()
31 21 : : GDALVectorOutputAbstractAlgorithm(NAME, DESCRIPTION, HELP_URL)
32 : {
33 21 : AddProgressArg();
34 21 : AddInputDatasetArg(&m_inputDatasets, GDAL_OF_RASTER)
35 21 : .SetAutoOpenDataset(false)
36 21 : .SetDatasetInputFlags(GADV_NAME);
37 21 : GDALVectorOutputAbstractAlgorithm::AddAllOutputArgs();
38 :
39 21 : AddCommonOptions();
40 :
41 : AddArg("source-crs-field-name", 0,
42 : _("Name of the field to store the CRS of each dataset"),
43 42 : &m_sourceCrsName)
44 21 : .SetMinCharCount(1);
45 : AddArg("source-crs-format", 0,
46 : _("Format in which the CRS of each dataset must be written"),
47 42 : &m_sourceCrsFormat)
48 21 : .SetMinCharCount(1)
49 21 : .SetDefault(m_sourceCrsFormat)
50 21 : .SetChoices("auto", "WKT", "EPSG", "PROJ");
51 21 : }
52 :
53 : /************************************************************************/
54 : /* GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm() */
55 : /************************************************************************/
56 :
57 19 : GDALRasterIndexAlgorithm::GDALRasterIndexAlgorithm(
58 : const std::string &name, const std::string &description,
59 19 : const std::string &helpURL)
60 19 : : GDALVectorOutputAbstractAlgorithm(name, description, helpURL)
61 : {
62 19 : }
63 :
64 : /************************************************************************/
65 : /* GDALRasterIndexAlgorithm::AddCommonOptions() */
66 : /************************************************************************/
67 :
68 40 : void GDALRasterIndexAlgorithm::AddCommonOptions()
69 : {
70 : AddArg("recursive", 0,
71 : _("Whether input directories should be explored recursively."),
72 40 : &m_recursive);
73 : AddArg("filename-filter", 0,
74 : _("Pattern that the filenames in input directories should follow "
75 : "('*' and '?' wildcard)"),
76 40 : &m_filenameFilter);
77 : AddArg("min-pixel-size", 0,
78 : _("Minimum pixel size in term of geospatial extent per pixel "
79 : "(resolution) that a raster should have to be selected."),
80 80 : &m_minPixelSize)
81 40 : .SetMinValueExcluded(0);
82 : AddArg("max-pixel-size", 0,
83 : _("Maximum pixel size in term of geospatial extent per pixel "
84 : "(resolution) that a raster should have to be selected."),
85 80 : &m_maxPixelSize)
86 40 : .SetMinValueExcluded(0);
87 : AddArg("location-name", 0, _("Name of the field with the raster path"),
88 80 : &m_locationName)
89 40 : .SetDefault(m_locationName)
90 40 : .SetMinCharCount(1);
91 : AddAbsolutePathArg(
92 : &m_writeAbsolutePaths,
93 : _("Whether the path to the input datasets should be stored as an "
94 40 : "absolute path"));
95 80 : AddArg("dst-crs", 0, _("Destination CRS"), &m_crs)
96 80 : .SetIsCRSArg()
97 40 : .AddHiddenAlias("t_srs");
98 :
99 : {
100 : auto &arg =
101 80 : AddArg("metadata", 0, _("Add dataset metadata item"), &m_metadata)
102 80 : .SetMetaVar("<KEY>=<VALUE>")
103 40 : .SetPackedValuesAllowed(false);
104 1 : arg.AddValidationAction([this, &arg]()
105 41 : { return ParseAndValidateKeyValue(arg); });
106 40 : arg.AddHiddenAlias("mo");
107 : }
108 :
109 : AddArg("skip-errors", 0, _("Skip errors related to input datasets"),
110 40 : &m_skipErrors);
111 40 : }
112 :
113 : /************************************************************************/
114 : /* GDALRasterIndexAlgorithm::RunImpl() */
115 : /************************************************************************/
116 :
117 21 : bool GDALRasterIndexAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
118 : void *pProgressData)
119 : {
120 42 : CPLStringList aosSources;
121 41 : for (auto &srcDS : m_inputDatasets)
122 : {
123 21 : if (srcDS.GetDatasetRef())
124 : {
125 1 : ReportError(
126 : CE_Failure, CPLE_IllegalArg,
127 : "Input datasets must be provided by name, not as object");
128 1 : return false;
129 : }
130 20 : aosSources.push_back(srcDS.GetName());
131 : }
132 :
133 40 : auto setupRet = SetupOutputDataset();
134 20 : if (!setupRet.outDS)
135 1 : return false;
136 :
137 19 : if (!SetDefaultOutputLayerNameIfNeeded(setupRet.outDS))
138 1 : return false;
139 :
140 36 : CPLStringList aosOptions;
141 18 : aosOptions.push_back("--invoked-from-gdal-raster-index");
142 :
143 18 : if (m_skipErrors)
144 : {
145 2 : aosOptions.push_back("-skip_errors");
146 : }
147 18 : if (m_recursive)
148 : {
149 1 : aosOptions.push_back("-recursive");
150 : }
151 20 : for (const std::string &s : m_filenameFilter)
152 : {
153 2 : aosOptions.push_back("-filename_filter");
154 2 : aosOptions.push_back(s);
155 : }
156 18 : if (m_minPixelSize > 0)
157 : {
158 2 : aosOptions.push_back("-min_pixel_size");
159 2 : aosOptions.push_back(CPLSPrintf("%.17g", m_minPixelSize));
160 : }
161 18 : if (m_maxPixelSize > 0)
162 : {
163 0 : aosOptions.push_back("-max_pixel_size");
164 0 : aosOptions.push_back(CPLSPrintf("%.17g", m_maxPixelSize));
165 : }
166 :
167 18 : if (!m_outputLayerName.empty())
168 : {
169 18 : aosOptions.push_back("-lyr_name");
170 18 : aosOptions.push_back(m_outputLayerName);
171 : }
172 :
173 18 : aosOptions.push_back("-tileindex");
174 18 : aosOptions.push_back(m_locationName);
175 :
176 18 : if (m_writeAbsolutePaths)
177 : {
178 1 : aosOptions.push_back("-write_absolute_path");
179 : }
180 18 : if (m_crs.empty())
181 : {
182 15 : if (m_sourceCrsName.empty())
183 15 : aosOptions.push_back("-skip_different_projection");
184 : }
185 : else
186 : {
187 3 : aosOptions.push_back("-t_srs");
188 3 : aosOptions.push_back(m_crs);
189 : }
190 18 : if (!m_sourceCrsName.empty())
191 : {
192 1 : aosOptions.push_back("-src_srs_name");
193 1 : aosOptions.push_back(m_sourceCrsName);
194 :
195 1 : aosOptions.push_back("-src_srs_format");
196 1 : aosOptions.push_back(CPLString(m_sourceCrsFormat).toupper());
197 : }
198 :
199 19 : for (const std::string &s : m_metadata)
200 : {
201 1 : aosOptions.push_back("-mo");
202 1 : aosOptions.push_back(s);
203 : }
204 :
205 18 : if (!AddExtraOptions(aosOptions))
206 2 : return false;
207 :
208 : std::unique_ptr<GDALTileIndexOptions, decltype(&GDALTileIndexOptionsFree)>
209 : options(GDALTileIndexOptionsNew(aosOptions.List(), nullptr),
210 16 : GDALTileIndexOptionsFree);
211 :
212 16 : if (options)
213 : {
214 16 : GDALTileIndexOptionsSetProgress(options.get(), pfnProgress,
215 : pProgressData);
216 : }
217 :
218 : const bool ret =
219 32 : options && GDALTileIndexInternal(m_outputDataset.GetName().c_str(),
220 : GDALDataset::ToHandle(setupRet.outDS),
221 : OGRLayer::ToHandle(setupRet.layer),
222 16 : aosSources.size(), aosSources.List(),
223 32 : options.get(), nullptr) != nullptr;
224 :
225 16 : if (ret && setupRet.newDS)
226 : {
227 12 : m_outputDataset.Set(std::move(setupRet.newDS));
228 : }
229 :
230 16 : return ret;
231 : }
232 :
233 : //! @endcond
|