/src/gdal/alg/gdalrasterpolygonenumerator.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL |
4 | | * Purpose: Raster Polygon Enumerator |
5 | | * Author: Frank Warmerdam, warmerdam@pobox.com |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2008, Frank Warmerdam |
9 | | * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #include "cpl_port.h" |
15 | | #include "gdal_alg_priv.h" |
16 | | |
17 | | #include <cstddef> |
18 | | #include <limits> |
19 | | |
20 | | #include "cpl_conv.h" |
21 | | #include "cpl_error.h" |
22 | | |
23 | | /*! @cond Doxygen_Suppress */ |
24 | | |
25 | | /************************************************************************/ |
26 | | /* GDALRasterPolygonEnumeratorT() */ |
27 | | /************************************************************************/ |
28 | | |
29 | | template <class DataType, class EqualityTest> |
30 | | GDALRasterPolygonEnumeratorT< |
31 | | DataType, EqualityTest>::GDALRasterPolygonEnumeratorT(int nConnectednessIn) |
32 | 0 | : nConnectedness(nConnectednessIn) |
33 | | |
34 | 0 | { |
35 | 0 | CPLAssert(nConnectedness == 4 || nConnectedness == 8); |
36 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::GDALRasterPolygonEnumeratorT(int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::GDALRasterPolygonEnumeratorT(int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::GDALRasterPolygonEnumeratorT(int) |
37 | | |
38 | | /************************************************************************/ |
39 | | /* ~GDALRasterPolygonEnumeratorT() */ |
40 | | /************************************************************************/ |
41 | | |
42 | | template <class DataType, class EqualityTest> |
43 | | GDALRasterPolygonEnumeratorT<DataType, |
44 | | EqualityTest>::~GDALRasterPolygonEnumeratorT() |
45 | | |
46 | 0 | { |
47 | 0 | Clear(); |
48 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::~GDALRasterPolygonEnumeratorT() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::~GDALRasterPolygonEnumeratorT() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::~GDALRasterPolygonEnumeratorT() |
49 | | |
50 | | /************************************************************************/ |
51 | | /* Clear() */ |
52 | | /************************************************************************/ |
53 | | |
54 | | template <class DataType, class EqualityTest> |
55 | | void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::Clear() |
56 | | |
57 | 0 | { |
58 | 0 | CPLFree(panPolyIdMap); |
59 | 0 | CPLFree(panPolyValue); |
60 | |
|
61 | 0 | panPolyIdMap = nullptr; |
62 | 0 | panPolyValue = nullptr; |
63 | |
|
64 | 0 | nNextPolygonId = 0; |
65 | 0 | nPolyAlloc = 0; |
66 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::Clear() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::Clear() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::Clear() |
67 | | |
68 | | /************************************************************************/ |
69 | | /* MergePolygon() */ |
70 | | /* */ |
71 | | /* Update the polygon map to indicate the merger of two polygons. */ |
72 | | /************************************************************************/ |
73 | | |
74 | | template <class DataType, class EqualityTest> |
75 | | void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::MergePolygon( |
76 | | int nSrcId, int nDstIdInit) |
77 | | |
78 | 0 | { |
79 | | // Figure out the final dest id. |
80 | 0 | int nDstIdFinal = nDstIdInit; |
81 | 0 | while (panPolyIdMap[nDstIdFinal] != nDstIdFinal) |
82 | 0 | nDstIdFinal = panPolyIdMap[nDstIdFinal]; |
83 | | |
84 | | // Map the whole intermediate chain to it. |
85 | 0 | int nDstIdCur = nDstIdInit; |
86 | 0 | while (panPolyIdMap[nDstIdCur] != nDstIdCur) |
87 | 0 | { |
88 | 0 | int nNextDstId = panPolyIdMap[nDstIdCur]; |
89 | 0 | panPolyIdMap[nDstIdCur] = nDstIdFinal; |
90 | 0 | nDstIdCur = nNextDstId; |
91 | 0 | } |
92 | | |
93 | | // And map the whole source chain to it too (can be done in one pass). |
94 | 0 | while (panPolyIdMap[nSrcId] != nSrcId) |
95 | 0 | { |
96 | 0 | int nNextSrcId = panPolyIdMap[nSrcId]; |
97 | 0 | panPolyIdMap[nSrcId] = nDstIdFinal; |
98 | 0 | nSrcId = nNextSrcId; |
99 | 0 | } |
100 | 0 | panPolyIdMap[nSrcId] = nDstIdFinal; |
101 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::MergePolygon(int, int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::MergePolygon(int, int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::MergePolygon(int, int) |
102 | | |
103 | | /************************************************************************/ |
104 | | /* NewPolygon() */ |
105 | | /* */ |
106 | | /* Allocate a new polygon id, and reallocate the polygon maps */ |
107 | | /* if needed. */ |
108 | | /************************************************************************/ |
109 | | |
110 | | template <class DataType, class EqualityTest> |
111 | | int GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::NewPolygon( |
112 | | DataType nValue) |
113 | | |
114 | 0 | { |
115 | 0 | if (nNextPolygonId == std::numeric_limits<int>::max()) |
116 | 0 | { |
117 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
118 | 0 | "GDALRasterPolygonEnumeratorT::NewPolygon(): maximum number " |
119 | 0 | "of polygons reached"); |
120 | 0 | return -1; |
121 | 0 | } |
122 | 0 | if (nNextPolygonId >= nPolyAlloc) |
123 | 0 | { |
124 | 0 | int nPolyAllocNew; |
125 | 0 | if (nPolyAlloc < (std::numeric_limits<int>::max() - 20) / 2) |
126 | 0 | nPolyAllocNew = nPolyAlloc * 2 + 20; |
127 | 0 | else |
128 | 0 | nPolyAllocNew = std::numeric_limits<int>::max(); |
129 | | #if SIZEOF_VOIDP == 4 |
130 | | if (nPolyAllocNew > |
131 | | static_cast<int>(std::numeric_limits<size_t>::max() / |
132 | | sizeof(GInt32)) || |
133 | | nPolyAllocNew > |
134 | | static_cast<int>(std::numeric_limits<size_t>::max() / |
135 | | sizeof(DataType))) |
136 | | { |
137 | | CPLError(CE_Failure, CPLE_OutOfMemory, |
138 | | "GDALRasterPolygonEnumeratorT::NewPolygon(): too many " |
139 | | "polygons"); |
140 | | return -1; |
141 | | } |
142 | | #endif |
143 | 0 | auto panPolyIdMapNew = static_cast<GInt32 *>( |
144 | 0 | VSI_REALLOC_VERBOSE(panPolyIdMap, nPolyAllocNew * sizeof(GInt32))); |
145 | 0 | auto panPolyValueNew = static_cast<DataType *>(VSI_REALLOC_VERBOSE( |
146 | 0 | panPolyValue, nPolyAllocNew * sizeof(DataType))); |
147 | 0 | if (panPolyIdMapNew == nullptr || panPolyValueNew == nullptr) |
148 | 0 | { |
149 | 0 | VSIFree(panPolyIdMapNew); |
150 | 0 | VSIFree(panPolyValueNew); |
151 | 0 | return -1; |
152 | 0 | } |
153 | 0 | panPolyIdMap = panPolyIdMapNew; |
154 | 0 | panPolyValue = panPolyValueNew; |
155 | 0 | nPolyAlloc = nPolyAllocNew; |
156 | 0 | } |
157 | | |
158 | 0 | const int nPolyId = nNextPolygonId; |
159 | 0 | panPolyIdMap[nPolyId] = nPolyId; |
160 | 0 | panPolyValue[nPolyId] = nValue; |
161 | 0 | nNextPolygonId++; |
162 | |
|
163 | 0 | return nPolyId; |
164 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::NewPolygon(long) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::NewPolygon(float) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::NewPolygon(double) |
165 | | |
166 | | /************************************************************************/ |
167 | | /* CompleteMerges() */ |
168 | | /* */ |
169 | | /* Make a pass through the maps, ensuring every polygon id */ |
170 | | /* points to the final id it should use, not an intermediate */ |
171 | | /* value. */ |
172 | | /************************************************************************/ |
173 | | |
174 | | template <class DataType, class EqualityTest> |
175 | | void GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::CompleteMerges() |
176 | | |
177 | 0 | { |
178 | 0 | int nFinalPolyCount = 0; |
179 | |
|
180 | 0 | for (int iPoly = 0; iPoly < nNextPolygonId; iPoly++) |
181 | 0 | { |
182 | | // Figure out the final id. |
183 | 0 | int nId = panPolyIdMap[iPoly]; |
184 | 0 | while (nId != panPolyIdMap[nId]) |
185 | 0 | { |
186 | 0 | nId = panPolyIdMap[nId]; |
187 | 0 | } |
188 | | |
189 | | // Then map the whole intermediate chain to it. |
190 | 0 | int nIdCur = panPolyIdMap[iPoly]; |
191 | 0 | panPolyIdMap[iPoly] = nId; |
192 | 0 | while (nIdCur != panPolyIdMap[nIdCur]) |
193 | 0 | { |
194 | 0 | int nNextId = panPolyIdMap[nIdCur]; |
195 | 0 | panPolyIdMap[nIdCur] = nId; |
196 | 0 | nIdCur = nNextId; |
197 | 0 | } |
198 | |
|
199 | 0 | if (panPolyIdMap[iPoly] == iPoly) |
200 | 0 | nFinalPolyCount++; |
201 | 0 | } |
202 | |
|
203 | 0 | CPLDebug("GDALRasterPolygonEnumerator", |
204 | 0 | "Counted %d polygon fragments forming %d final polygons.", |
205 | 0 | nNextPolygonId, nFinalPolyCount); |
206 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::CompleteMerges() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::CompleteMerges() Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::CompleteMerges() |
207 | | |
208 | | /************************************************************************/ |
209 | | /* ProcessLine() */ |
210 | | /* */ |
211 | | /* Assign ids to polygons, one line at a time. */ |
212 | | /************************************************************************/ |
213 | | |
214 | | template <class DataType, class EqualityTest> |
215 | | bool GDALRasterPolygonEnumeratorT<DataType, EqualityTest>::ProcessLine( |
216 | | DataType *panLastLineVal, DataType *panThisLineVal, GInt32 *panLastLineId, |
217 | | GInt32 *panThisLineId, int nXSize) |
218 | | |
219 | 0 | { |
220 | 0 | EqualityTest eq; |
221 | | |
222 | | /* -------------------------------------------------------------------- */ |
223 | | /* Special case for the first line. */ |
224 | | /* -------------------------------------------------------------------- */ |
225 | 0 | if (panLastLineVal == nullptr) |
226 | 0 | { |
227 | 0 | for (int i = 0; i < nXSize; i++) |
228 | 0 | { |
229 | 0 | if (panThisLineVal[i] == GP_NODATA_MARKER) |
230 | 0 | { |
231 | 0 | panThisLineId[i] = -1; |
232 | 0 | } |
233 | 0 | else if (i == 0 || |
234 | 0 | !(eq.operator()(panThisLineVal[i], panThisLineVal[i - 1]))) |
235 | 0 | { |
236 | 0 | panThisLineId[i] = NewPolygon(panThisLineVal[i]); |
237 | 0 | if (panThisLineId[i] < 0) |
238 | 0 | return false; |
239 | 0 | } |
240 | 0 | else |
241 | 0 | { |
242 | 0 | panThisLineId[i] = panThisLineId[i - 1]; |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | 0 | return true; |
247 | 0 | } |
248 | | |
249 | | /* -------------------------------------------------------------------- */ |
250 | | /* Process each pixel comparing to the previous pixel, and to */ |
251 | | /* the last line. */ |
252 | | /* -------------------------------------------------------------------- */ |
253 | 0 | for (int i = 0; i < nXSize; i++) |
254 | 0 | { |
255 | 0 | if (panThisLineVal[i] == GP_NODATA_MARKER) |
256 | 0 | { |
257 | 0 | panThisLineId[i] = -1; |
258 | 0 | } |
259 | 0 | else if (i > 0 && |
260 | 0 | eq.operator()(panThisLineVal[i], panThisLineVal[i - 1])) |
261 | 0 | { |
262 | 0 | panThisLineId[i] = panThisLineId[i - 1]; |
263 | |
|
264 | 0 | if (eq.operator()(panLastLineVal[i], panThisLineVal[i]) && |
265 | 0 | (panPolyIdMap[panLastLineId[i]] != |
266 | 0 | panPolyIdMap[panThisLineId[i]])) |
267 | 0 | { |
268 | 0 | MergePolygon(panLastLineId[i], panThisLineId[i]); |
269 | 0 | } |
270 | |
|
271 | 0 | if (nConnectedness == 8 && |
272 | 0 | eq.operator()(panLastLineVal[i - 1], panThisLineVal[i]) && |
273 | 0 | (panPolyIdMap[panLastLineId[i - 1]] != |
274 | 0 | panPolyIdMap[panThisLineId[i]])) |
275 | 0 | { |
276 | 0 | MergePolygon(panLastLineId[i - 1], panThisLineId[i]); |
277 | 0 | } |
278 | |
|
279 | 0 | if (nConnectedness == 8 && i < nXSize - 1 && |
280 | 0 | eq.operator()(panLastLineVal[i + 1], panThisLineVal[i]) && |
281 | 0 | (panPolyIdMap[panLastLineId[i + 1]] != |
282 | 0 | panPolyIdMap[panThisLineId[i]])) |
283 | 0 | { |
284 | 0 | MergePolygon(panLastLineId[i + 1], panThisLineId[i]); |
285 | 0 | } |
286 | 0 | } |
287 | 0 | else if (eq.operator()(panLastLineVal[i], panThisLineVal[i])) |
288 | 0 | { |
289 | 0 | panThisLineId[i] = panLastLineId[i]; |
290 | 0 | } |
291 | 0 | else if (i > 0 && nConnectedness == 8 && |
292 | 0 | eq.operator()(panLastLineVal[i - 1], panThisLineVal[i])) |
293 | 0 | { |
294 | 0 | panThisLineId[i] = panLastLineId[i - 1]; |
295 | |
|
296 | 0 | if (i < nXSize - 1 && |
297 | 0 | eq.operator()(panLastLineVal[i + 1], panThisLineVal[i]) && |
298 | 0 | (panPolyIdMap[panLastLineId[i + 1]] != |
299 | 0 | panPolyIdMap[panThisLineId[i]])) |
300 | 0 | { |
301 | 0 | MergePolygon(panLastLineId[i + 1], panThisLineId[i]); |
302 | 0 | } |
303 | 0 | } |
304 | 0 | else if (i < nXSize - 1 && nConnectedness == 8 && |
305 | 0 | eq.operator()(panLastLineVal[i + 1], panThisLineVal[i])) |
306 | 0 | { |
307 | 0 | panThisLineId[i] = panLastLineId[i + 1]; |
308 | 0 | } |
309 | 0 | else |
310 | 0 | { |
311 | 0 | panThisLineId[i] = NewPolygon(panThisLineVal[i]); |
312 | 0 | if (panThisLineId[i] < 0) |
313 | 0 | return false; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | return true; |
317 | 0 | } Unexecuted instantiation: GDALRasterPolygonEnumeratorT<long, IntEqualityTest>::ProcessLine(long*, long*, int*, int*, int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>::ProcessLine(float*, float*, int*, int*, int) Unexecuted instantiation: GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>::ProcessLine(double*, double*, int*, int*, int) |
318 | | |
319 | | template class GDALRasterPolygonEnumeratorT<std::int64_t, IntEqualityTest>; |
320 | | |
321 | | template class GDALRasterPolygonEnumeratorT<float, FloatEqualityTest>; |
322 | | |
323 | | template class GDALRasterPolygonEnumeratorT<double, DoubleEqualityTest>; |
324 | | |
325 | | /*! @endcond */ |