/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 |