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