LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_concave_hull.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 54 59 91.5 %
Date: 2026-04-03 14:38:35 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "gdal vector concave-hull"
       5             :  * Author:   Daniel Baston
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2026, ISciences LLC
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_vector_concave_hull.h"
      14             : 
      15             : #include "gdal_priv.h"
      16             : #include "ogrsf_frmts.h"
      17             : 
      18             : #include <cinttypes>
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : #ifndef _
      23             : #define _(x) (x)
      24             : #endif
      25             : 
      26          91 : GDALVectorConcaveHullAlgorithm::GDALVectorConcaveHullAlgorithm(
      27          91 :     bool standaloneStep)
      28             :     : GDALVectorGeomAbstractAlgorithm(NAME, DESCRIPTION, HELP_URL,
      29          91 :                                       standaloneStep, m_opts)
      30             : {
      31         182 :     AddArg("ratio", 0, _("Ratio controlling the concavity"), &m_opts.m_ratio)
      32          91 :         .SetRequired()
      33          91 :         .SetMinValueIncluded(0)
      34          91 :         .SetMaxValueIncluded(1);
      35             : 
      36             :     AddArg("allow-holes", 0, _("Allow holes in the output polygon"),
      37         182 :            &m_opts.m_allowHoles)
      38          91 :         .SetDefault(false);
      39             : 
      40             :     AddArg("tight", 0,
      41             :            _("Whether the hull must follow the outer boundaries of the input "
      42             :              "polygons"),
      43         182 :            &m_opts.m_tight)
      44          91 :         .SetDefault(false);
      45          91 : }
      46             : 
      47             : #ifdef HAVE_GEOS
      48             : 
      49             : namespace
      50             : {
      51             : 
      52             : class GDALVectorConcaveHullAlgorithmLayer final
      53             :     : public GDALVectorGeomOneToOneAlgorithmLayer<
      54             :           GDALVectorConcaveHullAlgorithm>
      55             : {
      56             :   public:
      57          12 :     GDALVectorConcaveHullAlgorithmLayer(
      58             :         OGRLayer &oSrcLayer,
      59             :         const GDALVectorConcaveHullAlgorithm::Options &opts)
      60          12 :         : GDALVectorGeomOneToOneAlgorithmLayer<GDALVectorConcaveHullAlgorithm>(
      61             :               oSrcLayer, opts),
      62          12 :           m_poFeatureDefn(oSrcLayer.GetLayerDefn()->Clone())
      63             :     {
      64          12 :         m_poFeatureDefn->Reference();
      65             : 
      66             :         // Concave hull output type can vary; advertise unknown to avoid schema conflicts.
      67             :         // In polygon/multipolygoon mode, preserve input type
      68          24 :         for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
      69             :         {
      70          12 :             if (IsSelectedGeomField(i))
      71             :             {
      72             :                 const auto eType =
      73          12 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->GetType();
      74          12 :                 if (eType != wkbPolygon && eType != wkbMultiPolygon)
      75           8 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->SetType(wkbUnknown);
      76             :             }
      77             :         }
      78          12 :     }
      79             : 
      80          24 :     ~GDALVectorConcaveHullAlgorithmLayer() override
      81          12 :     {
      82          12 :         m_poFeatureDefn->Release();
      83          24 :     }
      84             : 
      85          14 :     const OGRFeatureDefn *GetLayerDefn() const override
      86             :     {
      87          14 :         return m_poFeatureDefn;
      88             :     }
      89             : 
      90             :   protected:
      91             :     using GDALVectorGeomOneToOneAlgorithmLayer::TranslateFeature;
      92             : 
      93             :     std::unique_ptr<OGRFeature>
      94          12 :     TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature) const override
      95             :     {
      96          12 :         const int nGeomFieldCount = poSrcFeature->GetGeomFieldCount();
      97          24 :         for (int i = 0; i < nGeomFieldCount; ++i)
      98             :         {
      99          12 :             if (!IsSelectedGeomField(i))
     100           0 :                 continue;
     101             : 
     102          12 :             if (const OGRGeometry *poGeom = poSrcFeature->GetGeomFieldRef(i))
     103             :             {
     104          12 :                 const auto eType = wkbFlatten(poGeom->getGeometryType());
     105             :                 std::unique_ptr<OGRGeometry> poHull(
     106          10 :                     (eType == wkbPolygon || eType == wkbMultiPolygon)
     107           6 :                         ? poGeom->ConcaveHullOfPolygons(m_opts.m_ratio,
     108           6 :                                                         m_opts.m_tight,
     109           6 :                                                         m_opts.m_allowHoles)
     110           6 :                         : poGeom->ConcaveHull(m_opts.m_ratio,
     111          30 :                                               m_opts.m_allowHoles));
     112          12 :                 if (!poHull)
     113             :                 {
     114           0 :                     CPLError(
     115             :                         CE_Failure, CPLE_AppDefined,
     116             :                         "Failed to compute concave hull of feature %" PRId64,
     117           0 :                         static_cast<int64_t>(poSrcFeature->GetFID()));
     118           0 :                     return nullptr;
     119             :                 }
     120             :                 const auto eLayerGeomType =
     121          12 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->GetType();
     122          12 :                 if (eLayerGeomType == wkbPolygon)
     123             :                 {
     124           0 :                     poHull.reset(
     125             :                         OGRGeometryFactory::forceToPolygon(poHull.release()));
     126             :                 }
     127          12 :                 else if (eLayerGeomType == wkbMultiPolygon)
     128             :                 {
     129           4 :                     poHull.reset(OGRGeometryFactory::forceToMultiPolygon(
     130             :                         poHull.release()));
     131             :                 }
     132             : 
     133          12 :                 poHull->assignSpatialReference(poGeom->getSpatialReference());
     134          12 :                 poSrcFeature->SetGeomField(i, std::move(poHull));
     135             :             }
     136             :         }
     137             : 
     138          12 :         poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn);
     139          12 :         return poSrcFeature;
     140             :     }
     141             : 
     142             :   private:
     143             :     OGRFeatureDefn *const m_poFeatureDefn;
     144             : 
     145             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorConcaveHullAlgorithmLayer)
     146             : };
     147             : 
     148             : }  // namespace
     149             : 
     150             : #endif  // HAVE_GEOS
     151             : 
     152             : std::unique_ptr<OGRLayerWithTranslateFeature>
     153          12 : GDALVectorConcaveHullAlgorithm::CreateAlgLayer(
     154             :     [[maybe_unused]] OGRLayer &srcLayer)
     155             : {
     156             : #ifdef HAVE_GEOS
     157          12 :     return std::make_unique<GDALVectorConcaveHullAlgorithmLayer>(srcLayer,
     158          12 :                                                                  m_opts);
     159             : #else
     160             :     CPLAssert(false);
     161             :     return nullptr;
     162             : #endif
     163             : }
     164             : 
     165          12 : bool GDALVectorConcaveHullAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     166             : {
     167             : #ifdef HAVE_GEOS
     168          12 :     return GDALVectorGeomAbstractAlgorithm::RunStep(ctxt);
     169             : #else
     170             :     (void)ctxt;
     171             :     ReportError(CE_Failure, CPLE_NotSupported,
     172             :                 "This algorithm is only supported for builds against GEOS");
     173             :     return false;
     174             : #endif
     175             : }
     176             : 
     177             : GDALVectorConcaveHullAlgorithmStandalone::
     178             :     ~GDALVectorConcaveHullAlgorithmStandalone() = default;
     179             : 
     180             : //! @endcond

Generated by: LCOV version 1.14