LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_edit.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 107 114 93.9 %
Date: 2025-09-10 17:48:50 Functions: 11 11 100.0 %

          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

Generated by: LCOV version 1.14