LCOV - code coverage report
Current view: directory - alg - gdalsievefilter.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 161 139 86.3 %
Date: 2012-04-28 Functions: 3 3 100.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: gdalsievefilter.cpp 23156 2011-10-01 15:34:16Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL
       5                 :  * Purpose:  Raster to Polygon Converter
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2008, Frank Warmerdam
      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 "gdal_alg_priv.h"
      31                 : #include "cpl_conv.h"
      32                 : #include <vector>
      33                 : 
      34                 : CPL_CVSID("$Id: gdalsievefilter.cpp 23156 2011-10-01 15:34:16Z rouault $");
      35                 : 
      36                 : #define GP_NODATA_MARKER -51502112
      37                 : #define MY_MAX_INT 2147483647
      38                 : 
      39                 : /*
      40                 :  * General Plan
      41                 :  *
      42                 :  * 1) make a pass with the polygon enumerator to build up the 
      43                 :  *    polygon map array.  Also accumulate polygon size information.
      44                 :  *
      45                 :  * 2) Identify the polygons that need to be merged.
      46                 :  * 
      47                 :  * 3) Make a pass with the polygon enumerator.  For each "to be merged" 
      48                 :  *    polygon keep track of it's largest neighbour. 
      49                 :  * 
      50                 :  * 4) Fix up remappings that would go to polygons smaller than the seive
      51                 :  *    size.  Ensure these in term map to the largest neighbour of the 
      52                 :  *    "to be seieved" polygons. 
      53                 :  * 
      54                 :  * 5) Make another pass with the polygon enumerator. This time we remap
      55                 :  *    the actual pixel values of all polygons to be merged.
      56                 :  * 
      57                 :  */
      58                 : 
      59                 : /************************************************************************/
      60                 : /*                          GPMaskImageData()                           */
      61                 : /*                                                                      */
      62                 : /*      Mask out image pixels to a special nodata value if the mask     */
      63                 : /*      band is zero.                                                   */
      64                 : /************************************************************************/
      65                 : 
      66                 : static CPLErr 
      67              42 : GPMaskImageData( GDALRasterBandH hMaskBand, GByte *pabyMaskLine, int iY, int nXSize, 
      68                 :                  GInt32 *panImageLine )
      69                 : 
      70                 : {
      71                 :     CPLErr eErr;
      72                 : 
      73                 :     eErr = GDALRasterIO( hMaskBand, GF_Read, 0, iY, nXSize, 1, 
      74              42 :                          pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
      75              42 :     if( eErr == CE_None )
      76                 :     {
      77                 :         int i;
      78             252 :         for( i = 0; i < nXSize; i++ )
      79                 :         {
      80             210 :             if( pabyMaskLine[i] == 0 )
      81               0 :                 panImageLine[i] = GP_NODATA_MARKER;
      82                 :         }
      83                 :     }
      84                 : 
      85              42 :     return eErr;
      86                 : }
      87                 : 
      88                 : /************************************************************************/
      89                 : /*                          CompareNeighbour()                          */
      90                 : /*                                                                      */
      91                 : /*      Compare two neighbouring polygons, and update eaches            */
      92                 : /*      "biggest neighbour" if the other is larger than it's current    */
      93                 : /*      largest neighbour.                                              */
      94                 : /*                                                                      */
      95                 : /*      Note that this should end up with each polygon knowing the      */
      96                 : /*      id of it's largest neighbour.  No attempt is made to            */
      97                 : /*      restrict things to small polygons that we will be merging,      */
      98                 : /*      nor to exclude assigning "biggest neighbours" that are still    */
      99                 : /*      smaller than our sieve threshold.                               */
     100                 : /************************************************************************/
     101                 : 
     102            1056 : static inline void CompareNeighbour( int nPolyId1, int nPolyId2, 
     103                 :                                      int *panPolyIdMap, 
     104                 :                                      int *panPolyValue,
     105                 :                                      std::vector<int> &anPolySizes,
     106                 :                                      std::vector<int> &anBigNeighbour )
     107                 : 
     108                 : {
     109                 :     // make sure we are working with the final merged polygon ids. 
     110            1056 :     nPolyId1 = panPolyIdMap[nPolyId1];
     111            1056 :     nPolyId2 = panPolyIdMap[nPolyId2];
     112                 : 
     113            1056 :     if( nPolyId1 == nPolyId2 )
     114             408 :         return;
     115                 : 
     116                 :     // nodata polygon do not need neighbours, and cannot be neighbours
     117                 :     // to valid polygons. 
     118            1296 :     if( panPolyValue[nPolyId1] == GP_NODATA_MARKER
     119             648 :         || panPolyValue[nPolyId2] == GP_NODATA_MARKER )
     120               0 :         return;
     121                 : 
     122             648 :     if( anBigNeighbour[nPolyId1] == -1
     123                 :         || anPolySizes[anBigNeighbour[nPolyId1]] < anPolySizes[nPolyId2] )
     124             254 :         anBigNeighbour[nPolyId1] = nPolyId2;
     125                 : 
     126             648 :     if( anBigNeighbour[nPolyId2] == -1
     127                 :         || anPolySizes[anBigNeighbour[nPolyId2]] < anPolySizes[nPolyId1] )
     128             110 :         anBigNeighbour[nPolyId2] = nPolyId1;
     129                 : }
     130                 : 
     131                 : /************************************************************************/
     132                 : /*                          GDALSieveFilter()                           */
     133                 : /************************************************************************/
     134                 : 
     135                 : /** 
     136                 :  * Removes small raster polygons. 
     137                 :  *
     138                 :  * The function removes raster polygons smaller than a provided
     139                 :  * threshold size (in pixels) and replaces replaces them with the pixel value 
     140                 :  * of the largest neighbour polygon.  
     141                 :  *
     142                 :  * Polygon are determined (per GDALRasterPolygonEnumerator) as regions of
     143                 :  * the raster where the pixels all have the same value, and that are contiguous
     144                 :  * (connected).  
     145                 :  *
     146                 :  * Pixels determined to be "nodata" per hMaskBand will not be treated as part
     147                 :  * of a polygon regardless of their pixel values.  Nodata areas will never be
     148                 :  * changed nor affect polygon sizes. 
     149                 :  *
     150                 :  * Polygons smaller than the threshold with no neighbours that are as large
     151                 :  * as the threshold will not be altered.  Polygons surrounded by nodata areas
     152                 :  * will therefore not be altered.  
     153                 :  *
     154                 :  * The algorithm makes three passes over the input file to enumerate the
     155                 :  * polygons and collect limited information about them.  Memory use is 
     156                 :  * proportional to the number of polygons (roughly 24 bytes per polygon), but
     157                 :  * is not directly related to the size of the raster.  So very large raster
     158                 :  * files can be processed effectively if there aren't too many polygons.  But
     159                 :  * extremely noisy rasters with many one pixel polygons will end up being 
     160                 :  * expensive (in memory) to process.
     161                 :  * 
     162                 :  * @param hSrcBand the source raster band to be processed.
     163                 :  * @param hMaskBand an optional mask band.  All pixels in the mask band with a 
     164                 :  * value other than zero will be considered suitable for inclusion in polygons.
     165                 :  * @param hDstBand the output raster band.  It may be the same as hSrcBand
     166                 :  * to update the source in place. 
     167                 :  * @param nSizeThreshold raster polygons with sizes smaller than this will
     168                 :  * be merged into their largest neighbour.
     169                 :  * @param nConnectedness either 4 indicating that diagonal pixels are not
     170                 :  * considered directly adjacent for polygon membership purposes or 8
     171                 :  * indicating they are. 
     172                 :  * @param papszOptions algorithm options in name=value list form.  None currently
     173                 :  * supported.
     174                 :  * @param pfnProgress callback for reporting algorithm progress matching the
     175                 :  * GDALProgressFunc() semantics.  May be NULL.
     176                 :  * @param pProgressArg callback argument passed to pfnProgress.
     177                 :  *
     178                 :  * @return CE_None on success or CE_Failure if an error occurs.
     179                 :  */
     180                 : 
     181                 : CPLErr CPL_STDCALL
     182              12 : GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
     183                 :                  GDALRasterBandH hDstBand,
     184                 :                  int nSizeThreshold, int nConnectedness,
     185                 :                  char **papszOptions,
     186                 :                  GDALProgressFunc pfnProgress, 
     187                 :                  void * pProgressArg )
     188                 : 
     189                 : {
     190              12 :     VALIDATE_POINTER1( hSrcBand, "GDALSieveFilter", CE_Failure );
     191              12 :     VALIDATE_POINTER1( hDstBand, "GDALSieveFilter", CE_Failure );
     192                 : 
     193              12 :     if( pfnProgress == NULL )
     194              10 :         pfnProgress = GDALDummyProgress;
     195                 : 
     196                 : /* -------------------------------------------------------------------- */
     197                 : /*      Allocate working buffers.                                       */
     198                 : /* -------------------------------------------------------------------- */
     199              12 :     CPLErr eErr = CE_None;
     200              12 :     int nXSize = GDALGetRasterBandXSize( hSrcBand );
     201              12 :     int nYSize = GDALGetRasterBandYSize( hSrcBand );
     202              12 :     GInt32 *panLastLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     203              12 :     GInt32 *panThisLineVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     204              12 :     GInt32 *panLastLineId =  (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     205              12 :     GInt32 *panThisLineId =  (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     206              12 :     GInt32 *panThisLineWriteVal = (GInt32 *) VSIMalloc2(sizeof(GInt32), nXSize);
     207              12 :     GByte *pabyMaskLine = (hMaskBand != NULL) ? (GByte *) VSIMalloc(nXSize) : NULL;
     208              12 :     if (panLastLineVal == NULL || panThisLineVal == NULL ||
     209                 :         panLastLineId == NULL || panThisLineId == NULL ||
     210                 :         panThisLineWriteVal == NULL ||
     211                 :         (hMaskBand != NULL && pabyMaskLine == NULL))
     212                 :     {
     213                 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     214               0 :                  "Could not allocate enough memory for temporary buffers");
     215               0 :         CPLFree( panThisLineId );
     216               0 :         CPLFree( panLastLineId );
     217               0 :         CPLFree( panThisLineVal );
     218               0 :         CPLFree( panLastLineVal );
     219               0 :         CPLFree( panThisLineWriteVal );
     220               0 :         CPLFree( pabyMaskLine );
     221               0 :         return CE_Failure;
     222                 :     }
     223                 : 
     224                 : /* -------------------------------------------------------------------- */
     225                 : /*      The first pass over the raster is only used to build up the     */
     226                 : /*      polygon id map so we will know in advance what polygons are     */
     227                 : /*      what on the second pass.                                        */
     228                 : /* -------------------------------------------------------------------- */
     229                 :     int iY, iX, iPoly;
     230              12 :     GDALRasterPolygonEnumerator oFirstEnum( nConnectedness );
     231              12 :     std::vector<int> anPolySizes;
     232                 : 
     233              98 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     234                 :     {
     235                 :         eErr = GDALRasterIO( 
     236                 :             hSrcBand,
     237                 :             GF_Read, 0, iY, nXSize, 1, 
     238              86 :             panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     239                 :         
     240              86 :         if( eErr == CE_None && hMaskBand != NULL )
     241              14 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     242                 : 
     243              86 :         if( iY == 0 )
     244                 :             oFirstEnum.ProcessLine( 
     245              12 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     246                 :         else
     247                 :             oFirstEnum.ProcessLine(
     248                 :                 panLastLineVal, panThisLineVal, 
     249                 :                 panLastLineId,  panThisLineId, 
     250              74 :                 nXSize );
     251                 : 
     252                 : /* -------------------------------------------------------------------- */
     253                 : /*      Accumulate polygon sizes.                                       */
     254                 : /* -------------------------------------------------------------------- */
     255              86 :         if( oFirstEnum.nNextPolygonId > (int) anPolySizes.size() )
     256              78 :             anPolySizes.resize( oFirstEnum.nNextPolygonId );
     257                 : 
     258             596 :         for( iX = 0; iX < nXSize; iX++ )
     259                 :         {
     260             510 :             iPoly = panThisLineId[iX]; 
     261                 : 
     262             510 :             CPLAssert( iPoly >= 0 );
     263             510 :             if( anPolySizes[iPoly] < MY_MAX_INT )
     264             510 :                 anPolySizes[iPoly] += 1;
     265                 :         }
     266                 : 
     267                 : /* -------------------------------------------------------------------- */
     268                 : /*      swap this/last lines.                                           */
     269                 : /* -------------------------------------------------------------------- */
     270              86 :         GInt32 *panTmp = panLastLineVal;
     271              86 :         panLastLineVal = panThisLineVal;
     272              86 :         panThisLineVal = panTmp;
     273                 : 
     274              86 :         panTmp = panThisLineId;
     275              86 :         panThisLineId = panLastLineId;
     276              86 :         panLastLineId = panTmp;
     277                 : 
     278                 : /* -------------------------------------------------------------------- */
     279                 : /*      Report progress, and support interrupts.                        */
     280                 : /* -------------------------------------------------------------------- */
     281              86 :         if( eErr == CE_None 
     282                 :             && !pfnProgress( 0.25 * ((iY+1) / (double) nYSize), 
     283                 :                              "", pProgressArg ) )
     284                 :         {
     285               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     286               0 :             eErr = CE_Failure;
     287                 :         }
     288                 :     }
     289                 : 
     290                 : /* -------------------------------------------------------------------- */
     291                 : /*      Make a pass through the maps, ensuring every polygon id         */
     292                 : /*      points to the final id it should use, not an intermediate       */
     293                 : /*      value.                                                          */
     294                 : /* -------------------------------------------------------------------- */
     295              12 :     oFirstEnum.CompleteMerges();
     296                 : 
     297                 : /* -------------------------------------------------------------------- */
     298                 : /*      Push the sizes of merged polygon fragments into the the         */
     299                 : /*      merged polygon id's count.                                      */
     300                 : /* -------------------------------------------------------------------- */
     301             240 :     for( iPoly = 0; iPoly < oFirstEnum.nNextPolygonId; iPoly++ )
     302                 :     {
     303             228 :         if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
     304                 :         {
     305              22 :             GIntBig nSize = anPolySizes[oFirstEnum.panPolyIdMap[iPoly]];
     306                 : 
     307              22 :             nSize += anPolySizes[iPoly];
     308                 :             
     309              22 :             if( nSize > MY_MAX_INT )
     310               0 :                 nSize = MY_MAX_INT;
     311                 : 
     312              22 :             anPolySizes[oFirstEnum.panPolyIdMap[iPoly]] = (int)nSize;
     313              22 :             anPolySizes[iPoly] = 0;
     314                 :         }
     315                 :     }
     316                 : 
     317                 : /* -------------------------------------------------------------------- */
     318                 : /*      We will use a new enumerator for the second pass primariliy     */
     319                 : /*      so we can preserve the first pass map.                          */
     320                 : /* -------------------------------------------------------------------- */
     321              12 :     GDALRasterPolygonEnumerator oSecondEnum( nConnectedness );
     322                 : 
     323              12 :     std::vector<int> anBigNeighbour;
     324              12 :     anBigNeighbour.resize( anPolySizes.size() );
     325                 : 
     326             240 :     for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
     327             228 :         anBigNeighbour[iPoly] = -1;
     328                 : 
     329                 : /* ==================================================================== */
     330                 : /*      Second pass ... identify the largest neighbour for each         */
     331                 : /*      polygon.                                                        */
     332                 : /* ==================================================================== */
     333              98 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     334                 :     {
     335                 : /* -------------------------------------------------------------------- */
     336                 : /*      Read the image data.                                            */
     337                 : /* -------------------------------------------------------------------- */
     338                 :         eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, 
     339              86 :                              panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     340                 : 
     341              86 :         if( eErr == CE_None && hMaskBand != NULL )
     342              14 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     343                 : 
     344              86 :         if( eErr != CE_None )
     345               0 :             continue;
     346                 : 
     347                 : /* -------------------------------------------------------------------- */
     348                 : /*      Determine what polygon the various pixels belong to (redoing    */
     349                 : /*      the same thing done in the first pass above).                   */
     350                 : /* -------------------------------------------------------------------- */
     351              86 :         if( iY == 0 )
     352                 :             oSecondEnum.ProcessLine( 
     353              12 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     354                 :         else
     355                 :             oSecondEnum.ProcessLine(
     356                 :                 panLastLineVal, panThisLineVal, 
     357                 :                 panLastLineId,  panThisLineId, 
     358              74 :                 nXSize );
     359                 : 
     360                 : /* -------------------------------------------------------------------- */
     361                 : /*      Check our neighbours, and update our biggest neighbour map      */
     362                 : /*      as appropriate.                                                 */
     363                 : /* -------------------------------------------------------------------- */
     364             596 :         for( iX = 0; iX < nXSize; iX++ )
     365                 :         {
     366             510 :             if( iY > 0 )
     367                 :             {
     368                 :                 CompareNeighbour( panThisLineId[iX], 
     369                 :                                   panLastLineId[iX],
     370                 :                                   oFirstEnum.panPolyIdMap,
     371                 :                                   oFirstEnum.panPolyValue,
     372             440 :                                   anPolySizes, anBigNeighbour );
     373                 : 
     374             440 :                 if( iX > 0 && nConnectedness == 8 )
     375                 :                     CompareNeighbour( panThisLineId[iX], 
     376                 :                                       panLastLineId[iX-1],
     377                 :                                       oFirstEnum.panPolyIdMap,
     378                 :                                       oFirstEnum.panPolyValue,
     379              96 :                                       anPolySizes, anBigNeighbour );
     380                 :                     
     381             440 :                 if( iX < nXSize-1 && nConnectedness == 8 )
     382                 :                     CompareNeighbour( panThisLineId[iX], 
     383                 :                                       panLastLineId[iX+1],
     384                 :                                       oFirstEnum.panPolyIdMap,
     385                 :                                       oFirstEnum.panPolyValue,
     386              96 :                                       anPolySizes, anBigNeighbour );
     387                 :                     
     388                 :             }
     389                 :             
     390             510 :             if( iX > 0 )
     391                 :                 CompareNeighbour( panThisLineId[iX], 
     392                 :                                   panThisLineId[iX-1],
     393                 :                                   oFirstEnum.panPolyIdMap,
     394                 :                                   oFirstEnum.panPolyValue,
     395             424 :                                   anPolySizes, anBigNeighbour );
     396                 : 
     397                 :             // We don't need to compare to next pixel or next line
     398                 :             // since they will be compared to us.
     399                 :         }                     
     400                 : 
     401                 : /* -------------------------------------------------------------------- */
     402                 : /*      Swap pixel value, and polygon id lines to be ready for the      */
     403                 : /*      next line.                                                      */
     404                 : /* -------------------------------------------------------------------- */
     405              86 :         GInt32 *panTmp = panLastLineVal;
     406              86 :         panLastLineVal = panThisLineVal;
     407              86 :         panThisLineVal = panTmp;
     408                 : 
     409              86 :         panTmp = panThisLineId;
     410              86 :         panThisLineId = panLastLineId;
     411              86 :         panLastLineId = panTmp;
     412                 : 
     413                 : /* -------------------------------------------------------------------- */
     414                 : /*      Report progress, and support interrupts.                        */
     415                 : /* -------------------------------------------------------------------- */
     416              86 :         if( eErr == CE_None 
     417                 :             && !pfnProgress( 0.25 + 0.25 * ((iY+1) / (double) nYSize), 
     418                 :                              "", pProgressArg ) )
     419                 :         {
     420               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     421               0 :             eErr = CE_Failure;
     422                 :         }
     423                 :     }
     424                 : 
     425                 : /* -------------------------------------------------------------------- */
     426                 : /*      If our biggest neighbour is still smaller than the              */
     427                 : /*      threshold, then try tracking to that polygons biggest           */
     428                 : /*      neighbour, and so forth.                                        */
     429                 : /* -------------------------------------------------------------------- */
     430              12 :     int nFailedMerges = 0;
     431              12 :     int nIsolatedSmall = 0;
     432              12 :     int nSieveTargets = 0;
     433                 : 
     434             240 :     for( iPoly = 0; iPoly < (int) anPolySizes.size(); iPoly++ )
     435                 :     {
     436             228 :         if( oFirstEnum.panPolyIdMap[iPoly] != iPoly )
     437              22 :             continue;
     438                 : 
     439                 :         // Ignore nodata polygons. 
     440             206 :         if( oFirstEnum.panPolyValue[iPoly] == GP_NODATA_MARKER )
     441               0 :             continue;
     442                 : 
     443                 :         // Don't try to merge polygons larger than the threshold.
     444             206 :         if( anPolySizes[iPoly] >= nSizeThreshold )
     445                 :         {
     446              46 :             anBigNeighbour[iPoly] = -1;
     447              46 :             continue;
     448                 :         }
     449                 : 
     450             160 :         nSieveTargets++;
     451                 : 
     452                 :         // if we have no neighbours but we are small, what shall we do?
     453             160 :         if( anBigNeighbour[iPoly] == -1 )
     454                 :         {
     455               0 :             nIsolatedSmall++;
     456               0 :             continue;
     457                 :         }
     458                 : 
     459                 :         // If our biggest neighbour is larger than the threshold
     460                 :         // then we are golden. 
     461             160 :         if( anPolySizes[anBigNeighbour[iPoly]] >= nSizeThreshold )
     462             108 :             continue;
     463                 : 
     464                 : #ifdef notdef
     465                 :         // Will our neighbours biggest neighbour do?  
     466                 :         // Eventually we need something sort of recursive here with
     467                 :         // loop detection.
     468                 :         if( anPolySizes[anBigNeighbour[anBigNeighbour[iPoly]]] 
     469                 :             >= nSizeThreshold )
     470                 :         {
     471                 :             anBigNeighbour[iPoly] = anBigNeighbour[anBigNeighbour[iPoly]];
     472                 :             continue;
     473                 :         }
     474                 : #endif
     475                 : 
     476              52 :         nFailedMerges++;
     477              52 :         anBigNeighbour[iPoly] = -1;
     478                 :     }                 
     479                 : 
     480                 :     CPLDebug( "GDALSieveFilter", 
     481                 :               "Small Polygons: %d, Isolated: %d, Unmergable: %d",
     482              12 :               nSieveTargets, nIsolatedSmall, nFailedMerges );
     483                 : 
     484                 : /* ==================================================================== */
     485                 : /*      Make a third pass over the image, actually applying the         */
     486                 : /*      merges.  We reuse the second enumerator but preserve the        */
     487                 : /*      "final maps" from the first.                                    */
     488                 : /* ==================================================================== */
     489              12 :     oSecondEnum.Clear();
     490                 :     
     491                 : 
     492              98 :     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     493                 :     {
     494                 : /* -------------------------------------------------------------------- */
     495                 : /*      Read the image data.                                            */
     496                 : /* -------------------------------------------------------------------- */
     497                 :         eErr = GDALRasterIO( hSrcBand, GF_Read, 0, iY, nXSize, 1, 
     498              86 :                              panThisLineVal, nXSize, 1, GDT_Int32, 0, 0 );
     499                 : 
     500              86 :         memcpy( panThisLineWriteVal, panThisLineVal, 4 * nXSize );
     501                 : 
     502              86 :         if( eErr == CE_None && hMaskBand != NULL )
     503              14 :             eErr = GPMaskImageData( hMaskBand, pabyMaskLine, iY, nXSize, panThisLineVal );
     504                 : 
     505              86 :         if( eErr != CE_None )
     506               0 :             continue;
     507                 : 
     508                 : /* -------------------------------------------------------------------- */
     509                 : /*      Determine what polygon the various pixels belong to (redoing    */
     510                 : /*      the same thing done in the first pass above).                   */
     511                 : /* -------------------------------------------------------------------- */
     512              86 :         if( iY == 0 )
     513                 :             oSecondEnum.ProcessLine( 
     514              12 :                 NULL, panThisLineVal, NULL, panThisLineId, nXSize );
     515                 :         else
     516                 :             oSecondEnum.ProcessLine(
     517                 :                 panLastLineVal, panThisLineVal, 
     518                 :                 panLastLineId,  panThisLineId, 
     519              74 :                 nXSize );
     520                 : 
     521                 : /* -------------------------------------------------------------------- */
     522                 : /*      Reprocess the actual pixel values according to the polygon      */
     523                 : /*      merging, and write out this line of image data.                 */
     524                 : /* -------------------------------------------------------------------- */
     525             596 :         for( iX = 0; iX < nXSize; iX++ )
     526                 :         {
     527             510 :             int iThisPoly = oFirstEnum.panPolyIdMap[panThisLineId[iX]];
     528                 : 
     529             510 :             if( anBigNeighbour[iThisPoly] != -1 )
     530                 :             {
     531             108 :                 panThisLineWriteVal[iX] = 
     532                 :                     oFirstEnum.panPolyValue[
     533             108 :                         anBigNeighbour[iThisPoly]];
     534                 :             }
     535                 :         }
     536                 : 
     537                 : /* -------------------------------------------------------------------- */
     538                 : /*      Write the update data out.                                      */
     539                 : /* -------------------------------------------------------------------- */
     540                 :         eErr = GDALRasterIO( hDstBand, GF_Write, 0, iY, nXSize, 1, 
     541              86 :                              panThisLineWriteVal, nXSize, 1, GDT_Int32, 0, 0 );
     542                 : 
     543                 : /* -------------------------------------------------------------------- */
     544                 : /*      Swap pixel value, and polygon id lines to be ready for the      */
     545                 : /*      next line.                                                      */
     546                 : /* -------------------------------------------------------------------- */
     547              86 :         GInt32 *panTmp = panLastLineVal;
     548              86 :         panLastLineVal = panThisLineVal;
     549              86 :         panThisLineVal = panTmp;
     550                 : 
     551              86 :         panTmp = panThisLineId;
     552              86 :         panThisLineId = panLastLineId;
     553              86 :         panLastLineId = panTmp;
     554                 : 
     555                 : /* -------------------------------------------------------------------- */
     556                 : /*      Report progress, and support interrupts.                        */
     557                 : /* -------------------------------------------------------------------- */
     558              86 :         if( eErr == CE_None 
     559                 :             && !pfnProgress( 0.5 + 0.5 * ((iY+1) / (double) nYSize), 
     560                 :                              "", pProgressArg ) )
     561                 :         {
     562               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
     563               0 :             eErr = CE_Failure;
     564                 :         }
     565                 :     }
     566                 : 
     567                 : /* -------------------------------------------------------------------- */
     568                 : /*      Cleanup                                                         */
     569                 : /* -------------------------------------------------------------------- */
     570              12 :     CPLFree( panThisLineId );
     571              12 :     CPLFree( panLastLineId );
     572              12 :     CPLFree( panThisLineVal );
     573              12 :     CPLFree( panLastLineVal );
     574              12 :     CPLFree( panThisLineWriteVal );
     575              12 :     CPLFree( pabyMaskLine );
     576                 : 
     577              12 :     return eErr;
     578                 : }
     579                 : 

Generated by: LCOV version 1.7