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 :
|