LCOV - code coverage report
Current view: directory - alg - gdalwarpoperation.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 689 539 78.2 %
Date: 2012-12-26 Functions: 26 18 69.2 %

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

Generated by: LCOV version 1.7