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