LCOV - code coverage report
Current view: directory - alg - gdalwarpoperation.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 687 530 77.1 %
Date: 2012-04-28 Functions: 26 18 69.2 %

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

Generated by: LCOV version 1.7