LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_polygonize.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 105 111 94.6 %
Date: 2025-05-15 13:16:46 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster polygonize" subcommand
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdalalg_raster_polygonize.h"
      14             : 
      15             : #include "cpl_conv.h"
      16             : #include "gdal_priv.h"
      17             : #include "gdal_alg.h"
      18             : #include "ogrsf_frmts.h"
      19             : 
      20             : //! @cond Doxygen_Suppress
      21             : 
      22             : #ifndef _
      23             : #define _(x) (x)
      24             : #endif
      25             : 
      26             : /************************************************************************/
      27             : /*     GDALRasterPolygonizeAlgorithm::GDALRasterPolygonizeAlgorithm()   */
      28             : /************************************************************************/
      29             : 
      30          19 : GDALRasterPolygonizeAlgorithm::GDALRasterPolygonizeAlgorithm()
      31          19 :     : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
      32             : {
      33             : 
      34          19 :     AddProgressArg();
      35          19 :     AddOutputFormatArg(&m_outputFormat)
      36             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      37          57 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      38          19 :     AddOpenOptionsArg(&m_openOptions);
      39          19 :     AddInputFormatsArg(&m_inputFormats)
      40          38 :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_RASTER});
      41          19 :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER);
      42          19 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR)
      43          19 :         .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
      44          19 :     AddCreationOptionsArg(&m_creationOptions);
      45          19 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
      46          19 :     AddOverwriteArg(&m_overwrite);
      47          19 :     auto &updateArg = AddUpdateArg(&m_update);
      48             :     AddArg("overwrite-layer", 0,
      49             :            _("Whether overwriting existing layer is allowed"),
      50          38 :            &m_overwriteLayer)
      51          19 :         .SetDefault(false)
      52             :         .AddValidationAction(
      53           1 :             [&updateArg]
      54             :             {
      55           1 :                 updateArg.Set(true);
      56           1 :                 return true;
      57          19 :             });
      58             :     AddAppendUpdateArg(&m_appendLayer,
      59          19 :                        _("Whether appending to existing layer is allowed"));
      60             : 
      61             :     // gdal_polygonize specific options
      62          19 :     AddBandArg(&m_band).SetDefault(m_band);
      63          19 :     AddLayerNameArg(&m_outputLayerName)
      64          38 :         .AddAlias("nln")
      65          19 :         .SetDefault(m_outputLayerName);
      66             :     AddArg("attribute-name", 0, _("Name of the field with the pixel value"),
      67          38 :            &m_attributeName)
      68          19 :         .SetDefault(m_attributeName);
      69             : 
      70             :     AddArg("connect-diagonal-pixels", 'c',
      71          38 :            _("Consider diagonal pixels as connected"), &m_connectDiagonalPixels)
      72          19 :         .SetDefault(m_connectDiagonalPixels);
      73          19 : }
      74             : 
      75             : /************************************************************************/
      76             : /*                GDALRasterPolygonizeAlgorithm::RunImpl()              */
      77             : /************************************************************************/
      78             : 
      79          15 : bool GDALRasterPolygonizeAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
      80             :                                             void *pProgressData)
      81             : {
      82          15 :     auto poSrcDS = m_inputDataset.GetDatasetRef();
      83          15 :     CPLAssert(poSrcDS);
      84             : 
      85          15 :     GDALDataset *poDstDS = m_outputDataset.GetDatasetRef();
      86          15 :     std::unique_ptr<GDALDataset> poRetDS;
      87          15 :     if (!poDstDS)
      88             :     {
      89          10 :         if (m_outputFormat.empty())
      90             :         {
      91             :             const auto aosFormats =
      92             :                 CPLStringList(GDALGetOutputDriversForDatasetName(
      93           5 :                     m_outputDataset.GetName().c_str(), GDAL_OF_VECTOR,
      94             :                     /* bSingleMatch = */ true,
      95           5 :                     /* bWarn = */ true));
      96           5 :             if (aosFormats.size() != 1)
      97             :             {
      98           1 :                 ReportError(CE_Failure, CPLE_AppDefined,
      99             :                             "Cannot guess driver for %s",
     100           1 :                             m_outputDataset.GetName().c_str());
     101           1 :                 return false;
     102             :             }
     103           4 :             m_outputFormat = aosFormats[0];
     104             :         }
     105             : 
     106             :         auto poDriver =
     107           9 :             GetGDALDriverManager()->GetDriverByName(m_outputFormat.c_str());
     108           9 :         if (!poDriver)
     109             :         {
     110             :             // shouldn't happen given checks done in GDALAlgorithm
     111           0 :             ReportError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
     112             :                         m_outputFormat.c_str());
     113           0 :             return false;
     114             :         }
     115             : 
     116           9 :         poRetDS.reset(poDriver->Create(
     117           9 :             m_outputDataset.GetName().c_str(), 0, 0, 0, GDT_Unknown,
     118          18 :             CPLStringList(m_creationOptions).List()));
     119           9 :         if (!poRetDS)
     120           1 :             return false;
     121             : 
     122           8 :         poDstDS = poRetDS.get();
     123             :     }
     124             : 
     125          13 :     auto poDstDriver = poDstDS->GetDriver();
     126          13 :     if (poDstDriver && EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile") &&
     127          31 :         EQUAL(CPLGetExtensionSafe(poDstDS->GetDescription()).c_str(), "shp") &&
     128           5 :         poDstDS->GetLayerCount() <= 1)
     129             :     {
     130           5 :         m_outputLayerName = CPLGetBasenameSafe(poDstDS->GetDescription());
     131             :     }
     132             : 
     133          13 :     auto poDstLayer = poDstDS->GetLayerByName(m_outputLayerName.c_str());
     134          13 :     if (poDstLayer)
     135             :     {
     136           4 :         if (m_overwriteLayer)
     137             :         {
     138           1 :             int iLayer = -1;
     139           1 :             const int nLayerCount = poDstDS->GetLayerCount();
     140           1 :             for (iLayer = 0; iLayer < nLayerCount; iLayer++)
     141             :             {
     142           1 :                 if (poDstDS->GetLayer(iLayer) == poDstLayer)
     143           1 :                     break;
     144             :             }
     145             : 
     146           1 :             if (iLayer < nLayerCount)
     147             :             {
     148           1 :                 if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
     149             :                 {
     150           0 :                     ReportError(CE_Failure, CPLE_AppDefined,
     151             :                                 "Cannot delete layer '%s'",
     152             :                                 m_outputLayerName.c_str());
     153           0 :                     return false;
     154             :                 }
     155             :             }
     156           1 :             poDstLayer = nullptr;
     157             :         }
     158           3 :         else if (!m_appendLayer)
     159             :         {
     160           1 :             ReportError(CE_Failure, CPLE_AppDefined,
     161             :                         "Layer '%s' already exists. Specify the "
     162             :                         "--overwrite-layer option to overwrite it, or --append "
     163             :                         "to append to it.",
     164             :                         m_outputLayerName.c_str());
     165           1 :             return false;
     166             :         }
     167             :     }
     168           9 :     else if (m_appendLayer || m_overwriteLayer)
     169             :     {
     170           1 :         ReportError(CE_Failure, CPLE_AppDefined, "Cannot find layer '%s'",
     171             :                     m_outputLayerName.c_str());
     172           1 :         return false;
     173             :     }
     174             : 
     175          11 :     auto poSrcBand = poSrcDS->GetRasterBand(m_band);
     176          11 :     const auto eDT = poSrcBand->GetRasterDataType();
     177             : 
     178          11 :     if (!poDstLayer)
     179             :     {
     180           9 :         poDstLayer = poDstDS->CreateLayer(
     181           9 :             m_outputLayerName.c_str(), poSrcDS->GetSpatialRef(), wkbPolygon,
     182          18 :             CPLStringList(m_layerCreationOptions).List());
     183           9 :         if (!poDstLayer)
     184             :         {
     185           1 :             ReportError(CE_Failure, CPLE_AppDefined, "Cannot create layer '%s'",
     186             :                         m_outputLayerName.c_str());
     187           1 :             return false;
     188             :         }
     189             : 
     190             :         OGRFieldDefn oFieldDefn(m_attributeName.c_str(),
     191           8 :                                 !GDALDataTypeIsInteger(eDT) ? OFTReal
     192           6 :                                 : eDT == GDT_Int64 || eDT == GDT_UInt64
     193          13 :                                     ? OFTInteger64
     194          15 :                                     : OFTInteger);
     195           8 :         if (poDstLayer->CreateField(&oFieldDefn) != OGRERR_NONE)
     196             :         {
     197           0 :             ReportError(CE_Failure, CPLE_AppDefined,
     198             :                         "Cannot create field '%s' in layer '%s'",
     199             :                         m_attributeName.c_str(), m_outputLayerName.c_str());
     200           0 :             return false;
     201             :         }
     202             :     }
     203             : 
     204             :     const int iPixValField =
     205          10 :         poDstLayer->GetLayerDefn()->GetFieldIndex(m_attributeName.c_str());
     206          10 :     if (iPixValField < 0)
     207             :     {
     208           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     209             :                     "Cannot find field '%s' in layer '%s'",
     210             :                     m_attributeName.c_str(), m_outputLayerName.c_str());
     211           1 :         return false;
     212             :     }
     213             : 
     214           9 :     CPLStringList aosPolygonizeOptions;
     215           9 :     if (m_connectDiagonalPixels)
     216             :     {
     217           1 :         aosPolygonizeOptions.SetNameValue("8CONNECTED", "8");
     218             :     }
     219             : 
     220             :     bool ret;
     221           9 :     if (GDALDataTypeIsInteger(eDT))
     222             :     {
     223          16 :         ret = GDALPolygonize(GDALRasterBand::ToHandle(poSrcBand),
     224           8 :                              GDALRasterBand::ToHandle(poSrcBand->GetMaskBand()),
     225             :                              OGRLayer::ToHandle(poDstLayer), iPixValField,
     226             :                              aosPolygonizeOptions.List(), pfnProgress,
     227             :                              pProgressData) == CE_None;
     228             :     }
     229             :     else
     230             :     {
     231           1 :         ret =
     232           2 :             GDALFPolygonize(GDALRasterBand::ToHandle(poSrcBand),
     233           1 :                             GDALRasterBand::ToHandle(poSrcBand->GetMaskBand()),
     234             :                             OGRLayer::ToHandle(poDstLayer), iPixValField,
     235             :                             aosPolygonizeOptions.List(), pfnProgress,
     236             :                             pProgressData) == CE_None;
     237             :     }
     238             : 
     239           9 :     if (ret && poRetDS)
     240             :     {
     241           7 :         m_outputDataset.Set(std::move(poRetDS));
     242             :     }
     243             : 
     244           9 :     return ret;
     245             : }
     246             : 
     247             : //! @endcond

Generated by: LCOV version 1.14