LTP GCOV extension - code coverage report
Current view: directory - alg - gdalwarpoperation.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 651
Code covered: 77.1 % Executed lines: 502

       1                 : /******************************************************************************
       2                 :  * $Id: gdalwarpoperation.cpp 19285 2010-04-02 14:30:37Z warmerdam $
       3                 :  *
       4                 :  * Project:  High Performance Image Reprojector
       5                 :  * Purpose:  Implementation of the GDALWarpOperation class.
       6                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdalwarper.h"
      31                 : #include "cpl_string.h"
      32                 : #include "cpl_multiproc.h"
      33                 : #include "ogr_api.h"
      34                 : 
      35                 : CPL_CVSID("$Id: gdalwarpoperation.cpp 19285 2010-04-02 14:30:37Z warmerdam $");
      36                 : 
      37                 : /* Defined in gdalwarpkernel.cpp */
      38                 : int GWKGetFilterRadius(GDALResampleAlg eResampleAlg);
      39                 : 
      40                 : 
      41                 : /************************************************************************/
      42                 : /* ==================================================================== */
      43                 : /*                          GDALWarpOperation                           */
      44                 : /* ==================================================================== */
      45                 : /************************************************************************/
      46                 : 
      47                 : /**
      48                 :  * \class GDALWarpOperation "gdalwarper.h"
      49                 :  *
      50                 :  * High level image warping class. 
      51                 : 
      52                 : <h2>Warper Design</h2>
      53                 : 
      54                 : The overall GDAL high performance image warper is split into a few components.
      55                 : 
      56                 :  - The transformation between input and output file coordinates is handled
      57                 : via GDALTransformerFunc() implementations such as the one returned by
      58                 : GDALCreateGenImgProjTransformer().  The transformers are ultimately responsible
      59                 : for translating pixel/line locations on the destination image to pixel/line
      60                 : locations on the source image. 
      61                 : 
      62                 :  - In order to handle images too large to hold in RAM, the warper needs to
      63                 : segment large images.  This is the responsibility of the GDALWarpOperation
      64                 : class.  The GDALWarpOperation::ChunkAndWarpImage() invokes 
      65                 : GDALWarpOperation::WarpRegion() on chunks of output and input image that
      66                 : are small enough to hold in the amount of memory allowed by the application. 
      67                 : This process is described in greater detail in the <b>Image Chunking</b> 
      68                 : section. 
      69                 : 
      70                 :  - The GDALWarpOperation::WarpRegion() function creates and loads an output 
      71                 : image buffer, and then calls WarpRegionToBuffer(). 
      72                 : 
      73                 :  - GDALWarpOperation::WarpRegionToBuffer() is responsible for loading the 
      74                 : source imagery corresponding to a particular output region, and generating
      75                 : masks and density masks from the source and destination imagery using
      76                 : the generator functions found in the GDALWarpOptions structure.  Binds this
      77                 : all into an instance of GDALWarpKernel on which the 
      78                 : GDALWarpKernel::PerformWarp() method is called. 
      79                 : 
      80                 :  - GDALWarpKernel does the actual image warping, but is given an input image
      81                 : and an output image to operate on.  The GDALWarpKernel does no IO, and in
      82                 : fact knows nothing about GDAL.  It invokes the transformation function to 
      83                 : get sample locations, builds output values based on the resampling algorithm
      84                 : in use.  It also takes any validity and density masks into account during
      85                 : this operation.  
      86                 : 
      87                 : <h3>Chunk Size Selection</h3>
      88                 : 
      89                 : The GDALWarpOptions ChunkAndWarpImage() method is responsible for invoking
      90                 : the WarpRegion() method on appropriate sized output chunks such that the
      91                 : memory required for the output image buffer, input image buffer and any
      92                 : required density and validity buffers is less than or equal to the application
      93                 : defined maximum memory available for use.  
      94                 : 
      95                 : It checks the memory requrired by walking the edges of the output region, 
      96                 : transforming the locations back into source pixel/line coordinates and 
      97                 : establishing a bounding rectangle of source imagery that would be required
      98                 : for the output area.  This is actually accomplished by the private
      99                 : GDALWarpOperation::ComputeSourceWindow() method. 
     100                 : 
     101                 : Then memory requirements are used by totaling the memory required for all
     102                 : output bands, input bands, validity masks and density masks.  If this is
     103                 : greater than the GDALWarpOptions::dfWarpMemoryLimit then the destination
     104                 : region is divided in two (splitting the longest dimension), and 
     105                 : ChunkAndWarpImage() recursively invoked on each destination subregion. 
     106                 : 
     107                 : <h3>Validity and Density Masks Generation</h3>
     108                 : 
     109                 : Fill in ways in which the validity and density masks may be generated here. 
     110                 : Note that detailed semantics of the masks should be found in
     111                 : GDALWarpKernel. 
     112                 : 
     113                 : */
     114                 : 
     115                 : /************************************************************************/
     116                 : /*                         GDALWarpOperation()                          */
     117                 : /************************************************************************/
     118                 : 
     119             321 : GDALWarpOperation::GDALWarpOperation()
     120                 : 
     121                 : {
     122             321 :     psOptions = NULL;
     123                 : 
     124             321 :     dfProgressBase = 0.0;
     125             321 :     dfProgressScale = 1.0;
     126                 : 
     127             321 :     hThread1Mutex = NULL;
     128             321 :     hThread2Mutex = NULL;
     129             321 :     hIOMutex = NULL;
     130             321 :     hWarpMutex = NULL;
     131                 : 
     132             321 :     nChunkListCount = 0;
     133             321 :     nChunkListMax = 0;
     134             321 :     panChunkList = NULL;
     135                 : 
     136             321 :     bReportTimings = FALSE;
     137             321 :     nLastTimeReported = 0;
     138             321 : }
     139                 : 
     140                 : /************************************************************************/
     141                 : /*                         ~GDALWarpOperation()                         */
     142                 : /************************************************************************/
     143                 : 
     144             321 : GDALWarpOperation::~GDALWarpOperation()
     145                 : 
     146                 : {
     147             321 :     WipeOptions();
     148                 : 
     149             321 :     if( hThread1Mutex != NULL )
     150                 :     {
     151               1 :         CPLDestroyMutex( hThread1Mutex );
     152               1 :         CPLDestroyMutex( hThread2Mutex );
     153               1 :         CPLDestroyMutex( hIOMutex );
     154               1 :         CPLDestroyMutex( hWarpMutex );
     155                 :     }
     156                 : 
     157             321 :     WipeChunkList();
     158             321 : }
     159                 : 
     160                 : /************************************************************************/
     161                 : /*                             GetOptions()                             */
     162                 : /************************************************************************/
     163                 : 
     164             126 : const GDALWarpOptions *GDALWarpOperation::GetOptions()
     165                 : 
     166                 : {
     167             126 :     return psOptions;
     168                 : }
     169                 : 
     170                 : /************************************************************************/
     171                 : /*                            WipeOptions()                             */
     172                 : /************************************************************************/
     173                 : 
     174             321 : void GDALWarpOperation::WipeOptions()
     175                 : 
     176                 : {
     177             321 :     if( psOptions != NULL )
     178                 :     {
     179             321 :         GDALDestroyWarpOptions( psOptions );
     180             321 :         psOptions = NULL;
     181                 :     }
     182             321 : }
     183                 : 
     184                 : /************************************************************************/
     185                 : /*                          ValidateOptions()                           */
     186                 : /************************************************************************/
     187                 : 
     188             321 : int GDALWarpOperation::ValidateOptions()
     189                 : 
     190                 : {
     191             321 :     if( psOptions == NULL )
     192                 :     {
     193                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     194                 :                   "GDALWarpOptions.Validate()\n"
     195               0 :                   "  no options currently initialized." );
     196               0 :         return FALSE;
     197                 :     }
     198                 : 
     199             321 :     if( psOptions->dfWarpMemoryLimit < 100000.0 )
     200                 :     {
     201                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     202                 :                   "GDALWarpOptions.Validate()\n"
     203                 :                   "  dfWarpMemoryLimit=%g is unreasonably small.",
     204               0 :                   psOptions->dfWarpMemoryLimit );
     205               0 :         return FALSE;
     206                 :     }
     207                 : 
     208             321 :     if( psOptions->eResampleAlg != GRA_NearestNeighbour 
     209                 :         && psOptions->eResampleAlg != GRA_Bilinear
     210                 :         && psOptions->eResampleAlg != GRA_Cubic
     211                 :         && psOptions->eResampleAlg != GRA_CubicSpline
     212                 :         && psOptions->eResampleAlg != GRA_Lanczos )
     213                 :     {
     214                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     215                 :                   "GDALWarpOptions.Validate()\n"
     216                 :                   "  eResampleArg=%d is not a supported value.",
     217               0 :                   psOptions->eResampleAlg );
     218               0 :         return FALSE;
     219                 :     }
     220                 : 
     221             321 :     if( (int) psOptions->eWorkingDataType < 1
     222                 :         && (int) psOptions->eWorkingDataType >= GDT_TypeCount )
     223                 :     {
     224                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     225                 :                   "GDALWarpOptions.Validate()\n"
     226                 :                   "  eWorkingDataType=%d is not a supported value.",
     227               0 :                   psOptions->eWorkingDataType );
     228               0 :         return FALSE;
     229                 :     }
     230                 : 
     231             321 :     if( psOptions->hSrcDS == NULL )
     232                 :     {
     233                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     234                 :                   "GDALWarpOptions.Validate()\n"
     235               0 :                   "  hSrcDS is not set." );
     236               0 :         return FALSE;
     237                 :     }
     238                 : 
     239             321 :     if( psOptions->nBandCount == 0 )
     240                 :     {
     241                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     242                 :                   "GDALWarpOptions.Validate()\n"
     243               0 :                   "  nBandCount=0, no bands configured!" );
     244               0 :         return FALSE;
     245                 :     }
     246                 : 
     247             321 :     if( psOptions->panSrcBands == NULL )
     248                 :     {
     249                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     250                 :                   "GDALWarpOptions.Validate()\n"
     251               0 :                   "  panSrcBands is NULL." );
     252               0 :         return FALSE;
     253                 :     }
     254                 : 
     255             321 :     if( psOptions->hDstDS != NULL && psOptions->panDstBands == NULL )
     256                 :     {
     257                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     258                 :                   "GDALWarpOptions.Validate()\n"
     259               0 :                   "  panDstBands is NULL." );
     260               0 :         return FALSE;
     261                 :     }
     262                 : 
     263             686 :     for( int iBand = 0; iBand < psOptions->nBandCount; iBand++ )
     264                 :     {
     265             365 :         if( psOptions->panSrcBands[iBand] < 1 
     266                 :             || psOptions->panSrcBands[iBand] 
     267                 :             > GDALGetRasterCount( psOptions->hSrcDS ) )
     268                 :         {
     269                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     270                 :                       "panSrcBands[%d] = %d ... out of range for dataset.",
     271               0 :                       iBand, psOptions->panSrcBands[iBand] );
     272               0 :             return FALSE;
     273                 :         }
     274             365 :         if( psOptions->hDstDS != NULL
     275                 :             && (psOptions->panDstBands[iBand] < 1 
     276                 :                 || psOptions->panDstBands[iBand]
     277                 :                 > GDALGetRasterCount( psOptions->hDstDS ) ) )
     278                 :         {
     279                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     280                 :                       "panDstBands[%d] = %d ... out of range for dataset.",
     281               0 :                       iBand, psOptions->panDstBands[iBand] );
     282               0 :             return FALSE;
     283                 :         }
     284                 : 
     285             365 :         if( psOptions->hDstDS != NULL
     286                 :             && GDALGetRasterAccess( 
     287                 :                 GDALGetRasterBand(psOptions->hDstDS,
     288                 :                                   psOptions->panDstBands[iBand]))
     289                 :             == GA_ReadOnly )
     290                 :         {
     291                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     292                 :                       "Destination band %d appears to be read-only.",
     293               0 :                       psOptions->panDstBands[iBand] );
     294               0 :             return FALSE;
     295                 :         }
     296                 :     }
     297                 : 
     298             321 :     if( psOptions->nBandCount == 0 )
     299                 :     {
     300                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     301                 :                   "GDALWarpOptions.Validate()\n"
     302               0 :                   "  nBandCount=0, no bands configured!" );
     303               0 :         return FALSE;
     304                 :     }
     305                 : 
     306             321 :     if( psOptions->padfSrcNoDataReal != NULL
     307                 :         && psOptions->padfSrcNoDataImag == NULL )
     308                 :     {
     309                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     310                 :                   "GDALWarpOptions.Validate()\n"
     311               0 :                   "  padfSrcNoDataReal set, but padfSrcNoDataImag not set." );
     312               0 :         return FALSE;
     313                 :     }
     314                 : 
     315             321 :     if( psOptions->pfnProgress == NULL )
     316                 :     {
     317                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     318                 :                   "GDALWarpOptions.Validate()\n"
     319               0 :                   "  pfnProgress is NULL." );
     320               0 :         return FALSE;
     321                 :     }
     322                 : 
     323             321 :     if( psOptions->pfnTransformer == NULL )
     324                 :     {
     325                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     326                 :                   "GDALWarpOptions.Validate()\n"
     327               0 :                   "  pfnTransformer is NULL." );
     328               0 :         return FALSE;
     329                 :     }
     330                 : 
     331             321 :     if( CSLFetchNameValue( psOptions->papszWarpOptions, 
     332                 :                            "SAMPLE_STEPS" ) != NULL )
     333                 :     {
     334               0 :         if( atoi(CSLFetchNameValue( psOptions->papszWarpOptions, 
     335                 :                                     "SAMPLE_STEPS" )) < 2 )
     336                 :         {
     337                 :             CPLError( CE_Failure, CPLE_IllegalArg, 
     338                 :                       "GDALWarpOptions.Validate()\n"
     339               0 :                       "  SAMPLE_STEPS warp option has illegal value." );
     340               0 :             return FALSE;
     341                 :         }
     342                 :     }
     343                 : 
     344             321 :     if( psOptions->nSrcAlphaBand > 0)
     345                 :     {
     346               8 :         if ( psOptions->hSrcDS == NULL ||
     347                 :              psOptions->nSrcAlphaBand > GDALGetRasterCount(psOptions->hSrcDS) )
     348                 :         {
     349                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     350                 :                       "nSrcAlphaBand = %d ... out of range for dataset.",
     351               0 :                       psOptions->nSrcAlphaBand );
     352               0 :             return FALSE;
     353                 :         }
     354                 :     }
     355                 : 
     356             321 :     if( psOptions->nDstAlphaBand > 0)
     357                 :     {
     358              10 :         if ( psOptions->hDstDS == NULL ||
     359                 :              psOptions->nDstAlphaBand > GDALGetRasterCount(psOptions->hDstDS) )
     360                 :         {
     361                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     362                 :                       "nDstAlphaBand = %d ... out of range for dataset.",
     363               0 :                       psOptions->nDstAlphaBand );
     364               0 :             return FALSE;
     365                 :         }
     366                 :     }
     367                 : 
     368             321 :     if( psOptions->nSrcAlphaBand > 0 
     369                 :         && psOptions->pfnSrcDensityMaskFunc != NULL )
     370                 :     {
     371                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     372                 :                "GDALWarpOptions.Validate()\n"
     373               0 :                "  pfnSrcDensityMaskFunc provided as well as a SrcAlphaBand." );
     374               0 :         return FALSE;
     375                 :     }
     376                 : 
     377             321 :     if( psOptions->nDstAlphaBand > 0 
     378                 :         && psOptions->pfnDstDensityMaskFunc != NULL )
     379                 :     {
     380                 :         CPLError( CE_Failure, CPLE_IllegalArg, 
     381                 :                "GDALWarpOptions.Validate()\n"
     382               0 :                "  pfnDstDensityMaskFunc provided as well as a DstAlphaBand." );
     383               0 :         return FALSE;
     384                 :     }
     385                 : 
     386             321 :     return TRUE;
     387                 : }
     388                 : 
     389                 : /************************************************************************/
     390                 : /*                             Initialize()                             */
     391                 : /************************************************************************/
     392                 : 
     393                 : /**
     394                 :  * \fn CPLErr GDALWarpOperation::Initialize( const GDALWarpOptions * );
     395                 :  *
     396                 :  * This method initializes the GDALWarpOperation's concept of the warp
     397                 :  * options in effect.  It creates an internal copy of the GDALWarpOptions
     398                 :  * structure and defaults a variety of additional fields in the internal
     399                 :  * copy if not set in the provides warp options.
     400                 :  *
     401                 :  * Defaulting operations include:
     402                 :  *  - If the nBandCount is 0, it will be set to the number of bands in the
     403                 :  *    source image (which must match the output image) and the panSrcBands
     404                 :  *    and panDstBands will be populated. 
     405                 :  *
     406                 :  * @param psNewOptions input set of warp options.  These are copied and may
     407                 :  * be destroyed after this call by the application. 
     408                 :  *
     409                 :  * @return CE_None on success or CE_Failure if an error occurs.
     410                 :  */
     411                 : 
     412             321 : CPLErr GDALWarpOperation::Initialize( const GDALWarpOptions *psNewOptions )
     413                 : 
     414                 : {
     415             321 :     CPLErr eErr = CE_None;
     416                 : 
     417                 : /* -------------------------------------------------------------------- */
     418                 : /*      Copy the passed in options.                                     */
     419                 : /* -------------------------------------------------------------------- */
     420             321 :     if( psOptions != NULL )
     421               0 :         WipeOptions();
     422                 : 
     423             321 :     psOptions = GDALCloneWarpOptions( psNewOptions );
     424                 : 
     425                 : /* -------------------------------------------------------------------- */
     426                 : /*      Default band mapping if missing.                                */
     427                 : /* -------------------------------------------------------------------- */
     428             321 :     if( psOptions->nBandCount == 0 
     429                 :         && psOptions->hSrcDS != NULL
     430                 :         && psOptions->hDstDS != NULL 
     431                 :         && GDALGetRasterCount( psOptions->hSrcDS ) 
     432                 :         == GDALGetRasterCount( psOptions->hDstDS ) )
     433                 :     {
     434                 :         int  i;
     435                 : 
     436               0 :         psOptions->nBandCount = GDALGetRasterCount( psOptions->hSrcDS );
     437                 : 
     438                 :         psOptions->panSrcBands = (int *) 
     439               0 :             CPLMalloc(sizeof(int) * psOptions->nBandCount );
     440                 :         psOptions->panDstBands = (int *) 
     441               0 :             CPLMalloc(sizeof(int) * psOptions->nBandCount );
     442                 : 
     443               0 :         for( i = 0; i < psOptions->nBandCount; i++ )
     444                 :         {
     445               0 :             psOptions->panSrcBands[i] = i+1;
     446               0 :             psOptions->panDstBands[i] = i+1;
     447                 :         }
     448                 :     }
     449                 : 
     450                 : /* -------------------------------------------------------------------- */
     451                 : /*      If no working data type was provided, set one now.              */
     452                 : /*                                                                      */
     453                 : /*      Default to the highest resolution output band.  But if the      */
     454                 : /*      input band is higher resolution and has a nodata value "out     */
     455                 : /*      of band" with the output type we may need to use the higher     */
     456                 : /*      resolution input type to ensure we can identify nodata values.  */
     457                 : /* -------------------------------------------------------------------- */
     458             321 :     if( psOptions->eWorkingDataType == GDT_Unknown 
     459                 :         && psOptions->hSrcDS != NULL 
     460                 :         && psOptions->hDstDS != NULL 
     461                 :         && psOptions->nBandCount >= 1 )
     462                 :     {
     463                 :         int iBand;
     464             281 :         psOptions->eWorkingDataType = GDT_Byte;
     465                 : 
     466             586 :         for( iBand = 0; iBand < psOptions->nBandCount; iBand++ )
     467                 :         {
     468                 :             GDALRasterBandH hDstBand = GDALGetRasterBand( 
     469             305 :                 psOptions->hDstDS, psOptions->panDstBands[iBand] );
     470                 :             GDALRasterBandH hSrcBand = GDALGetRasterBand( 
     471             305 :                 psOptions->hSrcDS, psOptions->panSrcBands[iBand] );
     472                 :                                                   
     473             305 :             if( hDstBand != NULL )
     474                 :                 psOptions->eWorkingDataType = 
     475                 :                     GDALDataTypeUnion( psOptions->eWorkingDataType, 
     476             305 :                                        GDALGetRasterDataType( hDstBand ) );
     477                 :             
     478             305 :             if( hSrcBand != NULL 
     479                 :                 && psOptions->padfSrcNoDataReal != NULL )
     480                 :             {
     481              11 :                 int bMergeSource = FALSE;
     482                 : 
     483              11 :                 if( psOptions->padfSrcNoDataImag != NULL
     484                 :                     && psOptions->padfSrcNoDataImag[iBand] != 0.0
     485                 :                     && !GDALDataTypeIsComplex( psOptions->eWorkingDataType ) )
     486               0 :                     bMergeSource = TRUE;
     487              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] < 0.0 
     488                 :                          && (psOptions->eWorkingDataType == GDT_Byte
     489                 :                              || psOptions->eWorkingDataType == GDT_UInt16
     490                 :                              || psOptions->eWorkingDataType == GDT_UInt32) )
     491               0 :                     bMergeSource = TRUE;
     492              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] < -32768.0 
     493                 :                          && psOptions->eWorkingDataType == GDT_Int16 )
     494               0 :                     bMergeSource = TRUE;
     495              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] < -2147483648.0 
     496                 :                          && psOptions->eWorkingDataType == GDT_Int32 )
     497               0 :                     bMergeSource = TRUE;
     498              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] > 256 
     499                 :                          && psOptions->eWorkingDataType == GDT_Byte )
     500               0 :                     bMergeSource = TRUE;
     501              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] > 32767
     502                 :                          && psOptions->eWorkingDataType == GDT_Int16 )
     503               0 :                     bMergeSource = TRUE;
     504              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] > 65535
     505                 :                          && psOptions->eWorkingDataType == GDT_UInt16 )
     506               0 :                     bMergeSource = TRUE;
     507              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] > 2147483648.0 
     508                 :                          && psOptions->eWorkingDataType == GDT_Int32 )
     509               0 :                     bMergeSource = TRUE;
     510              11 :                 else if( psOptions->padfSrcNoDataReal[iBand] > 4294967295.0
     511                 :                          && psOptions->eWorkingDataType == GDT_UInt32 )
     512               0 :                     bMergeSource = TRUE;
     513                 : 
     514              11 :                 if( bMergeSource )
     515                 :                     psOptions->eWorkingDataType = 
     516                 :                         GDALDataTypeUnion( psOptions->eWorkingDataType, 
     517               0 :                                            GDALGetRasterDataType( hSrcBand ) );
     518                 :             }
     519                 :         }
     520                 :     }
     521                 : 
     522                 : /* -------------------------------------------------------------------- */
     523                 : /*      Default memory available.                                       */
     524                 : /*                                                                      */
     525                 : /*      For now we default to 64MB of RAM, but eventually we should     */
     526                 : /*      try various schemes to query physical RAM.  This can            */
     527                 : /*      certainly be done on Win32 and Linux.                           */
     528                 : /* -------------------------------------------------------------------- */
     529             321 :     if( psOptions->dfWarpMemoryLimit == 0.0 )
     530                 :     {
     531             272 :         psOptions->dfWarpMemoryLimit = 64.0 * 1024*1024;
     532                 :     }
     533                 : 
     534                 : /* -------------------------------------------------------------------- */
     535                 : /*      Are we doing timings?                                           */
     536                 : /* -------------------------------------------------------------------- */
     537                 :     bReportTimings = CSLFetchBoolean( psOptions->papszWarpOptions, 
     538             321 :                                       "REPORT_TIMINGS", FALSE );
     539                 : 
     540                 : /* -------------------------------------------------------------------- */
     541                 : /*      Support creating cutline from text warpoption.                  */
     542                 : /* -------------------------------------------------------------------- */
     543                 :     const char *pszCutlineWKT = 
     544             321 :         CSLFetchNameValue( psOptions->papszWarpOptions, "CUTLINE" );
     545                 :         
     546             321 :     if( pszCutlineWKT )
     547                 :     {
     548               3 :         if( OGR_G_CreateFromWkt( (char **) &pszCutlineWKT, NULL, 
     549                 :                                  (OGRGeometryH *) &(psOptions->hCutline) )
     550                 :             != OGRERR_NONE )
     551                 :         {
     552               0 :             eErr = CE_Failure;
     553                 :             CPLError( CE_Failure, CPLE_AppDefined,
     554               0 :                       "Failed to parse CUTLINE geometry wkt." );
     555                 :         }
     556                 :         else
     557                 :         {
     558                 :             const char *pszBD = CSLFetchNameValue( psOptions->papszWarpOptions,
     559               3 :                                                    "CUTLINE_BLEND_DIST" );
     560               3 :             if( pszBD )
     561               0 :                 psOptions->dfCutlineBlendDist = atof(pszBD);
     562                 :         }
     563                 :     }
     564                 : 
     565                 : /* -------------------------------------------------------------------- */
     566                 : /*      If the options don't validate, then wipe them.                  */
     567                 : /* -------------------------------------------------------------------- */
     568             321 :     if( !ValidateOptions() )
     569               0 :         eErr = CE_Failure;
     570                 : 
     571             321 :     if( eErr != CE_None )
     572               0 :         WipeOptions();
     573                 : 
     574             321 :     return eErr;
     575                 : }
     576                 : 
     577                 : /************************************************************************/
     578                 : /*                         GDALCreateWarpOperation()                    */
     579                 : /************************************************************************/
     580                 : 
     581                 : /**
     582                 :  * @see GDALWarpOperation::Initialize()
     583                 :  */
     584                 : 
     585                 : GDALWarpOperationH GDALCreateWarpOperation(
     586               0 :     const GDALWarpOptions *psNewOptions )
     587                 : {
     588                 :     GDALWarpOperation *poOperation;
     589                 : 
     590               0 :     poOperation = new GDALWarpOperation;
     591               0 :     if ( poOperation->Initialize( psNewOptions ) != CE_None )
     592                 :     {
     593               0 :         delete poOperation;
     594               0 :         return NULL;
     595                 :     }
     596                 : 
     597               0 :     return (GDALWarpOperationH)poOperation;
     598                 : }
     599                 : 
     600                 : /************************************************************************/
     601                 : /*                         GDALDestroyWarpOperation()                   */
     602                 : /************************************************************************/
     603                 : 
     604                 : /**
     605                 :  * @see GDALWarpOperation::~GDALWarpOperation()
     606                 :  */
     607                 : 
     608               0 : void GDALDestroyWarpOperation( GDALWarpOperationH hOperation )
     609                 : {
     610               0 :     if ( hOperation )
     611               0 :         delete static_cast<GDALWarpOperation *>(hOperation);
     612               0 : }
     613                 : 
     614                 : /************************************************************************/
     615                 : /*                         ChunkAndWarpImage()                          */
     616                 : /************************************************************************/
     617                 : 
     618                 : /**
     619                 :  * \fn CPLErr GDALWarpOperation::ChunkAndWarpImage(
     620                 :                 int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize );
     621                 :  *
     622                 :  * This method does a complete warp of the source image to the destination
     623                 :  * image for the indicated region with the current warp options in effect.  
     624                 :  * Progress is reported to the installed progress monitor, if any.  
     625                 :  *
     626                 :  * This function will subdivide the region and recursively call itself 
     627                 :  * until the total memory required to process a region chunk will all fit
     628                 :  * in the memory pool defined by GDALWarpOptions::dfWarpMemoryLimit.  
     629                 :  *
     630                 :  * Once an appropriate region is selected GDALWarpOperation::WarpRegion()
     631                 :  * is invoked to do the actual work. 
     632                 :  *
     633                 :  * @param nDstXOff X offset to window of destination data to be produced.
     634                 :  * @param nDstYOff Y offset to window of destination data to be produced.
     635                 :  * @param nDstXSize Width of output window on destination file to be produced.
     636                 :  * @param nDstYSize Height of output window on destination file to be produced.
     637                 :  *
     638                 :  * @return CE_None on success or CE_Failure if an error occurs.
     639                 :  */
     640                 :  
     641                 :  struct WarpChunk { 
     642                 :     int dx, dy, dsx, dsy; 
     643                 :     int sx, sy, ssx, ssy; 
     644                 : }; 
     645                 :  
     646             601 : static int OrderWarpChunk(const void* _a, const void *_b)
     647                 : { 
     648             601 :     const WarpChunk* a = (const WarpChunk* )_a;
     649             601 :     const WarpChunk* b = (const WarpChunk* )_b;
     650             601 :     if (a->dy < b->dy)
     651             323 :         return -1; 
     652             278 :     else if (a->dy > b->dy)
     653             125 :         return 1; 
     654             153 :     else if (a->dx < b->dx)
     655             153 :         return -1; 
     656               0 :     else if (a->dx > b->dx)
     657               0 :         return 1; 
     658                 :     else
     659               0 :         return 0; 
     660                 : } 
     661                 : 
     662                 : CPLErr GDALWarpOperation::ChunkAndWarpImage( 
     663             277 :     int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize )
     664                 : 
     665                 : {
     666                 : /* -------------------------------------------------------------------- */
     667                 : /*      Collect the list of chunks to operate on.                       */
     668                 : /* -------------------------------------------------------------------- */
     669             277 :     WipeChunkList();
     670             277 :     CollectChunkList( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
     671                 :     
     672                 :     /* Sort chucks from top to bottom, and for equal y, from left to right */
     673             277 :     qsort(panChunkList, nChunkListCount, sizeof(WarpChunk), OrderWarpChunk); 
     674                 : 
     675                 : /* -------------------------------------------------------------------- */
     676                 : /*      Total up output pixels to process.                              */
     677                 : /* -------------------------------------------------------------------- */
     678                 :     int iChunk;
     679             277 :     double dfTotalPixels = 0;
     680                 : 
     681             746 :     for( iChunk = 0; iChunk < nChunkListCount; iChunk++ )
     682                 :     {
     683             469 :         int *panThisChunk = panChunkList + iChunk*8;
     684             469 :         double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
     685                 : 
     686             469 :         dfTotalPixels += dfChunkPixels;
     687                 :     }
     688                 : 
     689                 : /* -------------------------------------------------------------------- */
     690                 : /*      Process them one at a time, updating the progress               */
     691                 : /*      information for each region.                                    */
     692                 : /* -------------------------------------------------------------------- */
     693             277 :     double dfPixelsProcessed=0.0;
     694                 : 
     695             746 :     for( iChunk = 0; iChunk < nChunkListCount; iChunk++ )
     696                 :     {
     697             469 :         int *panThisChunk = panChunkList + iChunk*8;
     698             469 :         double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
     699                 :         CPLErr eErr;
     700                 : 
     701             469 :         dfProgressBase = dfPixelsProcessed / dfTotalPixels;
     702             469 :         dfProgressScale = dfChunkPixels / dfTotalPixels;
     703                 : 
     704                 :         eErr = WarpRegion( panThisChunk[0], panThisChunk[1], 
     705                 :                            panThisChunk[2], panThisChunk[3],
     706                 :                            panThisChunk[4], panThisChunk[5],
     707             469 :                            panThisChunk[6], panThisChunk[7] );
     708                 : 
     709             469 :         if( eErr != CE_None )
     710               0 :             return eErr;
     711                 : 
     712             469 :         dfPixelsProcessed += dfChunkPixels;
     713                 :     }
     714                 : 
     715             277 :     WipeChunkList();
     716                 : 
     717             277 :     psOptions->pfnProgress( 1.00001, "", psOptions->pProgressArg );
     718                 : 
     719             277 :     return CE_None;
     720                 : }
     721                 : 
     722                 : /************************************************************************/
     723                 : /*                         GDALChunkAndWarpImage()                      */
     724                 : /************************************************************************/
     725                 : 
     726                 : /**
     727                 :  * @see GDALWarpOperation::ChunkAndWarpImage()
     728                 :  */
     729                 : 
     730                 : CPLErr GDALChunkAndWarpImage( GDALWarpOperationH hOperation,
     731               0 :     int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize )
     732                 : {
     733               0 :     VALIDATE_POINTER1( hOperation, "GDALChunkAndWarpImage", CE_Failure );
     734                 : 
     735                 :     return ( (GDALWarpOperation *)hOperation )->
     736               0 :         ChunkAndWarpImage( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
     737                 : }
     738                 : 
     739                 : /************************************************************************/
     740                 : /*                          ChunkThreadMain()                           */
     741                 : /************************************************************************/
     742                 : 
     743               1 : static void ChunkThreadMain( void *pThreadData )
     744                 : 
     745                 : {
     746               1 :     void *hThreadMutex = ((void **) pThreadData)[0];
     747                 :     GDALWarpOperation *poOperation = 
     748               1 :         (GDALWarpOperation *) (((void **) pThreadData)[1]);
     749               1 :     int *panChunkInfo = (int *) (((void **) pThreadData)[2]);
     750                 : 
     751               1 :     if( !CPLAcquireMutex( hThreadMutex, 2.0 ) )
     752                 :     {
     753                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     754               0 :                   "Failed to acquire thread mutex in ChunkThreadMain()." );
     755               0 :         return;
     756                 :     }
     757                 : 
     758                 :     CPLErr eErr;
     759                 : 
     760                 :     eErr = 
     761                 :         poOperation->WarpRegion( panChunkInfo[0], panChunkInfo[1], 
     762                 :                                  panChunkInfo[2], panChunkInfo[3], 
     763                 :                                  panChunkInfo[4], panChunkInfo[5], 
     764               1 :                                  panChunkInfo[6], panChunkInfo[7] );
     765                 : 
     766                 :     /* Return error. */
     767               1 :     ((void **) pThreadData)[2] = (void *) (long) eErr;
     768                 : 
     769                 :     /* Marks that we are done. */
     770               1 :     ((void **) pThreadData)[1] = NULL;
     771                 : 
     772                 :     /* Release mutex so parent knows we are done. */
     773               1 :     CPLReleaseMutex( hThreadMutex );
     774                 : }
     775                 : 
     776                 : /************************************************************************/
     777                 : /*                         ChunkAndWarpMulti()                          */
     778                 : /************************************************************************/
     779                 : 
     780                 : /**
     781                 :  * \fn CPLErr GDALWarpOperation::ChunkAndWarpMulti(
     782                 :                 int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize );
     783                 :  *
     784                 :  * This method does a complete warp of the source image to the destination
     785                 :  * image for the indicated region with the current warp options in effect.  
     786                 :  * Progress is reported to the installed progress monitor, if any.  
     787                 :  *
     788                 :  * Externally this method operates the same as ChunkAndWarpImage(), but
     789                 :  * internally this method uses multiple threads to interleave input/output
     790                 :  * for one region while the processing is being done for another.
     791                 :  *
     792                 :  * @param nDstXOff X offset to window of destination data to be produced.
     793                 :  * @param nDstYOff Y offset to window of destination data to be produced.
     794                 :  * @param nDstXSize Width of output window on destination file to be produced.
     795                 :  * @param nDstYSize Height of output window on destination file to be produced.
     796                 :  *
     797                 :  * @return CE_None on success or CE_Failure if an error occurs.
     798                 :  */
     799                 : 
     800                 : CPLErr GDALWarpOperation::ChunkAndWarpMulti( 
     801               1 :     int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize )
     802                 : 
     803                 : {
     804               1 :     hThread1Mutex = CPLCreateMutex();
     805               1 :     hThread2Mutex = CPLCreateMutex();
     806               1 :     hIOMutex = CPLCreateMutex();
     807               1 :     hWarpMutex = CPLCreateMutex();
     808                 : 
     809               1 :     CPLReleaseMutex( hThread1Mutex );
     810               1 :     CPLReleaseMutex( hThread2Mutex );
     811               1 :     CPLReleaseMutex( hIOMutex );
     812               1 :     CPLReleaseMutex( hWarpMutex );
     813                 : 
     814                 : /* -------------------------------------------------------------------- */
     815                 : /*      Collect the list of chunks to operate on.                       */
     816                 : /* -------------------------------------------------------------------- */
     817               1 :     WipeChunkList();
     818               1 :     CollectChunkList( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
     819                 : 
     820                 :     /* Sort chucks from top to bottom, and for equal y, from left to right */
     821               1 :     qsort(panChunkList, nChunkListCount, sizeof(WarpChunk), OrderWarpChunk); 
     822                 : 
     823                 : /* -------------------------------------------------------------------- */
     824                 : /*      Process them one at a time, updating the progress               */
     825                 : /*      information for each region.                                    */
     826                 : /* -------------------------------------------------------------------- */
     827                 :     void * volatile papThreadDataList[6] = { hThread1Mutex, NULL, NULL, 
     828               1 :                                             hThread2Mutex, NULL, NULL };
     829                 :     int iChunk;
     830               1 :     double dfPixelsProcessed=0.0, dfTotalPixels = nDstXSize*(double)nDstYSize;
     831               1 :     CPLErr eErr = CE_None;
     832                 : 
     833               3 :     for( iChunk = 0; iChunk < nChunkListCount+1; iChunk++ )
     834                 :     {
     835               2 :         int    iThread = iChunk % 2;
     836                 : 
     837                 : /* -------------------------------------------------------------------- */
     838                 : /*      Launch thread for this chunk.                                   */
     839                 : /* -------------------------------------------------------------------- */
     840               2 :         if( iChunk < nChunkListCount )
     841                 :         {
     842               1 :             int *panThisChunk = panChunkList + iChunk*8;
     843               1 :             double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
     844                 : 
     845               1 :             dfProgressBase = dfPixelsProcessed / dfTotalPixels;
     846               1 :             dfProgressScale = dfChunkPixels / dfTotalPixels;
     847                 : 
     848               1 :             dfPixelsProcessed += dfChunkPixels;
     849                 :             
     850               1 :             papThreadDataList[iThread*3+1] = (void *) this;
     851               1 :             papThreadDataList[iThread*3+2] = (void *) panThisChunk;
     852                 : 
     853               1 :             CPLDebug( "GDAL", "Start chunk %d.", iChunk );
     854               1 :             if( CPLCreateThread( ChunkThreadMain, 
     855                 :                           (void *) (papThreadDataList + iThread*3)) == -1 )
     856                 :             {
     857                 :                 CPLError( CE_Failure, CPLE_AppDefined, 
     858               0 :                           "CPLCreateThread() failed in ChunkAndWarpMulti()" );
     859               0 :                 return CE_Failure;
     860                 :             }
     861                 : 
     862                 :             /* Eventually we need a mechanism to ensure we wait for this 
     863                 :                thread to acquire the IO mutex before proceeding. */
     864               1 :             if( iChunk == 0 )
     865               1 :                 CPLSleep( 0.25 );
     866                 :         }
     867                 : 
     868                 :         
     869                 : /* -------------------------------------------------------------------- */
     870                 : /*      Wait for previous chunks thread to complete.                    */
     871                 : /* -------------------------------------------------------------------- */
     872               2 :         if( iChunk > 0 )
     873                 :         {
     874               1 :             iThread = (iChunk-1) % 2;
     875                 :             
     876                 :             /* Wait for thread to finish. */
     877               2 :             while( papThreadDataList[iThread*3+1] != NULL )
     878                 :             {
     879               0 :                 if( CPLAcquireMutex( papThreadDataList[iThread*3+0], 1.0 ) )
     880               0 :                     CPLReleaseMutex( papThreadDataList[iThread*3+0] );
     881                 :             }
     882                 : 
     883               1 :             CPLDebug( "GDAL", "Finished chunk %d.", iChunk-1 );
     884                 : 
     885               1 :             eErr = (CPLErr) (long) (GIntBig) papThreadDataList[iThread*3+2];
     886                 : 
     887               1 :             if( eErr != CE_None )
     888               0 :                 break;
     889                 :         }
     890                 :     }
     891                 : 
     892                 :     /* -------------------------------------------------------------------- */
     893                 :     /*      Wait for all threads to complete.                               */
     894                 :     /* -------------------------------------------------------------------- */
     895                 :     int iThread;
     896               3 :     for(iThread = 0; iThread < 2; iThread ++)
     897                 :     {
     898               4 :         while( papThreadDataList[iThread*3+1] != NULL )
     899                 :         {
     900               0 :             if( CPLAcquireMutex( papThreadDataList[iThread*3+0], 1.0 ) )
     901               0 :                 CPLReleaseMutex( papThreadDataList[iThread*3+0] );
     902                 :         }
     903                 :     }
     904                 : 
     905               1 :     WipeChunkList();
     906                 : 
     907               1 :     return eErr;
     908                 : }
     909                 : 
     910                 : /************************************************************************/
     911                 : /*                         GDALChunkAndWarpMulti()                      */
     912                 : /************************************************************************/
     913                 : 
     914                 : /**
     915                 :  * @see GDALWarpOperation::ChunkAndWarpMulti()
     916                 :  */
     917                 : 
     918                 : CPLErr GDALChunkAndWarpMulti( GDALWarpOperationH hOperation,
     919               0 :     int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize )
     920                 : {
     921               0 :     VALIDATE_POINTER1( hOperation, "GDALChunkAndWarpMulti", CE_Failure );
     922                 : 
     923                 :     return ( (GDALWarpOperation *)hOperation )->
     924               0 :         ChunkAndWarpMulti( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
     925                 : }
     926                 : 
     927                 : /************************************************************************/
     928                 : /*                           WipeChunkList()                            */
     929                 : /************************************************************************/
     930                 : 
     931             877 : void GDALWarpOperation::WipeChunkList()
     932                 : 
     933                 : {
     934             877 :     CPLFree( panChunkList );
     935             877 :     panChunkList = NULL;
     936             877 :     nChunkListCount = 0;
     937             877 :     nChunkListMax = 0;
     938             877 : }
     939                 : 
     940                 : /************************************************************************/
     941                 : /*                          CollectChunkList()                          */
     942                 : /************************************************************************/
     943                 : 
     944                 : CPLErr GDALWarpOperation::CollectChunkList( 
     945             662 :     int nDstXOff, int nDstYOff,  int nDstXSize, int nDstYSize )
     946                 : 
     947                 : {
     948                 : /* -------------------------------------------------------------------- */
     949                 : /*      Compute the bounds of the input area corresponding to the       */
     950                 : /*      output area.                                                    */
     951                 : /* -------------------------------------------------------------------- */
     952                 :     int nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize;
     953                 :     CPLErr eErr;
     954                 : 
     955                 :     eErr = ComputeSourceWindow( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
     956             662 :                                 &nSrcXOff, &nSrcYOff, &nSrcXSize, &nSrcYSize );
     957                 :     
     958             662 :     if( eErr != CE_None )
     959               0 :         return eErr;
     960                 : 
     961                 : /* -------------------------------------------------------------------- */
     962                 : /*      If we are allowed to drop no-source regons, do so now if       */
     963                 : /*      appropriate.                                                    */
     964                 : /* -------------------------------------------------------------------- */
     965             662 :     if( (nSrcXSize == 0 || nSrcYSize == 0)
     966                 :         && CSLFetchBoolean( psOptions->papszWarpOptions, "SKIP_NOSOURCE",0 ))
     967               0 :         return CE_None;
     968                 : 
     969                 : /* -------------------------------------------------------------------- */
     970                 : /*      Based on the types of masks in use, how many bits will each     */
     971                 : /*      source pixel cost us?                                           */
     972                 : /* -------------------------------------------------------------------- */
     973                 :     int nSrcPixelCostInBits;
     974                 : 
     975                 :     nSrcPixelCostInBits = 
     976                 :         GDALGetDataTypeSize( psOptions->eWorkingDataType ) 
     977             662 :         * psOptions->nBandCount;
     978                 : 
     979             662 :     if( psOptions->pfnSrcDensityMaskFunc != NULL )
     980               0 :         nSrcPixelCostInBits += 32; /* ?? float mask */
     981                 : 
     982             662 :     if( psOptions->nSrcAlphaBand > 0 || psOptions->hCutline != NULL )
     983               4 :         nSrcPixelCostInBits += 32; /* UnifiedSrcDensity float mask */
     984                 : 
     985             662 :     if( psOptions->papfnSrcPerBandValidityMaskFunc != NULL 
     986                 :         || psOptions->padfSrcNoDataReal != NULL )
     987               7 :         nSrcPixelCostInBits += psOptions->nBandCount; /* bit/band mask */
     988                 : 
     989             662 :     if( psOptions->pfnSrcValidityMaskFunc != NULL )
     990               0 :         nSrcPixelCostInBits += 1; /* bit mask */
     991                 : 
     992                 : /* -------------------------------------------------------------------- */
     993                 : /*      What about the cost for the destination.                        */
     994                 : /* -------------------------------------------------------------------- */
     995                 :     int nDstPixelCostInBits;
     996                 : 
     997                 :     nDstPixelCostInBits = 
     998                 :         GDALGetDataTypeSize( psOptions->eWorkingDataType ) 
     999             662 :         * psOptions->nBandCount;
    1000                 : 
    1001             662 :     if( psOptions->pfnDstDensityMaskFunc != NULL )
    1002               0 :         nDstPixelCostInBits += 32;
    1003                 : 
    1004             662 :     if( psOptions->padfDstNoDataReal != NULL
    1005                 :         || psOptions->pfnDstValidityMaskFunc != NULL )
    1006               1 :         nDstPixelCostInBits += psOptions->nBandCount;
    1007                 : 
    1008                 : /* -------------------------------------------------------------------- */
    1009                 : /*      Does the cost of the current rectangle exceed our memory        */
    1010                 : /*      limit? If so, split the destination along the longest           */
    1011                 : /*      dimension and recurse.                                          */
    1012                 : /* -------------------------------------------------------------------- */
    1013                 :     double dfTotalMemoryUse;
    1014                 : 
    1015                 :     dfTotalMemoryUse =
    1016                 :         (((double) nSrcPixelCostInBits) * nSrcXSize * nSrcYSize
    1017             662 :          + ((double) nDstPixelCostInBits) * nDstXSize * nDstYSize) / 8.0;
    1018                 :          
    1019                 :         
    1020             662 :     int nBlockXSize = 1, nBlockYSize = 1;
    1021             662 :     if (psOptions->hDstDS)
    1022                 :     {
    1023                 :         GDALGetBlockSize(GDALGetRasterBand(psOptions->hDstDS, 1),
    1024             662 :                          &nBlockXSize, &nBlockYSize);
    1025                 :     }
    1026                 :     
    1027             662 :     if( dfTotalMemoryUse > psOptions->dfWarpMemoryLimit 
    1028                 :         && (nDstXSize > 2 || nDstYSize > 2) )
    1029                 :     {
    1030                 :         int bOptimizeSize =
    1031             192 :                 CSLFetchBoolean( psOptions->papszWarpOptions, "OPTIMIZE_SIZE", FALSE );
    1032                 : 
    1033                 :         /* If the region width is greater than the region height, */
    1034                 :         /* cut in half in the width. When we want to optimize the size */
    1035                 :         /* of a compressed output dataset, do this only if each half part */
    1036                 :         /* is at least as wide as the block width */
    1037             250 :         if( nDstXSize > nDstYSize &&
    1038                 :             (!bOptimizeSize ||
    1039                 :              (bOptimizeSize && (nDstXSize / 2 >= nBlockXSize || nDstYSize == 1))) )
    1040                 :         {
    1041              58 :             int nChunk1 = nDstXSize / 2;
    1042                 :             
    1043                 :             /* In the optimize size case, try to stick on target block boundaries */
    1044              58 :             if (bOptimizeSize && nChunk1 > nBlockXSize)
    1045              21 :                 nChunk1 = (nChunk1 / nBlockXSize) * nBlockXSize;
    1046                 :             
    1047              58 :             int nChunk2 = nDstXSize - nChunk1;
    1048                 : 
    1049                 :             eErr = CollectChunkList( nDstXOff, nDstYOff, 
    1050              58 :                                      nChunk1, nDstYSize );
    1051                 : 
    1052              58 :             if( eErr == CE_None )
    1053                 :             {
    1054                 :                 eErr = CollectChunkList( nDstXOff+nChunk1, nDstYOff, 
    1055              58 :                                          nChunk2, nDstYSize );
    1056                 :             }
    1057                 :         }
    1058                 :         else
    1059                 :         {
    1060             134 :             int nChunk1 = nDstYSize / 2;
    1061                 : 
    1062                 :             /* In the optimize size case, try to stick on target block boundaries */
    1063             134 :             if (bOptimizeSize && nChunk1 > nBlockYSize)
    1064              51 :                 nChunk1 = (nChunk1 / nBlockYSize) * nBlockYSize;
    1065                 : 
    1066             134 :             int nChunk2 = nDstYSize - nChunk1;
    1067                 : 
    1068                 :             eErr = CollectChunkList( nDstXOff, nDstYOff, 
    1069             134 :                                      nDstXSize, nChunk1 );
    1070                 : 
    1071             134 :             if( eErr == CE_None )
    1072                 :             {
    1073                 :                 eErr = CollectChunkList( nDstXOff, nDstYOff+nChunk1, 
    1074             134 :                                          nDstXSize, nChunk2 );
    1075                 :             }
    1076                 :         }
    1077                 : 
    1078             192 :         return eErr;
    1079                 :     }
    1080                 : 
    1081                 : /* -------------------------------------------------------------------- */
    1082                 : /*      OK, everything fits, so add to the chunk list.                  */
    1083                 : /* -------------------------------------------------------------------- */
    1084             470 :     if( nChunkListCount == nChunkListMax )
    1085                 :     {
    1086             312 :         nChunkListMax = nChunkListMax * 2 + 1;
    1087                 :         panChunkList = (int *) 
    1088             312 :             CPLRealloc(panChunkList,sizeof(int)*nChunkListMax*8 );
    1089                 :     }
    1090                 : 
    1091             470 :     panChunkList[nChunkListCount*8+0] = nDstXOff;
    1092             470 :     panChunkList[nChunkListCount*8+1] = nDstYOff;
    1093             470 :     panChunkList[nChunkListCount*8+2] = nDstXSize;
    1094             470 :     panChunkList[nChunkListCount*8+3] = nDstYSize;
    1095             470 :     panChunkList[nChunkListCount*8+4] = nSrcXOff;
    1096             470 :     panChunkList[nChunkListCount*8+5] = nSrcYOff;
    1097             470 :     panChunkList[nChunkListCount*8+6] = nSrcXSize;
    1098             470 :     panChunkList[nChunkListCount*8+7] = nSrcYSize;
    1099                 : 
    1100             470 :     nChunkListCount++;
    1101                 : 
    1102             470 :     return CE_None;
    1103                 : }
    1104                 : 
    1105                 : 
    1106                 : /************************************************************************/
    1107                 : /*                             WarpRegion()                             */
    1108                 : /************************************************************************/
    1109                 : 
    1110                 : /**
    1111                 :  * \fn CPLErr GDALWarpOperation::WarpRegion(int nDstXOff, int nDstYOff, 
    1112                 :                                             int nDstXSize, int nDstYSize,
    1113                 :                                             int nSrcXOff=0, int nSrcYOff=0,
    1114                 :                                             int nSrcXSize=0, int nSrcYSize=0 );
    1115                 :  *
    1116                 :  * This method requests the indicated region of the output file be generated.
    1117                 :  * 
    1118                 :  * Note that WarpRegion() will produce the requested area in one low level warp
    1119                 :  * operation without verifying that this does not exceed the stated memory
    1120                 :  * limits for the warp operation.  Applications should take care not to call
    1121                 :  * WarpRegion() on too large a region!  This function 
    1122                 :  * is normally called by ChunkAndWarpImage(), the normal entry point for 
    1123                 :  * applications.  Use it instead if staying within memory constraints is
    1124                 :  * desired. 
    1125                 :  *
    1126                 :  * Progress is reported from 0.0 to 1.0 for the indicated region. 
    1127                 :  *
    1128                 :  * @param nDstXOff X offset to window of destination data to be produced.
    1129                 :  * @param nDstYOff Y offset to window of destination data to be produced.
    1130                 :  * @param nDstXSize Width of output window on destination file to be produced.
    1131                 :  * @param nDstYSize Height of output window on destination file to be produced.
    1132                 :  * @param nSrcXOff source window X offset (computed if window all zero)
    1133                 :  * @param nSrcYOff source window Y offset (computed if window all zero)
    1134                 :  * @param nSrcXSize source window X size (computed if window all zero)
    1135                 :  * @param nSrcYSize source window Y size (computed if window all zero)
    1136                 :  *
    1137                 :  * @return CE_None on success or CE_Failure if an error occurs.
    1138                 :  */
    1139                 : 
    1140                 : CPLErr GDALWarpOperation::WarpRegion( int nDstXOff, int nDstYOff, 
    1141                 :                                       int nDstXSize, int nDstYSize,
    1142                 :                                       int nSrcXOff, int nSrcYOff,
    1143             470 :                                       int nSrcXSize, int nSrcYSize )
    1144                 : 
    1145                 : {
    1146                 :     CPLErr eErr;
    1147                 :     int   iBand;
    1148                 : 
    1149                 : /* -------------------------------------------------------------------- */
    1150                 : /*      Acquire IO mutex.                                               */
    1151                 : /* -------------------------------------------------------------------- */
    1152             470 :     if( hIOMutex != NULL )
    1153                 :     {
    1154               1 :         if( !CPLAcquireMutex( hIOMutex, 600.0 ) )
    1155                 :         {
    1156                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1157               0 :                       "Failed to acquire IOMutex in WarpRegion()." );
    1158               0 :             return CE_Failure;
    1159                 :         }
    1160                 :     }
    1161                 : 
    1162             470 :     ReportTiming( NULL );
    1163                 : 
    1164                 : /* -------------------------------------------------------------------- */
    1165                 : /*      Allocate the output buffer.                                     */
    1166                 : /* -------------------------------------------------------------------- */
    1167                 :     void *pDstBuffer;
    1168             470 :     int  nWordSize = GDALGetDataTypeSize(psOptions->eWorkingDataType)/8;
    1169             470 :     int  nBandSize = nWordSize * nDstXSize * nDstYSize;
    1170                 : 
    1171             470 :     if (nDstXSize > INT_MAX / nDstYSize ||
    1172                 :         nDstXSize * nDstYSize > INT_MAX / (nWordSize * psOptions->nBandCount))
    1173                 :     {
    1174                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1175                 :                   "Integer overflow : nDstXSize=%d, nDstYSize=%d",
    1176               0 :                   nDstXSize, nDstYSize);
    1177               0 :         return CE_Failure;
    1178                 :     }
    1179                 : 
    1180             470 :     pDstBuffer = VSIMalloc( nBandSize * psOptions->nBandCount );
    1181             470 :     if( pDstBuffer == NULL )
    1182                 :     {
    1183                 :         CPLError( CE_Failure, CPLE_OutOfMemory,
    1184                 :                   "Out of memory allocating %d byte destination buffer.",
    1185               0 :                   nBandSize * psOptions->nBandCount );
    1186               0 :         return CE_Failure;
    1187                 :     }
    1188                 : 
    1189                 : /* -------------------------------------------------------------------- */
    1190                 : /*      If the INIT_DEST option is given the initialize the output      */
    1191                 : /*      destination buffer to the indicated value without reading it    */
    1192                 : /*      from the hDstDS.  This is sometimes used to optimize            */
    1193                 : /*      operation to a new output file ... it doesn't have to           */
    1194                 : /*      written out and read back for nothing.                          */
    1195                 : /* NOTE:The following code is 99% similar in gdalwarpoperation.cpp and  */
    1196                 : /*      vrtwarped.cpp. Be careful to keep it in sync !                  */
    1197                 : /* -------------------------------------------------------------------- */
    1198                 :     const char *pszInitDest = CSLFetchNameValue( psOptions->papszWarpOptions,
    1199             470 :                                                  "INIT_DEST" );
    1200                 : 
    1201             470 :     if( pszInitDest != NULL && !EQUAL(pszInitDest, "") )
    1202                 :     {
    1203                 :         char **papszInitValues = 
    1204             450 :             CSLTokenizeStringComplex( pszInitDest, ",", FALSE, FALSE );
    1205             450 :         int nInitCount = CSLCount(papszInitValues);
    1206                 :                                                            
    1207             934 :         for( iBand = 0; iBand < psOptions->nBandCount; iBand++ )
    1208                 :         {
    1209                 :             double adfInitRealImag[2];
    1210                 :             GByte *pBandData;
    1211             484 :             const char *pszBandInit = papszInitValues[MIN(iBand,nInitCount-1)];
    1212                 : 
    1213             485 :             if( EQUAL(pszBandInit,"NO_DATA")
    1214                 :                 && psOptions->padfDstNoDataReal != NULL )
    1215                 :             {
    1216               1 :                 adfInitRealImag[0] = psOptions->padfDstNoDataReal[iBand];
    1217               1 :                 adfInitRealImag[1] = psOptions->padfDstNoDataImag[iBand];
    1218                 :             }
    1219                 :             else
    1220                 :             {
    1221                 :                 CPLStringToComplex( pszBandInit,
    1222             483 :                                     adfInitRealImag + 0, adfInitRealImag + 1);
    1223                 :             }
    1224                 : 
    1225             484 :             pBandData = ((GByte *) pDstBuffer) + iBand * nBandSize;
    1226                 :             
    1227             484 :             if( psOptions->eWorkingDataType == GDT_Byte )
    1228                 :                 memset( pBandData, 
    1229                 :                         MAX(0,MIN(255,(int)adfInitRealImag[0])), 
    1230             283 :                         nBandSize);
    1231             402 :             else if( adfInitRealImag[0] == 0.0 && adfInitRealImag[1] == 0 )
    1232                 :             {
    1233             201 :                 memset( pBandData, 0, nBandSize );
    1234                 :             }
    1235               0 :             else if( adfInitRealImag[1] == 0.0 )
    1236                 :             {
    1237                 :                 GDALCopyWords( &adfInitRealImag, GDT_Float64, 0, 
    1238                 :                                pBandData,psOptions->eWorkingDataType,nWordSize,
    1239               0 :                                nDstXSize * nDstYSize );
    1240                 :             }
    1241                 :             else
    1242                 :             {
    1243                 :                 GDALCopyWords( &adfInitRealImag, GDT_CFloat64, 0, 
    1244                 :                                pBandData,psOptions->eWorkingDataType,nWordSize,
    1245               0 :                                nDstXSize * nDstYSize );
    1246                 :             }
    1247                 :         }
    1248                 : 
    1249             450 :         CSLDestroy( papszInitValues );
    1250                 :     }
    1251                 : 
    1252                 : /* -------------------------------------------------------------------- */
    1253                 : /*      If we aren't doing fixed initialization of the output buffer    */
    1254                 : /*      then read it from disk so we can overlay on existing imagery.   */
    1255                 : /* -------------------------------------------------------------------- */
    1256             470 :     if( pszInitDest == NULL )
    1257                 :     {
    1258                 :         eErr = GDALDatasetRasterIO( psOptions->hDstDS, GF_Read, 
    1259                 :                                     nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1260                 :                                     pDstBuffer, nDstXSize, nDstYSize, 
    1261                 :                                     psOptions->eWorkingDataType, 
    1262                 :                                     psOptions->nBandCount, 
    1263                 :                                     psOptions->panDstBands,
    1264              20 :                                     0, 0, 0 );
    1265                 : 
    1266              20 :         if( eErr != CE_None )
    1267                 :         {
    1268               0 :             CPLFree( pDstBuffer );
    1269               0 :             return eErr;
    1270                 :         }
    1271                 : 
    1272              20 :         ReportTiming( "Output buffer read" );
    1273                 :     }
    1274                 : 
    1275                 : /* -------------------------------------------------------------------- */
    1276                 : /*      Perform the warp.                                               */
    1277                 : /* -------------------------------------------------------------------- */
    1278                 :     eErr = WarpRegionToBuffer( nDstXOff, nDstYOff, nDstXSize, nDstYSize, 
    1279                 :                                pDstBuffer, psOptions->eWorkingDataType, 
    1280             470 :                                nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize );
    1281                 : 
    1282                 : /* -------------------------------------------------------------------- */
    1283                 : /*      Write the output data back to disk if all went well.            */
    1284                 : /* -------------------------------------------------------------------- */
    1285             470 :     if( eErr == CE_None )
    1286                 :     {
    1287                 :         eErr = GDALDatasetRasterIO( psOptions->hDstDS, GF_Write, 
    1288                 :                                     nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1289                 :                                     pDstBuffer, nDstXSize, nDstYSize, 
    1290                 :                                     psOptions->eWorkingDataType, 
    1291                 :                                     psOptions->nBandCount, 
    1292                 :                                     psOptions->panDstBands,
    1293             470 :                                     0, 0, 0 );
    1294             470 :         if( CSLFetchBoolean( psOptions->papszWarpOptions, "WRITE_FLUSH", 
    1295                 :                              FALSE ) )          
    1296                 :         {
    1297               0 :             GDALFlushCache( psOptions->hDstDS );
    1298                 :         }
    1299             470 :         ReportTiming( "Output buffer write" );
    1300                 :     }
    1301                 : 
    1302                 : /* -------------------------------------------------------------------- */
    1303                 : /*      Cleanup and return.                                             */
    1304                 : /* -------------------------------------------------------------------- */
    1305             470 :     VSIFree( pDstBuffer );
    1306                 :     
    1307             470 :     if( hIOMutex != NULL )
    1308               1 :         CPLReleaseMutex( hIOMutex );
    1309                 : 
    1310             470 :     return eErr;
    1311                 : }
    1312                 : 
    1313                 : /************************************************************************/
    1314                 : /*                             GDALWarpRegion()                         */
    1315                 : /************************************************************************/
    1316                 : 
    1317                 : /**
    1318                 :  * @see GDALWarpOperation::WarpRegion()
    1319                 :  */
    1320                 : 
    1321                 : CPLErr GDALWarpRegion( GDALWarpOperationH hOperation,
    1322                 :                        int nDstXOff, int nDstYOff,
    1323                 :                        int nDstXSize, int nDstYSize,
    1324                 :                        int nSrcXOff, int nSrcYOff,
    1325               0 :                        int nSrcXSize, int nSrcYSize )
    1326                 : 
    1327                 : {
    1328               0 :     VALIDATE_POINTER1( hOperation, "GDALWarpRegion", CE_Failure );
    1329                 : 
    1330                 :     return ( (GDALWarpOperation *)hOperation )->
    1331                 :         WarpRegion( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1332               0 :                     nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize);
    1333                 : }
    1334                 : 
    1335                 : /************************************************************************/
    1336                 : /*                            WarpRegionToBuffer()                      */
    1337                 : /************************************************************************/
    1338                 : 
    1339                 : /**
    1340                 :  * \fn CPLErr GDALWarpOperation::WarpRegionToBuffer( 
    1341                 :                                   int nDstXOff, int nDstYOff, 
    1342                 :                                   int nDstXSize, int nDstYSize, 
    1343                 :                                   void *pDataBuf, 
    1344                 :                                   GDALDataType eBufDataType,
    1345                 :                                   int nSrcXOff=0, int nSrcYOff=0,
    1346                 :                                   int nSrcXSize=0, int nSrcYSize=0 );
    1347                 :  * 
    1348                 :  * This method requests that a particular window of the output dataset
    1349                 :  * be warped and the result put into the provided data buffer.  The output
    1350                 :  * dataset doesn't even really have to exist to use this method as long as
    1351                 :  * the transformation function in the GDALWarpOptions is setup to map to
    1352                 :  * a virtual pixel/line space. 
    1353                 :  *
    1354                 :  * This method will do the whole region in one chunk, so be wary of the
    1355                 :  * amount of memory that might be used. 
    1356                 :  *
    1357                 :  * @param nDstXOff X offset to window of destination data to be produced.
    1358                 :  * @param nDstYOff Y offset to window of destination data to be produced.
    1359                 :  * @param nDstXSize Width of output window on destination file to be produced.
    1360                 :  * @param nDstYSize Height of output window on destination file to be produced.
    1361                 :  * @param pDataBuf the data buffer to place result in, of type eBufDataType.
    1362                 :  * @param eBufDataType the type of the output data buffer.  For now this
    1363                 :  * must match GDALWarpOptions::eWorkingDataType. 
    1364                 :  * @param nSrcXOff source window X offset (computed if window all zero)
    1365                 :  * @param nSrcYOff source window Y offset (computed if window all zero)
    1366                 :  * @param nSrcXSize source window X size (computed if window all zero)
    1367                 :  * @param nSrcYSize source window Y size (computed if window all zero)
    1368                 :  *
    1369                 :  * @return CE_None on success or CE_Failure if an error occurs.
    1370                 :  */
    1371                 :                                  
    1372                 : CPLErr GDALWarpOperation::WarpRegionToBuffer( 
    1373                 :     int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize, 
    1374                 :     void *pDataBuf, GDALDataType eBufDataType,
    1375             539 :     int nSrcXOff, int nSrcYOff, int nSrcXSize, int nSrcYSize )
    1376                 : 
    1377                 : {
    1378             539 :     CPLErr eErr = CE_None;
    1379                 :     int    i;
    1380             539 :     int    nWordSize = GDALGetDataTypeSize(psOptions->eWorkingDataType)/8;
    1381                 : 
    1382                 :     (void) eBufDataType;
    1383             539 :     CPLAssert( eBufDataType == psOptions->eWorkingDataType );
    1384                 : 
    1385                 : /* -------------------------------------------------------------------- */
    1386                 : /*      If not given a corresponding source window compute one now.     */
    1387                 : /* -------------------------------------------------------------------- */
    1388             539 :     if( nSrcXSize == 0 && nSrcYSize == 0 )
    1389                 :     {
    1390                 :         eErr = ComputeSourceWindow( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1391                 :                                     &nSrcXOff, &nSrcYOff, 
    1392              69 :                                     &nSrcXSize, &nSrcYSize );
    1393                 :     
    1394              69 :         if( eErr != CE_None )
    1395               0 :             return eErr;
    1396                 :     }
    1397                 : 
    1398                 : /* -------------------------------------------------------------------- */
    1399                 : /*      Prepare a WarpKernel object to match this operation.            */
    1400                 : /* -------------------------------------------------------------------- */
    1401             539 :     GDALWarpKernel   oWK;
    1402                 : 
    1403             539 :     oWK.eResample = psOptions->eResampleAlg;
    1404             539 :     oWK.nBands = psOptions->nBandCount;
    1405             539 :     oWK.eWorkingDataType = psOptions->eWorkingDataType;
    1406                 : 
    1407             539 :     oWK.pfnTransformer = psOptions->pfnTransformer;
    1408             539 :     oWK.pTransformerArg = psOptions->pTransformerArg;
    1409                 :     
    1410             539 :     oWK.pfnProgress = psOptions->pfnProgress;
    1411             539 :     oWK.pProgress = psOptions->pProgressArg;
    1412             539 :     oWK.dfProgressBase = dfProgressBase;
    1413             539 :     oWK.dfProgressScale = dfProgressScale;
    1414                 : 
    1415             539 :     oWK.papszWarpOptions = psOptions->papszWarpOptions;
    1416                 :     
    1417             539 :     oWK.padfDstNoDataReal = psOptions->padfDstNoDataReal;
    1418                 : 
    1419                 : /* -------------------------------------------------------------------- */
    1420                 : /*      Setup the source buffer.                                        */
    1421                 : /*                                                                      */
    1422                 : /*      Eventually we may need to take advantage of pixel               */
    1423                 : /*      interleaved reading here.                                       */
    1424                 : /* -------------------------------------------------------------------- */
    1425             539 :     oWK.nSrcXOff = nSrcXOff;
    1426             539 :     oWK.nSrcYOff = nSrcYOff;
    1427             539 :     oWK.nSrcXSize = nSrcXSize;
    1428             539 :     oWK.nSrcYSize = nSrcYSize;
    1429                 : 
    1430             539 :     if (nSrcXSize != 0 && nSrcYSize != 0 &&
    1431                 :         (nSrcXSize > INT_MAX / nSrcYSize ||
    1432                 :          nSrcXSize * nSrcYSize > INT_MAX / (nWordSize * psOptions->nBandCount)))
    1433                 :     {
    1434                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1435                 :                   "Integer overflow : nSrcXSize=%d, nSrcYSize=%d",
    1436               0 :                   nSrcXSize, nSrcYSize);
    1437             539 :         return CE_Failure;
    1438                 :     }
    1439                 : 
    1440                 :     oWK.papabySrcImage = (GByte **) 
    1441             539 :         CPLCalloc(sizeof(GByte*),psOptions->nBandCount);
    1442                 :     oWK.papabySrcImage[0] = (GByte *)
    1443             539 :         VSIMalloc( nWordSize * nSrcXSize * nSrcYSize * psOptions->nBandCount );
    1444                 : 
    1445             539 :     if( nSrcXSize != 0 && nSrcYSize != 0 && oWK.papabySrcImage[0] == NULL )
    1446                 :     {
    1447                 :         CPLError( CE_Failure, CPLE_OutOfMemory, 
    1448                 :                   "Failed to allocate %d byte source buffer.",
    1449               0 :                   nWordSize * nSrcXSize * nSrcYSize * psOptions->nBandCount );
    1450               0 :         eErr = CE_Failure;
    1451                 :     }
    1452                 :         
    1453            1134 :     for( i = 0; i < psOptions->nBandCount && eErr == CE_None; i++ )
    1454                 :         oWK.papabySrcImage[i] = ((GByte *) oWK.papabySrcImage[0])
    1455             595 :             + nWordSize * nSrcXSize * nSrcYSize * i;
    1456                 : 
    1457             539 :     if( eErr == CE_None && nSrcXSize > 0 && nSrcYSize > 0 )
    1458                 :         eErr = 
    1459                 :             GDALDatasetRasterIO( psOptions->hSrcDS, GF_Read, 
    1460                 :                                  nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize, 
    1461                 :                                  oWK.papabySrcImage[0], nSrcXSize, nSrcYSize,
    1462                 :                                  psOptions->eWorkingDataType, 
    1463                 :                                  psOptions->nBandCount, psOptions->panSrcBands,
    1464             538 :                                  0, 0, 0 );
    1465                 : 
    1466             539 :     ReportTiming( "Input buffer read" );
    1467                 : 
    1468                 : /* -------------------------------------------------------------------- */
    1469                 : /*      Initialize destination buffer.                                  */
    1470                 : /* -------------------------------------------------------------------- */
    1471             539 :     oWK.nDstXOff = nDstXOff;
    1472             539 :     oWK.nDstYOff = nDstYOff;
    1473             539 :     oWK.nDstXSize = nDstXSize;
    1474             539 :     oWK.nDstYSize = nDstYSize;
    1475                 : 
    1476                 :     oWK.papabyDstImage = (GByte **) 
    1477             539 :         CPLCalloc(sizeof(GByte*),psOptions->nBandCount);
    1478                 : 
    1479            1134 :     for( i = 0; i < psOptions->nBandCount && eErr == CE_None; i++ )
    1480                 :     {
    1481                 :         oWK.papabyDstImage[i] = ((GByte *) pDataBuf)
    1482             595 :             + i * nDstXSize * nDstYSize * nWordSize;
    1483                 :     }
    1484                 : 
    1485                 : /* -------------------------------------------------------------------- */
    1486                 : /*      Eventually we need handling for a whole bunch of the            */
    1487                 : /*      validity and density masks here.                                */
    1488                 : /* -------------------------------------------------------------------- */
    1489                 :     
    1490                 :     /* TODO */
    1491                 : 
    1492                 : /* -------------------------------------------------------------------- */
    1493                 : /*      Generate a source density mask if we have a source alpha band   */
    1494                 : /* -------------------------------------------------------------------- */
    1495             539 :     if( eErr == CE_None && psOptions->nSrcAlphaBand > 0 )
    1496                 :     {
    1497               8 :         CPLAssert( oWK.pafDstDensity == NULL );
    1498                 : 
    1499               8 :         eErr = CreateKernelMask( &oWK, 0, "UnifiedSrcDensity" );
    1500                 :         
    1501               8 :         if( eErr == CE_None )
    1502                 :             eErr = 
    1503                 :                 GDALWarpSrcAlphaMasker( psOptions, 
    1504                 :                                         psOptions->nBandCount, 
    1505                 :                                         psOptions->eWorkingDataType,
    1506                 :                                         oWK.nSrcXOff, oWK.nSrcYOff, 
    1507                 :                                         oWK.nSrcXSize, oWK.nSrcYSize,
    1508                 :                                         oWK.papabySrcImage,
    1509               8 :                                         TRUE, oWK.pafUnifiedSrcDensity );
    1510                 :     }
    1511                 :     
    1512                 : /* -------------------------------------------------------------------- */
    1513                 : /*      Generate a source density mask if we have a source cutline.     */
    1514                 : /* -------------------------------------------------------------------- */
    1515             539 :     if( eErr == CE_None && psOptions->hCutline != NULL )
    1516                 :     {
    1517               6 :         if( oWK.pafUnifiedSrcDensity == NULL )
    1518                 :         {
    1519               6 :             int j = oWK.nSrcXSize * oWK.nSrcYSize;
    1520                 : 
    1521               6 :             eErr = CreateKernelMask( &oWK, 0, "UnifiedSrcDensity" );
    1522                 : 
    1523               6 :             if( eErr == CE_None )
    1524                 :             {
    1525           60006 :                 for( j = oWK.nSrcXSize * oWK.nSrcYSize - 1; j >= 0; j-- )
    1526           60000 :                     oWK.pafUnifiedSrcDensity[j] = 1.0;
    1527                 :             }
    1528                 :         }
    1529                 :         
    1530               6 :         if( eErr == CE_None )
    1531                 :             eErr = 
    1532                 :                 GDALWarpCutlineMasker( psOptions, 
    1533                 :                                        psOptions->nBandCount, 
    1534                 :                                        psOptions->eWorkingDataType,
    1535                 :                                        oWK.nSrcXOff, oWK.nSrcYOff, 
    1536                 :                                        oWK.nSrcXSize, oWK.nSrcYSize,
    1537                 :                                        oWK.papabySrcImage,
    1538               6 :                                        TRUE, oWK.pafUnifiedSrcDensity );
    1539                 :     }
    1540                 :     
    1541                 : /* -------------------------------------------------------------------- */
    1542                 : /*      Generate a destination density mask if we have a destination    */
    1543                 : /*      alpha band.                                                     */
    1544                 : /* -------------------------------------------------------------------- */
    1545             539 :     if( eErr == CE_None && psOptions->nDstAlphaBand > 0 )
    1546                 :     {
    1547              10 :         CPLAssert( oWK.pafDstDensity == NULL );
    1548                 : 
    1549              10 :         eErr = CreateKernelMask( &oWK, i, "DstDensity" );
    1550                 :         
    1551              10 :         if( eErr == CE_None )
    1552                 :             eErr = 
    1553                 :                 GDALWarpDstAlphaMasker( psOptions, 
    1554                 :                                         psOptions->nBandCount, 
    1555                 :                                         psOptions->eWorkingDataType,
    1556                 :                                         oWK.nDstXOff, oWK.nDstYOff, 
    1557                 :                                         oWK.nDstXSize, oWK.nDstYSize,
    1558                 :                                         oWK.papabyDstImage,
    1559              10 :                                         TRUE, oWK.pafDstDensity );
    1560                 :     }
    1561                 :     
    1562                 : /* -------------------------------------------------------------------- */
    1563                 : /*      If we have source nodata values create, or update the           */
    1564                 : /*      validity mask.                                                  */
    1565                 : /* -------------------------------------------------------------------- */
    1566             539 :     if( eErr == CE_None && psOptions->padfSrcNoDataReal != NULL )
    1567                 :     {
    1568              28 :         for( i = 0; i < psOptions->nBandCount && eErr == CE_None; i++ )
    1569                 :         {
    1570              16 :             eErr = CreateKernelMask( &oWK, i, "BandSrcValid" );
    1571              16 :             if( eErr == CE_None )
    1572                 :             {
    1573                 :                 double adfNoData[2];
    1574                 : 
    1575              16 :                 adfNoData[0] = psOptions->padfSrcNoDataReal[i];
    1576              16 :                 adfNoData[1] = psOptions->padfSrcNoDataImag[i];
    1577                 : 
    1578                 :                 eErr = 
    1579                 :                     GDALWarpNoDataMasker( adfNoData, 1, 
    1580                 :                                           psOptions->eWorkingDataType,
    1581                 :                                           oWK.nSrcXOff, oWK.nSrcYOff, 
    1582                 :                                           oWK.nSrcXSize, oWK.nSrcYSize,
    1583                 :                                           &(oWK.papabySrcImage[i]),
    1584              16 :                                           FALSE, oWK.papanBandSrcValid[i] );
    1585                 :             }
    1586                 :         }
    1587                 :         
    1588                 : /* -------------------------------------------------------------------- */
    1589                 : /*      If UNIFIED_SRC_NODATA is set, then compute a unified input      */
    1590                 : /*      pixel mask if and only if all bands nodata is true.  That       */
    1591                 : /*      is, we only treat a pixel as nodata if all bands match their    */
    1592                 : /*      respective nodata values.                                       */
    1593                 : /* -------------------------------------------------------------------- */
    1594              12 :         if( CSLFetchBoolean( psOptions->papszWarpOptions, "UNIFIED_SRC_NODATA",
    1595                 :                              FALSE ) 
    1596                 :             && eErr == CE_None )
    1597                 :         {
    1598               2 :             int nBytesInMask = (oWK.nSrcXSize * oWK.nSrcYSize + 31) / 8;
    1599                 :             int iWord;
    1600                 : 
    1601               2 :             eErr = CreateKernelMask( &oWK, i, "UnifiedSrcValid" );
    1602                 : 
    1603               2 :             memset( oWK.panUnifiedSrcValid, 0, nBytesInMask );
    1604                 :             
    1605               6 :             for( i = 0; i < psOptions->nBandCount; i++ )
    1606                 :             {
    1607             254 :                 for( iWord = nBytesInMask/4 - 1; iWord >= 0; iWord-- )
    1608                 :                     oWK.panUnifiedSrcValid[iWord] |= 
    1609             250 :                         oWK.papanBandSrcValid[i][iWord];
    1610               4 :                 CPLFree( oWK.papanBandSrcValid[i] );
    1611               4 :                 oWK.papanBandSrcValid[i] = NULL;
    1612                 :             }
    1613                 :             
    1614               2 :             CPLFree( oWK.papanBandSrcValid );
    1615               2 :             oWK.papanBandSrcValid = NULL;
    1616                 :         }
    1617                 :     }
    1618                 : 
    1619                 : /* -------------------------------------------------------------------- */
    1620                 : /*      If we have destination nodata values create, or update the      */
    1621                 : /*      validity mask.  We clear the DstValid for any pixel that we     */
    1622                 : /*      do no have valid data in *any* of the source bands.             */
    1623                 : /*                                                                      */
    1624                 : /*      Note that we don't support any concept of unified nodata on     */
    1625                 : /*      the destination image.  At some point that should be added      */
    1626                 : /*      and then this logic will be significantly different.            */
    1627                 : /* -------------------------------------------------------------------- */
    1628             539 :     if( eErr == CE_None && psOptions->padfDstNoDataReal != NULL )
    1629                 :     {
    1630               6 :         GUInt32 *panBandMask = NULL, *panMergedMask = NULL;
    1631               6 :         int     nMaskWords = (oWK.nDstXSize * oWK.nDstYSize + 31)/32;
    1632                 : 
    1633               6 :         eErr = CreateKernelMask( &oWK, 0, "DstValid" );
    1634               6 :         if( eErr == CE_None )
    1635                 :         {
    1636               6 :             panBandMask = (GUInt32 *) CPLMalloc(nMaskWords*4);
    1637               6 :             panMergedMask = (GUInt32 *) CPLCalloc(nMaskWords,4);
    1638                 :         }
    1639                 : 
    1640               6 :         if( eErr == CE_None && panBandMask != NULL )
    1641                 :         {
    1642                 :             int iBand, iWord;
    1643                 :             
    1644              12 :             for( iBand = 0; iBand < psOptions->nBandCount; iBand++ )
    1645                 :             {
    1646                 :                 double adfNoData[2];
    1647                 :             
    1648               6 :                 memset( panBandMask, 0xff, nMaskWords * 4 );
    1649                 : 
    1650               6 :                 adfNoData[0] = psOptions->padfDstNoDataReal[iBand];
    1651               6 :                 adfNoData[1] = psOptions->padfDstNoDataImag[iBand];
    1652                 :             
    1653                 :                 eErr = 
    1654                 :                     GDALWarpNoDataMasker( adfNoData, 1, 
    1655                 :                                           psOptions->eWorkingDataType,
    1656                 :                                           oWK.nDstXOff, oWK.nDstYOff, 
    1657                 :                                           oWK.nDstXSize, oWK.nDstYSize,
    1658                 :                                           oWK.papabyDstImage + iBand,
    1659               6 :                                           FALSE, panBandMask );
    1660                 : 
    1661           10260 :                 for( iWord = nMaskWords - 1; iWord >= 0; iWord-- )
    1662           10254 :                     panMergedMask[iWord] |= panBandMask[iWord];
    1663                 :             }
    1664               6 :             CPLFree( panBandMask );
    1665                 : 
    1666           10260 :             for( iWord = nMaskWords - 1; iWord >= 0; iWord-- )
    1667           10254 :                 oWK.panDstValid[iWord] &= panMergedMask[iWord];
    1668                 : 
    1669               6 :             CPLFree( panMergedMask );
    1670                 :         }
    1671                 :     }
    1672                 :         
    1673                 : /* -------------------------------------------------------------------- */
    1674                 : /*      Release IO Mutex, and acquire warper mutex.                     */
    1675                 : /* -------------------------------------------------------------------- */
    1676             539 :     if( hIOMutex != NULL )
    1677                 :     {
    1678               1 :         CPLReleaseMutex( hIOMutex );
    1679               1 :         if( !CPLAcquireMutex( hWarpMutex, 600.0 ) )
    1680                 :         {
    1681                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1682               0 :                       "Failed to acquire WarpMutex in WarpRegion()." );
    1683               0 :             return CE_Failure;
    1684                 :         }
    1685                 :     }
    1686                 : 
    1687                 : /* -------------------------------------------------------------------- */
    1688                 : /*      Optional application provided prewarp chunk processor.          */
    1689                 : /* -------------------------------------------------------------------- */
    1690             539 :     if( eErr == CE_None && psOptions->pfnPreWarpChunkProcessor != NULL )
    1691                 :         eErr = psOptions->pfnPreWarpChunkProcessor( 
    1692               0 :             (void *) &oWK, psOptions->pPreWarpProcessorArg );
    1693                 : 
    1694                 : /* -------------------------------------------------------------------- */
    1695                 : /*      Perform the warp.                                               */
    1696                 : /* -------------------------------------------------------------------- */
    1697             539 :     if( eErr == CE_None )
    1698                 :     {
    1699             539 :         eErr = oWK.PerformWarp();
    1700             539 :         ReportTiming( "In memory warp operation" );
    1701                 :     }
    1702                 : 
    1703                 : /* -------------------------------------------------------------------- */
    1704                 : /*      Optional application provided postwarp chunk processor.         */
    1705                 : /* -------------------------------------------------------------------- */
    1706             539 :     if( eErr == CE_None && psOptions->pfnPostWarpChunkProcessor != NULL )
    1707                 :         eErr = psOptions->pfnPostWarpChunkProcessor( 
    1708               0 :             (void *) &oWK, psOptions->pPostWarpProcessorArg );
    1709                 : 
    1710                 : /* -------------------------------------------------------------------- */
    1711                 : /*      Release Warp Mutex, and acquire io mutex.                       */
    1712                 : /* -------------------------------------------------------------------- */
    1713             539 :     if( hIOMutex != NULL )
    1714                 :     {
    1715               1 :         CPLReleaseMutex( hWarpMutex );
    1716               1 :         if( !CPLAcquireMutex( hIOMutex, 600.0 ) )
    1717                 :         {
    1718                 :             CPLError( CE_Failure, CPLE_AppDefined, 
    1719               0 :                       "Failed to acquire IOMutex in WarpRegion()." );
    1720               0 :             return CE_Failure;
    1721                 :         }
    1722                 :     }
    1723                 :         
    1724                 : /* -------------------------------------------------------------------- */
    1725                 : /*      Write destination alpha if available.                           */
    1726                 : /* -------------------------------------------------------------------- */
    1727             539 :     if( eErr == CE_None && psOptions->nDstAlphaBand > 0 )
    1728                 :     {
    1729                 :         eErr = 
    1730                 :             GDALWarpDstAlphaMasker( psOptions, 
    1731                 :                                     -psOptions->nBandCount, 
    1732                 :                                     psOptions->eWorkingDataType,
    1733                 :                                     oWK.nDstXOff, oWK.nDstYOff, 
    1734                 :                                     oWK.nDstXSize, oWK.nDstYSize,
    1735                 :                                     oWK.papabyDstImage,
    1736              10 :                                     TRUE, oWK.pafDstDensity );
    1737                 :     }
    1738                 :     
    1739                 : /* -------------------------------------------------------------------- */
    1740                 : /*      Cleanup.                                                        */
    1741                 : /* -------------------------------------------------------------------- */
    1742             539 :     CPLFree( oWK.papabySrcImage[0] );
    1743             539 :     CPLFree( oWK.papabySrcImage );
    1744             539 :     CPLFree( oWK.papabyDstImage );
    1745                 : 
    1746             539 :     if( oWK.papanBandSrcValid != NULL )
    1747                 :     {
    1748              22 :         for( i = 0; i < oWK.nBands; i++ )
    1749              12 :             CPLFree( oWK.papanBandSrcValid[i] );
    1750              10 :         CPLFree( oWK.papanBandSrcValid );
    1751                 :     }
    1752             539 :     CPLFree( oWK.panUnifiedSrcValid );
    1753             539 :     CPLFree( oWK.pafUnifiedSrcDensity );
    1754             539 :     CPLFree( oWK.panDstValid );
    1755             539 :     CPLFree( oWK.pafDstDensity );
    1756                 :     
    1757             539 :     return eErr;
    1758                 : }
    1759                 : 
    1760                 : /************************************************************************/
    1761                 : /*                            GDALWarpRegionToBuffer()                  */
    1762                 : /************************************************************************/
    1763                 : 
    1764                 : /**
    1765                 :  * @see GDALWarpOperation::WarpRegionToBuffer()
    1766                 :  */
    1767                 :                                  
    1768                 : CPLErr GDALWarpRegionToBuffer( GDALWarpOperationH hOperation,
    1769                 :     int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize, 
    1770                 :     void *pDataBuf, GDALDataType eBufDataType,
    1771               0 :     int nSrcXOff, int nSrcYOff, int nSrcXSize, int nSrcYSize )
    1772                 : 
    1773                 : {
    1774               0 :     VALIDATE_POINTER1( hOperation, "GDALWarpRegionToBuffer", CE_Failure );
    1775                 : 
    1776                 :     return ( (GDALWarpOperation *)hOperation )->
    1777                 :         WarpRegionToBuffer( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
    1778                 :                             pDataBuf, eBufDataType,
    1779               0 :                             nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize );
    1780                 : }
    1781                 : 
    1782                 : /************************************************************************/
    1783                 : /*                          CreateKernelMask()                          */
    1784                 : /*                                                                      */
    1785                 : /*      If mask does not yet exist, create it.  Supported types are     */
    1786                 : /*      the name of the variable in question.  That is                  */
    1787                 : /*      "BandSrcValid", "UnifiedSrcValid", "UnifiedSrcDensity",         */
    1788                 : /*      "DstValid", and "DstDensity".                                   */
    1789                 : /************************************************************************/
    1790                 : 
    1791                 : CPLErr GDALWarpOperation::CreateKernelMask( GDALWarpKernel *poKernel,
    1792              48 :                                             int iBand, const char *pszType )
    1793                 : 
    1794                 : {
    1795                 :     void **ppMask;
    1796                 :     int  nXSize, nYSize, nBitsPerPixel, nDefault;
    1797                 : 
    1798                 : /* -------------------------------------------------------------------- */
    1799                 : /*      Get particulars of mask to be updated.                          */
    1800                 : /* -------------------------------------------------------------------- */
    1801              48 :     if( EQUAL(pszType,"BandSrcValid") )
    1802                 :     {
    1803              16 :         if( poKernel->papanBandSrcValid == NULL )
    1804                 :             poKernel->papanBandSrcValid = (GUInt32 **)
    1805              12 :                 CPLCalloc( sizeof(void*),poKernel->nBands);
    1806                 :                 
    1807              16 :         ppMask = (void **) &(poKernel->papanBandSrcValid[iBand]);
    1808              16 :         nXSize = poKernel->nSrcXSize;
    1809              16 :         nYSize = poKernel->nSrcYSize;
    1810              16 :         nBitsPerPixel = 1;
    1811              16 :         nDefault = 0xff;
    1812                 :     }
    1813              32 :     else if( EQUAL(pszType,"UnifiedSrcValid") )
    1814                 :     {
    1815               2 :         ppMask = (void **) &(poKernel->panUnifiedSrcValid);
    1816               2 :         nXSize = poKernel->nSrcXSize;
    1817               2 :         nYSize = poKernel->nSrcYSize;
    1818               2 :         nBitsPerPixel = 1;
    1819               2 :         nDefault = 0xff;
    1820                 :     }
    1821              30 :     else if( EQUAL(pszType,"UnifiedSrcDensity") )
    1822                 :     {
    1823              14 :         ppMask = (void **) &(poKernel->pafUnifiedSrcDensity);
    1824              14 :         nXSize = poKernel->nSrcXSize;
    1825              14 :         nYSize = poKernel->nSrcYSize;
    1826              14 :         nBitsPerPixel = 32;
    1827              14 :         nDefault = 0;
    1828                 :     }
    1829              16 :     else if( EQUAL(pszType,"DstValid") )
    1830                 :     {
    1831               6 :         ppMask = (void **) &(poKernel->panDstValid);
    1832               6 :         nXSize = poKernel->nDstXSize;
    1833               6 :         nYSize = poKernel->nDstYSize;
    1834               6 :         nBitsPerPixel = 1;
    1835               6 :         nDefault = 0xff;
    1836                 :     }
    1837              10 :     else if( EQUAL(pszType,"DstDensity") )
    1838                 :     {
    1839              10 :         ppMask = (void **) &(poKernel->pafDstDensity);
    1840              10 :         nXSize = poKernel->nDstXSize;
    1841              10 :         nYSize = poKernel->nDstYSize;
    1842              10 :         nBitsPerPixel = 32;
    1843              10 :         nDefault = 0;
    1844                 :     }
    1845                 :     else
    1846                 :     {
    1847                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1848                 :                   "Internal error in CreateKernelMask(%s).",
    1849               0 :                   pszType );
    1850               0 :         return CE_Failure;
    1851                 :     }
    1852                 : 
    1853                 : /* -------------------------------------------------------------------- */
    1854                 : /*      Allocate if needed.                                             */
    1855                 : /* -------------------------------------------------------------------- */
    1856              48 :     if( *ppMask == NULL )
    1857                 :     {
    1858                 :         int nBytes;
    1859                 : 
    1860              48 :         if( nBitsPerPixel == 32 )
    1861              24 :             nBytes = nXSize * nYSize * 4;
    1862                 :         else
    1863              24 :             nBytes = (nXSize * nYSize + 31) / 8;
    1864                 : 
    1865              48 :         *ppMask = VSIMalloc( nBytes );
    1866                 : 
    1867              48 :         if( *ppMask == NULL )
    1868                 :         {
    1869                 :             CPLError( CE_Failure, CPLE_OutOfMemory, 
    1870                 :                       "Out of memory allocating %d bytes for %s mask.", 
    1871               0 :                       nBytes, pszType );
    1872               0 :             return CE_Failure;
    1873                 :         }
    1874                 : 
    1875              48 :         memset( *ppMask, nDefault, nBytes );
    1876                 :     }
    1877                 : 
    1878              48 :     return CE_None;
    1879                 : }
    1880                 : 
    1881                 : 
    1882                 : 
    1883                 : /************************************************************************/
    1884                 : /*                        ComputeSourceWindow()                         */
    1885                 : /************************************************************************/
    1886                 : 
    1887                 : CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff, 
    1888                 :                                               int nDstXSize, int nDstYSize,
    1889                 :                                               int *pnSrcXOff, int *pnSrcYOff, 
    1890             731 :                                               int *pnSrcXSize, int *pnSrcYSize)
    1891                 : 
    1892                 : {
    1893                 : /* -------------------------------------------------------------------- */
    1894                 : /*      Figure out whether we just want to do the usual "along the      */
    1895                 : /*      edge" sampling, or using a grid.  The grid usage is             */
    1896                 : /*      important in some weird "inside out" cases like WGS84 to        */
    1897                 : /*      polar stereographic around the pole.   Also figure out the      */
    1898                 : /*      sampling rate.                                                  */
    1899                 : /* -------------------------------------------------------------------- */
    1900                 :     double dfStepSize;
    1901             731 :     int nSampleMax, nStepCount = 21, bUseGrid;
    1902             731 :     int *pabSuccess = NULL;
    1903                 :     double *padfX, *padfY, *padfZ;
    1904                 :     int    nSamplePoints;
    1905                 :     double dfRatio;
    1906                 : 
    1907             731 :     if( CSLFetchNameValue( psOptions->papszWarpOptions, 
    1908                 :                            "SAMPLE_STEPS" ) != NULL )
    1909                 :     {
    1910                 :         nStepCount = 
    1911                 :             atoi(CSLFetchNameValue( psOptions->papszWarpOptions, 
    1912               0 :                                     "SAMPLE_STEPS" ));
    1913               0 :         nStepCount = MAX(2,nStepCount);
    1914                 :     }
    1915                 : 
    1916             731 :     dfStepSize = 1.0 / (nStepCount-1);
    1917                 : 
    1918                 :     bUseGrid = CSLFetchBoolean( psOptions->papszWarpOptions, 
    1919             731 :                                 "SAMPLE_GRID", FALSE );
    1920                 : 
    1921             736 :   TryAgainWithGrid:
    1922             736 :     nSamplePoints = 0;
    1923             736 :     if( bUseGrid )
    1924                 :     {
    1925               5 :         if (nStepCount > INT_MAX / nStepCount)
    1926                 :         {
    1927                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1928               0 :                       "Too many steps : %d", nStepCount);
    1929               0 :             return CE_Failure;
    1930                 :         }
    1931               5 :         nSampleMax = nStepCount * nStepCount;
    1932                 :     }
    1933                 :     else
    1934                 :     {
    1935             731 :         if (nStepCount > INT_MAX / 4)
    1936                 :         {
    1937                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1938               0 :                       "Too many steps : %d", nStepCount);
    1939               0 :             return CE_Failure;
    1940                 :         }
    1941             731 :         nSampleMax = nStepCount * 4;
    1942                 :     }
    1943                 : 
    1944             736 :     pabSuccess = (int *) VSIMalloc2(sizeof(int), nSampleMax);
    1945             736 :     padfX = (double *) VSIMalloc2(sizeof(double) * 3, nSampleMax);
    1946             736 :     if (pabSuccess == NULL || padfX == NULL)
    1947                 :     {
    1948               0 :         CPLFree( padfX );
    1949               0 :         CPLFree( pabSuccess );
    1950               0 :         return CE_Failure;
    1951                 :     }
    1952             736 :     padfY = padfX + nSampleMax;
    1953             736 :     padfZ = padfX + nSampleMax * 2;
    1954                 : 
    1955                 : /* -------------------------------------------------------------------- */
    1956                 : /*      Setup sample points on a grid pattern throughout the area.      */
    1957                 : /* -------------------------------------------------------------------- */
    1958             736 :     if( bUseGrid )
    1959                 :     {
    1960                 :         double dfRatioY;
    1961                 : 
    1962             110 :         for( dfRatioY = 0.0; 
    1963                 :              dfRatioY <= 1.0 + dfStepSize*0.5; 
    1964                 :              dfRatioY += dfStepSize )
    1965                 :         {
    1966            2310 :             for( dfRatio = 0.0; 
    1967                 :                  dfRatio <= 1.0 + dfStepSize*0.5; 
    1968                 :                  dfRatio += dfStepSize )
    1969                 :             {
    1970            2205 :                 padfX[nSamplePoints]   = dfRatio * nDstXSize + nDstXOff;
    1971            2205 :                 padfY[nSamplePoints]   = dfRatioY * nDstYSize + nDstYOff;
    1972            2205 :                 padfZ[nSamplePoints++] = 0.0;
    1973                 :             }
    1974                 :         }
    1975                 :     }
    1976                 :  /* -------------------------------------------------------------------- */
    1977                 :  /*      Setup sample points all around the edge of the output raster.   */
    1978                 :  /* -------------------------------------------------------------------- */
    1979                 :     else
    1980                 :     {
    1981           16082 :         for( dfRatio = 0.0; dfRatio <= 1.0 + dfStepSize*0.5; dfRatio += dfStepSize )
    1982                 :         {
    1983                 :             // Along top 
    1984           15351 :             padfX[nSamplePoints]   = dfRatio * nDstXSize + nDstXOff;
    1985           15351 :             padfY[nSamplePoints]   = nDstYOff;
    1986           15351 :             padfZ[nSamplePoints++] = 0.0;
    1987                 :             
    1988                 :             // Along bottom 
    1989           15351 :             padfX[nSamplePoints]   = dfRatio * nDstXSize + nDstXOff;
    1990           15351 :             padfY[nSamplePoints]   = nDstYOff + nDstYSize;
    1991           15351 :             padfZ[nSamplePoints++] = 0.0;
    1992                 :             
    1993                 :             // Along left
    1994           15351 :             padfX[nSamplePoints]   = nDstXOff;
    1995           15351 :             padfY[nSamplePoints]   = dfRatio * nDstYSize + nDstYOff;
    1996           15351 :             padfZ[nSamplePoints++] = 0.0;
    1997                 :             
    1998                 :             // Along right
    1999           15351 :             padfX[nSamplePoints]   = nDstXSize + nDstXOff;
    2000           15351 :             padfY[nSamplePoints]   = dfRatio * nDstYSize + nDstYOff;
    2001           15351 :             padfZ[nSamplePoints++] = 0.0;
    2002                 :         }
    2003                 :     }
    2004                 :         
    2005             736 :     CPLAssert( nSamplePoints == nSampleMax );
    2006                 : 
    2007                 : /* -------------------------------------------------------------------- */
    2008                 : /*      Transform them to the input pixel coordinate space              */
    2009                 : /* -------------------------------------------------------------------- */
    2010             736 :     if( !psOptions->pfnTransformer( psOptions->pTransformerArg, 
    2011                 :                                     TRUE, nSamplePoints, 
    2012                 :                                     padfX, padfY, padfZ, pabSuccess ) )
    2013                 :     {
    2014               0 :         CPLFree( padfX );
    2015               0 :         CPLFree( pabSuccess );
    2016                 : 
    2017                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2018                 :                   "GDALWarperOperation::ComputeSourceWindow() failed because\n"
    2019               0 :                   "the pfnTransformer failed." );
    2020               0 :         return CE_Failure;
    2021                 :     }
    2022                 :         
    2023                 : /* -------------------------------------------------------------------- */
    2024                 : /*      Collect the bounds, ignoring any failed points.                 */
    2025                 : /* -------------------------------------------------------------------- */
    2026             736 :     double dfMinXOut=0.0, dfMinYOut=0.0, dfMaxXOut=0.0, dfMaxYOut=0.0;
    2027             736 :     int    bGotInitialPoint = FALSE;
    2028             736 :     int    nFailedCount = 0, i;
    2029                 : 
    2030           64345 :     for( i = 0; i < nSamplePoints; i++ )
    2031                 :     {
    2032           63609 :         if( !pabSuccess[i] )
    2033                 :         {
    2034            1341 :             nFailedCount++;
    2035            1341 :             continue;
    2036                 :         }
    2037                 : 
    2038           62268 :         if( !bGotInitialPoint )
    2039                 :         {
    2040             735 :             bGotInitialPoint = TRUE;
    2041             735 :             dfMinXOut = dfMaxXOut = padfX[i];
    2042             735 :             dfMinYOut = dfMaxYOut = padfY[i];
    2043                 :         }
    2044                 :         else
    2045                 :         {
    2046           61533 :             dfMinXOut = MIN(dfMinXOut,padfX[i]);
    2047           61533 :             dfMinYOut = MIN(dfMinYOut,padfY[i]);
    2048           61533 :             dfMaxXOut = MAX(dfMaxXOut,padfX[i]);
    2049           61533 :             dfMaxYOut = MAX(dfMaxYOut,padfY[i]);
    2050                 :         }
    2051                 :     }
    2052                 : 
    2053             736 :     CPLFree( padfX );
    2054             736 :     CPLFree( pabSuccess );
    2055                 : 
    2056                 : /* -------------------------------------------------------------------- */
    2057                 : /*      If we got any failures when not using a grid, we should         */
    2058                 : /*      really go back and try again with the grid.  Sorry for the      */
    2059                 : /*      goto.                                                           */
    2060                 : /* -------------------------------------------------------------------- */
    2061             736 :     if( !bUseGrid && nFailedCount > 0 )
    2062                 :     {
    2063               5 :         bUseGrid = TRUE;
    2064               5 :         goto TryAgainWithGrid;
    2065                 :     }
    2066                 : 
    2067                 : /* -------------------------------------------------------------------- */
    2068                 : /*      If we get hardly any points (or none) transforming, we give     */
    2069                 : /*      up.                                                             */
    2070                 : /* -------------------------------------------------------------------- */
    2071             731 :     if( nFailedCount > nSamplePoints - 5 )
    2072                 :     {
    2073                 :         CPLError( CE_Failure, CPLE_AppDefined, 
    2074                 :                   "Too many points (%d out of %d) failed to transform,\n"
    2075                 :                   "unable to compute output bounds.",
    2076               0 :                   nFailedCount, nSamplePoints );
    2077               0 :         return CE_Failure;
    2078                 :     }
    2079                 : 
    2080             731 :     if( nFailedCount > 0 )
    2081                 :         CPLDebug( "GDAL", 
    2082                 :                   "GDALWarpOperation::ComputeSourceWindow() %d out of %d points failed to transform.", 
    2083               5 :                   nFailedCount, nSamplePoints );
    2084                 : 
    2085                 : /* -------------------------------------------------------------------- */
    2086                 : /*      How much of a window around our source pixel might we need      */
    2087                 : /*      to collect data from based on the resampling kernel?  Even      */
    2088                 : /*      if the requested central pixel falls off the source image,      */
    2089                 : /*      we may need to collect data if some portion of the              */
    2090                 : /*      resampling kernel could be on-image.                            */
    2091                 : /* -------------------------------------------------------------------- */
    2092             731 :     int nResWinSize = GWKGetFilterRadius(psOptions->eResampleAlg);
    2093                 : 
    2094                 : /* -------------------------------------------------------------------- */
    2095                 : /*      Allow addition of extra sample pixels to source window to       */
    2096                 : /*      avoid missing pixels due to sampling error.  In fact,           */
    2097                 : /*      fallback to adding a bit to the window if any points failed     */
    2098                 : /*      to transform.                                                   */
    2099                 : /* -------------------------------------------------------------------- */
    2100             731 :     if( CSLFetchNameValue( psOptions->papszWarpOptions, 
    2101                 :                            "SOURCE_EXTRA" ) != NULL )
    2102                 :     {
    2103                 :         nResWinSize += atoi(
    2104               0 :             CSLFetchNameValue( psOptions->papszWarpOptions, "SOURCE_EXTRA" ));
    2105                 :     }
    2106             731 :     else if( nFailedCount > 0 )
    2107               5 :         nResWinSize += 10;
    2108                 : 
    2109                 : /* -------------------------------------------------------------------- */
    2110                 : /*      return bounds.                                                  */
    2111                 : /* -------------------------------------------------------------------- */
    2112             731 :     *pnSrcXOff = MAX(0,(int) floor( dfMinXOut ) - nResWinSize );
    2113             731 :     *pnSrcYOff = MAX(0,(int) floor( dfMinYOut ) - nResWinSize );
    2114             731 :     *pnSrcXOff = MIN(*pnSrcXOff,GDALGetRasterXSize(psOptions->hSrcDS));
    2115             731 :     *pnSrcYOff = MIN(*pnSrcYOff,GDALGetRasterYSize(psOptions->hSrcDS));
    2116                 : 
    2117             731 :     *pnSrcXSize = MIN( GDALGetRasterXSize(psOptions->hSrcDS) - *pnSrcXOff,
    2118                 :                        ((int) ceil( dfMaxXOut )) - *pnSrcXOff + nResWinSize );
    2119             731 :     *pnSrcYSize = MIN( GDALGetRasterYSize(psOptions->hSrcDS) - *pnSrcYOff,
    2120                 :                        ((int) ceil( dfMaxYOut )) - *pnSrcYOff + nResWinSize );
    2121             731 :     *pnSrcXSize = MAX(0,*pnSrcXSize);
    2122             731 :     *pnSrcYSize = MAX(0,*pnSrcYSize);
    2123                 : 
    2124                 : 
    2125             731 :     return CE_None;
    2126                 : }
    2127                 : 
    2128                 : /************************************************************************/
    2129                 : /*                            ReportTiming()                            */
    2130                 : /************************************************************************/
    2131                 : 
    2132            2038 : void GDALWarpOperation::ReportTiming( const char * pszMessage )
    2133                 : 
    2134                 : {
    2135            2038 :     if( !bReportTimings )
    2136            2038 :         return;
    2137                 : 
    2138               0 :     unsigned long nNewTime = VSITime(NULL);
    2139                 : 
    2140               0 :     if( pszMessage != NULL )
    2141                 :     {
    2142                 :         CPLDebug( "WARP_TIMING", "%s: %lds", 
    2143               0 :                   pszMessage, (long)(nNewTime - nLastTimeReported) );
    2144                 :     }
    2145                 : 
    2146               0 :     nLastTimeReported = nNewTime;
    2147                 : }
    2148                 : 

Generated by: LTP GCOV extension version 1.5