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