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 34 : m_bOverrideCrs(!overrideCrs.empty()), m_unsetFID(unsetFID),
90 17 : m_poFeatureDefn(oSrcLayer.GetLayerDefn()->Clone())
91 : {
92 17 : SetDescription(oSrcLayer.GetDescription());
93 17 : SetMetadata(oSrcLayer.GetMetadata());
94 :
95 17 : if (activeLayer.empty() || activeLayer == GetDescription())
96 : {
97 32 : const CPLStringList aosMD(layerMetadata);
98 18 : for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
99 : {
100 2 : if (SetMetadataItem(key, value) != CE_None)
101 : {
102 0 : CPLError(CE_Warning, CPLE_AppDefined,
103 : "SetMetadataItem('%s', '%s') failed", key, value);
104 : }
105 : }
106 :
107 17 : for (const std::string &key : unsetLayerMetadata)
108 : {
109 1 : if (SetMetadataItem(key.c_str(), nullptr) != CE_None)
110 : {
111 0 : CPLError(CE_Warning, CPLE_AppDefined,
112 : "SetMetadataItem('%s', NULL) failed", key.c_str());
113 : }
114 : }
115 :
116 16 : if (bChangeGeomType)
117 : {
118 6 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
119 : {
120 3 : m_poFeatureDefn->GetGeomFieldDefn(i)->SetType(eType);
121 : }
122 : }
123 :
124 16 : if (!overrideCrs.empty())
125 : {
126 4 : if (!EQUAL(overrideCrs.c_str(), "null") &&
127 2 : !EQUAL(overrideCrs.c_str(), "none"))
128 : {
129 1 : m_poSRS = OGRSpatialReferenceRefCountedPtr::makeInstance();
130 1 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
131 : // already checked by GDALAlgorithmArg framework
132 1 : CPL_IGNORE_RET_VAL(
133 1 : m_poSRS->SetFromUserInput(overrideCrs.c_str()));
134 : }
135 4 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
136 : {
137 4 : m_poFeatureDefn->GetGeomFieldDefn(i)->SetSpatialRef(
138 2 : m_poSRS.get());
139 : }
140 : }
141 : }
142 17 : }
143 :
144 24 : const char *GetFIDColumn() const override
145 : {
146 24 : if (m_unsetFID)
147 2 : return "";
148 22 : return m_srcLayer.GetFIDColumn();
149 : }
150 :
151 88 : const OGRFeatureDefn *GetLayerDefn() const override
152 : {
153 88 : return m_poFeatureDefn.get();
154 : }
155 :
156 305 : void TranslateFeature(
157 : std::unique_ptr<OGRFeature> poSrcFeature,
158 : std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
159 : {
160 305 : poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn.get());
161 305 : if (m_bOverrideCrs)
162 : {
163 4 : for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
164 : {
165 2 : auto poGeom = poSrcFeature->GetGeomFieldRef(i);
166 2 : if (poGeom)
167 2 : poGeom->assignSpatialReference(m_poSRS.get());
168 : }
169 : }
170 305 : if (m_unsetFID)
171 1 : poSrcFeature->SetFID(OGRNullFID);
172 305 : apoOutFeatures.push_back(std::move(poSrcFeature));
173 305 : }
174 :
175 12 : int TestCapability(const char *pszCap) const override
176 : {
177 12 : if (EQUAL(pszCap, OLCStringsAsUTF8) ||
178 12 : EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
179 0 : return m_srcLayer.TestCapability(pszCap);
180 12 : return false;
181 : }
182 :
183 : private:
184 : const bool m_bOverrideCrs;
185 : const bool m_unsetFID;
186 : const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
187 : OGRSpatialReferenceRefCountedPtr m_poSRS{};
188 :
189 : CPL_DISALLOW_COPY_ASSIGN(GDALVectorEditAlgorithmLayer)
190 : };
191 :
192 : /************************************************************************/
193 : /* GDALVectorEditOutputDataset */
194 : /************************************************************************/
195 :
196 : class GDALVectorEditOutputDataset final : public GDALVectorPipelineOutputDataset
197 : {
198 : public:
199 16 : explicit GDALVectorEditOutputDataset(GDALDataset &oSrcDS)
200 16 : : GDALVectorPipelineOutputDataset(oSrcDS)
201 : {
202 16 : }
203 :
204 : CSLConstList GetMetadata(const char *pszDomain) override;
205 :
206 0 : const char *GetMetadataItem(const char *pszName,
207 : const char *pszDomain) override
208 : {
209 0 : if (!pszDomain || pszDomain[0] == 0)
210 0 : return GDALDataset::GetMetadataItem(pszName, pszDomain);
211 0 : return m_srcDS.GetMetadataItem(pszName, pszDomain);
212 : }
213 : };
214 :
215 11 : CSLConstList GDALVectorEditOutputDataset::GetMetadata(const char *pszDomain)
216 : {
217 11 : if (!pszDomain || pszDomain[0] == 0)
218 11 : return GDALDataset::GetMetadata(pszDomain);
219 0 : return m_srcDS.GetMetadata(pszDomain);
220 : }
221 :
222 : } // namespace
223 :
224 : /************************************************************************/
225 : /* GDALVectorEditAlgorithm::RunStep() */
226 : /************************************************************************/
227 :
228 16 : bool GDALVectorEditAlgorithm::RunStep(GDALPipelineStepRunContext &)
229 : {
230 16 : auto poSrcDS = m_inputDataset[0].GetDatasetRef();
231 16 : CPLAssert(poSrcDS);
232 :
233 16 : CPLAssert(m_outputDataset.GetName().empty());
234 16 : CPLAssert(!m_outputDataset.GetDatasetRef());
235 :
236 16 : const int nLayerCount = poSrcDS->GetLayerCount();
237 :
238 16 : bool bChangeGeomType = false;
239 16 : OGRwkbGeometryType eType = wkbUnknown;
240 16 : if (!m_geometryType.empty())
241 : {
242 3 : eType = OGRFromOGCGeomType(m_geometryType.c_str());
243 3 : bChangeGeomType = true;
244 : }
245 :
246 32 : auto outDS = std::make_unique<GDALVectorEditOutputDataset>(*poSrcDS);
247 :
248 16 : outDS->SetMetadata(poSrcDS->GetMetadata());
249 :
250 32 : const CPLStringList aosMD(m_metadata);
251 18 : for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
252 : {
253 2 : if (outDS->SetMetadataItem(key, value) != CE_None)
254 : {
255 0 : ReportError(CE_Failure, CPLE_AppDefined,
256 : "SetMetadataItem('%s', '%s') failed", key, value);
257 0 : return false;
258 : }
259 : }
260 :
261 17 : for (const std::string &key : m_unsetMetadata)
262 : {
263 1 : if (outDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
264 : {
265 0 : ReportError(CE_Failure, CPLE_AppDefined,
266 : "SetMetadataItem('%s', NULL) failed", key.c_str());
267 0 : return false;
268 : }
269 : }
270 :
271 16 : bool ret = true;
272 33 : for (int i = 0; ret && i < nLayerCount; ++i)
273 : {
274 17 : auto poSrcLayer = poSrcDS->GetLayer(i);
275 17 : ret = (poSrcLayer != nullptr);
276 17 : if (ret)
277 : {
278 34 : outDS->AddLayer(*poSrcLayer,
279 17 : std::make_unique<GDALVectorEditAlgorithmLayer>(
280 17 : *poSrcLayer, m_activeLayer, bChangeGeomType,
281 17 : eType, m_overrideCrs, m_layerMetadata,
282 17 : m_unsetLayerMetadata, m_unsetFID));
283 : }
284 : }
285 :
286 16 : if (ret)
287 16 : m_outputDataset.Set(std::move(outDS));
288 :
289 16 : return ret;
290 : }
291 :
292 : GDALVectorEditAlgorithmStandalone::~GDALVectorEditAlgorithmStandalone() =
293 : default;
294 :
295 : //! @endcond
|