LCOV - code coverage report
Current view: directory - alg - contour.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 501 457 91.2 %
Date: 2012-12-26 Functions: 38 29 76.3 %

       1                 : /******************************************************************************
       2                 :  * $Id: contour.cpp 25311 2012-12-15 12:48:14Z rouault $
       3                 :  *
       4                 :  * Project:  Contour Generation
       5                 :  * Purpose:  Core algorithm implementation for contour line generation. 
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  * Copyright (c) 2003, Applied Coherent Technology Corporation, www.actgate.com
      11                 :  *
      12                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      13                 :  * copy of this software and associated documentation files (the "Software"),
      14                 :  * to deal in the Software without restriction, including without limitation
      15                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16                 :  * and/or sell copies of the Software, and to permit persons to whom the
      17                 :  * Software is furnished to do so, subject to the following conditions:
      18                 :  *
      19                 :  * The above copyright notice and this permission notice shall be included
      20                 :  * in all copies or substantial portions of the Software.
      21                 :  *
      22                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28                 :  * DEALINGS IN THE SOFTWARE.
      29                 :  ****************************************************************************/
      30                 : 
      31                 : #include "gdal_priv.h"
      32                 : #include "gdal_alg.h"
      33                 : #include "ogr_api.h"
      34                 : 
      35                 : CPL_CVSID("$Id: contour.cpp 25311 2012-12-15 12:48:14Z rouault $");
      36                 : 
      37                 : #ifdef OGR_ENABLED
      38                 : 
      39                 : // The amount of a contour interval that pixels should be fudged by if they
      40                 : // match a contour level exactly.
      41                 : 
      42                 : #define FUDGE_EXACT 0.001
      43                 : 
      44                 : // The amount of a pixel that line ends need to be within to be considered to
      45                 : // match for joining purposes. 
      46                 : 
      47                 : #define JOIN_DIST 0.0001
      48                 : 
      49                 : /************************************************************************/
      50                 : /*                           GDALContourItem                            */
      51                 : /************************************************************************/
      52                 : class GDALContourItem
      53                 : {
      54                 : public:
      55                 :     int    bRecentlyAccessed;
      56                 :     double dfLevel;
      57                 : 
      58                 :     int  nPoints;
      59                 :     int  nMaxPoints;
      60                 :     double *padfX;
      61                 :     double *padfY;
      62                 : 
      63                 :     int bLeftIsHigh;
      64                 : 
      65                 :     double dfTailX;
      66                 : 
      67                 :     GDALContourItem( double dfLevel );
      68                 :     ~GDALContourItem();
      69                 : 
      70                 :     int    AddSegment( double dfXStart, double dfYStart,
      71                 :                        double dfXEnd, double dfYEnd, int bLeftHigh );
      72                 :     void   MakeRoomFor( int );
      73                 :     int    Merge( GDALContourItem * );
      74                 :     void   PrepareEjection();
      75                 : };
      76                 : 
      77                 : /************************************************************************/
      78                 : /*                           GDALContourLevel                           */
      79                 : /************************************************************************/
      80                 : class GDALContourLevel 
      81                 : {
      82                 :     double dfLevel;
      83                 : 
      84                 :     int nEntryMax;
      85                 :     int nEntryCount;
      86                 :     GDALContourItem **papoEntries;
      87                 :     
      88                 : public:
      89                 :     GDALContourLevel( double );
      90                 :     ~GDALContourLevel();
      91                 : 
      92          287936 :     double GetLevel() { return dfLevel; }
      93          200244 :     int    GetContourCount() { return nEntryCount; }
      94          164845 :     GDALContourItem *GetContour( int i) { return papoEntries[i]; }
      95                 :     void   AdjustContour( int );
      96                 :     void   RemoveContour( int );
      97                 :     int    FindContour( double dfX, double dfY );
      98                 :     int    InsertContour( GDALContourItem * );
      99                 : };
     100                 : 
     101                 : /************************************************************************/
     102                 : /*                         GDALContourGenerator                         */
     103                 : /************************************************************************/
     104                 : class GDALContourGenerator
     105                 : {
     106                 :     int    nWidth;
     107                 :     int    nHeight;
     108                 :     int    iLine;
     109                 : 
     110                 :     double *padfLastLine;
     111                 :     double *padfThisLine;
     112                 : 
     113                 :     int    nLevelMax;
     114                 :     int    nLevelCount;
     115                 :     GDALContourLevel **papoLevels;
     116                 : 
     117                 :     int     bNoDataActive;
     118                 :     double  dfNoDataValue;
     119                 : 
     120                 :     int     bFixedLevels;
     121                 :     double  dfContourInterval;
     122                 :     double  dfContourOffset;
     123                 : 
     124                 :     CPLErr AddSegment( double dfLevel, 
     125                 :                        double dfXStart, double dfYStart,
     126                 :                        double dfXEnd, double dfYEnd, int bLeftHigh );
     127                 : 
     128                 :     CPLErr ProcessPixel( int iPixel );
     129                 :     CPLErr ProcessRect( double, double, double, 
     130                 :                         double, double, double, 
     131                 :                         double, double, double,
     132                 :                         double, double, double );
     133                 : 
     134                 :     void   Intersect( double, double, double, 
     135                 :                       double, double, double, 
     136                 :                       double, double, int *, double *, double * );
     137                 : 
     138                 :     GDALContourLevel *FindLevel( double dfLevel );
     139                 : 
     140                 : public:
     141                 :     GDALContourWriter pfnWriter;
     142                 :     void   *pWriterCBData;
     143                 : 
     144                 :     GDALContourGenerator( int nWidth, int nHeight,
     145                 :                           GDALContourWriter pfnWriter, void *pWriterCBData );
     146                 :     ~GDALContourGenerator();
     147                 : 
     148                 :     void                SetNoData( double dfNoDataValue );
     149               6 :     void                SetContourLevels( double dfContourInterval, 
     150                 :                                           double dfContourOffset = 0.0 )
     151               6 :         { this->dfContourInterval = dfContourInterval;
     152               6 :           this->dfContourOffset = dfContourOffset; }
     153                 : 
     154                 :     void                SetFixedLevels( int, double * );
     155                 :     CPLErr              FeedLine( double *padfScanline );
     156                 :     CPLErr              EjectContours( int bOnlyUnused = FALSE );
     157                 :     
     158                 : };
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                           GDAL_CG_Create()                           */
     162                 : /************************************************************************/
     163                 : 
     164                 : GDALContourGeneratorH 
     165               0 : GDAL_CG_Create( int nWidth, int nHeight, int bNoDataSet, double dfNoDataValue, 
     166                 :                 double dfContourInterval, double dfContourBase, 
     167                 :                 GDALContourWriter pfnWriter, void *pCBData )
     168                 : 
     169                 : {
     170                 :     GDALContourGenerator *poCG = new GDALContourGenerator( nWidth, nHeight, 
     171               0 :                                                            pfnWriter, pCBData );
     172                 : 
     173               0 :     if( bNoDataSet )
     174               0 :         poCG->SetNoData( dfNoDataValue );
     175                 : 
     176               0 :     poCG->SetContourLevels( dfContourInterval, dfContourBase );
     177               0 :     return (GDALContourGeneratorH) poCG;
     178                 : }
     179                 : 
     180                 : /************************************************************************/
     181                 : /*                          GDAL_CG_FeedLine()                          */
     182                 : /************************************************************************/
     183                 : 
     184               0 : CPLErr GDAL_CG_FeedLine( GDALContourGeneratorH hCG, double *padfScanline )
     185                 : 
     186                 : {
     187               0 :     VALIDATE_POINTER1( hCG, "GDAL_CG_FeedLine", CE_Failure );
     188                 : 
     189               0 :     return ((GDALContourGenerator *) hCG)->FeedLine( padfScanline );
     190                 : }
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                          GDAL_CG_Destroy()                           */
     194                 : /************************************************************************/
     195                 : 
     196               0 : void GDAL_CG_Destroy( GDALContourGeneratorH hCG )
     197                 : 
     198                 : {
     199               0 :     delete ((GDALContourGenerator *) hCG);
     200               0 : }
     201                 : 
     202                 : /************************************************************************/
     203                 : /* ==================================================================== */
     204                 : /*                         GDALContourGenerator                         */
     205                 : /* ==================================================================== */
     206                 : /************************************************************************/
     207                 : 
     208                 : /************************************************************************/
     209                 : /*                        GDALContourGenerator()                        */
     210                 : /************************************************************************/
     211                 : 
     212               8 : GDALContourGenerator::GDALContourGenerator( int nWidthIn, int nHeightIn,
     213                 :                                             GDALContourWriter pfnWriterIn, 
     214                 :                                             void *pWriterCBDataIn )
     215                 : {
     216               8 :     nWidth = nWidthIn;
     217               8 :     nHeight = nHeightIn;
     218                 : 
     219               8 :     padfLastLine = (double *) CPLCalloc(sizeof(double),nWidth);
     220               8 :     padfThisLine = (double *) CPLCalloc(sizeof(double),nWidth);
     221                 : 
     222               8 :     pfnWriter = pfnWriterIn;
     223               8 :     pWriterCBData = pWriterCBDataIn;
     224                 : 
     225               8 :     iLine = -1;
     226                 : 
     227               8 :     bNoDataActive = FALSE;
     228               8 :     dfNoDataValue = -1000000.0;
     229               8 :     dfContourInterval = 10.0;
     230               8 :     dfContourOffset = 0.0;
     231                 : 
     232               8 :     nLevelMax = 0;
     233               8 :     nLevelCount = 0;
     234               8 :     papoLevels = NULL;
     235               8 :     bFixedLevels = FALSE;
     236               8 : }
     237                 : 
     238                 : /************************************************************************/
     239                 : /*                       ~GDALContourGenerator()                        */
     240                 : /************************************************************************/
     241                 : 
     242               8 : GDALContourGenerator::~GDALContourGenerator()
     243                 : 
     244                 : {
     245                 :     int i;
     246                 : 
     247              68 :     for( i = 0; i < nLevelCount; i++ )
     248              60 :         delete papoLevels[i];
     249               8 :     CPLFree( papoLevels );
     250                 : 
     251               8 :     CPLFree( padfLastLine );
     252               8 :     CPLFree( padfThisLine );
     253               8 : }
     254                 : 
     255                 : /************************************************************************/
     256                 : /*                           SetFixedLevels()                           */
     257                 : /************************************************************************/
     258                 : 
     259               2 : void GDALContourGenerator::SetFixedLevels( int nFixedLevelCount, 
     260                 :                                            double *padfFixedLevels )
     261                 : 
     262                 : {
     263               2 :     bFixedLevels = TRUE;
     264               8 :     for( int i = 0; i < nFixedLevelCount; i++ )
     265               6 :         FindLevel( padfFixedLevels[i] );
     266               2 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                             SetNoData()                              */
     270                 : /************************************************************************/
     271                 : 
     272               3 : void GDALContourGenerator::SetNoData( double dfNewValue )
     273                 : 
     274                 : {
     275               3 :     bNoDataActive = TRUE;
     276               3 :     dfNoDataValue = dfNewValue;
     277               3 : }
     278                 : 
     279                 : /************************************************************************/
     280                 : /*                            ProcessPixel()                            */
     281                 : /************************************************************************/
     282                 : 
     283          159403 : CPLErr GDALContourGenerator::ProcessPixel( int iPixel )
     284                 : 
     285                 : {
     286                 :     double  dfUpLeft, dfUpRight, dfLoLeft, dfLoRight;
     287          159403 :     int     bSubdivide = FALSE;
     288                 : 
     289                 : /* -------------------------------------------------------------------- */
     290                 : /*      Collect the four corner pixel values.  Value left or right      */
     291                 : /*      of the scanline are taken from the nearest pixel on the         */
     292                 : /*      scanline itself.                                                */
     293                 : /* -------------------------------------------------------------------- */
     294          159403 :     dfUpLeft = padfLastLine[MAX(0,iPixel-1)];
     295          159403 :     dfUpRight = padfLastLine[MIN(nWidth-1,iPixel)];
     296                 :     
     297          159403 :     dfLoLeft = padfThisLine[MAX(0,iPixel-1)];
     298          159403 :     dfLoRight = padfThisLine[MIN(nWidth-1,iPixel)];
     299                 : 
     300                 : /* -------------------------------------------------------------------- */
     301                 : /*      Check if we have any nodata values.                             */
     302                 : /* -------------------------------------------------------------------- */
     303          159403 :     if( bNoDataActive 
     304                 :         && ( dfUpLeft == dfNoDataValue
     305                 :              || dfLoLeft == dfNoDataValue
     306                 :              || dfLoRight == dfNoDataValue
     307                 :              || dfUpRight == dfNoDataValue ) )
     308               0 :         bSubdivide = TRUE;
     309                 : 
     310                 : /* -------------------------------------------------------------------- */
     311                 : /*      Check if we have any nodata, if so, go to a special case of     */
     312                 : /*      code.                                                           */
     313                 : /* -------------------------------------------------------------------- */
     314          159403 :     if( iPixel > 0 && iPixel < nWidth 
     315                 :         && iLine > 0 && iLine < nHeight && !bSubdivide )
     316                 :     {
     317                 :         return ProcessRect( dfUpLeft, iPixel - 0.5, iLine - 0.5, 
     318                 :                             dfLoLeft, iPixel - 0.5, iLine + 0.5, 
     319                 :                             dfLoRight, iPixel + 0.5, iLine + 0.5, 
     320          155217 :                             dfUpRight, iPixel + 0.5, iLine - 0.5 );
     321                 :     }
     322                 : 
     323                 : /* -------------------------------------------------------------------- */
     324                 : /*      Prepare subdivisions.                                           */
     325                 : /* -------------------------------------------------------------------- */
     326            4186 :     int nGoodCount = 0; 
     327            4186 :     double dfASum = 0.0;
     328            4186 :     double dfCenter, dfTop=0.0, dfRight=0.0, dfLeft=0.0, dfBottom=0.0;
     329                 :     
     330            4186 :     if( dfUpLeft != dfNoDataValue )
     331                 :     {
     332            4186 :         dfASum += dfUpLeft;
     333            4186 :         nGoodCount++;
     334                 :     }
     335                 : 
     336            4186 :     if( dfLoLeft != dfNoDataValue )
     337                 :     {
     338            4186 :         dfASum += dfLoLeft;
     339            4186 :         nGoodCount++;
     340                 :     }
     341                 : 
     342            4186 :     if( dfLoRight != dfNoDataValue )
     343                 :     {
     344            4186 :         dfASum += dfLoRight;
     345            4186 :         nGoodCount++;
     346                 :     }
     347                 : 
     348            4186 :     if( dfUpRight != dfNoDataValue )
     349                 :     {
     350            4186 :         dfASum += dfUpRight;
     351            4186 :         nGoodCount++;
     352                 :     }
     353                 : 
     354            4186 :     if( nGoodCount == 0.0 )
     355               0 :         return CE_None;
     356                 : 
     357            4186 :     dfCenter = dfASum / nGoodCount;
     358                 : 
     359            4186 :     if( dfUpLeft != dfNoDataValue )
     360                 :     {
     361            4186 :         if( dfUpRight != dfNoDataValue )
     362            4186 :             dfTop = (dfUpLeft + dfUpRight) / 2.0;
     363                 :         else
     364               0 :             dfTop = dfUpLeft;
     365                 : 
     366            4186 :         if( dfLoLeft != dfNoDataValue )
     367            4186 :             dfLeft = (dfUpLeft + dfLoLeft) / 2.0;
     368                 :         else
     369               0 :             dfLeft = dfUpLeft;
     370                 :     }
     371                 :     else
     372                 :     {
     373               0 :         dfTop = dfUpRight;
     374               0 :         dfLeft = dfLoLeft;
     375                 :     }
     376                 : 
     377            4186 :     if( dfLoRight != dfNoDataValue )
     378                 :     {
     379            4186 :         if( dfUpRight != dfNoDataValue )
     380            4186 :             dfRight = (dfLoRight + dfUpRight) / 2.0;
     381                 :         else
     382               0 :             dfRight = dfLoRight;
     383                 : 
     384            4186 :         if( dfLoLeft != dfNoDataValue )
     385            4186 :             dfBottom = (dfLoRight + dfLoLeft) / 2.0;
     386                 :         else
     387               0 :             dfBottom = dfLoRight;
     388                 :     }
     389                 :     else
     390                 :     {
     391               0 :         dfBottom = dfLoLeft;;
     392               0 :         dfRight = dfUpRight;
     393                 :     }
     394                 : 
     395                 : /* -------------------------------------------------------------------- */
     396                 : /*      Process any quadrants that aren't "nodata" anchored.            */
     397                 : /* -------------------------------------------------------------------- */
     398            4186 :     CPLErr eErr = CE_None;
     399                 : 
     400            4186 :     if( dfUpLeft != dfNoDataValue && iPixel > 0 && iLine > 0 )
     401                 :     {
     402                 :         eErr = ProcessRect( dfUpLeft, iPixel - 0.5, iLine - 0.5, 
     403                 :                             dfLeft, iPixel - 0.5, iLine, 
     404                 :                             dfCenter, iPixel, iLine, 
     405            2085 :                             dfTop, iPixel, iLine - 0.5 );
     406                 :     }
     407                 : 
     408            4186 :     if( dfLoLeft != dfNoDataValue && eErr == CE_None 
     409                 :         && iPixel > 0 && iLine < nHeight )
     410                 :     {
     411                 :         eErr = ProcessRect( dfLeft, iPixel - 0.5, iLine, 
     412                 :                             dfLoLeft, iPixel - 0.5, iLine + 0.5,
     413                 :                             dfBottom, iPixel, iLine + 0.5, 
     414            2085 :                             dfCenter, iPixel, iLine );
     415                 :     }
     416                 : 
     417            4186 :     if( dfLoRight != dfNoDataValue && iPixel < nWidth && iLine < nHeight )
     418                 :     {
     419                 :         eErr = ProcessRect( dfCenter, iPixel, iLine, 
     420                 :                             dfBottom, iPixel, iLine + 0.5,
     421                 :                             dfLoRight, iPixel + 0.5, iLine + 0.5, 
     422            2085 :                             dfRight, iPixel + 0.5, iLine );
     423                 :     }
     424                 : 
     425            4186 :     if( dfUpRight != dfNoDataValue && iPixel < nWidth && iLine > 0 )
     426                 :     {
     427                 :         eErr = ProcessRect( dfTop, iPixel, iLine - 0.5, 
     428                 :                             dfCenter, iPixel, iLine,
     429                 :                             dfRight, iPixel + 0.5, iLine, 
     430            2085 :                             dfUpRight, iPixel + 0.5, iLine - 0.5 );
     431                 :     }
     432                 : 
     433            4186 :     return eErr;
     434                 : }
     435                 : 
     436                 : /************************************************************************/
     437                 : /*                            ProcessRect()                             */
     438                 : /************************************************************************/
     439                 : 
     440          163557 : CPLErr GDALContourGenerator::ProcessRect( 
     441                 :     double dfUpLeft, double dfUpLeftX, double dfUpLeftY, 
     442                 :     double dfLoLeft, double dfLoLeftX, double dfLoLeftY, 
     443                 :     double dfLoRight, double dfLoRightX, double dfLoRightY, 
     444                 :     double dfUpRight, double dfUpRightX, double dfUpRightY )
     445                 :     
     446                 : {
     447                 : /* -------------------------------------------------------------------- */
     448                 : /*      Identify the range of elevations over this rect.                */
     449                 : /* -------------------------------------------------------------------- */
     450                 :     int iStartLevel, iEndLevel;
     451                 : 
     452          163557 :     double dfMin = MIN(MIN(dfUpLeft,dfUpRight),MIN(dfLoLeft,dfLoRight));
     453          163557 :     double dfMax = MAX(MAX(dfUpLeft,dfUpRight),MAX(dfLoLeft,dfLoRight));
     454                 :     
     455                 : 
     456                 : /* -------------------------------------------------------------------- */
     457                 : /*      Compute the set of levels to compute contours for.              */
     458                 : /* -------------------------------------------------------------------- */
     459                 : 
     460                 :     /* 
     461                 :     ** If we are using fixed levels, then find the min/max in the levels
     462                 :     ** table.
     463                 :     */
     464          163557 :     if( bFixedLevels )
     465                 :     {
     466           53114 :         int nStart=0, nEnd=nLevelCount-1, nMiddle;
     467                 : 
     468           53114 :         iStartLevel = -1;
     469          211734 :         while( nStart <= nEnd )
     470                 :         {
     471          106228 :             nMiddle = (nEnd + nStart) / 2;
     472                 :             
     473          106228 :             double dfMiddleLevel = papoLevels[nMiddle]->GetLevel();
     474                 :             
     475          106228 :             if( dfMiddleLevel < dfMin )
     476           12482 :                 nStart = nMiddle + 1;
     477           93746 :             else if( dfMiddleLevel > dfMin )
     478           93024 :                 nEnd = nMiddle - 1;
     479                 :             else
     480                 :             {
     481             722 :                 iStartLevel = nMiddle;
     482             722 :                 break;
     483                 :             }
     484                 :         }
     485                 : 
     486           53114 :         if( iStartLevel == -1 )
     487           52392 :             iStartLevel = nEnd + 1;
     488                 : 
     489           53114 :         iEndLevel = iStartLevel;
     490          156300 :         while( iEndLevel < nLevelCount-1 
     491           50072 :                && papoLevels[iEndLevel+1]->GetLevel() < dfMax )
     492               0 :             iEndLevel++;
     493                 : 
     494           53114 :         if( iStartLevel >= nLevelCount )
     495               0 :             return CE_None;
     496                 : 
     497           53114 :         CPLAssert( iStartLevel >= 0 && iStartLevel < nLevelCount );
     498           53114 :         CPLAssert( iEndLevel >= 0 && iEndLevel < nLevelCount );
     499                 :     }
     500                 : 
     501                 :     /*
     502                 :     ** Otherwise figure out the start and end using the base and offset.
     503                 :     */
     504                 :     else
     505                 :     {
     506                 :         iStartLevel = (int) 
     507          110443 :             ceil((dfMin - dfContourOffset) / dfContourInterval);
     508                 :         iEndLevel = (int)   
     509          110443 :             floor((dfMax - dfContourOffset) / dfContourInterval);
     510                 :     }
     511                 : 
     512          163557 :     if( iStartLevel > iEndLevel )
     513           98333 :         return CE_None;
     514                 : 
     515                 : /* -------------------------------------------------------------------- */
     516                 : /*      Loop over them.                                                 */
     517                 : /* -------------------------------------------------------------------- */
     518                 :     int iLevel;
     519                 : 
     520          137639 :     for( iLevel = iStartLevel; iLevel <= iEndLevel; iLevel++ )
     521                 :     {
     522                 :         double dfLevel;
     523                 : 
     524           72415 :         if( bFixedLevels )
     525           53114 :             dfLevel = papoLevels[iLevel]->GetLevel();
     526                 :         else
     527           19301 :             dfLevel = iLevel * dfContourInterval + dfContourOffset;
     528                 : 
     529           72415 :         int  nPoints = 0; 
     530                 :         double adfX[4], adfY[4];
     531           72415 :         CPLErr eErr = CE_None;
     532                 : 
     533                 :         /* Logs how many points we have af left + bottom,
     534                 :         ** and left + bottom + right.
     535                 :         */
     536           72415 :         int nPoints1 = 0, nPoints2 = 0, nPoints3 = 0;
     537                 : 
     538                 : 
     539                 :         Intersect( dfUpLeft, dfUpLeftX, dfUpLeftY,
     540                 :                    dfLoLeft, dfLoLeftX, dfLoLeftY,
     541           72415 :                    dfLoRight, dfLevel, &nPoints, adfX, adfY );
     542           72415 :         nPoints1 = nPoints;
     543                 :         Intersect( dfLoLeft, dfLoLeftX, dfLoLeftY,
     544                 :                    dfLoRight, dfLoRightX, dfLoRightY,
     545           72415 :                    dfUpRight, dfLevel, &nPoints, adfX, adfY );
     546           72415 :         nPoints2 = nPoints;
     547                 :         Intersect( dfLoRight, dfLoRightX, dfLoRightY,
     548                 :                    dfUpRight, dfUpRightX, dfUpRightY,
     549           72415 :                    dfUpLeft, dfLevel, &nPoints, adfX, adfY );
     550           72415 :         nPoints3 = nPoints;
     551                 :         Intersect( dfUpRight, dfUpRightX, dfUpRightY,
     552                 :                    dfUpLeft, dfUpLeftX, dfUpLeftY,
     553           72415 :                    dfLoLeft, dfLevel, &nPoints, adfX, adfY );
     554                 :         
     555           72415 :         if( nPoints == 1 || nPoints == 3 )
     556               8 :             CPLDebug( "CONTOUR", "Got nPoints = %d", nPoints );
     557                 : 
     558           72415 :         if( nPoints >= 2 )
     559                 :         {
     560           23530 :             if ( nPoints1 == 1 && nPoints2 == 2) // left + bottom
     561                 :             {
     562                 :                 eErr = AddSegment( dfLevel,
     563                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     564            3117 :                                    dfUpRight > dfLoLeft );
     565                 :             }
     566           22881 :             else if ( nPoints1 == 1 && nPoints3 == 2 ) // left + right 
     567                 :             {
     568                 :                 eErr = AddSegment( dfLevel,
     569                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     570            5585 :                                    dfUpLeft > dfLoRight );
     571                 :             }
     572           14887 :             else if ( nPoints1 == 1 && nPoints == 2 ) // left + top 
     573                 :             { // Do not do vertical contours on the left, due to symmetry
     574            3176 :               if ( !(dfUpLeft == dfLevel && dfLoLeft == dfLevel) )
     575                 :                 eErr = AddSegment( dfLevel,
     576                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     577            3115 :                                    dfUpLeft > dfLoRight );
     578                 :             }
     579           11611 :             else if(  nPoints2 == 1 && nPoints3 == 2) // bottom + right
     580                 :             {
     581                 :                 eErr = AddSegment( dfLevel,
     582                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     583            3076 :                                    dfUpLeft > dfLoRight );
     584                 :             }
     585            8277 :             else if ( nPoints2 == 1 && nPoints == 2 ) // bottom + top
     586                 :             {
     587                 :                 eErr = AddSegment( dfLevel,
     588                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     589            2818 :                                    dfLoLeft > dfUpRight );
     590                 :             }
     591            5282 :             else if ( nPoints3 == 1 && nPoints == 2 ) // right + top
     592                 :             { // Do not do horizontal contours on upside, due to symmetry
     593            2641 :               if ( !(dfUpRight == dfLevel && dfUpLeft == dfLevel) )
     594                 :                 eErr = AddSegment( dfLevel,
     595                 :                                    adfX[0], adfY[0], adfX[1], adfY[1],
     596            2586 :                                    dfLoLeft > dfUpRight );
     597                 :             }
     598                 :             else
     599                 :             {
     600                 :                 // If we get here it is a serious error!
     601               0 :                 CPLDebug( "CONTOUR", "Contour state not implemented!");
     602                 :             }
     603                 :  
     604           20413 :             if( eErr != CE_None )
     605               0 :                  return eErr;
     606                 :         }
     607                 : 
     608           72415 :         if( nPoints == 4 )
     609                 :         {
     610                 :           // Do not do horizontal contours on upside, due to symmetry
     611             461 :           if ( !(dfUpRight == dfLevel && dfUpLeft == dfLevel) )
     612                 :           {
     613                 : /* -------------------------------------------------------------------- */
     614                 : /*          If we get here, we know the first was left+bottom,          */
     615                 : /*          so we are at right+top, therefore "left is high"            */
     616                 : /*          if low-left is larger than up-right.                        */
     617                 : /*          We do not do a diagonal check here as we are dealing with   */
     618                 : /*          a saddle point.                                             */
     619                 : /* -------------------------------------------------------------------- */
     620                 :             eErr = AddSegment( dfLevel,
     621                 :                                adfX[2], adfY[2], adfX[3], adfY[3],
     622             461 :                                ( dfLoRight > dfUpRight) );
     623             461 :             if( eErr != CE_None )
     624               0 :                 return eErr;
     625                 :           }
     626                 :         }
     627                 :     }
     628                 : 
     629           65224 :     return CE_None;
     630                 : }
     631                 : 
     632                 : /************************************************************************/
     633                 : /*                             Intersect()                              */
     634                 : /************************************************************************/
     635                 : 
     636          289660 : void GDALContourGenerator::Intersect( double dfVal1, double dfX1, double dfY1, 
     637                 :                                       double dfVal2, double dfX2, double dfY2,
     638                 :                                       double dfNext, 
     639                 :                                       double dfLevel, int *pnPoints, 
     640                 :                                       double *padfX, double *padfY )
     641                 : 
     642                 : {
     643          310502 :     if( dfVal1 < dfLevel && dfVal2 >= dfLevel )
     644                 :     {
     645           20842 :         double dfRatio = (dfLevel - dfVal1) / (dfVal2 - dfVal1);
     646                 : 
     647           20842 :         padfX[*pnPoints] = dfX1 * (1.0 - dfRatio) + dfX2 * dfRatio;
     648           20842 :         padfY[*pnPoints] = dfY1 * (1.0 - dfRatio) + dfY2 * dfRatio;
     649           20842 :         (*pnPoints)++;
     650                 :     }
     651          289500 :     else if( dfVal1 > dfLevel && dfVal2 <= dfLevel )
     652                 :     {
     653           20682 :         double dfRatio = (dfLevel - dfVal2) / (dfVal1 - dfVal2);
     654                 : 
     655           20682 :         padfX[*pnPoints] = dfX2 * (1.0 - dfRatio) + dfX1 * dfRatio;
     656           20682 :         padfY[*pnPoints] = dfY2 * (1.0 - dfRatio) + dfY1 * dfRatio;
     657           20682 :         (*pnPoints)++;
     658                 :     }
     659          248136 :     else if( dfVal1 == dfLevel && dfVal2 == dfLevel && dfNext != dfLevel )
     660                 :     {
     661             232 :         padfX[*pnPoints] = dfX2;
     662             232 :         padfY[*pnPoints] = dfY2;
     663             232 :         (*pnPoints)++;
     664                 :     }
     665          289660 : }
     666                 : 
     667                 : /************************************************************************/
     668                 : /*                             AddSegment()                             */
     669                 : /************************************************************************/
     670                 : 
     671           20758 : CPLErr GDALContourGenerator::AddSegment( double dfLevel, 
     672                 :                                          double dfX1, double dfY1,
     673                 :                                          double dfX2, double dfY2,
     674                 :                                          int bLeftHigh)
     675                 : 
     676                 : {
     677           20758 :     GDALContourLevel *poLevel = FindLevel( dfLevel );
     678                 :     GDALContourItem *poTarget;
     679                 :     int iTarget;
     680                 : 
     681                 : /* -------------------------------------------------------------------- */
     682                 : /*      Check all active contours for any that this might attach        */
     683                 : /*      to. Eventually this should be recoded to find the contours      */
     684                 : /*      of the correct level more efficiently.                          */
     685                 : /* -------------------------------------------------------------------- */
     686                 : 
     687           20758 :     if( dfY1 < dfY2 )
     688            5207 :         iTarget = poLevel->FindContour( dfX1, dfY1 );
     689                 :     else
     690           15551 :         iTarget = poLevel->FindContour( dfX2, dfY2 );
     691                 : 
     692           20758 :     if( iTarget != -1 )
     693                 :     {
     694             148 :         poTarget = poLevel->GetContour( iTarget );
     695                 : 
     696             148 :         poTarget->AddSegment( dfX1, dfY1, dfX2, dfY2, bLeftHigh );
     697                 : 
     698             148 :         poLevel->AdjustContour( iTarget );
     699                 :         
     700             148 :         return CE_None;
     701                 :     }
     702                 : 
     703                 : /* -------------------------------------------------------------------- */
     704                 : /*      No existing contour found, lets create a new one.               */
     705                 : /* -------------------------------------------------------------------- */
     706           20610 :     poTarget = new GDALContourItem( dfLevel );
     707                 : 
     708           20610 :     poTarget->AddSegment( dfX1, dfY1, dfX2, dfY2, bLeftHigh );
     709                 : 
     710           20610 :     poLevel->InsertContour( poTarget );
     711                 : 
     712           20610 :     return CE_None;
     713                 : }
     714                 : 
     715                 : /************************************************************************/
     716                 : /*                              FeedLine()                              */
     717                 : /************************************************************************/
     718                 : 
     719            1055 : CPLErr GDALContourGenerator::FeedLine( double *padfScanline )
     720                 : 
     721                 : {
     722                 : /* -------------------------------------------------------------------- */
     723                 : /*      Switch current line to "lastline" slot, and copy new data       */
     724                 : /*      into new "this line".                                           */
     725                 : /* -------------------------------------------------------------------- */
     726            1055 :     double *padfTempLine = padfLastLine;
     727            1055 :     padfLastLine = padfThisLine;
     728            1055 :     padfThisLine = padfTempLine;
     729                 : 
     730                 : /* -------------------------------------------------------------------- */
     731                 : /*      If this is the end of the lines (NULL passed in), copy the      */
     732                 : /*      last line.                                                      */
     733                 : /* -------------------------------------------------------------------- */
     734            1055 :     if( padfScanline == NULL )
     735                 :     {
     736               8 :         memcpy( padfThisLine, padfLastLine, sizeof(double) * nWidth );
     737                 :     }
     738                 :     else
     739                 :     {
     740            1047 :         memcpy( padfThisLine, padfScanline, sizeof(double) * nWidth );
     741                 :     }
     742                 : 
     743                 : /* -------------------------------------------------------------------- */
     744                 : /*      Perturb any values that occur exactly on level boundaries.      */
     745                 : /* -------------------------------------------------------------------- */
     746                 :     int iPixel;
     747                 : 
     748          159403 :     for( iPixel = 0; iPixel < nWidth; iPixel++ )
     749                 :     {
     750          158348 :         if( bNoDataActive && padfThisLine[iPixel] == dfNoDataValue )
     751               0 :             continue;
     752                 : 
     753          158348 :         double dfLevel = (padfThisLine[iPixel] - dfContourOffset) 
     754          158348 :             / dfContourInterval;
     755                 : 
     756          158348 :         if( dfLevel - (int) dfLevel == 0.0 )
     757                 :         {
     758          102024 :             padfThisLine[iPixel] += dfContourInterval * FUDGE_EXACT;
     759                 :         }
     760                 :     }
     761                 : 
     762                 : /* -------------------------------------------------------------------- */
     763                 : /*      If this is the first line we need to initialize the previous    */
     764                 : /*      line from the first line of data.                               */
     765                 : /* -------------------------------------------------------------------- */
     766            1055 :     if( iLine == -1 )
     767                 :     {
     768               8 :         memcpy( padfLastLine, padfThisLine, sizeof(double) * nWidth );
     769               8 :         iLine = 0;
     770                 :     }
     771                 : 
     772                 : /* -------------------------------------------------------------------- */
     773                 : /*      Clear the recently used flags on the contours so we can         */
     774                 : /*      check later which ones were touched for this scanline.          */
     775                 : /* -------------------------------------------------------------------- */
     776                 :     int iLevel, iContour;
     777                 : 
     778            8118 :     for( iLevel = 0; iLevel < nLevelCount; iLevel++ )
     779                 :     {
     780            7063 :         GDALContourLevel *poLevel = papoLevels[iLevel];
     781                 : 
     782           35559 :         for( iContour = 0; iContour < poLevel->GetContourCount(); iContour++ )
     783           28496 :             poLevel->GetContour( iContour )->bRecentlyAccessed = FALSE;
     784                 :     }
     785                 : 
     786                 : /* -------------------------------------------------------------------- */
     787                 : /*      Process each pixel.                                             */
     788                 : /* -------------------------------------------------------------------- */
     789          160458 :     for( iPixel = 0; iPixel < nWidth+1; iPixel++ )
     790                 :     {
     791          159403 :         CPLErr eErr = ProcessPixel( iPixel );
     792          159403 :         if( eErr != CE_None )
     793               0 :             return eErr;
     794                 :     }
     795                 :     
     796                 : /* -------------------------------------------------------------------- */
     797                 : /*      eject any pending contours.                                     */
     798                 : /* -------------------------------------------------------------------- */
     799            1055 :     CPLErr eErr = EjectContours( padfScanline != NULL );
     800                 : 
     801            1055 :     iLine++;
     802                 : 
     803            1055 :     if( iLine == nHeight && eErr == CE_None )
     804               8 :         return FeedLine( NULL );
     805                 :     else
     806            1047 :         return eErr;
     807                 : }
     808                 : 
     809                 : /************************************************************************/
     810                 : /*                           EjectContours()                            */
     811                 : /************************************************************************/
     812                 : 
     813            1055 : CPLErr GDALContourGenerator::EjectContours( int bOnlyUnused )
     814                 : 
     815                 : {
     816                 :     int iLevel;
     817            1055 :     CPLErr eErr = CE_None;
     818                 : 
     819                 : /* -------------------------------------------------------------------- */
     820                 : /*      Process all contours of all levels that match our criteria      */
     821                 : /* -------------------------------------------------------------------- */
     822            8172 :     for( iLevel = 0; iLevel < nLevelCount && eErr == CE_None; iLevel++ )
     823                 :     {
     824            7117 :         GDALContourLevel *poLevel = papoLevels[iLevel];
     825                 :         int iContour;
     826                 : 
     827           63340 :         for( iContour = 0; 
     828                 :              iContour < poLevel->GetContourCount() && eErr == CE_None; 
     829                 :              /* increment in loop if we don't consume it. */ )
     830                 :         {
     831                 :             int  iC2;
     832           49106 :             GDALContourItem *poTarget = poLevel->GetContour( iContour );
     833                 :             
     834           49106 :             if( bOnlyUnused && poTarget->bRecentlyAccessed )
     835                 :             {
     836           28496 :                 iContour++;
     837           28496 :                 continue;
     838                 :             }
     839                 : 
     840           20610 :             poLevel->RemoveContour( iContour );
     841                 : 
     842                 :             // Try to find another contour we can merge with in this level.
     843                 :             
     844           87852 :             for( iC2 = 0; iC2 < poLevel->GetContourCount(); iC2++ )
     845                 :             {
     846           87095 :                 GDALContourItem *poOther = poLevel->GetContour( iC2 );
     847                 : 
     848           87095 :                 if( poOther->Merge( poTarget ) )
     849           19853 :                     break;
     850                 :             }
     851                 : 
     852                 :             // If we didn't merge it, then eject (write) it out. 
     853           20610 :             if( iC2 == poLevel->GetContourCount() )
     854                 :             {
     855             757 :                 if( pfnWriter != NULL )
     856                 :                 {
     857                 :                     // If direction is wrong, then reverse before ejecting.
     858             757 :                     poTarget->PrepareEjection();
     859                 : 
     860                 :                     eErr = pfnWriter( poTarget->dfLevel, poTarget->nPoints, 
     861                 :                                       poTarget->padfX, poTarget->padfY, 
     862             757 :                                       pWriterCBData );
     863                 :                 }
     864                 :             }
     865                 : 
     866           20610 :             delete poTarget;
     867                 :         }
     868                 :     }
     869                 : 
     870            1055 :     return eErr;
     871                 : }
     872                 : 
     873                 : /************************************************************************/
     874                 : /*                             FindLevel()                              */
     875                 : /************************************************************************/
     876                 : 
     877           20764 : GDALContourLevel *GDALContourGenerator::FindLevel( double dfLevel )
     878                 : 
     879                 : {
     880           20764 :     int nStart=0, nEnd=nLevelCount-1, nMiddle;
     881                 : 
     882                 : /* -------------------------------------------------------------------- */
     883                 : /*      Binary search to find the requested level.                      */
     884                 : /* -------------------------------------------------------------------- */
     885           99346 :     while( nStart <= nEnd )
     886                 :     {
     887           78522 :         nMiddle = (nEnd + nStart) / 2;
     888                 : 
     889           78522 :         double dfMiddleLevel = papoLevels[nMiddle]->GetLevel();
     890                 : 
     891           78522 :         if( dfMiddleLevel < dfLevel )
     892           23975 :             nStart = nMiddle + 1;
     893           54547 :         else if( dfMiddleLevel > dfLevel )
     894           33843 :             nEnd = nMiddle - 1;
     895                 :         else
     896           20704 :             return papoLevels[nMiddle];
     897                 :     }
     898                 : 
     899                 : /* -------------------------------------------------------------------- */
     900                 : /*      Didn't find the level, create a new one and insert it in        */
     901                 : /*      order.                                                          */
     902                 : /* -------------------------------------------------------------------- */
     903              60 :     GDALContourLevel *poLevel = new GDALContourLevel( dfLevel );
     904                 : 
     905              60 :     if( nLevelMax == nLevelCount )
     906                 :     {
     907              10 :         nLevelMax = nLevelMax * 2 + 10;
     908                 :         papoLevels = (GDALContourLevel **) 
     909              10 :             CPLRealloc( papoLevels, sizeof(void*) * nLevelMax );
     910                 :     }
     911                 : 
     912              60 :     if( nLevelCount - nEnd - 1 > 0 )
     913                 :         memmove( papoLevels + nEnd + 2, papoLevels + nEnd + 1, 
     914              28 :                  (nLevelCount - nEnd - 1) * sizeof(void*) );
     915              60 :     papoLevels[nEnd+1] = poLevel;
     916              60 :     nLevelCount++;
     917                 : 
     918              60 :     return poLevel;
     919                 : }
     920                 : 
     921                 : /************************************************************************/
     922                 : /* ==================================================================== */
     923                 : /*                           GDALContourLevel                           */
     924                 : /* ==================================================================== */
     925                 : /************************************************************************/
     926                 : 
     927                 : /************************************************************************/
     928                 : /*                          GDALContourLevel()                          */
     929                 : /************************************************************************/
     930                 : 
     931              60 : GDALContourLevel::GDALContourLevel( double dfLevelIn )
     932                 : 
     933                 : {
     934              60 :     dfLevel = dfLevelIn;
     935              60 :     nEntryMax = 0;
     936              60 :     nEntryCount = 0;
     937              60 :     papoEntries = NULL;
     938              60 : }
     939                 : 
     940                 : /************************************************************************/
     941                 : /*                         ~GDALContourLevel()                          */
     942                 : /************************************************************************/
     943                 : 
     944              60 : GDALContourLevel::~GDALContourLevel()
     945                 : 
     946                 : {
     947              60 :     CPLAssert( nEntryCount == 0 );
     948              60 :     CPLFree( papoEntries );
     949              60 : }
     950                 : 
     951                 : /************************************************************************/
     952                 : /*                           AdjustContour()                            */
     953                 : /*                                                                      */
     954                 : /*      Assume the indicated contour's tail may have changed, and       */
     955                 : /*      adjust it up or down in the list of contours to re-establish    */
     956                 : /*      proper ordering.                                                */
     957                 : /************************************************************************/
     958                 : 
     959             148 : void GDALContourLevel::AdjustContour( int iChanged )
     960                 : 
     961                 : {
     962             296 :     while( iChanged > 0 
     963               0 :          && papoEntries[iChanged]->dfTailX < papoEntries[iChanged-1]->dfTailX )
     964                 :     {
     965               0 :         GDALContourItem *poTemp = papoEntries[iChanged];
     966               0 :         papoEntries[iChanged] = papoEntries[iChanged-1];
     967               0 :         papoEntries[iChanged-1] = poTemp;
     968               0 :         iChanged--;
     969                 :     }
     970                 : 
     971             411 :     while( iChanged < nEntryCount-1
     972             106 :          && papoEntries[iChanged]->dfTailX > papoEntries[iChanged+1]->dfTailX )
     973                 :     {
     974               9 :         GDALContourItem *poTemp = papoEntries[iChanged];
     975               9 :         papoEntries[iChanged] = papoEntries[iChanged+1];
     976               9 :         papoEntries[iChanged+1] = poTemp;
     977               9 :         iChanged++;
     978                 :     }
     979             148 : }
     980                 : 
     981                 : /************************************************************************/
     982                 : /*                           RemoveContour()                            */
     983                 : /************************************************************************/
     984                 : 
     985           20610 : void GDALContourLevel::RemoveContour( int iTarget )
     986                 : 
     987                 : {
     988           20610 :     if( iTarget < nEntryCount )
     989                 :         memmove( papoEntries + iTarget, papoEntries + iTarget + 1, 
     990           20610 :                  (nEntryCount - iTarget - 1) * sizeof(void*) );
     991           20610 :     nEntryCount--;
     992           20610 : }
     993                 : 
     994                 : /************************************************************************/
     995                 : /*                            FindContour()                             */
     996                 : /*                                                                      */
     997                 : /*      Perform a binary search to find the requested "tail"            */
     998                 : /*      location.  If not available return -1.  In theory there can     */
     999                 : /*      be more than one contour with the same tail X and different     */
    1000                 : /*      Y tails ... ensure we check against them all.                   */
    1001                 : /************************************************************************/
    1002                 : 
    1003           20758 : int GDALContourLevel::FindContour( double dfX, double dfY )
    1004                 : 
    1005                 : {
    1006           20758 :     int nStart = 0, nEnd = nEntryCount-1, nMiddle;
    1007                 : 
    1008          114454 :     while( nEnd >= nStart )
    1009                 :     {
    1010           77566 :         nMiddle = (nEnd + nStart) / 2;
    1011                 : 
    1012           77566 :         double dfMiddleX = papoEntries[nMiddle]->dfTailX;
    1013                 : 
    1014           77566 :         if( dfMiddleX < dfX )
    1015           43829 :             nStart = nMiddle + 1;
    1016           33737 :         else if( dfMiddleX > dfX )
    1017           29109 :             nEnd = nMiddle - 1;
    1018                 :         else
    1019                 :         {
    1020           21073 :             while( nMiddle > 0 
    1021            7832 :                    && fabs(papoEntries[nMiddle]->dfTailX-dfX) < JOIN_DIST )
    1022            3985 :                 nMiddle--;
    1023                 : 
    1024           15366 :             while( nMiddle < nEntryCount
    1025            5133 :                    && fabs(papoEntries[nMiddle]->dfTailX-dfX) < JOIN_DIST )
    1026                 :             {
    1027            1125 :                 if( fabs(papoEntries[nMiddle]->padfY[papoEntries[nMiddle]->nPoints-1] - dfY) < JOIN_DIST )
    1028             148 :                     return nMiddle;
    1029             977 :                 nMiddle++;
    1030                 :             }
    1031                 : 
    1032            4480 :             return -1;
    1033                 :         }
    1034                 :     }
    1035                 : 
    1036           16130 :     return -1;
    1037                 : }
    1038                 : 
    1039                 : /************************************************************************/
    1040                 : /*                           InsertContour()                            */
    1041                 : /*                                                                      */
    1042                 : /*      Ensure the newly added contour is placed in order according     */
    1043                 : /*      to the X value relative to the other contours.                  */
    1044                 : /************************************************************************/
    1045                 : 
    1046           20610 : int GDALContourLevel::InsertContour( GDALContourItem *poNewContour )
    1047                 : 
    1048                 : {
    1049                 : /* -------------------------------------------------------------------- */
    1050                 : /*      Find where to insert by binary search.                          */
    1051                 : /* -------------------------------------------------------------------- */
    1052           20610 :     int nStart = 0, nEnd = nEntryCount-1, nMiddle;
    1053                 : 
    1054          127431 :     while( nEnd >= nStart )
    1055                 :     {
    1056           86211 :         nMiddle = (nEnd + nStart) / 2;
    1057                 : 
    1058           86211 :         double dfMiddleX = papoEntries[nMiddle]->dfTailX;
    1059                 : 
    1060           86211 :         if( dfMiddleX < poNewContour->dfLevel )
    1061           77279 :             nStart = nMiddle + 1;
    1062            8932 :         else if( dfMiddleX > poNewContour->dfLevel )
    1063            8932 :             nEnd = nMiddle - 1;
    1064                 :         else
    1065                 :         {
    1066               0 :             nEnd = nMiddle - 1;
    1067               0 :             break;
    1068                 :         }
    1069                 :     }
    1070                 : 
    1071                 : /* -------------------------------------------------------------------- */
    1072                 : /*      Do we need to grow the array?                                   */
    1073                 : /* -------------------------------------------------------------------- */
    1074           20610 :     if( nEntryMax == nEntryCount )
    1075                 :     {
    1076             160 :         nEntryMax = nEntryMax * 2 + 10;
    1077                 :         papoEntries = (GDALContourItem **) 
    1078             160 :             CPLRealloc( papoEntries, sizeof(void*) * nEntryMax );
    1079                 :     }
    1080                 : 
    1081                 : /* -------------------------------------------------------------------- */
    1082                 : /*      Insert the new contour at the appropriate location.             */
    1083                 : /* -------------------------------------------------------------------- */
    1084           20610 :     if( nEntryCount - nEnd - 1 > 0 )
    1085                 :         memmove( papoEntries + nEnd + 2, papoEntries + nEnd + 1, 
    1086            3718 :                  (nEntryCount - nEnd - 1) * sizeof(void*) );
    1087           20610 :     papoEntries[nEnd+1] = poNewContour;
    1088           20610 :     nEntryCount++;
    1089                 : 
    1090           20610 :     return nEnd+1;
    1091                 : }
    1092                 : 
    1093                 : 
    1094                 : /************************************************************************/
    1095                 : /* ==================================================================== */
    1096                 : /*                           GDALContourItem                            */
    1097                 : /* ==================================================================== */
    1098                 : /************************************************************************/
    1099                 : 
    1100                 : /************************************************************************/
    1101                 : /*                          GDALContourItem()                           */
    1102                 : /************************************************************************/
    1103                 : 
    1104           20610 : GDALContourItem::GDALContourItem( double dfLevelIn )
    1105                 : 
    1106                 : {
    1107           20610 :     dfLevel = dfLevelIn;
    1108           20610 :     bRecentlyAccessed = FALSE;
    1109           20610 :     nPoints = 0;
    1110           20610 :     nMaxPoints = 0;
    1111           20610 :     padfX = NULL;
    1112           20610 :     padfY = NULL;
    1113                 :     
    1114           20610 :     bLeftIsHigh = FALSE;
    1115                 : 
    1116           20610 :     dfTailX = 0.0;
    1117           20610 : }
    1118                 : 
    1119                 : /************************************************************************/
    1120                 : /*                          ~GDALContourItem()                          */
    1121                 : /************************************************************************/
    1122                 : 
    1123           20610 : GDALContourItem::~GDALContourItem()
    1124                 : 
    1125                 : {
    1126           20610 :     CPLFree( padfX );
    1127           20610 :     CPLFree( padfY );
    1128           20610 : }
    1129                 : 
    1130                 : /************************************************************************/
    1131                 : /*                             AddSegment()                             */
    1132                 : /************************************************************************/
    1133                 : 
    1134           20758 : int GDALContourItem::AddSegment( double dfXStart, double dfYStart, 
    1135                 :                                  double dfXEnd, double dfYEnd,
    1136                 :                                  int bLeftHigh)
    1137                 : 
    1138                 : {
    1139           20758 :     MakeRoomFor( nPoints + 1 );
    1140                 : 
    1141                 : /* -------------------------------------------------------------------- */
    1142                 : /*      If there are no segments, just add now.                         */
    1143                 : /* -------------------------------------------------------------------- */
    1144           20758 :     if( nPoints == 0 )
    1145                 :     {
    1146           20610 :         nPoints = 2;
    1147                 : 
    1148           20610 :         padfX[0] = dfXStart;
    1149           20610 :         padfY[0] = dfYStart;
    1150           20610 :         padfX[1] = dfXEnd;
    1151           20610 :         padfY[1] = dfYEnd;
    1152           20610 :         bRecentlyAccessed = TRUE;
    1153                 : 
    1154           20610 :         dfTailX = padfX[1];
    1155                 : 
    1156                 :         // Here we know that the left of this vector is the high side
    1157           20610 :         bLeftIsHigh = bLeftHigh;
    1158                 : 
    1159           20610 :         return TRUE;
    1160                 :     }
    1161                 : 
    1162                 : /* -------------------------------------------------------------------- */
    1163                 : /*      Try to matching up with one of the ends, and insert.            */
    1164                 : /* -------------------------------------------------------------------- */
    1165             245 :     if( fabs(padfX[nPoints-1]-dfXStart) < JOIN_DIST 
    1166              97 :              && fabs(padfY[nPoints-1]-dfYStart) < JOIN_DIST )
    1167                 :     {
    1168              97 :         padfX[nPoints] = dfXEnd;
    1169              97 :         padfY[nPoints] = dfYEnd;
    1170              97 :         nPoints++;
    1171                 : 
    1172              97 :         bRecentlyAccessed = TRUE;
    1173                 : 
    1174              97 :         dfTailX = dfXEnd;
    1175                 : 
    1176              97 :         return TRUE;
    1177                 :     }
    1178             102 :     else if( fabs(padfX[nPoints-1]-dfXEnd) < JOIN_DIST 
    1179              51 :              && fabs(padfY[nPoints-1]-dfYEnd) < JOIN_DIST )
    1180                 :     {
    1181              51 :         padfX[nPoints] = dfXStart;
    1182              51 :         padfY[nPoints] = dfYStart;
    1183              51 :         nPoints++;
    1184                 : 
    1185              51 :         bRecentlyAccessed = TRUE;
    1186                 : 
    1187              51 :         dfTailX = dfXStart;
    1188                 : 
    1189              51 :         return TRUE;
    1190                 :     }
    1191                 :     else
    1192               0 :         return FALSE;
    1193                 : }
    1194                 :  
    1195                 : /************************************************************************/
    1196                 : /*                               Merge()                                */
    1197                 : /************************************************************************/
    1198                 : 
    1199           87095 : int GDALContourItem::Merge( GDALContourItem *poOther )
    1200                 : 
    1201                 : {
    1202           87095 :     if( poOther->dfLevel != dfLevel )
    1203               0 :         return FALSE;
    1204                 : 
    1205                 : /* -------------------------------------------------------------------- */
    1206                 : /*      Try to matching up with one of the ends, and insert.            */
    1207                 : /* -------------------------------------------------------------------- */
    1208           96681 :     if( fabs(padfX[nPoints-1]-poOther->padfX[0]) < JOIN_DIST 
    1209            9586 :         && fabs(padfY[nPoints-1]-poOther->padfY[0]) < JOIN_DIST )
    1210                 :     {
    1211            8867 :         MakeRoomFor( nPoints + poOther->nPoints - 1 );
    1212                 : 
    1213                 :         memcpy( padfX + nPoints, poOther->padfX + 1, 
    1214            8867 :                 sizeof(double) * (poOther->nPoints-1) );
    1215                 :         memcpy( padfY + nPoints, poOther->padfY + 1, 
    1216            8867 :                 sizeof(double) * (poOther->nPoints-1) );
    1217            8867 :         nPoints += poOther->nPoints - 1;
    1218                 : 
    1219            8867 :         bRecentlyAccessed = TRUE;
    1220                 : 
    1221            8867 :         dfTailX = padfX[nPoints-1];
    1222                 : 
    1223            8867 :         return TRUE;
    1224                 :     }
    1225           83602 :     else if( fabs(padfX[0]-poOther->padfX[poOther->nPoints-1]) < JOIN_DIST 
    1226            5374 :              && fabs(padfY[0]-poOther->padfY[poOther->nPoints-1]) < JOIN_DIST )
    1227                 :     {
    1228            5035 :         MakeRoomFor( nPoints + poOther->nPoints - 1 );
    1229                 : 
    1230                 :         memmove( padfX + poOther->nPoints - 1, padfX, 
    1231            5035 :                 sizeof(double) * nPoints );
    1232                 :         memmove( padfY + poOther->nPoints - 1, padfY, 
    1233            5035 :                 sizeof(double) * nPoints );
    1234                 :         memcpy( padfX, poOther->padfX, 
    1235            5035 :                 sizeof(double) * (poOther->nPoints-1) );
    1236                 :         memcpy( padfY, poOther->padfY, 
    1237            5035 :                 sizeof(double) * (poOther->nPoints-1) );
    1238            5035 :         nPoints += poOther->nPoints - 1;
    1239                 : 
    1240            5035 :         bRecentlyAccessed = TRUE;
    1241                 : 
    1242            5035 :         dfTailX = padfX[nPoints-1];
    1243                 : 
    1244            5035 :         return TRUE;
    1245                 :     }
    1246           77117 :     else if( fabs(padfX[nPoints-1]-poOther->padfX[poOther->nPoints-1]) < JOIN_DIST 
    1247            3924 :         && fabs(padfY[nPoints-1]-poOther->padfY[poOther->nPoints-1]) < JOIN_DIST )
    1248                 :     {
    1249                 :         int i;
    1250                 : 
    1251            3607 :         MakeRoomFor( nPoints + poOther->nPoints - 1 );
    1252                 : 
    1253           19445 :         for( i = 0; i < poOther->nPoints-1; i++ )
    1254                 :         {
    1255           15838 :             padfX[i+nPoints] = poOther->padfX[poOther->nPoints-i-2];
    1256           15838 :             padfY[i+nPoints] = poOther->padfY[poOther->nPoints-i-2];
    1257                 :         }
    1258                 : 
    1259            3607 :         nPoints += poOther->nPoints - 1;
    1260                 : 
    1261            3607 :         bRecentlyAccessed = TRUE;
    1262                 : 
    1263            3607 :         dfTailX = padfX[nPoints-1];
    1264                 : 
    1265            3607 :         return TRUE;
    1266                 :     }
    1267           72219 :     else if( fabs(padfX[0]-poOther->padfX[0]) < JOIN_DIST 
    1268            2633 :         && fabs(padfY[0]-poOther->padfY[0]) < JOIN_DIST )
    1269                 :     {
    1270                 :         int i;
    1271                 : 
    1272            2344 :         MakeRoomFor( nPoints + poOther->nPoints - 1 );
    1273                 : 
    1274                 :         memmove( padfX + poOther->nPoints - 1, padfX, 
    1275            2344 :                 sizeof(double) * nPoints );
    1276                 :         memmove( padfY + poOther->nPoints - 1, padfY, 
    1277            2344 :                 sizeof(double) * nPoints );
    1278                 : 
    1279           17190 :         for( i = 0; i < poOther->nPoints-1; i++ )
    1280                 :         {
    1281           14846 :             padfX[i] = poOther->padfX[poOther->nPoints - i - 1];
    1282           14846 :             padfY[i] = poOther->padfY[poOther->nPoints - i - 1];
    1283                 :         }
    1284                 : 
    1285            2344 :         nPoints += poOther->nPoints - 1;
    1286                 : 
    1287            2344 :         bRecentlyAccessed = TRUE;
    1288                 : 
    1289            2344 :         dfTailX = padfX[nPoints-1];
    1290                 : 
    1291            2344 :         return TRUE;
    1292                 :     }
    1293                 :     else
    1294           67242 :         return FALSE;
    1295                 : }
    1296                 : 
    1297                 : /************************************************************************/
    1298                 : /*                            MakeRoomFor()                             */
    1299                 : /************************************************************************/
    1300                 : 
    1301           40611 : void GDALContourItem::MakeRoomFor( int nNewPoints )
    1302                 : 
    1303                 : {
    1304           40611 :     if( nNewPoints > nMaxPoints )
    1305                 :     {
    1306           23223 :         nMaxPoints = nNewPoints * 2 + 50;
    1307           23223 :         padfX = (double *) CPLRealloc(padfX,sizeof(double) * nMaxPoints);
    1308           23223 :         padfY = (double *) CPLRealloc(padfY,sizeof(double) * nMaxPoints);
    1309                 :     }
    1310           40611 : }
    1311                 : 
    1312                 : /************************************************************************/
    1313                 : /*                          PrepareEjection()                           */
    1314                 : /************************************************************************/
    1315                 : 
    1316             757 : void GDALContourItem::PrepareEjection()
    1317                 : 
    1318                 : {
    1319                 :     /* If left side is the high side, then reverse to get curve normal
    1320                 :     ** pointing downwards
    1321                 :     */
    1322             757 :     if( bLeftIsHigh )
    1323                 :     {
    1324                 :         int i;
    1325                 : 
    1326                 :         // Reverse the arrays
    1327            8088 :         for( i = 0; i < nPoints / 2; i++ )
    1328                 :         {
    1329                 :             double dfTemp;
    1330            7570 :             dfTemp = padfX[i];
    1331            7570 :             padfX[i] = padfX[ nPoints - i - 1];
    1332            7570 :             padfX[ nPoints - i - 1] = dfTemp;
    1333                 :             
    1334            7570 :             dfTemp = padfY[i];
    1335            7570 :             padfY[i] = padfY[ nPoints - i - 1];
    1336            7570 :             padfY[ nPoints - i - 1] = dfTemp;
    1337                 :         }
    1338                 :     }
    1339             757 : }
    1340                 : 
    1341                 : 
    1342                 : /************************************************************************/
    1343                 : /* ==================================================================== */
    1344                 : /*                   Additional C Callable Functions                    */
    1345                 : /* ==================================================================== */
    1346                 : /************************************************************************/
    1347                 : 
    1348                 : /************************************************************************/
    1349                 : /*                          OGRContourWriter()                          */
    1350                 : /************************************************************************/
    1351                 : 
    1352             757 : CPLErr OGRContourWriter( double dfLevel, 
    1353                 :                          int nPoints, double *padfX, double *padfY, 
    1354                 :                          void *pInfo )
    1355                 : 
    1356                 : {
    1357             757 :     OGRContourWriterInfo *poInfo = (OGRContourWriterInfo *) pInfo;
    1358                 :     OGRFeatureH hFeat;
    1359                 :     OGRGeometryH hGeom;
    1360                 :     int iPoint;
    1361                 : 
    1362             757 :     hFeat = OGR_F_Create( OGR_L_GetLayerDefn( (OGRLayerH) poInfo->hLayer ) );
    1363                 : 
    1364             757 :     if( poInfo->nIDField != -1 )
    1365             757 :         OGR_F_SetFieldInteger( hFeat, poInfo->nIDField, poInfo->nNextID++ );
    1366                 : 
    1367             757 :     if( poInfo->nElevField != -1 )
    1368             139 :         OGR_F_SetFieldDouble( hFeat, poInfo->nElevField, dfLevel );
    1369                 :     
    1370             757 :     hGeom = OGR_G_CreateGeometry( wkbLineString );
    1371                 :     
    1372           22272 :     for( iPoint = nPoints-1; iPoint >= 0; iPoint-- )
    1373                 :     {
    1374                 :         OGR_G_SetPoint( hGeom, iPoint,
    1375           21515 :                         poInfo->adfGeoTransform[0] 
    1376           21515 :                         + poInfo->adfGeoTransform[1] * padfX[iPoint]
    1377           21515 :                         + poInfo->adfGeoTransform[2] * padfY[iPoint],
    1378           21515 :                         poInfo->adfGeoTransform[3] 
    1379           21515 :                         + poInfo->adfGeoTransform[4] * padfX[iPoint]
    1380           21515 :                         + poInfo->adfGeoTransform[5] * padfY[iPoint],
    1381           86060 :                         dfLevel );
    1382                 :     }
    1383                 : 
    1384             757 :     OGR_F_SetGeometryDirectly( hFeat, hGeom );
    1385                 : 
    1386             757 :     OGR_L_CreateFeature( (OGRLayerH) poInfo->hLayer, hFeat );
    1387             757 :     OGR_F_Destroy( hFeat );
    1388                 : 
    1389             757 :     return CE_None;
    1390                 : }
    1391                 : #endif // OGR_ENABLED
    1392                 : 
    1393                 : /************************************************************************/
    1394                 : /*                        GDALContourGenerate()                         */
    1395                 : /************************************************************************/
    1396                 : 
    1397                 : /**
    1398                 :  * Create vector contours from raster DEM.
    1399                 :  *
    1400                 :  * This algorithm will generate contour vectors for the input raster band
    1401                 :  * on the requested set of contour levels.  The vector contours are written
    1402                 :  * to the passed in OGR vector layer.  Also, a NODATA value may be specified
    1403                 :  * to identify pixels that should not be considered in contour line generation.
    1404                 :  *
    1405                 :  * The gdal/apps/gdal_contour.cpp mainline can be used as an example of
    1406                 :  * how to use this function.
    1407                 :  *
    1408                 :  * ALGORITHM RULES
    1409                 : 
    1410                 : For contouring purposes raster pixel values are assumed to represent a point 
    1411                 : value at the center of the corresponding pixel region.  For the purpose of 
    1412                 : contour generation we virtually connect each pixel center to the values to
    1413                 : the left, right, top and bottom.  We assume that the pixel value is linearly
    1414                 : interpolated between the pixel centers along each line, and determine where
    1415                 : (if any) contour lines will appear along these line segements.  Then the
    1416                 : contour crossings are connected.  
    1417                 : 
    1418                 : This means that contour lines' nodes won't actually be on pixel edges, but 
    1419                 : rather along vertical and horizontal lines connecting the pixel centers. 
    1420                 : 
    1421                 : \verbatim
    1422                 : General Case:
    1423                 : 
    1424                 :       5 |                  | 3
    1425                 :      -- + ---------------- + -- 
    1426                 :         |                  |
    1427                 :         |                  |
    1428                 :         |                  |
    1429                 :         |                  |
    1430                 :      10 +                  |
    1431                 :         |\                 |
    1432                 :         | \                |
    1433                 :      -- + -+-------------- + -- 
    1434                 :      12 |  10              | 1
    1435                 : 
    1436                 : 
    1437                 : Saddle Point:
    1438                 : 
    1439                 :       5 |                  | 12
    1440                 :      -- + -------------+-- + -- 
    1441                 :         |               \  |
    1442                 :         |                 \|
    1443                 :         |                  + 
    1444                 :         |                  |
    1445                 :         +                  |
    1446                 :         |\                 |
    1447                 :         | \                |
    1448                 :      -- + -+-------------- + -- 
    1449                 :      12 |                  | 1
    1450                 : 
    1451                 : or:
    1452                 : 
    1453                 :       5 |                  | 12
    1454                 :      -- + -------------+-- + -- 
    1455                 :         |          __/     |
    1456                 :         |      ___/        |
    1457                 :         |  ___/          __+ 
    1458                 :         | /           __/  |
    1459                 :         +'         __/     |
    1460                 :         |       __/        |
    1461                 :         |   ,__/           |
    1462                 :      -- + -+-------------- + -- 
    1463                 :      12 |                  | 1
    1464                 : \endverbatim
    1465                 : 
    1466                 : Nodata:
    1467                 : 
    1468                 : In the "nodata" case we treat the whole nodata pixel as a no-mans land. 
    1469                 : We extend the corner pixels near the nodata out to half way and then
    1470                 : construct extra lines from those points to the center which is assigned
    1471                 : an averaged value from the two nearby points (in this case (12+3+5)/3). 
    1472                 : 
    1473                 : \verbatim
    1474                 :       5 |                  | 3
    1475                 :      -- + ---------------- + -- 
    1476                 :         |                  |
    1477                 :         |                  |
    1478                 :         |      6.7         |
    1479                 :         |        +---------+ 3
    1480                 :      10 +___     |          
    1481                 :         |   \____+ 10       
    1482                 :         |        |          
    1483                 :      -- + -------+        +    
    1484                 :      12 |       12           (nodata)
    1485                 : 
    1486                 : \endverbatim
    1487                 : 
    1488                 :  *
    1489                 :  * @param hBand The band to read raster data from.  The whole band will be 
    1490                 :  * processed.
    1491                 :  *
    1492                 :  * @param dfContourInterval The elevation interval between contours generated.
    1493                 :  * 
    1494                 :  * @param dfContourBase The "base" relative to which contour intervals are 
    1495                 :  * applied.  This is normally zero, but could be different.  To generate 10m 
    1496                 :  * contours at 5, 15, 25, ... the ContourBase would be 5.
    1497                 :  *
    1498                 :  * @param  nFixedLevelCount The number of fixed levels. If this is greater than
    1499                 :  * zero, then fixed levels will be used, and ContourInterval and ContourBase 
    1500                 :  * are ignored.
    1501                 :  *
    1502                 :  * @param padfFixedLevels The list of fixed contour levels at which contours 
    1503                 :  * should be generated.  It will contain FixedLevelCount entries, and may be 
    1504                 :  * NULL if fixed levels are disabled (FixedLevelCount = 0). 
    1505                 :  *
    1506                 :  * @param bUseNoData If TRUE the dfNoDataValue will be used.
    1507                 :  *
    1508                 :  * @param dfNoDataValue The value to use as a "nodata" value. That is, a
    1509                 :  * pixel value which should be ignored in generating contours as if the value
    1510                 :  * of the pixel were not known. 
    1511                 :  *
    1512                 :  * @param hLayer The layer to which new contour vectors will be written. 
    1513                 :  * Each contour will have a LINESTRING geometry attached to it.   This
    1514                 :  * is really of type OGRLayerH, but void * is used to avoid pulling the
    1515                 :  * ogr_api.h file in here. 
    1516                 :  *
    1517                 :  * @param iIDField If not -1 this will be used as a field index to indicate
    1518                 :  * where a unique id should be written for each feature (contour) written.
    1519                 :  * 
    1520                 :  * @param iElevField If not -1 this will be used as a field index to indicate
    1521                 :  * where the elevation value of the contour should be written.
    1522                 :  *
    1523                 :  * @param pfnProgress A GDALProgressFunc that may be used to report progress
    1524                 :  * to the user, or to interrupt the algorithm.  May be NULL if not required.
    1525                 :  * 
    1526                 :  * @param pProgressArg The callback data for the pfnProgress function.
    1527                 :  *
    1528                 :  * @return CE_None on success or CE_Failure if an error occurs.
    1529                 :  */
    1530                 : 
    1531               8 : CPLErr GDALContourGenerate( GDALRasterBandH hBand, 
    1532                 :                             double dfContourInterval, double dfContourBase,
    1533                 :                             int nFixedLevelCount, double *padfFixedLevels,
    1534                 :                             int bUseNoData, double dfNoDataValue, 
    1535                 :                             void *hLayer, int iIDField, int iElevField,
    1536                 :                             GDALProgressFunc pfnProgress, void *pProgressArg )
    1537                 : 
    1538                 : {
    1539                 : #ifndef OGR_ENABLED
    1540                 :     CPLError(CE_Failure, CPLE_NotSupported, "GDALContourGenerate() unimplemented in a non OGR build");
    1541                 :     return CE_Failure;
    1542                 : #else
    1543               8 :     VALIDATE_POINTER1( hBand, "GDALContourGenerate", CE_Failure );
    1544                 : 
    1545                 :     OGRContourWriterInfo oCWI;
    1546                 : 
    1547               8 :     if( pfnProgress == NULL )
    1548               2 :         pfnProgress = GDALDummyProgress;
    1549                 : 
    1550               8 :     if( !pfnProgress( 0.0, "", pProgressArg ) )
    1551                 :     {
    1552               0 :         CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1553               0 :         return CE_Failure;
    1554                 :     }
    1555                 : 
    1556                 : /* -------------------------------------------------------------------- */
    1557                 : /*      Setup contour writer information.                               */
    1558                 : /* -------------------------------------------------------------------- */
    1559                 :     GDALDatasetH hSrcDS;
    1560                 : 
    1561               8 :     oCWI.hLayer = (OGRLayerH) hLayer;
    1562                 : 
    1563               8 :     oCWI.nElevField = iElevField;
    1564               8 :     oCWI.nIDField = iIDField;
    1565                 : 
    1566               8 :     hSrcDS = GDALGetBandDataset( hBand );
    1567               8 :     GDALGetGeoTransform( hSrcDS, oCWI.adfGeoTransform );
    1568               8 :     oCWI.nNextID = 0;
    1569                 : 
    1570                 : /* -------------------------------------------------------------------- */
    1571                 : /*      Setup contour generator.                                        */
    1572                 : /* -------------------------------------------------------------------- */
    1573               8 :     int nXSize = GDALGetRasterBandXSize( hBand );
    1574               8 :     int nYSize = GDALGetRasterBandYSize( hBand );
    1575                 : 
    1576               8 :     GDALContourGenerator oCG( nXSize, nYSize, OGRContourWriter, &oCWI );
    1577                 : 
    1578               8 :     if( nFixedLevelCount > 0 )
    1579               2 :         oCG.SetFixedLevels( nFixedLevelCount, padfFixedLevels );
    1580                 :     else
    1581               6 :         oCG.SetContourLevels( dfContourInterval, dfContourBase );
    1582                 : 
    1583               8 :     if( bUseNoData )
    1584               3 :         oCG.SetNoData( dfNoDataValue );
    1585                 : 
    1586                 : /* -------------------------------------------------------------------- */
    1587                 : /*      Feed the data into the contour generator.                       */
    1588                 : /* -------------------------------------------------------------------- */
    1589                 :     int iLine;
    1590                 :     double *padfScanline;
    1591               8 :     CPLErr eErr = CE_None;
    1592                 : 
    1593               8 :     padfScanline = (double *) VSIMalloc(sizeof(double) * nXSize);
    1594               8 :     if (padfScanline == NULL)
    1595                 :     {
    1596                 :         CPLError( CE_Failure, CPLE_OutOfMemory,
    1597               0 :                   "VSIMalloc(): Out of memory in GDALContourGenerate" );
    1598               0 :         return CE_Failure;
    1599                 :     }
    1600                 : 
    1601            1055 :     for( iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )
    1602                 :     {
    1603                 :         GDALRasterIO( hBand, GF_Read, 0, iLine, nXSize, 1, 
    1604            1047 :                       padfScanline, nXSize, 1, GDT_Float64, 0, 0 );
    1605            1047 :         eErr = oCG.FeedLine( padfScanline );
    1606                 : 
    1607            1047 :         if( eErr == CE_None 
    1608                 :             && !pfnProgress( (iLine+1) / (double) nYSize, "", pProgressArg ) )
    1609                 :         {
    1610               0 :             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
    1611               0 :             eErr = CE_Failure;
    1612                 :         }
    1613                 :     }
    1614                 : 
    1615               8 :     CPLFree( padfScanline );
    1616                 : 
    1617               8 :     return eErr;
    1618                 : #endif // OGR_ENABLED
    1619                 : }

Generated by: LCOV version 1.7