LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_filter.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 74 98 75.5 %
Date: 2025-12-21 22:14:19 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          59 : GDALVectorFilterAlgorithm::GDALVectorFilterAlgorithm(bool standaloneStep)
      32             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      33          59 :                                       standaloneStep)
      34             : {
      35          59 :     AddActiveLayerArg(&m_activeLayer);
      36          59 :     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         118 :            &m_where)
      41          59 :         .SetReadFromFileAtSyntaxAllowed()
      42         118 :         .SetMetaVar("<WHERE>|@<filename>")
      43          59 :         .SetRemoveSQLCommentsEnabled();
      44             :     AddArg("update-extent", 0,
      45             :            _("Update layer extent to take into account the filter"),
      46          59 :            &m_updateExtent);
      47          59 : }
      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          13 : bool GDALVectorFilterAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     112             : {
     113          13 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     114          13 :     CPLAssert(poSrcDS);
     115             : 
     116          13 :     CPLAssert(m_outputDataset.GetName().empty());
     117          13 :     CPLAssert(!m_outputDataset.GetDatasetRef());
     118             : 
     119          13 :     const int nLayerCount = poSrcDS->GetLayerCount();
     120             : 
     121          13 :     bool ret = true;
     122          13 :     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          13 :     if (ret && !m_where.empty())
     139             :     {
     140          17 :         for (int i = 0; i < nLayerCount; ++i)
     141             :         {
     142          10 :             auto poSrcLayer = poSrcDS->GetLayer(i);
     143          10 :             ret = ret && (poSrcLayer != nullptr);
     144          14 :             if (ret && (m_activeLayer.empty() ||
     145           4 :                         m_activeLayer == poSrcLayer->GetDescription()))
     146             :             {
     147           8 :                 ret = poSrcLayer->SetAttributeFilter(m_where.c_str()) ==
     148             :                       OGRERR_NONE;
     149             :             }
     150             :         }
     151             :     }
     152             : 
     153          13 :     if (ret && m_updateExtent)
     154             :     {
     155             :         auto outDS =
     156           1 :             std::make_unique<GDALVectorPipelineOutputDataset>(*poSrcDS);
     157             : 
     158           1 :         int64_t nTotalFeatures = 0;
     159           1 :         if (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           1 :         int64_t nFeatureCounter = 0;
     186           3 :         for (int i = 0; ret && i < nLayerCount; ++i)
     187             :         {
     188           2 :             auto poSrcLayer = poSrcDS->GetLayer(i);
     189           2 :             ret = (poSrcLayer != nullptr);
     190           2 :             if (ret)
     191             :             {
     192           4 :                 if (m_activeLayer.empty() ||
     193           2 :                     m_activeLayer == poSrcLayer->GetDescription())
     194             :                 {
     195           1 :                     OGREnvelope3D sLayerEnvelope, sFeatureEnvelope;
     196           2 :                     for (auto &&poFeature : poSrcLayer)
     197             :                     {
     198           1 :                         const auto poGeom = poFeature->GetGeometryRef();
     199           1 :                         if (poGeom && !poGeom->IsEmpty())
     200             :                         {
     201           1 :                             poGeom->getEnvelope(&sFeatureEnvelope);
     202           1 :                             sLayerEnvelope.Merge(sFeatureEnvelope);
     203             :                         }
     204             : 
     205           1 :                         ++nFeatureCounter;
     206           1 :                         if (nTotalFeatures > 0 && ctxt.m_pfnProgress &&
     207           0 :                             !ctxt.m_pfnProgress(
     208           0 :                                 static_cast<double>(nFeatureCounter) /
     209           0 :                                     static_cast<double>(nTotalFeatures),
     210             :                                 "", ctxt.m_pProgressData))
     211             :                         {
     212           0 :                             ReportError(CE_Failure, CPLE_UserInterrupt,
     213             :                                         "Interrupted by user");
     214           0 :                             return false;
     215             :                         }
     216             :                     }
     217           2 :                     outDS->AddLayer(
     218             :                         *poSrcLayer,
     219             :                         std::make_unique<
     220           2 :                             GDALVectorFilterAlgorithmLayerChangeExtent>(
     221             :                             *poSrcLayer, sLayerEnvelope));
     222             :                 }
     223             :                 else
     224             :                 {
     225           2 :                     outDS->AddLayer(
     226             :                         *poSrcLayer,
     227           2 :                         std::make_unique<GDALVectorPipelinePassthroughLayer>(
     228             :                             *poSrcLayer));
     229             :                 }
     230             :             }
     231             :         }
     232             : 
     233           1 :         if (ret)
     234           2 :             m_outputDataset.Set(std::move(outDS));
     235             :     }
     236          12 :     else if (ret)
     237             :     {
     238          11 :         m_outputDataset.Set(poSrcDS);
     239             :     }
     240             : 
     241          13 :     return ret;
     242             : }
     243             : 
     244             : GDALVectorFilterAlgorithmStandalone::~GDALVectorFilterAlgorithmStandalone() =
     245             :     default;
     246             : 
     247             : //! @endcond

Generated by: LCOV version 1.14