Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "reproject" step of "raster pipeline"
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_raster_reproject.h"
14 :
15 : #include "gdal_alg.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_utils.h"
18 : #include "gdalwarper.h"
19 :
20 : #include <cmath>
21 :
22 : //! @cond Doxygen_Suppress
23 :
24 : #ifndef _
25 : #define _(x) (x)
26 : #endif
27 :
28 : /************************************************************************/
29 : /* GDALRasterReprojectAlgorithm::GDALRasterReprojectAlgorithm() */
30 : /************************************************************************/
31 :
32 46 : GDALRasterReprojectAlgorithm::GDALRasterReprojectAlgorithm(bool standaloneStep)
33 : : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
34 46 : standaloneStep)
35 : {
36 92 : AddArg("src-crs", 's', _("Source CRS"), &m_srsCrs)
37 92 : .SetIsCRSArg()
38 46 : .AddHiddenAlias("s_srs");
39 92 : AddArg("dst-crs", 'd', _("Destination CRS"), &m_dstCrs)
40 92 : .SetIsCRSArg()
41 46 : .AddHiddenAlias("t_srs");
42 92 : AddArg("resampling", 'r', _("Resampling method"), &m_resampling)
43 : .SetChoices("nearest", "bilinear", "cubic", "cubicspline", "lanczos",
44 : "average", "rms", "mode", "min", "max", "med", "q1", "q3",
45 46 : "sum")
46 46 : .SetDefault("nearest")
47 46 : .SetHiddenChoices("near");
48 :
49 : AddArg("resolution", 0, _("Target resolution (in destination CRS units)"),
50 92 : &m_resolution)
51 46 : .SetMinCount(2)
52 46 : .SetMaxCount(2)
53 46 : .SetMinValueExcluded(0)
54 46 : .SetRepeatedArgAllowed(false)
55 46 : .SetDisplayHintAboutRepetition(false)
56 92 : .SetMetaVar("<xres>,<yres>")
57 46 : .SetMutualExclusionGroup("resolution-size");
58 :
59 92 : AddArg("size", 0, _("Target size in pixels"), &m_size)
60 46 : .SetMinCount(2)
61 46 : .SetMaxCount(2)
62 46 : .SetMinValueIncluded(0)
63 46 : .SetRepeatedArgAllowed(false)
64 46 : .SetDisplayHintAboutRepetition(false)
65 92 : .SetMetaVar("<width>,<height>")
66 46 : .SetMutualExclusionGroup("resolution-size");
67 :
68 46 : AddBBOXArg(&m_bbox, _("Target bounding box (in destination CRS units)"));
69 92 : AddArg("bbox-crs", 0, _("CRS of target bounding box"), &m_bboxCrs)
70 92 : .SetIsCRSArg()
71 46 : .AddHiddenAlias("bbox_srs");
72 :
73 : AddArg("target-aligned-pixels", 0,
74 : _("Round target extent to target resolution"),
75 92 : &m_targetAlignedPixels)
76 92 : .AddHiddenAlias("tap")
77 46 : .SetCategory(GAAC_ADVANCED);
78 : AddArg("src-nodata", 0,
79 : _("Set nodata values for input bands ('None' to unset)."),
80 92 : &m_srcNoData)
81 46 : .SetMinCount(1)
82 46 : .SetRepeatedArgAllowed(false)
83 46 : .SetCategory(GAAC_ADVANCED);
84 : AddArg("dst-nodata", 0,
85 : _("Set nodata values for output bands ('None' to unset)."),
86 92 : &m_dstNoData)
87 46 : .SetMinCount(1)
88 46 : .SetRepeatedArgAllowed(false)
89 46 : .SetCategory(GAAC_ADVANCED);
90 : AddArg("add-alpha", 0,
91 : _("Adds an alpha mask band to the destination when the source "
92 : "raster have none."),
93 92 : &m_addAlpha)
94 46 : .SetCategory(GAAC_ADVANCED);
95 : {
96 : auto &arg =
97 92 : AddArg("warp-option", 0, _("Warping option(s)"), &m_warpOptions)
98 92 : .AddAlias("wo")
99 92 : .SetMetaVar("<NAME>=<VALUE>")
100 92 : .SetCategory(GAAC_ADVANCED)
101 46 : .SetPackedValuesAllowed(false);
102 1 : arg.AddValidationAction([this, &arg]()
103 47 : { return ParseAndValidateKeyValue(arg); });
104 : arg.SetAutoCompleteFunction(
105 0 : [](const std::string ¤tValue)
106 : {
107 0 : std::vector<std::string> ret;
108 0 : GDALAlgorithm::AddOptionsSuggestions(GDALWarpGetOptionList(), 0,
109 : currentValue, ret);
110 0 : return ret;
111 46 : });
112 : }
113 : {
114 : auto &arg = AddArg("transform-option", 0, _("Transform option(s)"),
115 92 : &m_transformOptions)
116 92 : .AddAlias("to")
117 92 : .SetMetaVar("<NAME>=<VALUE>")
118 92 : .SetCategory(GAAC_ADVANCED)
119 46 : .SetPackedValuesAllowed(false);
120 1 : arg.AddValidationAction([this, &arg]()
121 47 : { return ParseAndValidateKeyValue(arg); });
122 : arg.SetAutoCompleteFunction(
123 0 : [](const std::string ¤tValue)
124 : {
125 0 : std::vector<std::string> ret;
126 0 : GDALAlgorithm::AddOptionsSuggestions(
127 : GDALGetGenImgProjTranformerOptionList(), 0, currentValue,
128 : ret);
129 0 : return ret;
130 46 : });
131 : }
132 92 : AddArg("error-threshold", 0, _("Error threshold"), &m_errorThreshold)
133 92 : .AddAlias("et")
134 46 : .SetCategory(GAAC_ADVANCED);
135 46 : }
136 :
137 : /************************************************************************/
138 : /* GDALRasterReprojectAlgorithm::RunStep() */
139 : /************************************************************************/
140 :
141 16 : bool GDALRasterReprojectAlgorithm::RunStep(GDALProgressFunc, void *)
142 : {
143 16 : CPLAssert(m_inputDataset.GetDatasetRef());
144 16 : CPLAssert(m_outputDataset.GetName().empty());
145 16 : CPLAssert(!m_outputDataset.GetDatasetRef());
146 :
147 32 : CPLStringList aosOptions;
148 16 : aosOptions.AddString("-of");
149 16 : aosOptions.AddString("VRT");
150 16 : if (!m_srsCrs.empty())
151 : {
152 5 : aosOptions.AddString("-s_srs");
153 5 : aosOptions.AddString(m_srsCrs.c_str());
154 : }
155 16 : if (!m_dstCrs.empty())
156 : {
157 8 : aosOptions.AddString("-t_srs");
158 8 : aosOptions.AddString(m_dstCrs.c_str());
159 : }
160 16 : if (!m_resampling.empty())
161 : {
162 16 : aosOptions.AddString("-r");
163 16 : aosOptions.AddString(m_resampling.c_str());
164 : }
165 16 : if (!m_resolution.empty())
166 : {
167 1 : aosOptions.AddString("-tr");
168 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[0]));
169 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_resolution[1]));
170 : }
171 16 : if (!m_size.empty())
172 : {
173 1 : aosOptions.AddString("-ts");
174 1 : aosOptions.AddString(CPLSPrintf("%d", m_size[0]));
175 1 : aosOptions.AddString(CPLSPrintf("%d", m_size[1]));
176 : }
177 16 : if (!m_bbox.empty())
178 : {
179 2 : aosOptions.AddString("-te");
180 2 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[0]));
181 2 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[1]));
182 2 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[2]));
183 2 : aosOptions.AddString(CPLSPrintf("%.17g", m_bbox[3]));
184 : }
185 16 : if (!m_bboxCrs.empty())
186 : {
187 1 : aosOptions.AddString("-te_srs");
188 1 : aosOptions.AddString(m_bboxCrs.c_str());
189 : }
190 16 : if (m_targetAlignedPixels)
191 : {
192 1 : aosOptions.AddString("-tap");
193 : }
194 16 : if (!m_srcNoData.empty())
195 : {
196 1 : aosOptions.push_back("-srcnodata");
197 2 : std::string s;
198 2 : for (const std::string &v : m_srcNoData)
199 : {
200 1 : if (!s.empty())
201 0 : s += " ";
202 1 : s += v;
203 : }
204 1 : aosOptions.push_back(s);
205 : }
206 16 : if (!m_dstNoData.empty())
207 : {
208 2 : aosOptions.push_back("-dstnodata");
209 4 : std::string s;
210 5 : for (const std::string &v : m_dstNoData)
211 : {
212 3 : if (!s.empty())
213 1 : s += " ";
214 3 : s += v;
215 : }
216 2 : aosOptions.push_back(s);
217 : }
218 16 : if (m_addAlpha)
219 : {
220 1 : aosOptions.AddString("-dstalpha");
221 : }
222 17 : for (const std::string &opt : m_warpOptions)
223 : {
224 1 : aosOptions.AddString("-wo");
225 1 : aosOptions.AddString(opt.c_str());
226 : }
227 17 : for (const std::string &opt : m_transformOptions)
228 : {
229 1 : aosOptions.AddString("-to");
230 1 : aosOptions.AddString(opt.c_str());
231 : }
232 16 : if (std::isfinite(m_errorThreshold))
233 : {
234 1 : aosOptions.AddString("-et");
235 1 : aosOptions.AddString(CPLSPrintf("%.17g", m_errorThreshold));
236 : }
237 :
238 : GDALWarpAppOptions *psOptions =
239 16 : GDALWarpAppOptionsNew(aosOptions.List(), nullptr);
240 :
241 16 : GDALDatasetH hSrcDS = GDALDataset::ToHandle(m_inputDataset.GetDatasetRef());
242 16 : auto poRetDS = GDALDataset::FromHandle(
243 : GDALWarp("", nullptr, 1, &hSrcDS, psOptions, nullptr));
244 16 : GDALWarpAppOptionsFree(psOptions);
245 16 : if (!poRetDS)
246 3 : return false;
247 :
248 13 : m_outputDataset.Set(std::unique_ptr<GDALDataset>(poRetDS));
249 :
250 13 : return true;
251 : }
252 :
253 : //! @endcond
|