LCOV - code coverage report
Current view: top level - alg - gdalproximity.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 169 205 82.4 %
Date: 2024-05-04 12:52:34 Functions: 3 3 100.0 %

          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             : }

Generated by: LCOV version 1.14