Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Compute each pixel's proximity to a set of target pixels.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2008, Frank Warmerdam
9 : * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "gdal_alg.h"
32 :
33 : #include <cmath>
34 : #include <cstdlib>
35 :
36 : #include <algorithm>
37 :
38 : #include "cpl_conv.h"
39 : #include "cpl_error.h"
40 : #include "cpl_progress.h"
41 : #include "cpl_string.h"
42 : #include "cpl_vsi.h"
43 : #include "gdal.h"
44 :
45 : static CPLErr ProcessProximityLine(GInt32 *panSrcScanline, int *panNearX,
46 : int *panNearY, int bForward, int iLine,
47 : int nXSize, double nMaxDist,
48 : float *pafProximity,
49 : double *pdfSrcNoDataValue, int nTargetValues,
50 : int *panTargetValues);
51 :
52 : /************************************************************************/
53 : /* GDALComputeProximity() */
54 : /************************************************************************/
55 :
56 : /**
57 : Compute the proximity of all pixels in the image to a set of pixels in
58 : the source image.
59 :
60 : This function attempts to compute the proximity of all pixels in
61 : the image to a set of pixels in the source image. The following
62 : options are used to define the behavior of the function. By
63 : default all non-zero pixels in hSrcBand will be considered the
64 : "target", and all proximities will be computed in pixels. Note
65 : that target pixels are set to the value corresponding to a distance
66 : of zero.
67 :
68 : The progress function args may be NULL or a valid progress reporting function
69 : such as GDALTermProgress/NULL.
70 :
71 : Options:
72 :
73 : VALUES=n[,n]*
74 :
75 : A list of target pixel values to measure the distance from. If this
76 : option is not provided proximity will be computed from non-zero
77 : pixel values. Currently pixel values are internally processed as
78 : integers.
79 :
80 : DISTUNITS=[PIXEL]/GEO
81 :
82 : Indicates whether distances will be computed in pixel units or
83 : in georeferenced units. The default is pixel units. This also
84 : determines the interpretation of MAXDIST.
85 :
86 : MAXDIST=n
87 :
88 : The maximum distance to search. Proximity distances greater than
89 : this value will not be computed. Instead output pixels will be
90 : set to a nodata value.
91 :
92 : NODATA=n
93 :
94 : The NODATA value to use on the output band for pixels that are
95 : beyond MAXDIST. If not provided, the hProximityBand will be
96 : queried for a nodata value. If one is not found, 65535 will be used.
97 :
98 : USE_INPUT_NODATA=YES/NO
99 :
100 : If this option is set, the input data set no-data value will be
101 : respected. Leaving no data pixels in the input as no data pixels in
102 : the proximity output.
103 :
104 : FIXED_BUF_VAL=n
105 :
106 : If this option is set, all pixels within the MAXDIST threadhold are
107 : set to this fixed value instead of to a proximity distance.
108 : */
109 :
110 6 : CPLErr CPL_STDCALL GDALComputeProximity(GDALRasterBandH hSrcBand,
111 : GDALRasterBandH hProximityBand,
112 : char **papszOptions,
113 : GDALProgressFunc pfnProgress,
114 : void *pProgressArg)
115 :
116 : {
117 6 : VALIDATE_POINTER1(hSrcBand, "GDALComputeProximity", CE_Failure);
118 6 : VALIDATE_POINTER1(hProximityBand, "GDALComputeProximity", CE_Failure);
119 :
120 6 : if (pfnProgress == nullptr)
121 5 : pfnProgress = GDALDummyProgress;
122 :
123 : /* -------------------------------------------------------------------- */
124 : /* Are we using pixels or georeferenced coordinates for distances? */
125 : /* -------------------------------------------------------------------- */
126 6 : double dfDistMult = 1.0;
127 6 : const char *pszOpt = CSLFetchNameValue(papszOptions, "DISTUNITS");
128 6 : if (pszOpt)
129 : {
130 0 : if (EQUAL(pszOpt, "GEO"))
131 : {
132 0 : GDALDatasetH hSrcDS = GDALGetBandDataset(hSrcBand);
133 0 : if (hSrcDS)
134 : {
135 0 : double adfGeoTransform[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
136 :
137 0 : GDALGetGeoTransform(hSrcDS, adfGeoTransform);
138 0 : if (std::abs(adfGeoTransform[1]) !=
139 0 : std::abs(adfGeoTransform[5]))
140 0 : CPLError(
141 : CE_Warning, CPLE_AppDefined,
142 : "Pixels not square, distances will be inaccurate.");
143 0 : dfDistMult = std::abs(adfGeoTransform[1]);
144 : }
145 : }
146 0 : else if (!EQUAL(pszOpt, "PIXEL"))
147 : {
148 0 : CPLError(
149 : CE_Failure, CPLE_AppDefined,
150 : "Unrecognized DISTUNITS value '%s', should be GEO or PIXEL.",
151 : pszOpt);
152 0 : return CE_Failure;
153 : }
154 : }
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* What is our maxdist value? */
158 : /* -------------------------------------------------------------------- */
159 6 : pszOpt = CSLFetchNameValue(papszOptions, "MAXDIST");
160 6 : const double dfMaxDist = pszOpt ? CPLAtof(pszOpt) / dfDistMult
161 2 : : GDALGetRasterBandXSize(hSrcBand) +
162 2 : GDALGetRasterBandYSize(hSrcBand);
163 :
164 6 : CPLDebug("GDAL", "MAXDIST=%g, DISTMULT=%g", dfMaxDist, dfDistMult);
165 :
166 : /* -------------------------------------------------------------------- */
167 : /* Verify the source and destination are compatible. */
168 : /* -------------------------------------------------------------------- */
169 6 : const int nXSize = GDALGetRasterBandXSize(hSrcBand);
170 6 : const int nYSize = GDALGetRasterBandYSize(hSrcBand);
171 12 : if (nXSize != GDALGetRasterBandXSize(hProximityBand) ||
172 6 : nYSize != GDALGetRasterBandYSize(hProximityBand))
173 : {
174 0 : CPLError(CE_Failure, CPLE_AppDefined,
175 : "Source and proximity bands are not the same size.");
176 0 : return CE_Failure;
177 : }
178 :
179 : /* -------------------------------------------------------------------- */
180 : /* Get input NODATA value. */
181 : /* -------------------------------------------------------------------- */
182 6 : double dfSrcNoDataValue = 0.0;
183 6 : double *pdfSrcNoData = nullptr;
184 6 : if (CPLFetchBool(papszOptions, "USE_INPUT_NODATA", false))
185 : {
186 2 : int bSrcHasNoData = 0;
187 2 : dfSrcNoDataValue = GDALGetRasterNoDataValue(hSrcBand, &bSrcHasNoData);
188 2 : if (bSrcHasNoData)
189 2 : pdfSrcNoData = &dfSrcNoDataValue;
190 : }
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Get output NODATA value. */
194 : /* -------------------------------------------------------------------- */
195 6 : float fNoDataValue = 0.0f;
196 6 : pszOpt = CSLFetchNameValue(papszOptions, "NODATA");
197 6 : if (pszOpt != nullptr)
198 : {
199 4 : fNoDataValue = static_cast<float>(CPLAtof(pszOpt));
200 : }
201 : else
202 : {
203 2 : int bSuccess = FALSE;
204 :
205 2 : fNoDataValue = static_cast<float>(
206 2 : GDALGetRasterNoDataValue(hProximityBand, &bSuccess));
207 2 : if (!bSuccess)
208 2 : fNoDataValue = 65535.0;
209 : }
210 :
211 : /* -------------------------------------------------------------------- */
212 : /* Is there a fixed value we wish to force the buffer area to? */
213 : /* -------------------------------------------------------------------- */
214 6 : double dfFixedBufVal = 0.0;
215 6 : bool bFixedBufVal = false;
216 6 : pszOpt = CSLFetchNameValue(papszOptions, "FIXED_BUF_VAL");
217 6 : if (pszOpt)
218 : {
219 2 : dfFixedBufVal = CPLAtof(pszOpt);
220 2 : bFixedBufVal = true;
221 : }
222 :
223 : /* -------------------------------------------------------------------- */
224 : /* Get the target value(s). */
225 : /* -------------------------------------------------------------------- */
226 6 : int *panTargetValues = nullptr;
227 6 : int nTargetValues = 0;
228 :
229 6 : pszOpt = CSLFetchNameValue(papszOptions, "VALUES");
230 6 : if (pszOpt != nullptr)
231 : {
232 : char **papszValuesTokens =
233 4 : CSLTokenizeStringComplex(pszOpt, ",", FALSE, FALSE);
234 :
235 4 : nTargetValues = CSLCount(papszValuesTokens);
236 : panTargetValues =
237 4 : static_cast<int *>(CPLCalloc(sizeof(int), nTargetValues));
238 :
239 12 : for (int i = 0; i < nTargetValues; i++)
240 8 : panTargetValues[i] = atoi(papszValuesTokens[i]);
241 4 : CSLDestroy(papszValuesTokens);
242 : }
243 :
244 : /* -------------------------------------------------------------------- */
245 : /* Initialize progress counter. */
246 : /* -------------------------------------------------------------------- */
247 6 : if (!pfnProgress(0.0, "", pProgressArg))
248 : {
249 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
250 0 : CPLFree(panTargetValues);
251 0 : return CE_Failure;
252 : }
253 :
254 : /* -------------------------------------------------------------------- */
255 : /* We need a signed type for the working proximity values kept */
256 : /* on disk. If our proximity band is not signed, then create a */
257 : /* temporary file for this purpose. */
258 : /* -------------------------------------------------------------------- */
259 6 : GDALRasterBandH hWorkProximityBand = hProximityBand;
260 6 : GDALDatasetH hWorkProximityDS = nullptr;
261 6 : const GDALDataType eProxType = GDALGetRasterDataType(hProximityBand);
262 6 : CPLErr eErr = CE_None;
263 :
264 : // TODO(schwehr): Localize after removing gotos.
265 6 : float *pafProximity = nullptr;
266 6 : int *panNearX = nullptr;
267 6 : int *panNearY = nullptr;
268 6 : GInt32 *panSrcScanline = nullptr;
269 6 : bool bTempFileAlreadyDeleted = false;
270 :
271 6 : if (eProxType == GDT_Byte || eProxType == GDT_UInt16 ||
272 : eProxType == GDT_UInt32)
273 : {
274 3 : GDALDriverH hDriver = GDALGetDriverByName("GTiff");
275 3 : if (hDriver == nullptr)
276 : {
277 0 : CPLError(CE_Failure, CPLE_AppDefined,
278 : "GDALComputeProximity needs GTiff driver");
279 0 : eErr = CE_Failure;
280 0 : goto end;
281 : }
282 3 : CPLString osTmpFile = CPLGenerateTempFilename("proximity");
283 3 : hWorkProximityDS = GDALCreate(hDriver, osTmpFile, nXSize, nYSize, 1,
284 : GDT_Float32, nullptr);
285 3 : if (hWorkProximityDS == nullptr)
286 : {
287 0 : eErr = CE_Failure;
288 0 : goto end;
289 : }
290 : // On Unix, attempt at deleting the temporary file now, so that
291 : // if the process gets interrupted, it is automatically destroyed
292 : // by the operating system.
293 3 : bTempFileAlreadyDeleted = VSIUnlink(osTmpFile) == 0;
294 3 : hWorkProximityBand = GDALGetRasterBand(hWorkProximityDS, 1);
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Allocate buffer for two scanlines of distances as floats */
299 : /* (the current and last line). */
300 : /* -------------------------------------------------------------------- */
301 : pafProximity =
302 6 : static_cast<float *>(VSI_MALLOC2_VERBOSE(sizeof(float), nXSize));
303 6 : panNearX = static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nXSize));
304 6 : panNearY = static_cast<int *>(VSI_MALLOC2_VERBOSE(sizeof(int), nXSize));
305 : panSrcScanline =
306 6 : static_cast<GInt32 *>(VSI_MALLOC2_VERBOSE(sizeof(GInt32), nXSize));
307 :
308 6 : if (pafProximity == nullptr || panNearX == nullptr || panNearY == nullptr ||
309 : panSrcScanline == nullptr)
310 : {
311 0 : eErr = CE_Failure;
312 0 : goto end;
313 : }
314 :
315 : /* -------------------------------------------------------------------- */
316 : /* Loop from top to bottom of the image. */
317 : /* -------------------------------------------------------------------- */
318 :
319 156 : for (int i = 0; i < nXSize; i++)
320 : {
321 150 : panNearX[i] = -1;
322 150 : panNearY[i] = -1;
323 : }
324 :
325 156 : for (int iLine = 0; eErr == CE_None && iLine < nYSize; iLine++)
326 : {
327 : // Read for target values.
328 150 : eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iLine, nXSize, 1,
329 : panSrcScanline, nXSize, 1, GDT_Int32, 0, 0);
330 150 : if (eErr != CE_None)
331 0 : break;
332 :
333 3900 : for (int i = 0; i < nXSize; i++)
334 3750 : pafProximity[i] = -1.0;
335 :
336 : // Left to right.
337 150 : ProcessProximityLine(panSrcScanline, panNearX, panNearY, TRUE, iLine,
338 : nXSize, dfMaxDist, pafProximity, pdfSrcNoData,
339 : nTargetValues, panTargetValues);
340 :
341 : // Right to Left.
342 150 : ProcessProximityLine(panSrcScanline, panNearX, panNearY, FALSE, iLine,
343 : nXSize, dfMaxDist, pafProximity, pdfSrcNoData,
344 : nTargetValues, panTargetValues);
345 :
346 : // Write out results.
347 150 : eErr = GDALRasterIO(hWorkProximityBand, GF_Write, 0, iLine, nXSize, 1,
348 : pafProximity, nXSize, 1, GDT_Float32, 0, 0);
349 :
350 150 : if (eErr != CE_None)
351 0 : break;
352 :
353 150 : if (!pfnProgress(0.5 * (iLine + 1) / static_cast<double>(nYSize), "",
354 : pProgressArg))
355 : {
356 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
357 0 : eErr = CE_Failure;
358 : }
359 : }
360 :
361 : /* -------------------------------------------------------------------- */
362 : /* Loop from bottom to top of the image. */
363 : /* -------------------------------------------------------------------- */
364 156 : for (int i = 0; i < nXSize; i++)
365 : {
366 150 : panNearX[i] = -1;
367 150 : panNearY[i] = -1;
368 : }
369 :
370 156 : for (int iLine = nYSize - 1; eErr == CE_None && iLine >= 0; iLine--)
371 : {
372 : // Read first pass proximity.
373 150 : eErr = GDALRasterIO(hWorkProximityBand, GF_Read, 0, iLine, nXSize, 1,
374 : pafProximity, nXSize, 1, GDT_Float32, 0, 0);
375 :
376 150 : if (eErr != CE_None)
377 0 : break;
378 :
379 : // Read pixel values.
380 :
381 150 : eErr = GDALRasterIO(hSrcBand, GF_Read, 0, iLine, nXSize, 1,
382 : panSrcScanline, nXSize, 1, GDT_Int32, 0, 0);
383 150 : if (eErr != CE_None)
384 0 : break;
385 :
386 : // Right to left.
387 150 : ProcessProximityLine(panSrcScanline, panNearX, panNearY, FALSE, iLine,
388 : nXSize, dfMaxDist, pafProximity, pdfSrcNoData,
389 : nTargetValues, panTargetValues);
390 :
391 : // Left to right.
392 150 : ProcessProximityLine(panSrcScanline, panNearX, panNearY, TRUE, iLine,
393 : nXSize, dfMaxDist, pafProximity, pdfSrcNoData,
394 : nTargetValues, panTargetValues);
395 :
396 : // Final post processing of distances.
397 3900 : for (int i = 0; i < nXSize; i++)
398 : {
399 3750 : if (pafProximity[i] < 0.0)
400 1428 : pafProximity[i] = fNoDataValue;
401 2322 : else if (pafProximity[i] > 0.0)
402 : {
403 2060 : if (bFixedBufVal)
404 570 : pafProximity[i] = static_cast<float>(dfFixedBufVal);
405 : else
406 1490 : pafProximity[i] =
407 1490 : static_cast<float>(pafProximity[i] * dfDistMult);
408 : }
409 : }
410 :
411 : // Write out results.
412 150 : eErr = GDALRasterIO(hProximityBand, GF_Write, 0, iLine, nXSize, 1,
413 : pafProximity, nXSize, 1, GDT_Float32, 0, 0);
414 :
415 150 : if (eErr != CE_None)
416 0 : break;
417 :
418 150 : if (!pfnProgress(0.5 + 0.5 * (nYSize - iLine) /
419 150 : static_cast<double>(nYSize),
420 : "", pProgressArg))
421 : {
422 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
423 0 : eErr = CE_Failure;
424 : }
425 : }
426 :
427 : /* -------------------------------------------------------------------- */
428 : /* Cleanup */
429 : /* -------------------------------------------------------------------- */
430 6 : end:
431 6 : CPLFree(panNearX);
432 6 : CPLFree(panNearY);
433 6 : CPLFree(panSrcScanline);
434 6 : CPLFree(pafProximity);
435 6 : CPLFree(panTargetValues);
436 :
437 6 : if (hWorkProximityDS != nullptr)
438 : {
439 6 : CPLString osProxFile = GDALGetDescription(hWorkProximityDS);
440 3 : GDALClose(hWorkProximityDS);
441 3 : if (!bTempFileAlreadyDeleted)
442 : {
443 0 : GDALDeleteDataset(GDALGetDriverByName("GTiff"), osProxFile);
444 : }
445 : }
446 :
447 6 : return eErr;
448 : }
449 :
450 : /************************************************************************/
451 : /* SquareDistance() */
452 : /************************************************************************/
453 :
454 26074 : static double SquareDistance(double dfX1, double dfX2, double dfY1, double dfY2)
455 : {
456 26074 : const double dfDX = dfX1 - dfX2;
457 26074 : const double dfDY = dfY1 - dfY2;
458 26074 : return dfDX * dfDX + dfDY * dfDY;
459 : }
460 :
461 : /************************************************************************/
462 : /* ProcessProximityLine() */
463 : /************************************************************************/
464 :
465 600 : static CPLErr ProcessProximityLine(GInt32 *panSrcScanline, int *panNearX,
466 : int *panNearY, int bForward, int iLine,
467 : int nXSize, double dfMaxDist,
468 : float *pafProximity,
469 : double *pdfSrcNoDataValue, int nTargetValues,
470 : int *panTargetValues)
471 :
472 : {
473 600 : const int iStart = bForward ? 0 : nXSize - 1;
474 600 : const int iEnd = bForward ? nXSize : -1;
475 600 : const int iStep = bForward ? 1 : -1;
476 :
477 15600 : for (int iPixel = iStart; iPixel != iEnd; iPixel += iStep)
478 : {
479 15000 : bool bIsTarget = false;
480 :
481 : /* --------------------------------------------------------------------
482 : */
483 : /* Is the current pixel a target pixel? */
484 : /* --------------------------------------------------------------------
485 : */
486 15000 : if (nTargetValues == 0)
487 : {
488 5000 : bIsTarget = panSrcScanline[iPixel] != 0;
489 : }
490 : else
491 : {
492 30000 : for (int i = 0; i < nTargetValues; i++)
493 : {
494 20000 : if (panSrcScanline[iPixel] == panTargetValues[i])
495 144 : bIsTarget = TRUE;
496 : }
497 : }
498 :
499 15000 : if (bIsTarget)
500 : {
501 1048 : pafProximity[iPixel] = 0.0;
502 1048 : panNearX[iPixel] = iPixel;
503 1048 : panNearY[iPixel] = iLine;
504 1048 : continue;
505 : }
506 :
507 : /* --------------------------------------------------------------------
508 : */
509 : /* Are we near(er) to the closest target to the above (below) */
510 : /* pixel? */
511 : /* --------------------------------------------------------------------
512 : */
513 13952 : double dfNearDistSq = std::max(dfMaxDist, static_cast<double>(nXSize)) *
514 13952 : std::max(dfMaxDist, static_cast<double>(nXSize)) *
515 13952 : 2.0;
516 :
517 13952 : if (panNearX[iPixel] != -1)
518 : {
519 8864 : const double dfDistSq = SquareDistance(panNearX[iPixel], iPixel,
520 8864 : panNearY[iPixel], iLine);
521 :
522 8864 : if (dfDistSq < dfNearDistSq)
523 : {
524 8864 : dfNearDistSq = dfDistSq;
525 : }
526 : else
527 : {
528 0 : panNearX[iPixel] = -1;
529 0 : panNearY[iPixel] = -1;
530 : }
531 : }
532 :
533 : /* --------------------------------------------------------------------
534 : */
535 : /* Are we near(er) to the closest target to the left (right) */
536 : /* pixel? */
537 : /* --------------------------------------------------------------------
538 : */
539 13952 : const int iLast = iPixel - iStep;
540 :
541 13952 : if (iPixel != iStart && panNearX[iLast] != -1)
542 : {
543 : const double dfDistSq =
544 8732 : SquareDistance(panNearX[iLast], iPixel, panNearY[iLast], iLine);
545 :
546 8732 : if (dfDistSq < dfNearDistSq)
547 : {
548 1500 : dfNearDistSq = dfDistSq;
549 1500 : panNearX[iPixel] = panNearX[iLast];
550 1500 : panNearY[iPixel] = panNearY[iLast];
551 : }
552 : }
553 :
554 : /* --------------------------------------------------------------------
555 : */
556 : /* Are we near(er) to the closest target to the topright */
557 : /* (bottom left) pixel? */
558 : /* --------------------------------------------------------------------
559 : */
560 13952 : const int iTR = iPixel + iStep;
561 :
562 13952 : if (iTR != iEnd && panNearX[iTR] != -1)
563 : {
564 : const double dfDistSq =
565 8478 : SquareDistance(panNearX[iTR], iPixel, panNearY[iTR], iLine);
566 :
567 8478 : if (dfDistSq < dfNearDistSq)
568 : {
569 52 : dfNearDistSq = dfDistSq;
570 52 : panNearX[iPixel] = panNearX[iTR];
571 52 : panNearY[iPixel] = panNearY[iTR];
572 : }
573 : }
574 :
575 : /* --------------------------------------------------------------------
576 : */
577 : /* Update our proximity value. */
578 : /* --------------------------------------------------------------------
579 : */
580 13952 : if (panNearX[iPixel] != -1 &&
581 2684 : (pdfSrcNoDataValue == nullptr ||
582 2684 : panSrcScanline[iPixel] != *pdfSrcNoDataValue) &&
583 8714 : dfNearDistSq <= dfMaxDist * dfMaxDist &&
584 6206 : (pafProximity[iPixel] < 0 ||
585 4146 : dfNearDistSq < static_cast<double>(pafProximity[iPixel]) *
586 4146 : pafProximity[iPixel]))
587 3208 : pafProximity[iPixel] = static_cast<float>(sqrt(dfNearDistSq));
588 : }
589 :
590 600 : return CE_None;
591 : }
|