LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_hillshade.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 87 90 96.7 %
Date: 2025-06-19 12:30:01 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  "hillshade" step of "raster pipeline"
       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_hillshade.h"
      14             : #include "gdalalg_raster_write.h"
      15             : 
      16             : #include "gdal_priv.h"
      17             : #include "gdal_utils.h"
      18             : 
      19             : #include <cmath>
      20             : 
      21             : //! @cond Doxygen_Suppress
      22             : 
      23             : #ifndef _
      24             : #define _(x) (x)
      25             : #endif
      26             : 
      27             : /************************************************************************/
      28             : /*       GDALRasterHillshadeAlgorithm::GDALRasterHillshadeAlgorithm()   */
      29             : /************************************************************************/
      30             : 
      31          47 : GDALRasterHillshadeAlgorithm::GDALRasterHillshadeAlgorithm(bool standaloneStep)
      32             :     : GDALRasterPipelineStepAlgorithm(NAME, DESCRIPTION, HELP_URL,
      33          47 :                                       standaloneStep)
      34             : {
      35          47 :     SetOutputVRTCompatible(false);
      36             : 
      37          47 :     AddBandArg(&m_band).SetDefault(m_band);
      38             :     AddArg("zfactor", 'z',
      39             :            _("Vertical exaggeration used to pre-multiply the elevations"),
      40          94 :            &m_zfactor)
      41          47 :         .SetMinValueExcluded(0);
      42             :     AddArg("xscale", 0, _("Ratio of vertical units to horizontal X axis units"),
      43          94 :            &m_xscale)
      44          47 :         .SetMinValueExcluded(0);
      45             :     AddArg("yscale", 0, _("Ratio of vertical units to horizontal Y axis units"),
      46          94 :            &m_yscale)
      47          47 :         .SetMinValueExcluded(0);
      48          94 :     AddArg("azimuth", 0, _("Azimuth of the light, in degrees"), &m_azimuth)
      49          47 :         .SetDefault(m_azimuth);
      50          94 :     AddArg("altitude", 0, _("Altitude of the light, in degrees"), &m_altitude)
      51          47 :         .SetDefault(m_altitude)
      52          47 :         .SetMinValueIncluded(0)
      53          47 :         .SetMaxValueIncluded(90);
      54             :     AddArg("gradient-alg", 0, _("Algorithm used to compute terrain gradient"),
      55          94 :            &m_gradientAlg)
      56          47 :         .SetChoices("Horn", "ZevenbergenThorne")
      57          47 :         .SetDefault(m_gradientAlg);
      58          94 :     AddArg("variant", 0, _("Variant of the hillshading algorithm"), &m_variant)
      59          47 :         .SetChoices("regular", "combined", "multidirectional", "Igor")
      60          47 :         .SetDefault(m_variant);
      61             :     AddArg("no-edges", 0,
      62             :            _("Do not try to interpolate values at dataset edges or close to "
      63             :              "nodata values"),
      64          47 :            &m_noEdges);
      65          47 : }
      66             : 
      67             : /************************************************************************/
      68             : /*          GDALRasterHillshadeAlgorithm::CanHandleNextStep()           */
      69             : /************************************************************************/
      70             : 
      71          28 : bool GDALRasterHillshadeAlgorithm::CanHandleNextStep(
      72             :     GDALPipelineStepAlgorithm *poNextStep) const
      73             : {
      74          56 :     return poNextStep->GetName() == GDALRasterWriteAlgorithm::NAME &&
      75          56 :            poNextStep->GetOutputFormat() != "stream";
      76             : }
      77             : 
      78             : /************************************************************************/
      79             : /*              GDALRasterHillshadeAlgorithm::RunStep()                 */
      80             : /************************************************************************/
      81             : 
      82          18 : bool GDALRasterHillshadeAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
      83             : {
      84          18 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      85          18 :     CPLAssert(poSrcDS);
      86          18 :     CPLAssert(m_outputDataset.GetName().empty());
      87          18 :     CPLAssert(!m_outputDataset.GetDatasetRef());
      88             : 
      89          36 :     CPLStringList aosOptions;
      90          36 :     std::string outputFilename;
      91          18 :     if (ctxt.m_poNextUsableStep)
      92             :     {
      93          14 :         CPLAssert(CanHandleNextStep(ctxt.m_poNextUsableStep));
      94          14 :         outputFilename = ctxt.m_poNextUsableStep->GetOutputDataset().GetName();
      95          14 :         const auto &format = ctxt.m_poNextUsableStep->GetOutputFormat();
      96          14 :         if (!format.empty())
      97             :         {
      98          14 :             aosOptions.AddString("-of");
      99          14 :             aosOptions.AddString(format.c_str());
     100             :         }
     101             : 
     102           0 :         for (const std::string &co :
     103          14 :              ctxt.m_poNextUsableStep->GetCreationOptions())
     104             :         {
     105           0 :             aosOptions.AddString("-co");
     106           0 :             aosOptions.AddString(co.c_str());
     107             :         }
     108             :     }
     109             :     else
     110             :     {
     111           4 :         aosOptions.AddString("-of");
     112           4 :         aosOptions.AddString("stream");
     113             :     }
     114             : 
     115          18 :     aosOptions.AddString("-b");
     116          18 :     aosOptions.AddString(CPLSPrintf("%d", m_band));
     117          18 :     aosOptions.AddString("-z");
     118          18 :     aosOptions.AddString(CPLSPrintf("%.17g", m_zfactor));
     119          18 :     if (!std::isnan(m_xscale))
     120             :     {
     121           2 :         aosOptions.AddString("-xscale");
     122           2 :         aosOptions.AddString(CPLSPrintf("%.17g", m_xscale));
     123             :     }
     124          18 :     if (!std::isnan(m_yscale))
     125             :     {
     126           2 :         aosOptions.AddString("-yscale");
     127           2 :         aosOptions.AddString(CPLSPrintf("%.17g", m_yscale));
     128             :     }
     129          18 :     if (m_variant == "multidirectional")
     130             :     {
     131           2 :         if (GetArg("azimuth")->IsExplicitlySet())
     132             :         {
     133           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     134             :                      "'azimuth' argument cannot be used with multidirectional "
     135             :                      "variant");
     136           1 :             return false;
     137             :         }
     138             :     }
     139             :     else
     140             :     {
     141          16 :         aosOptions.AddString("-az");
     142          16 :         aosOptions.AddString(CPLSPrintf("%.17g", m_azimuth));
     143             :     }
     144          17 :     if (m_variant == "Igor")
     145             :     {
     146           2 :         if (GetArg("altitude")->IsExplicitlySet())
     147             :         {
     148           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     149             :                      "'altitude' argument cannot be used with Igor variant");
     150           1 :             return false;
     151             :         }
     152             :     }
     153             :     else
     154             :     {
     155          15 :         aosOptions.AddString("-alt");
     156          15 :         aosOptions.AddString(CPLSPrintf("%.17g", m_altitude));
     157             :     }
     158          16 :     aosOptions.AddString("-alg");
     159          16 :     aosOptions.AddString(m_gradientAlg.c_str());
     160             : 
     161          16 :     if (m_variant == "combined")
     162           1 :         aosOptions.AddString("-combined");
     163          15 :     else if (m_variant == "multidirectional")
     164           1 :         aosOptions.AddString("-multidirectional");
     165          14 :     else if (m_variant == "Igor")
     166           1 :         aosOptions.AddString("-igor");
     167             : 
     168          16 :     if (!m_noEdges)
     169          15 :         aosOptions.AddString("-compute_edges");
     170             : 
     171             :     GDALDEMProcessingOptions *psOptions =
     172          16 :         GDALDEMProcessingOptionsNew(aosOptions.List(), nullptr);
     173          16 :     bool bOK = false;
     174          16 :     if (psOptions)
     175             :     {
     176          16 :         if (ctxt.m_poNextUsableStep)
     177             :         {
     178          12 :             GDALDEMProcessingOptionsSetProgress(psOptions, ctxt.m_pfnProgress,
     179             :                                                 ctxt.m_pProgressData);
     180             :         }
     181             :         auto poOutDS = std::unique_ptr<GDALDataset>(GDALDataset::FromHandle(
     182             :             GDALDEMProcessing(outputFilename.c_str(),
     183             :                               GDALDataset::ToHandle(poSrcDS), "hillshade",
     184          32 :                               nullptr, psOptions, nullptr)));
     185          16 :         GDALDEMProcessingOptionsFree(psOptions);
     186          16 :         bOK = poOutDS != nullptr;
     187          16 :         if (poOutDS)
     188             :         {
     189          16 :             m_outputDataset.Set(std::move(poOutDS));
     190             :         }
     191             :     }
     192             : 
     193          16 :     return bOK;
     194             : }
     195             : 
     196             : GDALRasterHillshadeAlgorithmStandalone::
     197             :     ~GDALRasterHillshadeAlgorithmStandalone() = default;
     198             : 
     199             : //! @endcond

Generated by: LCOV version 1.14