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-06-23 16:35:19 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         111 : GDALVectorEditAlgorithm::GDALVectorEditAlgorithm(bool standaloneStep)
      29             :     : GDALVectorPipelineStepAlgorithm(
      30             :           NAME, DESCRIPTION, HELP_URL,
      31           0 :           ConstructorOptions()
      32         111 :               .SetStandaloneStep(standaloneStep)
      33         222 :               .SetOutputLayerNameAvailableInPipelineStep(true))
      34             : {
      35         111 :     AddActiveLayerArg(&m_activeLayer);
      36         111 :     if (!standaloneStep)
      37             :     {
      38          59 :         AddOutputLayerNameArg(/* hiddenForCLI = */ false,
      39             :                               /* shortNameOutputLayerAllowed = */ false);
      40             :     }
      41             : 
      42         111 :     AddGeometryTypeArg(&m_geometryType, _("Layer geometry type"));
      43             : 
      44         222 :     AddArg("crs", 0, _("Override CRS (without reprojection)"), &m_overrideCrs)
      45         222 :         .AddHiddenAlias("a_srs")
      46         111 :         .SetIsCRSArg(/*noneAllowed=*/true);
      47             : 
      48             :     {
      49             :         auto &arg = AddArg("metadata", 0, _("Add/update dataset metadata item"),
      50         222 :                            &m_metadata)
      51         222 :                         .SetMetaVar("<KEY>=<VALUE>")
      52         111 :                         .SetPackedValuesAllowed(false);
      53           6 :         arg.AddValidationAction([this, &arg]()
      54         117 :                                 { return ParseAndValidateKeyValue(arg); });
      55         111 :         arg.AddHiddenAlias("mo");
      56             :     }
      57             : 
      58             :     AddArg("unset-metadata", 0, _("Remove dataset metadata item"),
      59         222 :            &m_unsetMetadata)
      60         111 :         .SetMetaVar("<KEY>");
      61             : 
      62             :     {
      63             :         auto &arg =
      64             :             AddArg("layer-metadata", 0, _("Add/update layer metadata item"),
      65         222 :                    &m_layerMetadata)
      66         222 :                 .SetMetaVar("<KEY>=<VALUE>")
      67         111 :                 .SetPackedValuesAllowed(false);
      68           6 :         arg.AddValidationAction([this, &arg]()
      69         117 :                                 { return ParseAndValidateKeyValue(arg); });
      70             :     }
      71             : 
      72             :     AddArg("unset-layer-metadata", 0, _("Remove layer metadata item"),
      73         222 :            &m_unsetLayerMetadata)
      74         111 :         .SetMetaVar("<KEY>");
      75             : 
      76             :     AddArg("unset-fid", 0,
      77             :            _("Unset the identifier of each feature and the FID column name"),
      78         111 :            &m_unsetFID);
      79             : 
      80         111 :     AddValidationAction(
      81          58 :         [this]()
      82             :         {
      83          49 :             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          44 :             return true;
      97             :         });
      98         111 : }
      99             : 
     100             : namespace
     101             : {
     102             : 
     103             : /************************************************************************/
     104             : /*                     GDALVectorEditAlgorithmLayer                     */
     105             : /************************************************************************/
     106             : 
     107             : class GDALVectorEditAlgorithmLayer final : public GDALVectorPipelineOutputLayer
     108             : {
     109             :   public:
     110          22 :     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          22 :         : GDALVectorPipelineOutputLayer(oSrcLayer),
     117          44 :           m_bOverrideCrs(!overrideCrs.empty()), m_unsetFID(unsetFID),
     118          22 :           m_poFeatureDefn(oSrcLayer.GetLayerDefn()->Clone())
     119             :     {
     120          22 :         SetMetadata(oSrcLayer.GetMetadata());
     121             : 
     122          22 :         if (activeLayer.empty() || activeLayer == oSrcLayer.GetDescription())
     123             :         {
     124          20 :             if (!outputLayerName.empty())
     125             :             {
     126           2 :                 m_poFeatureDefn->SetName(outputLayerName.c_str());
     127             :             }
     128             : 
     129          40 :             const CPLStringList aosMD(layerMetadata);
     130          22 :             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          21 :             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          20 :             if (bChangeGeomType)
     149             :             {
     150           6 :                 for (auto *poGeomFieldDefns : m_poFeatureDefn->GetGeomFields())
     151             :                 {
     152           3 :                     poGeomFieldDefns->SetType(eType);
     153             :                 }
     154             :             }
     155             : 
     156          20 :             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          22 :         SetDescription(m_poFeatureDefn->GetName());
     175          22 :     }
     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          95 :     const OGRFeatureDefn *GetLayerDefn() const override
     185             :     {
     186          95 :         return m_poFeatureDefn.get();
     187             :     }
     188             : 
     189         309 :     bool TranslateFeature(
     190             :         std::unique_ptr<OGRFeature> poSrcFeature,
     191             :         std::vector<std::unique_ptr<OGRFeature>> &apoOutFeatures) override
     192             :     {
     193         309 :         poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn.get());
     194         309 :         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         309 :         if (m_unsetFID)
     204           1 :             poSrcFeature->SetFID(OGRNullFID);
     205         309 :         apoOutFeatures.push_back(std::move(poSrcFeature));
     206             : 
     207         309 :         return true;
     208             :     }
     209             : 
     210          12 :     int TestCapability(const char *pszCap) const override
     211             :     {
     212          12 :         if (EQUAL(pszCap, OLCStringsAsUTF8) ||
     213          12 :             EQUAL(pszCap, OLCCurveGeometries) || EQUAL(pszCap, OLCZGeometries))
     214           0 :             return m_srcLayer.TestCapability(pszCap);
     215          12 :         return false;
     216             :     }
     217             : 
     218             :   private:
     219             :     const bool m_bOverrideCrs;
     220             :     const bool m_unsetFID;
     221             :     const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
     222             :     OGRSpatialReferenceRefCountedPtr m_poSRS{};
     223             : 
     224             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorEditAlgorithmLayer)
     225             : };
     226             : 
     227             : /************************************************************************/
     228             : /*                     GDALVectorEditOutputDataset                      */
     229             : /************************************************************************/
     230             : 
     231             : class GDALVectorEditOutputDataset final : public GDALVectorPipelineOutputDataset
     232             : {
     233             :   public:
     234          20 :     explicit GDALVectorEditOutputDataset(GDALDataset &oSrcDS)
     235          20 :         : GDALVectorPipelineOutputDataset(oSrcDS)
     236             :     {
     237          20 :     }
     238             : 
     239             :     CSLConstList GetMetadata(const char *pszDomain) override;
     240             : 
     241           0 :     const char *GetMetadataItem(const char *pszName,
     242             :                                 const char *pszDomain) override
     243             :     {
     244           0 :         if (!pszDomain || pszDomain[0] == 0)
     245           0 :             return GDALDataset::GetMetadataItem(pszName, pszDomain);
     246           0 :         return m_srcDS.GetMetadataItem(pszName, pszDomain);
     247             :     }
     248             : };
     249             : 
     250          11 : CSLConstList GDALVectorEditOutputDataset::GetMetadata(const char *pszDomain)
     251             : {
     252          11 :     if (!pszDomain || pszDomain[0] == 0)
     253          11 :         return GDALDataset::GetMetadata(pszDomain);
     254           0 :     return m_srcDS.GetMetadata(pszDomain);
     255             : }
     256             : 
     257             : }  // namespace
     258             : 
     259             : /************************************************************************/
     260             : /*                  GDALVectorEditAlgorithm::RunStep()                  */
     261             : /************************************************************************/
     262             : 
     263          20 : bool GDALVectorEditAlgorithm::RunStep(GDALPipelineStepRunContext &)
     264             : {
     265          20 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     266          20 :     CPLAssert(poSrcDS);
     267             : 
     268          20 :     CPLAssert(m_outputDataset.GetName().empty());
     269          20 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     270             : 
     271          20 :     const int nLayerCount = poSrcDS->GetLayerCount();
     272             : 
     273          20 :     bool bChangeGeomType = false;
     274          20 :     OGRwkbGeometryType eType = wkbUnknown;
     275          20 :     if (!m_geometryType.empty())
     276             :     {
     277           3 :         eType = OGRFromOGCGeomType(m_geometryType.c_str());
     278           3 :         bChangeGeomType = true;
     279             :     }
     280             : 
     281          40 :     auto outDS = std::make_unique<GDALVectorEditOutputDataset>(*poSrcDS);
     282             : 
     283          20 :     outDS->SetMetadata(poSrcDS->GetMetadata());
     284             : 
     285          40 :     const CPLStringList aosMD(m_metadata);
     286          22 :     for (const auto &[key, value] : cpl::IterateNameValue(aosMD))
     287             :     {
     288           2 :         if (outDS->SetMetadataItem(key, value) != CE_None)
     289             :         {
     290           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     291             :                         "SetMetadataItem('%s', '%s') failed", key, value);
     292           0 :             return false;
     293             :         }
     294             :     }
     295             : 
     296          21 :     for (const std::string &key : m_unsetMetadata)
     297             :     {
     298           1 :         if (outDS->SetMetadataItem(key.c_str(), nullptr) != CE_None)
     299             :         {
     300           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     301             :                         "SetMetadataItem('%s', NULL) failed", key.c_str());
     302           0 :             return false;
     303             :         }
     304             :     }
     305             : 
     306          20 :     bool ret = true;
     307          42 :     for (int i = 0; ret && i < nLayerCount; ++i)
     308             :     {
     309          22 :         auto poSrcLayer = poSrcDS->GetLayer(i);
     310          22 :         ret = (poSrcLayer != nullptr);
     311          22 :         if (ret)
     312             :         {
     313          44 :             outDS->AddLayer(*poSrcLayer,
     314          22 :                             std::make_unique<GDALVectorEditAlgorithmLayer>(
     315          22 :                                 *poSrcLayer, m_activeLayer, m_outputLayerName,
     316          22 :                                 bChangeGeomType, eType, m_overrideCrs,
     317          22 :                                 m_layerMetadata, m_unsetLayerMetadata,
     318          22 :                                 m_unsetFID));
     319             :         }
     320             :     }
     321             : 
     322          20 :     if (ret)
     323          20 :         m_outputDataset.Set(std::move(outDS));
     324             : 
     325          20 :     return ret;
     326             : }
     327             : 
     328             : GDALVectorEditAlgorithmStandalone::~GDALVectorEditAlgorithmStandalone() =
     329             :     default;
     330             : 
     331             : //! @endcond

Generated by: LCOV version 1.14