LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_filter.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 73 97 75.3 %
Date: 2026-04-23 19:47:11 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "filter" step of "vector pipeline"
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_filter.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "ogrsf_frmts.h"
      17             : #include "ogr_p.h"
      18             : 
      19             : #include <set>
      20             : 
      21             : //! @cond Doxygen_Suppress
      22             : 
      23             : #ifndef _
      24             : #define _(x) (x)
      25             : #endif
      26             : 
      27             : /************************************************************************/
      28             : /*        GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm()        */
      29             : /************************************************************************/
      30             : 
      31         101 : GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep)
      32             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      33         101 :                                       standaloneStep)
      34             : {
      35         101 :     AddActiveLayerArg(&m_activeLayer);
      36         101 :     AddBBOXArg(&m_bbox);
      37             :     AddArg("where", 0,
      38             :            _("Attribute query in a restricted form of the queries used in the "
      39             :              "SQL WHERE statement"),
      40         202 :            &m_where)
      41         101 :         .SetReadFromFileAtSyntaxAllowed()
      42         202 :         .SetMetaVar("<WHERE>|@<filename>")
      43         101 :         .SetRemoveSQLCommentsEnabled();
      44             :     AddArg("update-extent", 0,
      45             :            _("Update layer extent to take into account the filter"),
      46         101 :            &m_updateExtent);
      47         101 : }
      48             : 
      49             : /************************************************************************/
      50             : /*              GDALVectorFilterAlgorithmLayerChangeExtent              */
      51             : /************************************************************************/
      52             : 
      53             : namespace
      54             : {
      55             : class GDALVectorFilterAlgorithmLayerChangeExtent final
      56             :     : public GDALVectorPipelinePassthroughLayer
      57             : {
      58             :   public:
      59           1 :     GDALVectorFilterAlgorithmLayerChangeExtent(
      60             :         OGRLayer &oSrcLayer, const OGREnvelope3D &sLayerEnvelope)
      61           1 :         : GDALVectorPipelinePassthroughLayer(oSrcLayer),
      62           1 :           m_sLayerEnvelope(sLayerEnvelope)
      63             :     {
      64           1 :     }
      65             : 
      66           1 :     OGRErr IGetExtent(int /*iGeomField*/, OGREnvelope *psExtent,
      67             :                       bool /* bForce */) override
      68             :     {
      69           1 :         if (m_sLayerEnvelope.IsInit())
      70             :         {
      71           1 :             *psExtent = m_sLayerEnvelope;
      72           1 :             return OGRERR_NONE;
      73             :         }
      74             :         else
      75             :         {
      76           0 :             return OGRERR_FAILURE;
      77             :         }
      78             :     }
      79             : 
      80           1 :     OGRErr IGetExtent3D(int /*iGeomField*/, OGREnvelope3D *psExtent,
      81             :                         bool /* bForce */) override
      82             :     {
      83           1 :         if (m_sLayerEnvelope.IsInit())
      84             :         {
      85           1 :             *psExtent = m_sLayerEnvelope;
      86           1 :             return OGRERR_NONE;
      87             :         }
      88             :         else
      89             :         {
      90           0 :             return OGRERR_FAILURE;
      91             :         }
      92             :     }
      93             : 
      94           0 :     int TestCapability(const char *pszCap) const override
      95             :     {
      96           0 :         if (EQUAL(pszCap, OLCFastGetExtent))
      97           0 :             return true;
      98           0 :         return m_srcLayer.TestCapability(pszCap);
      99             :     }
     100             : 
     101             :   private:
     102             :     const OGREnvelope3D m_sLayerEnvelope;
     103             : };
     104             : 
     105             : }  // namespace
     106             : 
     107             : /************************************************************************/
     108             : /*                 GDALVectorFilterAlgorithm::RunStep()                 */
     109             : /************************************************************************/
     110             : 
     111          18 : bool GDALVectorFilterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     112             : {
     113          18 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     114          18 :     CPLAssert(poSrcDS);
     115             : 
     116          18 :     CPLAssert(m_outputDataset.GetName().empty());
     117          18 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     118             : 
     119          18 :     const int nLayerCount = poSrcDS->GetLayerCount();
     120             : 
     121          18 :     bool ret = true;
     122          18 :     if (m_bbox.size() == 4)
     123             :     {
     124           4 :         const double xmin = m_bbox[0];
     125           4 :         const double ymin = m_bbox[1];
     126           4 :         const double xmax = m_bbox[2];
     127           4 :         const double ymax = m_bbox[3];
     128           8 :         for (int i = 0; i < nLayerCount; ++i)
     129             :         {
     130           4 :             auto poSrcLayer = poSrcDS->GetLayer(i);
     131           4 :             ret = ret && (poSrcLayer != nullptr);
     132           4 :             if (poSrcLayer && (m_activeLayer.empty() ||
     133           0 :                                m_activeLayer == poSrcLayer->GetDescription()))
     134           4 :                 poSrcLayer->SetSpatialFilterRect(xmin, ymin, xmax, ymax);
     135             :         }
     136             :     }
     137             : 
     138          18 :     if (ret && !m_where.empty())
     139             :     {
     140          28 :         for (int i = 0; i < nLayerCount; ++i)
     141             :         {
     142          16 :             auto poSrcLayer = poSrcDS->GetLayer(i);
     143          16 :             ret = ret && (poSrcLayer != nullptr);
     144          22 :             if (ret && (m_activeLayer.empty() ||
     145           6 :                         m_activeLayer == poSrcLayer->GetDescription()))
     146             :             {
     147          13 :                 ret = poSrcLayer->SetAttributeFilter(m_where.c_str()) ==
     148             :                       OGRERR_NONE;
     149             :             }
     150             :         }
     151             :     }
     152             : 
     153          18 :     if (ret)
     154             :     {
     155             :         auto outDS =
     156          17 :             std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     157             : 
     158          17 :         int64_t nTotalFeatures = 0;
     159          17 :         if (m_updateExtent && ctxt.m_pfnProgress)
     160             :         {
     161           0 :             for (int i = 0; ret && i < nLayerCount; ++i)
     162             :             {
     163           0 :                 auto poSrcLayer = poSrcDS->GetLayer(i);
     164           0 :                 ret = (poSrcLayer != nullptr);
     165           0 :                 if (ret)
     166             :                 {
     167           0 :                     if (m_activeLayer.empty() ||
     168           0 :                         m_activeLayer == poSrcLayer->GetDescription())
     169             :                     {
     170           0 :                         if (poSrcLayer->TestCapability(OLCFastFeatureCount))
     171             :                         {
     172           0 :                             const auto nFC = poSrcLayer->GetFeatureCount(false);
     173           0 :                             if (nFC < 0)
     174             :                             {
     175           0 :                                 nTotalFeatures = 0;
     176           0 :                                 break;
     177             :                             }
     178           0 :                             nTotalFeatures += nFC;
     179             :                         }
     180             :                     }
     181             :                 }
     182             :             }
     183             :         }
     184             : 
     185          17 :         int64_t nFeatureCounter = 0;
     186          38 :         for (int i = 0; ret && i < nLayerCount; ++i)
     187             :         {
     188          21 :             auto poSrcLayer = poSrcDS->GetLayer(i);
     189          21 :             ret = (poSrcLayer != nullptr);
     190          21 :             if (ret)
     191             :             {
     192          25 :                 if (m_updateExtent &&
     193           4 :                     (m_activeLayer.empty() ||
     194           2 :                      m_activeLayer == poSrcLayer->GetDescription()))
     195             :                 {
     196           1 :                     OGREnvelope3D sLayerEnvelope, sFeatureEnvelope;
     197           2 :                     for (auto &&poFeature : poSrcLayer)
     198             :                     {
     199           1 :                         const auto poGeom = poFeature->GetGeometryRef();
     200           1 :                         if (poGeom && !poGeom->IsEmpty())
     201             :                         {
     202           1 :                             poGeom->getEnvelope(&sFeatureEnvelope);
     203           1 :                             sLayerEnvelope.Merge(sFeatureEnvelope);
     204             :                         }
     205             : 
     206           1 :                         ++nFeatureCounter;
     207           1 :                         if (nTotalFeatures > 0 && ctxt.m_pfnProgress &&
     208           0 :                             !ctxt.m_pfnProgress(
     209           0 :                                 static_cast<double>(nFeatureCounter) /
     210           0 :                                     static_cast<double>(nTotalFeatures),
     211             :                                 "", ctxt.m_pProgressData))
     212             :                         {
     213           0 :                             ReportError(CE_Failure, CPLE_UserInterrupt,
     214             :                                         "Interrupted by user");
     215           0 :                             return false;
     216             :                         }
     217             :                     }
     218           2 :                     outDS->AddLayer(
     219             :                         *poSrcLayer,
     220             :                         std::make_unique<
     221           2 :                             GDALVectorFilterAlgorithmLayerChangeExtent>(
     222             :                             *poSrcLayer, sLayerEnvelope));
     223             :                 }
     224             :                 else
     225             :                 {
     226          40 :                     outDS->AddLayer(
     227             :                         *poSrcLayer,
     228          40 :                         std::make_unique<GDALVectorPipelinePassthroughLayer>(
     229             :                             *poSrcLayer));
     230             :                 }
     231             :             }
     232             :         }
     233             : 
     234          17 :         if (ret)
     235          17 :             m_outputDataset.Set(std::move(outDS));
     236             :     }
     237             : 
     238          18 :     return ret;
     239             : }
     240             : 
     241             : GDALVectorFilterAlgorithmStandalone::~GDALVectorFilterAlgorithmStandalone() =
     242             :     default;
     243             : 
     244             : //! @endcond

Generated by: LCOV version 1.14