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