Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_raster_proximity.cpp
Line
Count
Source
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 "cpl_conv.h"
16
17
#include "gdal_alg.h"
18
#include "gdal_priv.h"
19
20
//! @cond Doxygen_Suppress
21
22
#ifndef _
23
0
#define _(x) (x)
24
#endif
25
26
/************************************************************************/
27
/*     GDALRasterProximityAlgorithm::GDALRasterProximityAlgorithm()     */
28
/************************************************************************/
29
30
GDALRasterProximityAlgorithm::GDALRasterProximityAlgorithm(bool standaloneStep)
31
0
    : GDALRasterPipelineNonNativelyStreamingAlgorithm(NAME, DESCRIPTION,
32
0
                                                      HELP_URL, standaloneStep)
33
0
{
34
0
    AddOutputDataTypeArg(&m_outputDataType)
35
0
        .SetChoices("Byte", "UInt16", "Int16", "UInt32", "Int32", "Float32",
36
0
                    "Float64")
37
0
        .SetDefault(m_outputDataType);
38
0
    AddBandArg(&m_inputBand);
39
0
    AddArg("target-values", 0, _("Target pixel values"), &m_targetPixelValues);
40
0
    AddArg("distance-units", 0, _("Distance units"), &m_distanceUnits)
41
0
        .SetChoices("pixel", "geo")
42
0
        .SetDefault(m_distanceUnits);
43
0
    AddArg("max-distance", 0,
44
0
           _("Maximum distance. The nodata value will be used for pixels "
45
0
             "beyond this distance"),
46
0
           &m_maxDistance)
47
0
        .SetDefault(m_maxDistance);
48
0
    AddArg("fixed-value", 0,
49
0
           _("Fixed value for the pixels that are beyond the "
50
0
             "maximum distance (instead of the actual distance)"),
51
0
           &m_fixedBufferValue)
52
0
        .SetMinValueIncluded(0)
53
0
        .SetDefault(m_fixedBufferValue);
54
0
    AddArg("nodata", 0,
55
0
           _("Specify a nodata value to use for pixels that are beyond the "
56
0
             "maximum distance"),
57
0
           &m_noDataValue);
58
0
}
59
60
/************************************************************************/
61
/*               GDALRasterProximityAlgorithm::RunStep()                */
62
/************************************************************************/
63
64
bool GDALRasterProximityAlgorithm::RunStep(GDALPipelineStepRunContext &ctxt)
65
0
{
66
0
    auto pfnProgress = ctxt.m_pfnProgress;
67
0
    auto pProgressData = ctxt.m_pProgressData;
68
69
0
    auto poSrcDS = m_inputDataset[0].GetDatasetRef();
70
0
    CPLAssert(poSrcDS);
71
72
0
    GDALDataType outputType = GDT_Float32;
73
0
    if (!m_outputDataType.empty())
74
0
    {
75
0
        outputType = GDALGetDataTypeByName(m_outputDataType.c_str());
76
0
    }
77
78
0
    auto poTmpDS = CreateTemporaryDataset(
79
0
        poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), 1, outputType,
80
0
        /* bTiledIfPossible = */ true, poSrcDS, /* bCopyMetadata = */ false);
81
0
    if (!poTmpDS)
82
0
        return false;
83
84
0
    const auto srcBand = poSrcDS->GetRasterBand(m_inputBand);
85
0
    CPLAssert(srcBand);
86
87
0
    const auto dstBand = poTmpDS->GetRasterBand(1);
88
0
    CPLAssert(dstBand);
89
90
    // Build options for GDALComputeProximity
91
0
    CPLStringList proximityOptions;
92
93
0
    if (GetArg("max-distance")->IsExplicitlySet())
94
0
    {
95
0
        proximityOptions.AddString(CPLSPrintf("MAXDIST=%.17g", m_maxDistance));
96
0
    }
97
98
0
    if (GetArg("distance-units")->IsExplicitlySet())
99
0
    {
100
0
        proximityOptions.AddString(
101
0
            CPLSPrintf("DISTUNITS=%s", m_distanceUnits.c_str()));
102
0
    }
103
104
0
    if (GetArg("fixed-value")->IsExplicitlySet())
105
0
    {
106
0
        proximityOptions.AddString(
107
0
            CPLSPrintf("FIXED_BUF_VAL=%.17g", m_fixedBufferValue));
108
0
    }
109
110
0
    if (GetArg("nodata")->IsExplicitlySet())
111
0
    {
112
0
        proximityOptions.AddString(CPLSPrintf("NODATA=%.17g", m_noDataValue));
113
0
        dstBand->SetNoDataValue(m_noDataValue);
114
0
    }
115
116
    // Always set this to YES. Note that this was NOT the
117
    // default behavior in the python implementation of the utility.
118
0
    proximityOptions.AddString("USE_INPUT_NODATA=YES");
119
120
0
    if (GetArg("target-values")->IsExplicitlySet())
121
0
    {
122
0
        std::string targetPixelValues;
123
0
        for (const auto &value : m_targetPixelValues)
124
0
        {
125
0
            if (!targetPixelValues.empty())
126
0
                targetPixelValues += ",";
127
0
            targetPixelValues += CPLSPrintf("%.17g", value);
128
0
        }
129
0
        proximityOptions.AddString(
130
0
            CPLSPrintf("VALUES=%s", targetPixelValues.c_str()));
131
0
    }
132
133
0
    const auto error = GDALComputeProximity(srcBand, dstBand, proximityOptions,
134
0
                                            pfnProgress, pProgressData);
135
0
    if (error == CE_None)
136
0
    {
137
0
        if (pfnProgress)
138
0
            pfnProgress(1.0, "", pProgressData);
139
0
        m_outputDataset.Set(std::move(poTmpDS));
140
0
    }
141
142
0
    return error == CE_None;
143
0
}
144
145
GDALRasterProximityAlgorithmStandalone::
146
0
    ~GDALRasterProximityAlgorithmStandalone() = default;
147
148
//! @endcond