Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: "edit" step of "vector pipeline"
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_vector_edit.h"
14 :
15 : #include "gdal_priv.h"
16 : #include "gdal_utils.h"
17 :
18 : //! @cond Doxygen_Suppress
19 :
20 : #ifndef _
21 : #define _(x) (x)
22 : #endif
23 :
24 : /************************************************************************/
25 : /* GDALVectorEditAlgorithm::GDALVectorEditAlgorithm() */
26 : /************************************************************************/
27 :
28 105 : GDALVectorEditAlgorithm::GDALVectorEditAlgorithm(bool standaloneStep)
29 : : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
30 105 : standaloneStep)
31 : {
32 105 : AddActiveLayerArg(&m_activeLayer);
33 105 : AddGeometryTypeArg(&m_geometryType, _("Layer geometry type"));
34 :
35 210 : AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
36 210 : .AddHiddenAlias("a_srs")
37 105 : .SetIsCRSArg(/*noneAllowed=*/true);
38 :
39 : {
40 : auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
41 210 : &m_metadata)
42 210 : .SetMetaVar("<KEY>=<VALUE>")
43 105 : .SetPackedValuesAllowed(false);
44 6 : arg.AddValidationAction([this, &arg]()
45 111 : { return ParseAndValidateKeyValue(arg); });
46 105 : arg.AddHiddenAlias("mo");
47 : }
48 :
49 : AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
50 210 : &m_unsetMetadata)
51 105 : .SetMetaVar("<KEY>");
52 :
53 : {
54 : auto &arg =
55 : AddArg("layer-metadata", 0, _("Add/update layer metadata item"),
56 210 : &m_layerMetadata)
57 210 : .SetMetaVar("<KEY>=<VALUE>")
58 105 : .SetPackedValuesAllowed(false);
59 6 : arg.AddValidationAction([this, &arg]()
60 111 : { return ParseAndValidateKeyValue(arg); });
61 : }
62 :
63 : AddArg("unset-layer-metadata", 0, _("Remove layer metadata item"),
64 210 : &m_unsetLayerMetadata)
65 105 : .SetMetaVar("<KEY>");
66 :
67 : AddArg("unset-fid", 0,
68 : _("Unset the identifier of each feature and the FID column name"),
69 105 : &m_unsetFID);
70 105 : }
71 :
72 : namespace
73 : {
74 :
75 : /************************************************************************/
76 : /* GDALVectorEditAlgorithmLayer */
77 : /************************************************************************/
78 :
79 : class GDALVectorEditAlgorithmLayer final : public GDALVectorPipelineOutputLayer
80 : {
81 : public:
82 17 : GDALVectorEditAlgorithmLayer(
83 : OGRLayer &oSrcLayer, const std::string &activeLayer,
84 : bool bChangeGeomType, OGRwkbGeometryType eType,
85 : const std::string &overrideCrs,
86 : const std::vector<std::string> &layerMetadata,
87 : const std::vector<std::string> &unsetLayerMetadata, bool unsetFID)
88 17 : : GDALVectorPipelineOutputLayer(oSrcLayer),
89 17 : m_bOverrideCrs(!overrideCrs.empty()), m_unsetFID(unsetFID)
90 : {
91 17 : SetDescription(oSrcLayer.GetDescription());
92 17 : SetMetadata(oSrcLayer.GetMetadata());
93 :
94 17 : m_poFeatureDefn = oSrcLayer.GetLayerDefn()->Clone();
95 17 : m_poFeatureDefn->Reference();
96 :
97 17 : if (activeLayer.empty() || activeLayer == GetDescription())
98 : {
99 32 : const CPLStringList aosMD(layerMetadata);
100 18 : for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
101 : {
102 2 : if (SetMetadataItem(key, value) != CE_None)
103 : {
104 0 : CPLError(CE_Warning, CPLE_AppDefined,
105 : "SetMetadataItem('%s', '%s') failed", key, value);
106 : }
107 : }
108 :
109 17 : for (const std::string &key : unsetLayerMetadata)
110 : {
111 1 : if (SetMetadataItem(key.c_str(), nullptr) != CE_None)
112 : {
113 0 : CPLError(CE_Warning, CPLE_AppDefined,
114 : "SetMetadataItem('%s', NULL) failed", key.c_str());
115 : }
116 : }
117 :
118 16 : if (bChangeGeomType)
119 : {
120 6 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
121 : {
122 3 : m_poFeatureDefn->GetGeomFieldDefn(i)->SetType(eType);
123 : }
124 : }
125 :
126 16 : if (!overrideCrs.empty())
127 : {
128 4 : if (!EQUAL(overrideCrs.c_str(), "null") &&
129 2 : !EQUAL(overrideCrs.c_str(), "none"))
130 : {
131 1 : m_poSRS = new OGRSpatialReference();
132 1 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
133 1 : m_poSRS->SetFromUserInput(overrideCrs.c_str());
134 : }
135 4 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
136 : {
137 2 : m_poFeatureDefn->GetGeomFieldDefn(i)->SetSpatialRef(
138 2 : m_poSRS);
139 : }
140 : }
141 : }
142 17 : }
143 :
144 34 : ~GDALVectorEditAlgorithmLayer() override
145 17 : {
146 17 : m_poFeatureDefn->Release();
147 17 : if (m_poSRS)
148 1 : m_poSRS->Release();
149 34 : }
150 :
151 24 : const char *GetFIDColumn() const override
152 : {
153 24 : if (m_unsetFID)
154 2 : return "";
155 22 : return m_srcLayer.GetFIDColumn();
156 : }
157 :
158 88 : const OGRFeatureDefn *GetLayerDefn() const override
159 : {
160 88 : return m_poFeatureDefn;
161 : }
162 :
163 305 : void TranslateFeature(
164 : std::unique_ptr<OGRFeature> poSrcFeature,
165 : std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
166 : {
167 305 : poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn);
168 305 : if (m_bOverrideCrs)
169 : {
170 4 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
171 : {
172 2 : auto poGeom = poSrcFeature->GetGeomFieldRef(i);
173 2 : if (poGeom)
174 2 : poGeom->assignSpatialReference(m_poSRS);
175 : }
176 : }
177 305 : if (m_unsetFID)
178 1 : poSrcFeature->SetFID(OGRNullFID);
179 305 : apoOutFeatures.push_back(std::move(poSrcFeature));
180 305 : }
181 :
182 12 : int TestCapability(const char *pszCap) const override
183 : {
184 12 : if (EQUAL(pszCap, OLCStringsAsUTF8) ||
185 12 : EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
186 0 : return m_srcLayer.TestCapability(pszCap);
187 12 : return false;
188 : }
189 :
190 : private:
191 : const bool m_bOverrideCrs;
192 : const bool m_unsetFID;
193 : OGRFeatureDefn *m_poFeatureDefn = nullptr;
194 : OGRSpatialReference *m_poSRS = nullptr;
195 :
196 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorEditAlgorithmLayer)
197 : };
198 :
199 : /************************************************************************/
200 : /* GDALVectorEditOutputDataset */
201 : /************************************************************************/
202 :
203 : class GDALVectorEditOutputDataset final : public GDALVectorPipelineOutputDataset
204 : {
205 : public:
206 16 : explicit GDALVectorEditOutputDataset(GDALDataset &oSrcDS)
207 16 : : GDALVectorPipelineOutputDataset(oSrcDS)
208 : {
209 16 : }
210 :
211 : CSLConstList GetMetadata(const char *pszDomain) override;
212 :
213 0 : const char *GetMetadataItem(const char *pszName,
214 : const char *pszDomain) override
215 : {
216 0 : if (!pszDomain || pszDomain[0] == 0)
217 0 : return GDALDataset::GetMetadataItem(pszName, pszDomain);
218 0 : return m_srcDS.GetMetadataItem(pszName, pszDomain);
219 : }
220 : };
221 :
222 11 : CSLConstList GDALVectorEditOutputDataset::GetMetadata(const char *pszDomain)
223 : {
224 11 : if (!pszDomain || pszDomain[0] == 0)
225 11 : return GDALDataset::GetMetadata(pszDomain);
226 0 : return m_srcDS.GetMetadata(pszDomain);
227 : }
228 :
229 : } // namespace
230 :
231 : /************************************************************************/
232 : /* GDALVectorEditAlgorithm::RunStep() */
233 : /************************************************************************/
234 :
235 16 : bool GDALVectorEditAlgorithm::RunStep(GDALPipelineStepRunContext &)
236 : {
237 16 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
238 16 : CPLAssert(poSrcDS);
239 :
240 16 : CPLAssert(m_outputDataset.GetName().empty());
241 16 : CPLAssert(!m_outputDataset.GetDatasetRef());
242 :
243 16 : const int nLayerCount = poSrcDS->GetLayerCount();
244 :
245 16 : bool bChangeGeomType = false;
246 16 : OGRwkbGeometryType eType = wkbUnknown;
247 16 : if (!m_geometryType.empty())
248 : {
249 3 : eType = OGRFromOGCGeomType(m_geometryType.c_str());
250 3 : bChangeGeomType = true;
251 : }
252 :
253 32 : auto outDS = std::make_unique<GDALVectorEditOutputDataset>(*poSrcDS);
254 :
255 16 : outDS->SetMetadata(poSrcDS->GetMetadata());
256 :
257 32 : const CPLStringList aosMD(m_metadata);
258 18 : for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
259 : {
260 2 : if (outDS->SetMetadataItem(key, value) != CE_None)
261 : {
262 0 : ReportError(CE_Failure, CPLE_AppDefined,
263 : "SetMetadataItem('%s', '%s') failed", key, value);
264 0 : return false;
265 : }
266 : }
267 :
268 17 : for (const std::string &key : m_unsetMetadata)
269 : {
270 1 : if (outDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
271 : {
272 0 : ReportError(CE_Failure, CPLE_AppDefined,
273 : "SetMetadataItem('%s', NULL) failed", key.c_str());
274 0 : return false;
275 : }
276 : }
277 :
278 16 : bool ret = true;
279 33 : for (int i = 0; ret && i < nLayerCount; ++i)
280 : {
281 17 : auto poSrcLayer = poSrcDS->GetLayer(i);
282 17 : ret = (poSrcLayer != nullptr);
283 17 : if (ret)
284 : {
285 34 : outDS->AddLayer(*poSrcLayer,
286 17 : std::make_unique<GDALVectorEditAlgorithmLayer>(
287 17 : *poSrcLayer, m_activeLayer, bChangeGeomType,
288 17 : eType, m_overrideCrs, m_layerMetadata,
289 17 : m_unsetLayerMetadata, m_unsetFID));
290 : }
291 : }
292 :
293 16 : if (ret)
294 16 : m_outputDataset.Set(std::move(outDS));
295 :
296 16 : return ret;
297 : }
298 :
299 : GDALVectorEditAlgorithmStandalone::~GDALVectorEditAlgorithmStandalone() =
300 : default;
301 :
302 : //! @endcond
|