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