LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_simplify_coverage.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 60 62 96.8 %
Date: 2026-09-11 05:09:32 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             : *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "gdal vector simplify-coverage" subcommand
       5             :  * Author:   Daniel Baston
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, ISciences LLC
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_simplify_coverage.h"
      14             : 
      15             : #include "cpl_error.h"
      16             : #include "gdal_priv.h"
      17             : #include "gdalalg_vector_geom.h"
      18             : #include "ogr_geometry.h"
      19             : #include "ogr_geos.h"
      20             : #include "ogrsf_frmts.h"
      21             : 
      22             : #include <cinttypes>
      23             : 
      24             : #ifndef _
      25             : #define _(x) (x)
      26             : #endif
      27             : 
      28             : //! @cond Doxygen_Suppress
      29             : 
      30          90 : GDALVectorSimplifyCoverageAlgorithm::GDALVectorSimplifyCoverageAlgorithm(
      31          90 :     bool standaloneStep)
      32             :     : GDALVectorPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      33          90 :                                       standaloneStep)
      34             : {
      35          90 :     AddActiveLayerArg(&m_activeLayer);
      36             :     AddArg("tolerance", 0, _("Distance tolerance for simplification."),
      37         180 :            &m_opts.tolerance)
      38          90 :         .SetPositional()
      39          90 :         .SetRequired()
      40          90 :         .SetMinValueIncluded(0);
      41             :     AddArg("preserve-boundary", 0,
      42             :            _("Whether the exterior boundary should be preserved."),
      43          90 :            &m_opts.preserveBoundary);
      44          90 : }
      45             : 
      46             : #if defined HAVE_GEOS &&                                                       \
      47             :     (GEOS_VERSION_MAJOR > 3 ||                                                 \
      48             :      (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 12))
      49             : 
      50          14 : class GDALVectorSimplifyCoverageOutputLayer final
      51             :     : public GDALGeosNonStreamingAlgorithmLayer
      52             : {
      53             :   public:
      54           7 :     GDALVectorSimplifyCoverageOutputLayer(
      55             :         OGRLayer &srcLayer, int geomFieldIndex,
      56             :         const GDALVectorSimplifyCoverageAlgorithm::Options &opts)
      57           7 :         : GDALGeosNonStreamingAlgorithmLayer(srcLayer, geomFieldIndex),
      58           7 :           m_opts(opts)
      59             :     {
      60           7 :     }
      61             : 
      62             :     ~GDALVectorSimplifyCoverageOutputLayer() override;
      63             : 
      64         317 :     const OGRFeatureDefn *GetLayerDefn() const override
      65             :     {
      66         317 :         return m_srcLayer.GetLayerDefn();
      67             :     }
      68             : 
      69          15 :     GIntBig GetFeatureCount(int bForce) override
      70             :     {
      71          15 :         if (!m_poAttrQuery && !m_poFilterGeom)
      72             :         {
      73           9 :             return m_srcLayer.GetFeatureCount(bForce);
      74             :         }
      75             : 
      76           6 :         return OGRLayer::GetFeatureCount(bForce);
      77             :     }
      78             : 
      79          37 :     bool TestCapability(const char *pszCap) const override
      80             :     {
      81          37 :         if (EQUAL(pszCap, OLCFastFeatureCount))
      82             :         {
      83           0 :             return m_srcLayer.TestCapability(pszCap);
      84             :         }
      85             : 
      86          37 :         return false;
      87             :     }
      88             : 
      89          43 :     bool PolygonsOnly() const override
      90             :     {
      91          43 :         return true;
      92             :     }
      93             : 
      94          30 :     bool SkipEmpty() const override
      95             :     {
      96          30 :         return false;
      97             :     }
      98             : 
      99           4 :     bool ProcessGeos(GDALProgressFunc pfnProgress, void *pProgressData) override
     100             :     {
     101             :         // Perform coverage simplification
     102           4 :         GEOSGeometry *coll = GEOSGeom_createCollection_r(
     103             :             m_poGeosContext, GEOS_GEOMETRYCOLLECTION, m_apoGeosInputs.data(),
     104           4 :             static_cast<unsigned int>(m_apoGeosInputs.size()));
     105             : 
     106           4 :         if (coll == nullptr)
     107             :         {
     108           0 :             return false;
     109             :         }
     110             : 
     111           4 :         m_apoGeosInputs.clear();
     112             : 
     113             :         GDALGEOSProgressReporter oReporter(m_poGeosContext, pfnProgress,
     114           4 :                                            pProgressData);
     115             : 
     116           8 :         m_poGeosResultAsCollection = GEOSCoverageSimplifyVW_r(
     117           4 :             m_poGeosContext, coll, m_opts.tolerance, m_opts.preserveBoundary);
     118           4 :         GEOSGeom_destroy_r(m_poGeosContext, coll);
     119             : 
     120           4 :         return m_poGeosResultAsCollection != nullptr;
     121             :     }
     122             : 
     123             :   private:
     124             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorSimplifyCoverageOutputLayer)
     125             : 
     126             :     const GDALVectorSimplifyCoverageAlgorithm::Options &m_opts;
     127             : };
     128             : 
     129             : GDALVectorSimplifyCoverageOutputLayer::
     130             :     ~GDALVectorSimplifyCoverageOutputLayer() = default;
     131             : 
     132           9 : bool GDALVectorSimplifyCoverageAlgorithm::RunStep(
     133             :     GDALPipelineStepRunContext &ctxt)
     134             : {
     135           9 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
     136             :     auto poDstDS =
     137          18 :         std::make_unique<GDALVectorNonStreamingAlgorithmDataset>(*poSrcDS);
     138             : 
     139          18 :     GDALVectorAlgorithmLayerProgressHelper progressHelper(ctxt);
     140             : 
     141          20 :     for (auto &&poSrcLayer : poSrcDS->GetLayers())
     142             :     {
     143          16 :         if ((m_activeLayer.empty() && poSrcLayer->GetGeomType() != wkbNone) ||
     144           5 :             m_activeLayer == poSrcLayer->GetDescription())
     145             :         {
     146           7 :             progressHelper.AddProcessedLayer(*poSrcLayer);
     147             :         }
     148             :         else
     149             :         {
     150           4 :             progressHelper.AddPassThroughLayer(*poSrcLayer);
     151             :         }
     152             :     }
     153             : 
     154           9 :     if (!m_activeLayer.empty() && !progressHelper.HasProcessedLayers())
     155             :     {
     156           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     157             :                     "Specified layer '%s' was not found",
     158             :                     m_activeLayer.c_str());
     159           1 :         return false;
     160             :     }
     161             : 
     162          15 :     for (auto [poSrcLayer, bProcessed, layerProgressFunc, layerProgressData] :
     163          20 :          progressHelper)
     164             :     {
     165           9 :         if (bProcessed)
     166             :         {
     167           7 :             constexpr int geomFieldIndex = 0;  // TODO: parametrize
     168             :             auto poLayer =
     169             :                 std::make_unique<GDALVectorSimplifyCoverageOutputLayer>(
     170           7 :                     *poSrcLayer, geomFieldIndex, m_opts);
     171             : 
     172           7 :             if (!poDstDS->AddProcessedLayer(std::move(poLayer),
     173             :                                             layerProgressFunc,
     174             :                                             layerProgressData.get()))
     175             :             {
     176           3 :                 return false;
     177             :             }
     178             :         }
     179             :         else
     180             :         {
     181           2 :             poDstDS->AddPassThroughLayer(*poSrcLayer);
     182             :         }
     183             :     }
     184             : 
     185           5 :     m_outputDataset.Set(std::move(poDstDS));
     186             : 
     187           5 :     return true;
     188             : }
     189             : 
     190             : #else
     191             : 
     192             : bool GDALVectorSimplifyCoverageAlgorithm::RunStep(GDALPipelineStepRunContext &)
     193             : {
     194             :     ReportError(CE_Failure, CPLE_AppDefined,
     195             :                 "%s requires GDAL to be built against version 3.12 or later of "
     196             :                 "the GEOS library.",
     197             :                 NAME);
     198             :     return false;
     199             : }
     200             : #endif  // HAVE_GEOS
     201             : 
     202             : GDALVectorSimplifyCoverageAlgorithmStandalone::
     203             :     ~GDALVectorSimplifyCoverageAlgorithmStandalone() = default;
     204             : 
     205             : //! @endcond

Generated by: LCOV version 1.14