LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_edit.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 122 135 90.4 %
Date: 2026-05-13 23:47:50 Functions: 12 13 92.3 %

          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         109 : GDALVectorEditAlgorithm::GDALVectorEditAlgorithm(bool standaloneStep)
      29             :     : GDALVectorPipelineStepAlgorithm(
      30             :           NAME, DESCRIPTION, HELP_URL,
      31           0 :           ConstructorOptions()
      32         109 :               .SetStandaloneStep(standaloneStep)
      33         218 :               .SetOutputLayerNameAvailableInPipelineStep(true))
      34             : {
      35         109 :     AddActiveLayerArg(&m_activeLayer);
      36         109 :     if (!standaloneStep)
      37             :     {
      38          57 :         AddOutputLayerNameArg(/* hiddenForCLI = */ false,
      39             :                               /* shortNameOutputLayerAllowed = */ false);
      40             :     }
      41             : 
      42         109 :     AddGeometryTypeArg(&m_geometryType, _("Layer geometry type"));
      43             : 
      44         218 :     AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
      45         218 :         .AddHiddenAlias("a_srs")
      46         109 :         .SetIsCRSArg(/*noneAllowed=*/true);
      47             : 
      48             :     {
      49             :         auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
      50         218 :                            &m_metadata)
      51         218 :                         .SetMetaVar("<KEY>=<VALUE>")
      52         109 :                         .SetPackedValuesAllowed(false);
      53           6 :         arg.AddValidationAction([this, &arg]()
      54         115 :                                 { return ParseAndValidateKeyValue(arg); });
      55         109 :         arg.AddHiddenAlias("mo");
      56             :     }
      57             : 
      58             :     AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
      59         218 :            &m_unsetMetadata)
      60         109 :         .SetMetaVar("<KEY>");
      61             : 
      62             :     {
      63             :         auto &arg =
      64             :             AddArg("layer-metadata", 0, _("Add/update layer metadata item"),
      65         218 :                    &m_layerMetadata)
      66         218 :                 .SetMetaVar("<KEY>=<VALUE>")
      67         109 :                 .SetPackedValuesAllowed(false);
      68           6 :         arg.AddValidationAction([this, &arg]()
      69         115 :                                 { return ParseAndValidateKeyValue(arg); });
      70             :     }
      71             : 
      72             :     AddArg("unset-layer-metadata", 0, _("Remove layer metadata item"),
      73         218 :            &m_unsetLayerMetadata)
      74         109 :         .SetMetaVar("<KEY>");
      75             : 
      76             :     AddArg("unset-fid", 0,
      77             :            _("Unset the identifier of each feature and the FID column name"),
      78         109 :            &m_unsetFID);
      79             : 
      80         109 :     AddValidationAction(
      81          56 :         [this]()
      82             :         {
      83          47 :             if (!m_outputLayerName.empty() && m_activeLayer.empty() &&
      84           4 :                 m_inputDataset.size() == 1)
      85             :             {
      86           2 :                 auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      87           2 :                 if (poSrcDS && poSrcDS->GetLayerCount() > 1)
      88             :                 {
      89           1 :                     ReportError(CE_Failure, CPLE_IllegalArg,
      90             :                                 "Argument 'output-layer' cannot be used when "
      91             :                                 "the input dataset has multiple layers, unless "
      92             :                                 "argument 'active-layer' is specified");
      93           1 :                     return false;
      94             :                 }
      95             :             }
      96          42 :             return true;
      97             :         });
      98         109 : }
      99             : 
     100             : namespace
     101             : {
     102             : 
     103             : /************************************************************************/
     104             : /*                     GDALVectorEditAlgorithmLayer                     */
     105             : /************************************************************************/
     106             : 
     107             : class GDALVectorEditAlgorithmLayer final : public GDALVectorPipelineOutputLayer
     108             : {
     109             :   public:
     110          21 :     GDALVectorEditAlgorithmLayer(
     111             :         OGRLayer &oSrcLayer, const std::string &activeLayer,
     112             :         const std::string &outputLayerName, bool bChangeGeomType,
     113             :         OGRwkbGeometryType eType, const std::string &overrideCrs,
     114             :         const std::vector<std::string> &layerMetadata,
     115             :         const std::vector<std::string> &unsetLayerMetadata, bool unsetFID)
     116          21 :         : GDALVectorPipelineOutputLayer(oSrcLayer),
     117          42 :           m_bOverrideCrs(!overrideCrs.empty()), m_unsetFID(unsetFID),
     118          21 :           m_poFeatureDefn(oSrcLayer.GetLayerDefn()->Clone())
     119             :     {
     120          21 :         SetMetadata(oSrcLayer.GetMetadata());
     121             : 
     122          21 :         if (activeLayer.empty() || activeLayer == oSrcLayer.GetDescription())
     123             :         {
     124          19 :             if (!outputLayerName.empty())
     125             :             {
     126           2 :                 m_poFeatureDefn->SetName(outputLayerName.c_str());
     127             :             }
     128             : 
     129          38 :             const CPLStringList aosMD(layerMetadata);
     130          21 :             for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
     131             :             {
     132           2 :                 if (SetMetadataItem(key, value) != CE_None)
     133             :                 {
     134           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     135             :                              "SetMetadataItem('%s', '%s') failed", key, value);
     136             :                 }
     137             :             }
     138             : 
     139          20 :             for (const std::string &key : unsetLayerMetadata)
     140             :             {
     141           1 :                 if (SetMetadataItem(key.c_str(), nullptr) != CE_None)
     142             :                 {
     143           0 :                     CPLError(CE_Warning, CPLE_AppDefined,
     144             :                              "SetMetadataItem('%s', NULL) failed", key.c_str());
     145             :                 }
     146             :             }
     147             : 
     148          19 :             if (bChangeGeomType)
     149             :             {
     150           6 :                 for (auto *poGeomFieldDefns : m_poFeatureDefn->GetGeomFields())
     151             :                 {
     152           3 :                     poGeomFieldDefns->SetType(eType);
     153             :                 }
     154             :             }
     155             : 
     156          19 :             if (!overrideCrs.empty())
     157             :             {
     158           4 :                 if (!EQUAL(overrideCrs.c_str(), "null") &&
     159           2 :                     !EQUAL(overrideCrs.c_str(), "none"))
     160             :                 {
     161           1 :                     m_poSRS = OGRSpatialReferenceRefCountedPtr::makeInstance();
     162           1 :                     m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     163             :                     // already checked by GDALAlgorithmArg framework
     164           1 :                     CPL_IGNORE_RET_VAL(
     165           1 :                         m_poSRS->SetFromUserInput(overrideCrs.c_str()));
     166             :                 }
     167           4 :                 for (auto *poGeomFieldDefns : m_poFeatureDefn->GetGeomFields())
     168             :                 {
     169           2 :                     poGeomFieldDefns->SetSpatialRef(m_poSRS.get());
     170             :                 }
     171             :             }
     172             :         }
     173             : 
     174          21 :         SetDescription(m_poFeatureDefn->GetName());
     175          21 :     }
     176             : 
     177          24 :     const char *GetFIDColumn() const override
     178             :     {
     179          24 :         if (m_unsetFID)
     180           2 :             return "";
     181          22 :         return m_srcLayer.GetFIDColumn();
     182             :     }
     183             : 
     184          91 :     const OGRFeatureDefn *GetLayerDefn() const override
     185             :     {
     186          91 :         return m_poFeatureDefn.get();
     187             :     }
     188             : 
     189         305 :     void TranslateFeature(
     190             :         std::unique_ptr<OGRFeature> poSrcFeature,
     191             :         std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
     192             :     {
     193         305 :         poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn.get());
     194         305 :         if (m_bOverrideCrs)
     195             :         {
     196           4 :             for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
     197             :             {
     198           2 :                 auto poGeom = poSrcFeature->GetGeomFieldRef(i);
     199           2 :                 if (poGeom)
     200           2 :                     poGeom->assignSpatialReference(m_poSRS.get());
     201             :             }
     202             :         }
     203         305 :         if (m_unsetFID)
     204           1 :             poSrcFeature->SetFID(OGRNullFID);
     205         305 :         apoOutFeatures.push_back(std::move(poSrcFeature));
     206         305 :     }
     207             : 
     208          12 :     int TestCapability(const char *pszCap) const override
     209             :     {
     210          12 :         if (EQUAL(pszCap, OLCStringsAsUTF8) ||
     211          12 :             EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
     212           0 :             return m_srcLayer.TestCapability(pszCap);
     213          12 :         return false;
     214             :     }
     215             : 
     216             :   private:
     217             :     const bool m_bOverrideCrs;
     218             :     const bool m_unsetFID;
     219             :     const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
     220             :     OGRSpatialReferenceRefCountedPtr m_poSRS{};
     221             : 
     222             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorEditAlgorithmLayer)
     223             : };
     224             : 
     225             : /************************************************************************/
     226             : /*                     GDALVectorEditOutputDataset                      */
     227             : /************************************************************************/
     228             : 
     229             : class GDALVectorEditOutputDataset final : public GDALVectorPipelineOutputDataset
     230             : {
     231             :   public:
     232          19 :     explicit GDALVectorEditOutputDataset(GDALDataset &oSrcDS)
     233          19 :         : GDALVectorPipelineOutputDataset(oSrcDS)
     234             :     {
     235          19 :     }
     236             : 
     237             :     CSLConstList GetMetadata(const char *pszDomain) override;
     238             : 
     239           0 :     const char *GetMetadataItem(const char *pszName,
     240             :                                 const char *pszDomain) override
     241             :     {
     242           0 :         if (!pszDomain || pszDomain[0] == 0)
     243           0 :             return GDALDataset::GetMetadataItem(pszName, pszDomain);
     244           0 :         return m_srcDS.GetMetadataItem(pszName, pszDomain);
     245             :     }
     246             : };
     247             : 
     248          11 : CSLConstList GDALVectorEditOutputDataset::GetMetadata(const char *pszDomain)
     249             : {
     250          11 :     if (!pszDomain || pszDomain[0] == 0)
     251          11 :         return GDALDataset::GetMetadata(pszDomain);
     252           0 :     return m_srcDS.GetMetadata(pszDomain);
     253             : }
     254             : 
     255             : }  // namespace
     256             : 
     257             : /************************************************************************/
     258             : /*                  GDALVectorEditAlgorithm::RunStep()                  */
     259             : /************************************************************************/
     260             : 
     261          19 : bool GDALVectorEditAlgorithm::RunStep(GDALPipelineStepRunContext &)
     262             : {
     263          19 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     264          19 :     CPLAssert(poSrcDS);
     265             : 
     266          19 :     CPLAssert(m_outputDataset.GetName().empty());
     267          19 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     268             : 
     269          19 :     const int nLayerCount = poSrcDS->GetLayerCount();
     270             : 
     271          19 :     bool bChangeGeomType = false;
     272          19 :     OGRwkbGeometryType eType = wkbUnknown;
     273          19 :     if (!m_geometryType.empty())
     274             :     {
     275           3 :         eType = OGRFromOGCGeomType(m_geometryType.c_str());
     276           3 :         bChangeGeomType = true;
     277             :     }
     278             : 
     279          38 :     auto outDS = std::make_unique<GDALVectorEditOutputDataset>(*poSrcDS);
     280             : 
     281          19 :     outDS->SetMetadata(poSrcDS->GetMetadata());
     282             : 
     283          38 :     const CPLStringList aosMD(m_metadata);
     284          21 :     for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
     285             :     {
     286           2 :         if (outDS->SetMetadataItem(key, value) != CE_None)
     287             :         {
     288           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     289             :                         "SetMetadataItem('%s', '%s') failed", key, value);
     290           0 :             return false;
     291             :         }
     292             :     }
     293             : 
     294          20 :     for (const std::string &key : m_unsetMetadata)
     295             :     {
     296           1 :         if (outDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
     297             :         {
     298           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     299             :                         "SetMetadataItem('%s', NULL) failed", key.c_str());
     300           0 :             return false;
     301             :         }
     302             :     }
     303             : 
     304          19 :     bool ret = true;
     305          40 :     for (int i = 0; ret && i < nLayerCount; ++i)
     306             :     {
     307          21 :         auto poSrcLayer = poSrcDS->GetLayer(i);
     308          21 :         ret = (poSrcLayer != nullptr);
     309          21 :         if (ret)
     310             :         {
     311          42 :             outDS->AddLayer(*poSrcLayer,
     312          21 :                             std::make_unique<GDALVectorEditAlgorithmLayer>(
     313          21 :                                 *poSrcLayer, m_activeLayer, m_outputLayerName,
     314          21 :                                 bChangeGeomType, eType, m_overrideCrs,
     315          21 :                                 m_layerMetadata, m_unsetLayerMetadata,
     316          21 :                                 m_unsetFID));
     317             :         }
     318             :     }
     319             : 
     320          19 :     if (ret)
     321          19 :         m_outputDataset.Set(std::move(outDS));
     322             : 
     323          19 :     return ret;
     324             : }
     325             : 
     326             : GDALVectorEditAlgorithmStandalone::~GDALVectorEditAlgorithmStandalone() =
     327             :     default;
     328             : 
     329             : //! @endcond

Generated by: LCOV version 1.14