LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_contour.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 101 109 92.7 %
Date: 2025-03-28 11:40:40 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster contour" subcommand
       5             :  * Author:   Alessandro Pasotti <elpaso at itopen dot it>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2025, Alessandro Pasotti <elpaso at itopen dot it>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include <cmath>
      14             : 
      15             : #include "gdalalg_raster_contour.h"
      16             : 
      17             : #include "cpl_conv.h"
      18             : #include "gdal_priv.h"
      19             : #include "gdal_utils.h"
      20             : #include "gdal_alg.h"
      21             : #include "gdal_utils_priv.h"
      22             : 
      23             : //! @cond Doxygen_Suppress
      24             : 
      25             : #ifndef _
      26             : #define _(x) (x)
      27             : #endif
      28             : 
      29             : /************************************************************************/
      30             : /*          GDALRasterContourAlgorithm::GDALRasterContourAlgorithm()    */
      31             : /************************************************************************/
      32             : 
      33          18 : GDALRasterContourAlgorithm::GDALRasterContourAlgorithm()
      34             :     : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL), m_outputLayerName("contour"),
      35          18 :       m_elevAttributeName(""), m_amin(""), m_amax(""), m_levels{}
      36             : {
      37             : 
      38          18 :     AddProgressArg();
      39          18 :     AddOutputFormatArg(&m_outputFormat)
      40             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      41          54 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATECOPY});
      42          18 :     AddOpenOptionsArg(&m_openOptions);
      43          18 :     AddInputFormatsArg(&m_inputFormats)
      44          36 :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_RASTER});
      45          18 :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER);
      46          18 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER);
      47          18 :     AddCreationOptionsArg(&m_creationOptions);
      48             : 
      49             :     // gdal_contour specific options
      50          18 :     AddArg("band", 'b', _("Specify input band number"), &m_band).SetDefault(1);
      51          18 :     AddLayerNameArg(&m_outputLayerName).AddAlias("nln");
      52             :     AddArg("elevation-name", 0, _("Name of the elevation field"),
      53          18 :            &m_elevAttributeName);
      54          18 :     AddArg("min-name", 0, _("Name of the minimum elevation field"), &m_amin);
      55          18 :     AddArg("max-name", 0, _("Name of the maximum elevation field"), &m_amax);
      56          18 :     AddArg("3d", 0, _("Force production of 3D vectors instead of 2D"), &m_3d);
      57             : 
      58             :     AddArg("srcnodata", 0, _("Input pixel value to treat as 'nodata'"),
      59          18 :            &m_sNodata);
      60          36 :     AddArg("interval", 0, _("Elevation interval between contours"), &m_interval)
      61          18 :         .SetMutualExclusionGroup("levels");
      62          36 :     AddArg("levels", 0, _("List of contour levels"), &m_levels)
      63          18 :         .SetMutualExclusionGroup("levels");
      64             :     AddArg("exp-base", 'e', _("Base for exponential contour level generation"),
      65          36 :            &m_expBase)
      66          18 :         .SetMutualExclusionGroup("levels");
      67          36 :     AddArg("offset", 0, _("Offset to apply to contour levels"), &m_offset)
      68          18 :         .AddAlias("off");
      69             :     AddArg("polygonize", 'p', _("Create polygons instead of lines"),
      70          18 :            &m_polygonize);
      71             :     AddArg("group-transactions", 0,
      72             :            _("Group n features per transaction (default 100 000)"),
      73          18 :            &m_groupTransactions);
      74          18 :     AddOverwriteArg(&m_overwrite);
      75          18 : }
      76             : 
      77             : /************************************************************************/
      78             : /*                  GDALRasterContourAlgorithm::RunImpl()               */
      79             : /************************************************************************/
      80             : 
      81          14 : bool GDALRasterContourAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
      82             :                                          void *pProgressData)
      83             : {
      84             : 
      85          14 :     CPLErrorReset();
      86             : 
      87          14 :     CPLAssert(m_inputDataset.GetDatasetRef());
      88          14 :     if (m_outputDataset.GetDatasetRef())
      89             :     {
      90           0 :         CPLError(CE_Failure, CPLE_NotSupported,
      91             :                  "gdal raster contour does not support outputting to an "
      92             :                  "already opened output dataset");
      93           0 :         return false;
      94             :     }
      95             : 
      96          28 :     CPLStringList aosOptions;
      97          14 :     if (!m_outputFormat.empty())
      98             :     {
      99           0 :         aosOptions.AddString("-of");
     100           0 :         aosOptions.AddString(m_outputFormat);
     101             :     }
     102             : 
     103          14 :     for (const auto &co : m_creationOptions)
     104             :     {
     105           0 :         aosOptions.AddString("-co");
     106           0 :         aosOptions.AddString(co);
     107             :     }
     108          14 :     if (m_band > 0)
     109             :     {
     110          14 :         aosOptions.AddString("-b");
     111          14 :         aosOptions.AddString(CPLSPrintf("%d", m_band));
     112             :     }
     113          14 :     if (!m_elevAttributeName.empty())
     114             :     {
     115           5 :         aosOptions.AddString("-a");
     116           5 :         aosOptions.AddString(m_elevAttributeName);
     117             :     }
     118          14 :     if (!m_amin.empty())
     119             :     {
     120           7 :         aosOptions.AddString("-amin");
     121           7 :         aosOptions.AddString(m_amin);
     122             :     }
     123          14 :     if (!m_amax.empty())
     124             :     {
     125           7 :         aosOptions.AddString("-amax");
     126           7 :         aosOptions.AddString(m_amax);
     127             :     }
     128          14 :     if (m_3d)
     129             :     {
     130           0 :         aosOptions.AddString("-3d");
     131             :     }
     132          14 :     if (!std::isnan(m_sNodata))
     133             :     {
     134           1 :         aosOptions.AddString("-snodata");
     135           1 :         aosOptions.AddString(CPLSPrintf("%.16g", m_sNodata));
     136             :     }
     137          14 :     if (m_levels.size() > 0)
     138             :     {
     139          12 :         for (const auto &level : m_levels)
     140             :         {
     141           8 :             aosOptions.AddString("-fl");
     142           8 :             aosOptions.AddString(level);
     143             :         }
     144             :     }
     145          14 :     if (!std::isnan(m_interval))
     146             :     {
     147           8 :         aosOptions.AddString("-i");
     148           8 :         aosOptions.AddString(CPLSPrintf("%.16g", m_interval));
     149             :     }
     150          14 :     if (m_expBase > 0)
     151             :     {
     152           1 :         aosOptions.AddString("-e");
     153           1 :         aosOptions.AddString(CPLSPrintf("%d", m_expBase));
     154             :     }
     155          14 :     if (!std::isnan(m_offset))
     156             :     {
     157           1 :         aosOptions.AddString("-off");
     158           1 :         aosOptions.AddString(CPLSPrintf("%.16g", m_offset));
     159             :     }
     160          14 :     if (m_polygonize)
     161             :     {
     162           6 :         aosOptions.AddString("-p");
     163             :     }
     164          14 :     if (!m_outputLayerName.empty())
     165             :     {
     166          14 :         aosOptions.AddString("-nln");
     167          14 :         aosOptions.AddString(m_outputLayerName);
     168             :     }
     169             : 
     170             :     VSIStatBufL sStat;
     171          27 :     if (!m_overwrite && !m_outputDataset.GetName().empty() &&
     172          25 :         (VSIStatL(m_outputDataset.GetName().c_str(), &sStat) == 0 ||
     173          26 :          std::unique_ptr<GDALDataset>(
     174          24 :              GDALDataset::Open(m_outputDataset.GetName().c_str()))))
     175             :     {
     176           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     177             :                     "File '%s' already exists. Specify the --overwrite "
     178             :                     "option to overwrite it.",
     179           1 :                     m_outputDataset.GetName().c_str());
     180           1 :         return false;
     181             :     }
     182             : 
     183             :     // Check that one of --interval, --levels, --exp-base is specified
     184          13 :     if (m_levels.size() == 0 && std::isnan(m_interval) && m_expBase == 0)
     185             :     {
     186           1 :         ReportError(
     187             :             CE_Failure, CPLE_AppDefined,
     188             :             "One of 'interval', 'levels', 'exp-base' must be specified.");
     189           1 :         return false;
     190             :     }
     191             : 
     192             :     // Check that interval is not negative
     193          12 :     if (!std::isnan(m_interval) && m_interval < 0)
     194             :     {
     195           1 :         ReportError(CE_Failure, CPLE_AppDefined,
     196             :                     "Interval must be a positive number.");
     197           1 :         return false;
     198             :     }
     199             : 
     200          11 :     aosOptions.AddString(m_inputDataset.GetName());
     201          11 :     aosOptions.AddString(m_outputDataset.GetName());
     202             : 
     203          22 :     GDALContourOptionsForBinary optionsForBinary;
     204             :     std::unique_ptr<GDALContourOptions, decltype(&GDALContourOptionsFree)>
     205             :         psOptions{GDALContourOptionsNew(aosOptions.List(), &optionsForBinary),
     206          22 :                   GDALContourOptionsFree};
     207             : 
     208          11 :     if (!psOptions)
     209             :     {
     210           0 :         return false;
     211             :     }
     212             : 
     213          11 :     GDALDatasetH hSrcDS{m_inputDataset.GetDatasetRef()};
     214          11 :     GDALRasterBandH hBand{nullptr};
     215          11 :     GDALDatasetH hDstDS{m_outputDataset.GetDatasetRef()};
     216          11 :     OGRLayerH hLayer{nullptr};
     217          11 :     char **papszStringOptions = nullptr;
     218             : 
     219             :     CPLErr eErr =
     220          11 :         GDALContourProcessOptions(psOptions.get(), &papszStringOptions, &hSrcDS,
     221             :                                   &hBand, &hDstDS, &hLayer);
     222             : 
     223          11 :     if (eErr == CE_None)
     224             :     {
     225          11 :         eErr = GDALContourGenerateEx(hBand, hLayer, papszStringOptions,
     226             :                                      pfnProgress, pProgressData);
     227             :     }
     228             : 
     229          11 :     CSLDestroy(papszStringOptions);
     230             : 
     231          11 :     auto poDstDS = GDALDataset::FromHandle(hDstDS);
     232          11 :     m_outputDataset.Set(std::unique_ptr<GDALDataset>(poDstDS));
     233             : 
     234          11 :     return eErr == CE_None;
     235             : }
     236             : 
     237             : //! @endcond

Generated by: LCOV version 1.14