LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_edit.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 108 120 90.0 %
Date: 2026-04-13 18:43:07 Functions: 11 12 91.7 %

          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

Generated by: LCOV version 1.14