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