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