LCOV - code coverage report
Current view: top level - apps - gdalalg_vector_concave_hull.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 49 54 90.7 %
Date: 2026-04-23 19:47:11 Functions: 6 6 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             :         // Concave hull output type can vary; advertise unknown to avoid schema conflicts.
      65             :         // In polygon/multipolygoon mode, preserve input type
      66          24 :         for (int i = 0; i < m_poFeatureDefn->GetGeomFieldCount(); ++i)
      67             :         {
      68          12 :             if (IsSelectedGeomField(i))
      69             :             {
      70             :                 const auto eType =
      71          12 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->GetType();
      72          12 :                 if (eType != wkbPolygon && eType != wkbMultiPolygon)
      73           8 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->SetType(wkbUnknown);
      74             :             }
      75             :         }
      76          12 :     }
      77             : 
      78          14 :     const OGRFeatureDefn *GetLayerDefn() const override
      79             :     {
      80          14 :         return m_poFeatureDefn.get();
      81             :     }
      82             : 
      83             :   protected:
      84             :     using GDALVectorGeomOneToOneAlgorithmLayer::TranslateFeature;
      85             : 
      86             :     std::unique_ptr<OGRFeature>
      87          12 :     TranslateFeature(std::unique_ptr<OGRFeature> poSrcFeature) const override
      88             :     {
      89          12 :         const int nGeomFieldCount = poSrcFeature->GetGeomFieldCount();
      90          24 :         for (int i = 0; i < nGeomFieldCount; ++i)
      91             :         {
      92          12 :             if (!IsSelectedGeomField(i))
      93           0 :                 continue;
      94             : 
      95          12 :             if (const OGRGeometry *poGeom = poSrcFeature->GetGeomFieldRef(i))
      96             :             {
      97          12 :                 const auto eType = wkbFlatten(poGeom->getGeometryType());
      98             :                 std::unique_ptr<OGRGeometry> poHull(
      99          10 :                     (eType == wkbPolygon || eType == wkbMultiPolygon)
     100           6 :                         ? poGeom->ConcaveHullOfPolygons(m_opts.m_ratio,
     101           6 :                                                         m_opts.m_tight,
     102           6 :                                                         m_opts.m_allowHoles)
     103           6 :                         : poGeom->ConcaveHull(m_opts.m_ratio,
     104          30 :                                               m_opts.m_allowHoles));
     105          12 :                 if (!poHull)
     106             :                 {
     107           0 :                     CPLError(
     108             :                         CE_Failure, CPLE_AppDefined,
     109             :                         "Failed to compute concave hull of feature %" PRId64,
     110           0 :                         static_cast<int64_t>(poSrcFeature->GetFID()));
     111           0 :                     return nullptr;
     112             :                 }
     113             :                 const auto eLayerGeomType =
     114          12 :                     m_poFeatureDefn->GetGeomFieldDefn(i)->GetType();
     115          12 :                 if (eLayerGeomType == wkbPolygon)
     116             :                 {
     117           0 :                     poHull.reset(
     118             :                         OGRGeometryFactory::forceToPolygon(poHull.release()));
     119             :                 }
     120          12 :                 else if (eLayerGeomType == wkbMultiPolygon)
     121             :                 {
     122           4 :                     poHull.reset(OGRGeometryFactory::forceToMultiPolygon(
     123             :                         poHull.release()));
     124             :                 }
     125             : 
     126          12 :                 poHull->assignSpatialReference(poGeom->getSpatialReference());
     127          12 :                 poSrcFeature->SetGeomField(i, std::move(poHull));
     128             :             }
     129             :         }
     130             : 
     131          12 :         poSrcFeature->SetFDefnUnsafe(m_poFeatureDefn.get());
     132          12 :         return poSrcFeature;
     133             :     }
     134             : 
     135             :   private:
     136             :     const OGRFeatureDefnRefCountedPtr m_poFeatureDefn;
     137             : 
     138             :     CPL_DISALLOW_COPY_ASSIGN(GDALVectorConcaveHullAlgorithmLayer)
     139             : };
     140             : 
     141             : }  // namespace
     142             : 
     143             : #endif  // HAVE_GEOS
     144             : 
     145             : std::unique_ptr<OGRLayerWithTranslateFeature>
     146          12 : GDALVectorConcaveHullAlgorithm::CreateAlgLayer(
     147             :     [[maybe_unused]] OGRLayer &srcLayer)
     148             : {
     149             : #ifdef HAVE_GEOS
     150          12 :     return std::make_unique<GDALVectorConcaveHullAlgorithmLayer>(srcLayer,
     151          12 :                                                                  m_opts);
     152             : #else
     153             :     CPLAssert(false);
     154             :     return nullptr;
     155             : #endif
     156             : }
     157             : 
     158          12 : bool GDALVectorConcaveHullAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
     159             : {
     160             : #ifdef HAVE_GEOS
     161          12 :     return GDALVectorGeomAbstractAlgorithm::RunStep(ctxt);
     162             : #else
     163             :     (void)ctxt;
     164             :     ReportError(CE_Failure, CPLE_NotSupported,
     165             :                 "This algorithm is only supported for builds against GEOS");
     166             :     return false;
     167             : #endif
     168             : }
     169             : 
     170             : GDALVectorConcaveHullAlgorithmStandalone::
     171             :     ~GDALVectorConcaveHullAlgorithmStandalone() = default;
     172             : 
     173             : //! @endcond

Generated by: LCOV version 1.14