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