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