LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_contour.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 100 106 94.3 %
Date: 2025-05-15 13:16:46 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          19 : GDALRasterContourAlgorithm::GDALRasterContourAlgorithm()
      34             :     : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL), m_outputLayerName("contour"),
      35          19 :       m_elevAttributeName(""), m_amin(""), m_amax(""), m_levels{}
      36             : {
      37             : 
      38          19 :     AddProgressArg();
      39          19 :     AddOutputFormatArg(&m_outputFormat)
      40             :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
      41          57 :                          {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE});
      42          19 :     AddOpenOptionsArg(&m_openOptions);
      43          19 :     AddInputFormatsArg(&m_inputFormats)
      44          38 :         .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_RASTER});
      45          19 :     AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER);
      46          19 :     AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR);
      47          19 :     AddCreationOptionsArg(&m_creationOptions);
      48          19 :     AddLayerCreationOptionsArg(&m_layerCreationOptions);
      49             : 
      50             :     // gdal_contour specific options
      51          19 :     AddBandArg(&m_band).SetDefault(1);
      52          19 :     AddLayerNameArg(&m_outputLayerName).AddAlias("nln");
      53             :     AddArg("elevation-name", 0, _("Name of the elevation field"),
      54          19 :            &m_elevAttributeName);
      55          19 :     AddArg("min-name", 0, _("Name of the minimum elevation field"), &m_amin);
      56          19 :     AddArg("max-name", 0, _("Name of the maximum elevation field"), &m_amax);
      57          19 :     AddArg("3d", 0, _("Force production of 3D vectors instead of 2D"), &m_3d);
      58             : 
      59             :     AddArg("src-nodata", 0, _("Input pixel value to treat as 'nodata'"),
      60          19 :            &m_sNodata);
      61          38 :     AddArg("interval", 0, _("Elevation interval between contours"), &m_interval)
      62          38 :         .SetMutualExclusionGroup("levels")
      63          19 :         .SetMinValueExcluded(0);
      64          38 :     AddArg("levels", 0, _("List of contour levels"), &m_levels)
      65          19 :         .SetMutualExclusionGroup("levels");
      66             :     AddArg("exp-base", 'e', _("Base for exponential contour level generation"),
      67          38 :            &m_expBase)
      68          19 :         .SetMutualExclusionGroup("levels");
      69          38 :     AddArg("offset", 0, _("Offset to apply to contour levels"), &m_offset)
      70          19 :         .AddAlias("off");
      71             :     AddArg("polygonize", 'p', _("Create polygons instead of lines"),
      72          19 :            &m_polygonize);
      73             :     AddArg("group-transactions", 0,
      74             :            _("Group n features per transaction (default 100 000)"),
      75          38 :            &m_groupTransactions)
      76          19 :         .SetMinValueIncluded(0);
      77          19 :     AddOverwriteArg(&m_overwrite);
      78          19 : }
      79             : 
      80             : /************************************************************************/
      81             : /*                  GDALRasterContourAlgorithm::RunImpl()               */
      82             : /************************************************************************/
      83             : 
      84          13 : bool GDALRasterContourAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
      85             :                                          void *pProgressData)
      86             : {
      87             : 
      88          13 :     CPLErrorReset();
      89             : 
      90          13 :     CPLAssert(m_inputDataset.GetDatasetRef());
      91          13 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      92             : 
      93          26 :     CPLStringList aosOptions;
      94          13 :     if (!m_outputFormat.empty())
      95             :     {
      96           0 :         aosOptions.AddString("-of");
      97           0 :         aosOptions.AddString(m_outputFormat);
      98             :     }
      99             : 
     100          14 :     for (const auto &co : m_creationOptions)
     101             :     {
     102           1 :         aosOptions.AddString("-co");
     103           1 :         aosOptions.AddString(co);
     104             :     }
     105             : 
     106          14 :     for (const auto &co : m_layerCreationOptions)
     107             :     {
     108           1 :         aosOptions.AddString("-lco");
     109           1 :         aosOptions.AddString(co);
     110             :     }
     111             : 
     112          13 :     if (m_band > 0)
     113             :     {
     114          13 :         aosOptions.AddString("-b");
     115          13 :         aosOptions.AddString(CPLSPrintf("%d", m_band));
     116             :     }
     117          13 :     if (!m_elevAttributeName.empty())
     118             :     {
     119           5 :         aosOptions.AddString("-a");
     120           5 :         aosOptions.AddString(m_elevAttributeName);
     121             :     }
     122          13 :     if (!m_amin.empty())
     123             :     {
     124           6 :         aosOptions.AddString("-amin");
     125           6 :         aosOptions.AddString(m_amin);
     126             :     }
     127          13 :     if (!m_amax.empty())
     128             :     {
     129           6 :         aosOptions.AddString("-amax");
     130           6 :         aosOptions.AddString(m_amax);
     131             :     }
     132          13 :     if (m_3d)
     133             :     {
     134           0 :         aosOptions.AddString("-3d");
     135             :     }
     136          13 :     if (!std::isnan(m_sNodata))
     137             :     {
     138           1 :         aosOptions.AddString("-snodata");
     139           1 :         aosOptions.AddString(CPLSPrintf("%.16g", m_sNodata));
     140             :     }
     141          13 :     if (m_levels.size() > 0)
     142             :     {
     143          12 :         for (const auto &level : m_levels)
     144             :         {
     145           8 :             aosOptions.AddString("-fl");
     146           8 :             aosOptions.AddString(level);
     147             :         }
     148             :     }
     149          13 :     if (!std::isnan(m_interval))
     150             :     {
     151           7 :         aosOptions.AddString("-i");
     152           7 :         aosOptions.AddString(CPLSPrintf("%.16g", m_interval));
     153             :     }
     154          13 :     if (m_expBase > 0)
     155             :     {
     156           1 :         aosOptions.AddString("-e");
     157           1 :         aosOptions.AddString(CPLSPrintf("%d", m_expBase));
     158             :     }
     159          13 :     if (!std::isnan(m_offset))
     160             :     {
     161           1 :         aosOptions.AddString("-off");
     162           1 :         aosOptions.AddString(CPLSPrintf("%.16g", m_offset));
     163             :     }
     164          13 :     if (m_polygonize)
     165             :     {
     166           5 :         aosOptions.AddString("-p");
     167             :     }
     168          13 :     if (!m_outputLayerName.empty())
     169             :     {
     170          13 :         aosOptions.AddString("-nln");
     171          13 :         aosOptions.AddString(m_outputLayerName);
     172             :     }
     173             : 
     174             :     // Check that one of --interval, --levels, --exp-base is specified
     175          13 :     if (m_levels.size() == 0 && std::isnan(m_interval) && m_expBase == 0)
     176             :     {
     177           1 :         ReportError(
     178             :             CE_Failure, CPLE_AppDefined,
     179             :             "One of 'interval', 'levels', 'exp-base' must be specified.");
     180           1 :         return false;
     181             :     }
     182             : 
     183             :     // Check that interval is not negative
     184          12 :     if (!std::isnan(m_interval) && m_interval < 0)
     185             :     {
     186           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     187             :                     "Interval must be a positive number.");
     188           0 :         return false;
     189             :     }
     190             : 
     191          12 :     aosOptions.AddString(m_inputDataset.GetName());
     192          12 :     aosOptions.AddString(m_outputDataset.GetName());
     193             : 
     194          24 :     GDALContourOptionsForBinary optionsForBinary;
     195             :     std::unique_ptr<GDALContourOptions, decltype(&GDALContourOptionsFree)>
     196             :         psOptions{GDALContourOptionsNew(aosOptions.List(), &optionsForBinary),
     197          24 :                   GDALContourOptionsFree};
     198             : 
     199          12 :     if (!psOptions)
     200             :     {
     201           0 :         return false;
     202             :     }
     203             : 
     204          12 :     GDALDatasetH hSrcDS{m_inputDataset.GetDatasetRef()};
     205          12 :     GDALRasterBandH hBand{nullptr};
     206          12 :     GDALDatasetH hDstDS{m_outputDataset.GetDatasetRef()};
     207          12 :     OGRLayerH hLayer{nullptr};
     208          12 :     char **papszStringOptions = nullptr;
     209             : 
     210             :     CPLErr eErr =
     211          12 :         GDALContourProcessOptions(psOptions.get(), &papszStringOptions, &hSrcDS,
     212             :                                   &hBand, &hDstDS, &hLayer);
     213             : 
     214          12 :     if (eErr == CE_None)
     215             :     {
     216          12 :         eErr = GDALContourGenerateEx(hBand, hLayer, papszStringOptions,
     217             :                                      pfnProgress, pProgressData);
     218             :     }
     219             : 
     220          12 :     CSLDestroy(papszStringOptions);
     221             : 
     222          12 :     auto poDstDS = GDALDataset::FromHandle(hDstDS);
     223          12 :     m_outputDataset.Set(std::unique_ptr<GDALDataset>(poDstDS));
     224             : 
     225          12 :     return eErr == CE_None;
     226             : }
     227             : 
     228             : //! @endcond

Generated by: LCOV version 1.14