Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "mdim convert" 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_mdim_convert.h"
14 :
15 : #include "cpl_conv.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_utils.h"
18 :
19 : //! @cond Doxygen_Suppress
20 :
21 : #ifndef _
22 : #define _(x) (x)
23 : #endif
24 :
25 : /************************************************************************/
26 : /* GDALMdimConvertAlgorithm::GDALMdimConvertAlgorithm() */
27 : /************************************************************************/
28 :
29 61 : GDALMdimConvertAlgorithm::GDALMdimConvertAlgorithm()
30 : : GDALMdimPipelineStepAlgorithm(
31 : NAME, DESCRIPTION, HELP_URL,
32 0 : ConstructorOptions()
33 61 : .SetStandaloneStep(true)
34 61 : .SetInputDatasetMaxCount(1)
35 61 : .SetAddDefaultArguments(false)
36 122 : .SetMdimOutputAcceptsClassicRaster(true))
37 : {
38 61 : AddMdimInputArgs(false, false, /* acceptRaster = */ true);
39 61 : AddProgressArg();
40 61 : AddMdimOutputArgs(false);
41 :
42 : {
43 : auto &arg = AddArg("array", 0,
44 : _("Select a single array instead of converting the "
45 : "whole dataset."),
46 122 : &m_arrays)
47 122 : .SetMetaVar("<ARRAY-SPEC>")
48 61 : .SetPackedValuesAllowed(false);
49 :
50 : arg.SetAutoCompleteFunction(
51 3 : [this](const std::string &)
52 : {
53 1 : std::vector<std::string> ret;
54 1 : if (m_inputDataset.size() == 1)
55 : {
56 1 : if (auto poDS =
57 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
58 1 : m_inputDataset[0].GetName().c_str(),
59 : GDAL_OF_MULTIDIM_RASTER, nullptr, nullptr,
60 2 : nullptr)))
61 : {
62 2 : if (auto poRG = poDS->GetRootGroup())
63 : {
64 1 : ret = poRG->GetMDArrayFullNamesRecursive();
65 : }
66 : }
67 : }
68 :
69 1 : return ret;
70 61 : });
71 : }
72 :
73 : {
74 : auto &arg = AddArg("array-option", 0,
75 : _("Option passed to GDALGroup::GetMDArrayNames() to "
76 : "filter arrays."),
77 122 : &m_arrayOptions)
78 122 : .SetMetaVar("<KEY>=<VALUE>")
79 61 : .SetPackedValuesAllowed(false);
80 3 : arg.AddValidationAction([this, &arg]()
81 64 : { return ParseAndValidateKeyValue(arg); });
82 :
83 : arg.SetAutoCompleteFunction(
84 3 : [this](const std::string ¤tValue)
85 : {
86 1 : std::vector<std::string> ret;
87 1 : if (m_inputDataset.size() == 1)
88 : {
89 1 : if (auto poDS =
90 : std::unique_ptr<GDALDataset>(GDALDataset::Open(
91 1 : m_inputDataset[0].GetName().c_str(),
92 : GDAL_OF_MULTIDIM_RASTER, nullptr, nullptr,
93 2 : nullptr)))
94 : {
95 1 : if (auto poDriver = poDS->GetDriver())
96 : {
97 1 : if (const char *pszXML = poDriver->GetMetadataItem(
98 1 : GDAL_DMD_MULTIDIM_ARRAY_OPENOPTIONLIST))
99 : {
100 1 : AddOptionsSuggestions(pszXML, 0, currentValue,
101 : ret);
102 : }
103 : }
104 : }
105 : }
106 :
107 1 : return ret;
108 61 : });
109 : }
110 :
111 : AddArg("group", 0,
112 : _("Select a single group instead of converting the whole dataset."),
113 122 : &m_groups)
114 122 : .SetMetaVar("<GROUP-SPEC>")
115 61 : .SetPackedValuesAllowed(false);
116 :
117 122 : AddArg("subset", 0, _("Select a subset of the data."), &m_subsets)
118 122 : .SetMetaVar("<SUBSET-SPEC>")
119 61 : .SetPackedValuesAllowed(false);
120 :
121 : AddArg("scale-axes", 0,
122 : _("Applies a integral scale factor to one or several dimensions"),
123 122 : &m_scaleAxes)
124 122 : .SetMetaVar("<SCALEAXES-SPEC>")
125 61 : .SetPackedValuesAllowed(false);
126 :
127 61 : AddArg("strict", 0, _("Turn warnings into failures."), &m_strict);
128 61 : }
129 :
130 : /************************************************************************/
131 : /* GDALMdimConvertAlgorithm::RunImpl() */
132 : /************************************************************************/
133 :
134 14 : bool GDALMdimConvertAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
135 : void *pProgressData)
136 : {
137 14 : GDALPipelineStepRunContext stepCtxt;
138 14 : stepCtxt.m_pfnProgress = pfnProgress;
139 14 : stepCtxt.m_pProgressData = pProgressData;
140 14 : return RunPreStepPipelineValidations() && RunStep(stepCtxt);
141 : }
142 :
143 : /************************************************************************/
144 : /* GDALMdimConvertAlgorithm::RunStep() */
145 : /************************************************************************/
146 :
147 14 : bool GDALMdimConvertAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
148 : {
149 14 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
150 14 : CPLAssert(poSrcDS);
151 :
152 14 : CPLAssert(!m_outputDataset.GetDatasetRef());
153 :
154 28 : CPLStringList aosOptions;
155 14 : if (!m_format.empty())
156 : {
157 4 : aosOptions.AddString("-of");
158 4 : aosOptions.AddString(m_format.c_str());
159 : }
160 14 : if (m_overwrite)
161 : {
162 1 : aosOptions.AddString("--overwrite");
163 : }
164 : else
165 : {
166 13 : aosOptions.AddString("--no-overwrite");
167 : }
168 14 : if (m_strict)
169 : {
170 1 : aosOptions.AddString("-strict");
171 : }
172 19 : for (const auto &array : m_arrays)
173 : {
174 5 : aosOptions.AddString("-array");
175 5 : aosOptions.AddString(array.c_str());
176 : }
177 15 : for (const auto &opt : m_arrayOptions)
178 : {
179 1 : aosOptions.AddString("-arrayoption");
180 1 : aosOptions.AddString(opt.c_str());
181 : }
182 15 : for (const auto &group : m_groups)
183 : {
184 1 : aosOptions.AddString("-group");
185 1 : aosOptions.AddString(group.c_str());
186 : }
187 16 : for (const auto &subset : m_subsets)
188 : {
189 2 : aosOptions.AddString("-subset");
190 2 : aosOptions.AddString(subset.c_str());
191 : }
192 :
193 28 : std::string scaleAxes;
194 15 : for (const auto &scaleAxis : m_scaleAxes)
195 : {
196 1 : if (!scaleAxes.empty())
197 0 : scaleAxes += ',';
198 1 : scaleAxes += scaleAxis;
199 : }
200 14 : if (!scaleAxes.empty())
201 : {
202 1 : aosOptions.AddString("-scaleaxes");
203 1 : aosOptions.AddString(scaleAxes.c_str());
204 : }
205 :
206 15 : for (const auto &co : m_creationOptions)
207 : {
208 1 : aosOptions.AddString("-co");
209 1 : aosOptions.AddString(co.c_str());
210 : }
211 :
212 : GDALMultiDimTranslateOptions *psOptions =
213 14 : GDALMultiDimTranslateOptionsNew(aosOptions.List(), nullptr);
214 14 : auto pfnProgress = ctxt.m_pfnProgress;
215 14 : auto pProgressData = ctxt.m_pProgressData;
216 14 : GDALMultiDimTranslateOptionsSetProgress(psOptions, pfnProgress,
217 : pProgressData);
218 :
219 14 : auto hSrcDS = GDALDataset::ToHandle(poSrcDS);
220 : auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle(
221 14 : GDALMultiDimTranslate(m_outputDataset.GetName().c_str(), nullptr, 1,
222 28 : &hSrcDS, psOptions, nullptr)));
223 14 : GDALMultiDimTranslateOptionsFree(psOptions);
224 14 : if (!poOutDS)
225 1 : return false;
226 :
227 13 : m_outputDataset.Set(std::move(poOutDS));
228 :
229 13 : return true;
230 : }
231 :
232 : //! @endcond
|