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