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