LCOV - code coverage report
Current view: top level - apps - gdalalg_raster_proximity.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 66 68 97.1 %
Date: 2026-09-11 05:09:32 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster proximity" 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 "gdalalg_raster_proximity.h"
      14             : 
      15             : #include <cmath>
      16             : #include <limits>
      17             : 
      18             : #include "cpl_conv.h"
      19             : 
      20             : #include "gdal_alg.h"
      21             : #include "gdal_priv.h"
      22             : 
      23             : //! @cond Doxygen_Suppress
      24             : 
      25             : #ifndef _
      26             : #define _(x) (x)
      27             : #endif
      28             : 
      29             : /************************************************************************/
      30             : /*     GDALRasterProximityAlgorithm::GDALRasterProximityAlgorithm()     */
      31             : /************************************************************************/
      32             : 
      33         114 : GDALRasterProximityAlgorithm::GDALRasterProximityAlgorithm(bool standaloneStep)
      34             :     : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION,
      35         114 :                                                       HELP_URL, standaloneStep)
      36             : {
      37         114 :     AddOutputDataTypeArg(&m_outputDataType)
      38             :         .SetChoices("Int8", "UInt16", "Int16", "UInt32", "Int32", "Float32",
      39         114 :                     "Float64")
      40         114 :         .SetHiddenChoices("Byte")
      41         114 :         .SetDefault(m_outputDataType);
      42         114 :     AddBandArg(&m_inputBand);
      43         114 :     AddArg("target-values", 0, _("Target pixel values"), &m_targetPixelValues);
      44         228 :     AddArg("distance-units", 0, _("Distance units"), &m_distanceUnits)
      45         114 :         .SetChoices("pixel", "geo")
      46         114 :         .SetDefault(m_distanceUnits);
      47             :     AddArg("max-distance", 0,
      48             :            _("Maximum distance. The nodata value will be used for pixels "
      49             :              "beyond this distance"),
      50         228 :            &m_maxDistance)
      51         114 :         .SetDefault(m_maxDistance);
      52             :     AddArg("fixed-value", 0,
      53             :            _("Fixed value for the pixels that are within the "
      54             :              "maximum distance (instead of the actual distance)"),
      55         228 :            &m_fixedBufferValue)
      56         114 :         .SetMinValueIncluded(0)
      57         114 :         .SetDefault(m_fixedBufferValue);
      58             :     AddArg("output-nodata", 0,
      59             :            _("Specify a nodata value to use for pixels that are beyond the "
      60             :              "maximum distance"),
      61         228 :            &m_noDataValue)
      62         114 :         .AddHiddenAlias("nodata");
      63         114 : }
      64             : 
      65             : /************************************************************************/
      66             : /*               GDALRasterProximityAlgorithm::RunStep()                */
      67             : /************************************************************************/
      68             : 
      69          25 : bool GDALRasterProximityAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
      70             : {
      71          25 :     auto pfnProgress = ctxt.m_pfnProgress;
      72          25 :     auto pProgressData = ctxt.m_pProgressData;
      73             : 
      74          25 :     auto poSrcDS = m_inputDataset[0].GetDatasetRef();
      75          25 :     CPLAssert(poSrcDS);
      76             : 
      77          25 :     GDALDataType outputType = GDT_Float32;
      78          25 :     if (!m_outputDataType.empty())
      79             :     {
      80          25 :         outputType = GDALGetDataTypeByName(m_outputDataType.c_str());
      81             :     }
      82             : 
      83             :     auto poTmpDS = CreateTemporaryDataset(
      84             :         poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), 1, outputType,
      85          50 :         /* bTiledIfPossible = */ true, poSrcDS, /* bCopyMetadata = */ false);
      86          25 :     if (!poTmpDS)
      87           1 :         return false;
      88             : 
      89          24 :     const auto srcBand = poSrcDS->GetRasterBand(m_inputBand);
      90          24 :     CPLAssert(srcBand);
      91             : 
      92          24 :     const auto dstBand = poTmpDS->GetRasterBand(1);
      93          24 :     CPLAssert(dstBand);
      94             : 
      95             :     // Build options for GDALComputeProximity
      96          48 :     CPLStringList proximityOptions;
      97             : 
      98          24 :     if (GetArg("max-distance")->IsExplicitlySet())
      99             :     {
     100          22 :         proximityOptions.AddString(CPLSPrintf("MAXDIST=%.17g", m_maxDistance));
     101             :     }
     102             : 
     103          24 :     if (GetArg("distance-units")->IsExplicitlySet())
     104             :     {
     105             :         proximityOptions.AddString(
     106          12 :             CPLSPrintf("DISTUNITS=%s", m_distanceUnits.c_str()));
     107             :     }
     108             : 
     109          24 :     if (GetArg("fixed-value")->IsExplicitlySet())
     110             :     {
     111             :         proximityOptions.AddString(
     112           4 :             CPLSPrintf("FIXED_BUF_VAL=%.17g", m_fixedBufferValue));
     113             :     }
     114             : 
     115          24 :     if (GetArg("output-nodata")->IsExplicitlySet())
     116             :     {
     117             :         // Because GDALComputeProximity does all of its work with 32-bit floats,
     118             :         // we need to check that a manually-specified NoData value can be represented
     119             :         // as a 32-bit float. The default NoData value for some integer types
     120             :         // also cannot be represented as 32-bit floats, but they still round-trip OK,
     121             :         // so we only perform the runtime check for manually-specified values.
     122          11 :         if (!std::isnan(m_noDataValue))
     123             :         {
     124          11 :             const float fNoData = static_cast<float>(m_noDataValue);
     125          11 :             if (static_cast<double>(fNoData) != m_noDataValue)
     126             :             {
     127           2 :                 CPLError(CE_Failure, CPLE_AppDefined,
     128             :                          "gdal raster proximity requires the output NoData "
     129             :                          "value to be representable as a 32-bit floating point "
     130             :                          "number, but the specified value of %g cannot.",
     131             :                          m_noDataValue);
     132           2 :                 return false;
     133             :             }
     134             :         }
     135           9 :         dstBand->SetNoDataValue(m_noDataValue);
     136             :     }
     137          13 :     else if (outputType == GDT_Float16 || outputType == GDT_Float32 ||
     138             :              outputType == GDT_Float64)
     139             :     {
     140           5 :         dstBand->SetNoDataValue(std::numeric_limits<double>::quiet_NaN());
     141             :     }
     142             :     else
     143             :     {
     144             :         double dfNoData;
     145           8 :         if (GDALGetDataTypeMinMaxAsDouble(outputType, nullptr, &dfNoData))
     146             :         {
     147           8 :             dstBand->SetNoDataValue(dfNoData);
     148             :         }
     149             :         else
     150             :         {
     151           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     152             :                      "No default NoData value for output data type %s",
     153             :                      GDALGetDataTypeName(outputType));
     154           0 :             return false;
     155             :         }
     156             :     }
     157             : 
     158             :     // Always set this to YES. Note that this was NOT the
     159             :     // default behavior in the python implementation of the utility.
     160          22 :     proximityOptions.AddString("USE_INPUT_NODATA=YES");
     161             : 
     162          22 :     if (GetArg("target-values")->IsExplicitlySet())
     163             :     {
     164          28 :         std::string targetPixelValues;
     165          29 :         for (const auto &value : m_targetPixelValues)
     166             :         {
     167          15 :             if (!targetPixelValues.empty())
     168           1 :                 targetPixelValues += ",";
     169          15 :             targetPixelValues += CPLSPrintf("%.17g", value);
     170             :         }
     171             :         proximityOptions.AddString(
     172          14 :             CPLSPrintf("VALUES=%s", targetPixelValues.c_str()));
     173             :     }
     174             : 
     175          22 :     const auto error = GDALComputeProximity(srcBand, dstBand, proximityOptions,
     176             :                                             pfnProgress, pProgressData);
     177          22 :     if (error == CE_None)
     178             :     {
     179          22 :         if (pfnProgress)
     180           1 :             pfnProgress(1.0, "", pProgressData);
     181          22 :         m_outputDataset.Set(std::move(poTmpDS));
     182             :     }
     183             : 
     184          22 :     return error == CE_None;
     185             : }
     186             : 
     187             : GDALRasterProximityAlgorithmStandalone::
     188             :     ~GDALRasterProximityAlgorithmStandalone() = default;
     189             : 
     190             : //! @endcond

Generated by: LCOV version 1.14