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