1 : /******************************************************************************
2 : * $Id: gdalwarpkernel.cpp 25304 2012-12-13 21:03:58Z rouault $
3 : *
4 : * Project: High Performance Image Reprojector
5 : * Purpose: Implementation of the GDALWarpKernel class. Implements the actual
6 : * image warping for a "chunk" of input and output imagery already
7 : * loaded into memory.
8 : * Author: Frank Warmerdam, warmerdam@pobox.com
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "gdalwarper.h"
33 : #include "gdal_alg_priv.h"
34 : #include "cpl_string.h"
35 : #include "gdalwarpkernel_opencl.h"
36 : #include "cpl_atomic_ops.h"
37 : #include "cpl_multiproc.h"
38 :
39 : CPL_CVSID("$Id: gdalwarpkernel.cpp 25304 2012-12-13 21:03:58Z rouault $");
40 :
41 : static const int anGWKFilterRadius[] =
42 : {
43 : 0, // Nearest neighbour
44 : 1, // Bilinear
45 : 2, // Cubic Convolution
46 : 2, // Cubic B-Spline
47 : 3 // Lanczos windowed sinc
48 : };
49 :
50 : /* Used in gdalwarpoperation.cpp */
51 777 : int GWKGetFilterRadius(GDALResampleAlg eResampleAlg)
52 : {
53 777 : return anGWKFilterRadius[eResampleAlg];
54 : }
55 :
56 : #ifdef HAVE_OPENCL
57 : static CPLErr GWKOpenCLCase( GDALWarpKernel * );
58 : #endif
59 :
60 : static CPLErr GWKGeneralCase( GDALWarpKernel * );
61 : static CPLErr GWKNearestNoMasksByte( GDALWarpKernel *poWK );
62 : static CPLErr GWKBilinearNoMasksByte( GDALWarpKernel *poWK );
63 : static CPLErr GWKCubicNoMasksByte( GDALWarpKernel *poWK );
64 : static CPLErr GWKCubicSplineNoMasksByte( GDALWarpKernel *poWK );
65 : static CPLErr GWKNearestByte( GDALWarpKernel *poWK );
66 : static CPLErr GWKNearestNoMasksShort( GDALWarpKernel *poWK );
67 : static CPLErr GWKBilinearNoMasksShort( GDALWarpKernel *poWK );
68 : static CPLErr GWKCubicNoMasksShort( GDALWarpKernel *poWK );
69 : static CPLErr GWKCubicSplineNoMasksShort( GDALWarpKernel *poWK );
70 : static CPLErr GWKNearestShort( GDALWarpKernel *poWK );
71 : static CPLErr GWKNearestNoMasksFloat( GDALWarpKernel *poWK );
72 : static CPLErr GWKNearestFloat( GDALWarpKernel *poWK );
73 :
74 : /************************************************************************/
75 : /* GWKJobStruct */
76 : /************************************************************************/
77 :
78 : typedef struct _GWKJobStruct GWKJobStruct;
79 :
80 : struct _GWKJobStruct
81 : {
82 : void *hThread;
83 : GDALWarpKernel *poWK;
84 : int iYMin;
85 : int iYMax;
86 : volatile int *pnCounter;
87 : volatile int *pbStop;
88 : void *hCond;
89 : void *hCondMutex;
90 : int (*pfnProgress)(GWKJobStruct* psJob);
91 : void *pTransformerArg;
92 : } ;
93 :
94 : /************************************************************************/
95 : /* GWKProgressThread() */
96 : /************************************************************************/
97 :
98 : /* Return TRUE if the computation must be interrupted */
99 261 : static int GWKProgressThread(GWKJobStruct* psJob)
100 : {
101 261 : CPLAcquireMutex(psJob->hCondMutex, 1.0);
102 262 : (*(psJob->pnCounter)) ++;
103 262 : CPLCondSignal(psJob->hCond);
104 262 : int bStop = *(psJob->pbStop);
105 262 : CPLReleaseMutex(psJob->hCondMutex);
106 :
107 262 : return bStop;
108 : }
109 :
110 : /************************************************************************/
111 : /* GWKProgressMonoThread() */
112 : /************************************************************************/
113 :
114 : /* Return TRUE if the computation must be interrupted */
115 44726 : static int GWKProgressMonoThread(GWKJobStruct* psJob)
116 : {
117 44726 : GDALWarpKernel *poWK = psJob->poWK;
118 44726 : int nCounter = ++(*(psJob->pnCounter));
119 44726 : if( !poWK->pfnProgress( poWK->dfProgressBase + poWK->dfProgressScale *
120 : (nCounter / (double) psJob->iYMax),
121 : "", poWK->pProgress ) )
122 : {
123 1 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
124 1 : *(psJob->pbStop) = TRUE;
125 1 : return TRUE;
126 : }
127 44725 : return FALSE;
128 : }
129 :
130 : /************************************************************************/
131 : /* GWKGenericMonoThread() */
132 : /************************************************************************/
133 :
134 580 : static CPLErr GWKGenericMonoThread( GDALWarpKernel *poWK,
135 : void (*pfnFunc) (void *pUserData) )
136 : {
137 580 : volatile int bStop = FALSE;
138 580 : volatile int nCounter = 0;
139 :
140 : GWKJobStruct sThreadJob;
141 580 : sThreadJob.poWK = poWK;
142 580 : sThreadJob.pnCounter = &nCounter;
143 580 : sThreadJob.iYMin = 0;
144 580 : sThreadJob.iYMax = poWK->nDstYSize;
145 580 : sThreadJob.pbStop = &bStop;
146 580 : sThreadJob.hCond = NULL;
147 580 : sThreadJob.hCondMutex = NULL;
148 580 : sThreadJob.hThread = NULL;
149 580 : sThreadJob.pfnProgress = GWKProgressMonoThread;
150 580 : sThreadJob.pTransformerArg = poWK->pTransformerArg;
151 :
152 580 : pfnFunc(&sThreadJob);
153 :
154 580 : return !bStop ? CE_None : CE_Failure;
155 : }
156 :
157 : /************************************************************************/
158 : /* GWKRun() */
159 : /************************************************************************/
160 :
161 583 : static CPLErr GWKRun( GDALWarpKernel *poWK,
162 : const char* pszFuncName,
163 : void (*pfnFunc) (void *pUserData) )
164 :
165 : {
166 583 : int nDstYSize = poWK->nDstYSize;
167 :
168 : CPLDebug( "GDAL", "GDALWarpKernel()::%s()\n"
169 : "Src=%d,%d,%dx%d Dst=%d,%d,%dx%d",
170 : pszFuncName,
171 : poWK->nSrcXOff, poWK->nSrcYOff,
172 : poWK->nSrcXSize, poWK->nSrcYSize,
173 : poWK->nDstXOff, poWK->nDstYOff,
174 583 : poWK->nDstXSize, poWK->nDstYSize );
175 :
176 583 : if( !poWK->pfnProgress( poWK->dfProgressBase, "", poWK->pProgress ) )
177 : {
178 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
179 0 : return CE_Failure;
180 : }
181 :
182 583 : const char* pszWarpThreads = CSLFetchNameValue(poWK->papszWarpOptions, "NUM_THREADS");
183 : int nThreads;
184 583 : if (pszWarpThreads == NULL)
185 583 : pszWarpThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "1");
186 583 : if (EQUAL(pszWarpThreads, "ALL_CPUS"))
187 1 : nThreads = CPLGetNumCPUs();
188 : else
189 582 : nThreads = atoi(pszWarpThreads);
190 583 : if (nThreads > 128)
191 0 : nThreads = 128;
192 583 : if (nThreads >= nDstYSize / 2)
193 165 : nThreads = nDstYSize / 2;
194 :
195 583 : if (nThreads <= 1)
196 : {
197 580 : return GWKGenericMonoThread(poWK, pfnFunc);
198 : }
199 : else
200 : {
201 : GWKJobStruct* pasThreadJob =
202 3 : (GWKJobStruct*)CPLCalloc(sizeof(GWKJobStruct), nThreads);
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Duplicate pTransformerArg per thread. */
206 : /* -------------------------------------------------------------------- */
207 : int i;
208 3 : int bTransformerCloningSuccess = TRUE;
209 :
210 11 : for(i=0;i<nThreads;i++)
211 : {
212 8 : pasThreadJob[i].pTransformerArg = GDALCloneTransformer(poWK->pTransformerArg);
213 8 : if( pasThreadJob[i].pTransformerArg == NULL )
214 : {
215 0 : CPLDebug("WARP", "Cannot deserialize transformer");
216 0 : bTransformerCloningSuccess = FALSE;
217 0 : break;
218 : }
219 : }
220 :
221 3 : if (!bTransformerCloningSuccess)
222 : {
223 0 : for(i=0;i<nThreads;i++)
224 : {
225 0 : if( pasThreadJob[i].pTransformerArg )
226 0 : GDALDestroyTransformer(pasThreadJob[i].pTransformerArg);
227 : }
228 0 : CPLFree(pasThreadJob);
229 :
230 : CPLDebug("WARP", "Cannot duplicate transformer function. "
231 0 : "Falling back to mono-thread computation");
232 0 : return GWKGenericMonoThread(poWK, pfnFunc);
233 : }
234 :
235 3 : void* hCond = CPLCreateCond();
236 3 : if (hCond == NULL)
237 : {
238 0 : for(i=0;i<nThreads;i++)
239 : {
240 0 : if( pasThreadJob[i].pTransformerArg )
241 0 : GDALDestroyTransformer(pasThreadJob[i].pTransformerArg);
242 : }
243 0 : CPLFree(pasThreadJob);
244 :
245 : CPLDebug("WARP", "Multithreading disabled. "
246 0 : "Falling back to mono-thread computation");
247 0 : return GWKGenericMonoThread(poWK, pfnFunc);
248 : }
249 :
250 3 : CPLDebug("WARP", "Using %d threads", nThreads);
251 :
252 3 : void* hCondMutex = CPLCreateMutex(); /* and take implicitely the mutex */
253 :
254 3 : volatile int bStop = FALSE;
255 3 : volatile int nCounter = 0;
256 :
257 : /* -------------------------------------------------------------------- */
258 : /* Lannch worker threads */
259 : /* -------------------------------------------------------------------- */
260 11 : for(i=0;i<nThreads;i++)
261 : {
262 8 : pasThreadJob[i].poWK = poWK;
263 8 : pasThreadJob[i].pnCounter = &nCounter;
264 8 : pasThreadJob[i].iYMin = (int)(((GIntBig)i) * nDstYSize / nThreads);
265 8 : pasThreadJob[i].iYMax = (int)(((GIntBig)(i + 1)) * nDstYSize / nThreads);
266 8 : pasThreadJob[i].pbStop = &bStop;
267 8 : pasThreadJob[i].hCond = hCond;
268 8 : pasThreadJob[i].hCondMutex = hCondMutex;
269 8 : pasThreadJob[i].pfnProgress = GWKProgressThread;
270 8 : pasThreadJob[i].hThread = CPLCreateJoinableThread( pfnFunc,
271 8 : (void*) &pasThreadJob[i] );
272 : }
273 :
274 : /* -------------------------------------------------------------------- */
275 : /* Report progress. */
276 : /* -------------------------------------------------------------------- */
277 253 : while(nCounter < nDstYSize)
278 : {
279 248 : CPLCondWait(hCond, hCondMutex);
280 :
281 248 : if( !poWK->pfnProgress( poWK->dfProgressBase + poWK->dfProgressScale *
282 : (nCounter / (double) nDstYSize),
283 : "", poWK->pProgress ) )
284 : {
285 1 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
286 1 : bStop = TRUE;
287 1 : break;
288 : }
289 : }
290 :
291 : /* Release mutex before joining threads, otherwise they will dead-lock */
292 : /* forever in GWKProgressThread() */
293 3 : CPLReleaseMutex(hCondMutex);
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Wait for all threads to complete and finish. */
297 : /* -------------------------------------------------------------------- */
298 11 : for(i=0;i<nThreads;i++)
299 : {
300 8 : CPLJoinThread(pasThreadJob[i].hThread);
301 8 : GDALDestroyTransformer(pasThreadJob[i].pTransformerArg);
302 : }
303 :
304 3 : CPLFree(pasThreadJob);
305 3 : CPLDestroyCond(hCond);
306 3 : CPLDestroyMutex(hCondMutex);
307 :
308 3 : return !bStop ? CE_None : CE_Failure;
309 : }
310 : }
311 :
312 : /************************************************************************/
313 : /* ==================================================================== */
314 : /* GDALWarpKernel */
315 : /* ==================================================================== */
316 : /************************************************************************/
317 :
318 : /**
319 : * \class GDALWarpKernel "gdalwarper.h"
320 : *
321 : * Low level image warping class.
322 : *
323 : * This class is responsible for low level image warping for one
324 : * "chunk" of imagery. The class is essentially a structure with all
325 : * data members public - primarily so that new special-case functions
326 : * can be added without changing the class declaration.
327 : *
328 : * Applications are normally intended to interactive with warping facilities
329 : * through the GDALWarpOperation class, though the GDALWarpKernel can in
330 : * theory be used directly if great care is taken in setting up the
331 : * control data.
332 : *
333 : * <h3>Design Issues</h3>
334 : *
335 : * My intention is that PerformWarp() would analyse the setup in terms
336 : * of the datatype, resampling type, and validity/density mask usage and
337 : * pick one of many specific implementations of the warping algorithm over
338 : * a continuim of optimization vs. generality. At one end there will be a
339 : * reference general purpose implementation of the algorithm that supports
340 : * any data type (working internally in double precision complex), all three
341 : * resampling types, and any or all of the validity/density masks. At the
342 : * other end would be highly optimized algorithms for common cases like
343 : * nearest neighbour resampling on GDT_Byte data with no masks.
344 : *
345 : * The full set of optimized versions have not been decided but we should
346 : * expect to have at least:
347 : * - One for each resampling algorithm for 8bit data with no masks.
348 : * - One for each resampling algorithm for float data with no masks.
349 : * - One for each resampling algorithm for float data with any/all masks
350 : * (essentially the generic case for just float data).
351 : * - One for each resampling algorithm for 8bit data with support for
352 : * input validity masks (per band or per pixel). This handles the common
353 : * case of nodata masking.
354 : * - One for each resampling algorithm for float data with support for
355 : * input validity masks (per band or per pixel). This handles the common
356 : * case of nodata masking.
357 : *
358 : * Some of the specializations would operate on all bands in one pass
359 : * (especially the ones without masking would do this), while others might
360 : * process each band individually to reduce code complexity.
361 : *
362 : * <h3>Masking Semantics</h3>
363 : *
364 : * A detailed explanation of the semantics of the validity and density masks,
365 : * and their effects on resampling kernels is needed here.
366 : */
367 :
368 : /************************************************************************/
369 : /* GDALWarpKernel Data Members */
370 : /************************************************************************/
371 :
372 : /**
373 : * \var GDALResampleAlg GDALWarpKernel::eResample;
374 : *
375 : * Resampling algorithm.
376 : *
377 : * The resampling algorithm to use. One of GRA_NearestNeighbour,
378 : * GRA_Bilinear, or GRA_Cubic.
379 : *
380 : * This field is required. GDT_NearestNeighbour may be used as a default
381 : * value.
382 : */
383 :
384 : /**
385 : * \var GDALDataType GDALWarpKernel::eWorkingDataType;
386 : *
387 : * Working pixel data type.
388 : *
389 : * The datatype of pixels in the source image (papabySrcimage) and
390 : * destination image (papabyDstImage) buffers. Note that operations on
391 : * some data types (such as GDT_Byte) may be much better optimized than other
392 : * less common cases.
393 : *
394 : * This field is required. It may not be GDT_Unknown.
395 : */
396 :
397 : /**
398 : * \var int GDALWarpKernel::nBands;
399 : *
400 : * Number of bands.
401 : *
402 : * The number of bands (layers) of imagery being warped. Determines the
403 : * number of entries in the papabySrcImage, papanBandSrcValid,
404 : * and papabyDstImage arrays.
405 : *
406 : * This field is required.
407 : */
408 :
409 : /**
410 : * \var int GDALWarpKernel::nSrcXSize;
411 : *
412 : * Source image width in pixels.
413 : *
414 : * This field is required.
415 : */
416 :
417 : /**
418 : * \var int GDALWarpKernel::nSrcYSize;
419 : *
420 : * Source image height in pixels.
421 : *
422 : * This field is required.
423 : */
424 :
425 : /**
426 : * \var int GDALWarpKernel::papabySrcImage;
427 : *
428 : * Array of source image band data.
429 : *
430 : * This is an array of pointers (of size GDALWarpKernel::nBands) pointers
431 : * to image data. Each individual band of image data is organized as a single
432 : * block of image data in left to right, then bottom to top order. The actual
433 : * type of the image data is determined by GDALWarpKernel::eWorkingDataType.
434 : *
435 : * To access the the pixel value for the (x=3,y=4) pixel (zero based) of
436 : * the second band with eWorkingDataType set to GDT_Float32 use code like
437 : * this:
438 : *
439 : * \code
440 : * float dfPixelValue;
441 : * int nBand = 1; // band indexes are zero based.
442 : * int nPixel = 3; // zero based
443 : * int nLine = 4; // zero based
444 : *
445 : * assert( nPixel >= 0 && nPixel < poKern->nSrcXSize );
446 : * assert( nLine >= 0 && nLine < poKern->nSrcYSize );
447 : * assert( nBand >= 0 && nBand < poKern->nBands );
448 : * dfPixelValue = ((float *) poKern->papabySrcImage[nBand-1])
449 : * [nPixel + nLine * poKern->nSrcXSize];
450 : * \endcode
451 : *
452 : * This field is required.
453 : */
454 :
455 : /**
456 : * \var GUInt32 **GDALWarpKernel::papanBandSrcValid;
457 : *
458 : * Per band validity mask for source pixels.
459 : *
460 : * Array of pixel validity mask layers for each source band. Each of
461 : * the mask layers is the same size (in pixels) as the source image with
462 : * one bit per pixel. Note that it is legal (and common) for this to be
463 : * NULL indicating that none of the pixels are invalidated, or for some
464 : * band validity masks to be NULL in which case all pixels of the band are
465 : * valid. The following code can be used to test the validity of a particular
466 : * pixel.
467 : *
468 : * \code
469 : * int bIsValid = TRUE;
470 : * int nBand = 1; // band indexes are zero based.
471 : * int nPixel = 3; // zero based
472 : * int nLine = 4; // zero based
473 : *
474 : * assert( nPixel >= 0 && nPixel < poKern->nSrcXSize );
475 : * assert( nLine >= 0 && nLine < poKern->nSrcYSize );
476 : * assert( nBand >= 0 && nBand < poKern->nBands );
477 : *
478 : * if( poKern->papanBandSrcValid != NULL
479 : * && poKern->papanBandSrcValid[nBand] != NULL )
480 : * {
481 : * GUInt32 *panBandMask = poKern->papanBandSrcValid[nBand];
482 : * int iPixelOffset = nPixel + nLine * poKern->nSrcXSize;
483 : *
484 : * bIsValid = panBandMask[iPixelOffset>>5]
485 : * & (0x01 << (iPixelOffset & 0x1f));
486 : * }
487 : * \endcode
488 : */
489 :
490 : /**
491 : * \var GUInt32 *GDALWarpKernel::panUnifiedSrcValid;
492 : *
493 : * Per pixel validity mask for source pixels.
494 : *
495 : * A single validity mask layer that applies to the pixels of all source
496 : * bands. It is accessed similarly to papanBandSrcValid, but without the
497 : * extra level of band indirection.
498 : *
499 : * This pointer may be NULL indicating that all pixels are valid.
500 : *
501 : * Note that if both panUnifiedSrcValid, and papanBandSrcValid are available,
502 : * the pixel isn't considered to be valid unless both arrays indicate it is
503 : * valid.
504 : */
505 :
506 : /**
507 : * \var float *GDALWarpKernel::pafUnifiedSrcDensity;
508 : *
509 : * Per pixel density mask for source pixels.
510 : *
511 : * A single density mask layer that applies to the pixels of all source
512 : * bands. It contains values between 0.0 and 1.0 indicating the degree to
513 : * which this pixel should be allowed to contribute to the output result.
514 : *
515 : * This pointer may be NULL indicating that all pixels have a density of 1.0.
516 : *
517 : * The density for a pixel may be accessed like this:
518 : *
519 : * \code
520 : * float fDensity = 1.0;
521 : * int nPixel = 3; // zero based
522 : * int nLine = 4; // zero based
523 : *
524 : * assert( nPixel >= 0 && nPixel < poKern->nSrcXSize );
525 : * assert( nLine >= 0 && nLine < poKern->nSrcYSize );
526 : * if( poKern->pafUnifiedSrcDensity != NULL )
527 : * fDensity = poKern->pafUnifiedSrcDensity
528 : * [nPixel + nLine * poKern->nSrcXSize];
529 : * \endcode
530 : */
531 :
532 : /**
533 : * \var int GDALWarpKernel::nDstXSize;
534 : *
535 : * Width of destination image in pixels.
536 : *
537 : * This field is required.
538 : */
539 :
540 : /**
541 : * \var int GDALWarpKernel::nDstYSize;
542 : *
543 : * Height of destination image in pixels.
544 : *
545 : * This field is required.
546 : */
547 :
548 : /**
549 : * \var GByte **GDALWarpKernel::papabyDstImage;
550 : *
551 : * Array of destination image band data.
552 : *
553 : * This is an array of pointers (of size GDALWarpKernel::nBands) pointers
554 : * to image data. Each individual band of image data is organized as a single
555 : * block of image data in left to right, then bottom to top order. The actual
556 : * type of the image data is determined by GDALWarpKernel::eWorkingDataType.
557 : *
558 : * To access the the pixel value for the (x=3,y=4) pixel (zero based) of
559 : * the second band with eWorkingDataType set to GDT_Float32 use code like
560 : * this:
561 : *
562 : * \code
563 : * float dfPixelValue;
564 : * int nBand = 1; // band indexes are zero based.
565 : * int nPixel = 3; // zero based
566 : * int nLine = 4; // zero based
567 : *
568 : * assert( nPixel >= 0 && nPixel < poKern->nDstXSize );
569 : * assert( nLine >= 0 && nLine < poKern->nDstYSize );
570 : * assert( nBand >= 0 && nBand < poKern->nBands );
571 : * dfPixelValue = ((float *) poKern->papabyDstImage[nBand-1])
572 : * [nPixel + nLine * poKern->nSrcYSize];
573 : * \endcode
574 : *
575 : * This field is required.
576 : */
577 :
578 : /**
579 : * \var GUInt32 *GDALWarpKernel::panDstValid;
580 : *
581 : * Per pixel validity mask for destination pixels.
582 : *
583 : * A single validity mask layer that applies to the pixels of all destination
584 : * bands. It is accessed similarly to papanUnitifiedSrcValid, but based
585 : * on the size of the destination image.
586 : *
587 : * This pointer may be NULL indicating that all pixels are valid.
588 : */
589 :
590 : /**
591 : * \var float *GDALWarpKernel::pafDstDensity;
592 : *
593 : * Per pixel density mask for destination pixels.
594 : *
595 : * A single density mask layer that applies to the pixels of all destination
596 : * bands. It contains values between 0.0 and 1.0.
597 : *
598 : * This pointer may be NULL indicating that all pixels have a density of 1.0.
599 : *
600 : * The density for a pixel may be accessed like this:
601 : *
602 : * \code
603 : * float fDensity = 1.0;
604 : * int nPixel = 3; // zero based
605 : * int nLine = 4; // zero based
606 : *
607 : * assert( nPixel >= 0 && nPixel < poKern->nDstXSize );
608 : * assert( nLine >= 0 && nLine < poKern->nDstYSize );
609 : * if( poKern->pafDstDensity != NULL )
610 : * fDensity = poKern->pafDstDensity[nPixel + nLine * poKern->nDstXSize];
611 : * \endcode
612 : */
613 :
614 : /**
615 : * \var int GDALWarpKernel::nSrcXOff;
616 : *
617 : * X offset to source pixel coordinates for transformation.
618 : *
619 : * See pfnTransformer.
620 : *
621 : * This field is required.
622 : */
623 :
624 : /**
625 : * \var int GDALWarpKernel::nSrcYOff;
626 : *
627 : * Y offset to source pixel coordinates for transformation.
628 : *
629 : * See pfnTransformer.
630 : *
631 : * This field is required.
632 : */
633 :
634 : /**
635 : * \var int GDALWarpKernel::nDstXOff;
636 : *
637 : * X offset to destination pixel coordinates for transformation.
638 : *
639 : * See pfnTransformer.
640 : *
641 : * This field is required.
642 : */
643 :
644 : /**
645 : * \var int GDALWarpKernel::nDstYOff;
646 : *
647 : * Y offset to destination pixel coordinates for transformation.
648 : *
649 : * See pfnTransformer.
650 : *
651 : * This field is required.
652 : */
653 :
654 : /**
655 : * \var GDALTransformerFunc GDALWarpKernel::pfnTransformer;
656 : *
657 : * Source/destination location transformer.
658 : *
659 : * The function to call to transform coordinates between source image
660 : * pixel/line coordinates and destination image pixel/line coordinates.
661 : * See GDALTransformerFunc() for details of the semantics of this function.
662 : *
663 : * The GDALWarpKern algorithm will only ever use this transformer in
664 : * "destination to source" mode (bDstToSrc=TRUE), and will always pass
665 : * partial or complete scanlines of points in the destination image as
666 : * input. This means, amoung other things, that it is safe to the the
667 : * approximating transform GDALApproxTransform() as the transformation
668 : * function.
669 : *
670 : * Source and destination images may be subsets of a larger overall image.
671 : * The transformation algorithms will expect and return pixel/line coordinates
672 : * in terms of this larger image, so coordinates need to be offset by
673 : * the offsets specified in nSrcXOff, nSrcYOff, nDstXOff, and nDstYOff before
674 : * passing to pfnTransformer, and after return from it.
675 : *
676 : * The GDALWarpKernel::pfnTransformerArg value will be passed as the callback
677 : * data to this function when it is called.
678 : *
679 : * This field is required.
680 : */
681 :
682 : /**
683 : * \var void *GDALWarpKernel::pTransformerArg;
684 : *
685 : * Callback data for pfnTransformer.
686 : *
687 : * This field may be NULL if not required for the pfnTransformer being used.
688 : */
689 :
690 : /**
691 : * \var GDALProgressFunc GDALWarpKernel::pfnProgress;
692 : *
693 : * The function to call to report progress of the algorithm, and to check
694 : * for a requested termination of the operation. It operates according to
695 : * GDALProgressFunc() semantics.
696 : *
697 : * Generally speaking the progress function will be invoked for each
698 : * scanline of the destination buffer that has been processed.
699 : *
700 : * This field may be NULL (internally set to GDALDummyProgress()).
701 : */
702 :
703 : /**
704 : * \var void *GDALWarpKernel::pProgress;
705 : *
706 : * Callback data for pfnProgress.
707 : *
708 : * This field may be NULL if not required for the pfnProgress being used.
709 : */
710 :
711 :
712 : /************************************************************************/
713 : /* GDALWarpKernel() */
714 : /************************************************************************/
715 :
716 585 : GDALWarpKernel::GDALWarpKernel()
717 :
718 : {
719 585 : eResample = GRA_NearestNeighbour;
720 585 : eWorkingDataType = GDT_Unknown;
721 585 : nBands = 0;
722 585 : nDstXOff = 0;
723 585 : nDstYOff = 0;
724 585 : nDstXSize = 0;
725 585 : nDstYSize = 0;
726 585 : nSrcXOff = 0;
727 585 : nSrcYOff = 0;
728 585 : nSrcXSize = 0;
729 585 : nSrcYSize = 0;
730 585 : dfXScale = 1.0;
731 585 : dfYScale = 1.0;
732 585 : dfXFilter = 0.0;
733 585 : dfYFilter = 0.0;
734 585 : nXRadius = 0;
735 585 : nYRadius = 0;
736 585 : nFiltInitX = 0;
737 585 : nFiltInitY = 0;
738 585 : pafDstDensity = NULL;
739 585 : pafUnifiedSrcDensity = NULL;
740 585 : panDstValid = NULL;
741 585 : panUnifiedSrcValid = NULL;
742 585 : papabyDstImage = NULL;
743 585 : papabySrcImage = NULL;
744 585 : papanBandSrcValid = NULL;
745 585 : pfnProgress = GDALDummyProgress;
746 585 : pProgress = NULL;
747 585 : dfProgressBase = 0.0;
748 585 : dfProgressScale = 1.0;
749 585 : pfnTransformer = NULL;
750 585 : pTransformerArg = NULL;
751 585 : papszWarpOptions = NULL;
752 585 : }
753 :
754 : /************************************************************************/
755 : /* ~GDALWarpKernel() */
756 : /************************************************************************/
757 :
758 585 : GDALWarpKernel::~GDALWarpKernel()
759 :
760 : {
761 585 : }
762 :
763 : /************************************************************************/
764 : /* PerformWarp() */
765 : /************************************************************************/
766 :
767 : /**
768 : * \fn CPLErr GDALWarpKernel::PerformWarp();
769 : *
770 : * This method performs the warp described in the GDALWarpKernel.
771 : *
772 : * @return CE_None on success or CE_Failure if an error occurs.
773 : */
774 :
775 584 : CPLErr GDALWarpKernel::PerformWarp()
776 :
777 : {
778 : CPLErr eErr;
779 :
780 584 : if( (eErr = Validate()) != CE_None )
781 0 : return eErr;
782 :
783 : // See #2445 and #3079
784 584 : if (nSrcXSize <= 0 || nSrcYSize <= 0)
785 : {
786 1 : if ( !pfnProgress( dfProgressBase + dfProgressScale,
787 : "", pProgress ) )
788 : {
789 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
790 0 : return CE_Failure;
791 : }
792 1 : return CE_None;
793 : }
794 :
795 : /* -------------------------------------------------------------------- */
796 : /* Pre-calculate resampling scales and window sizes for filtering. */
797 : /* -------------------------------------------------------------------- */
798 :
799 583 : dfXScale = (double)nDstXSize / nSrcXSize;
800 583 : dfYScale = (double)nDstYSize / nSrcYSize;
801 583 : if( nSrcXSize >= nDstXSize && nSrcXSize <= nDstXSize + 1 + 2 * anGWKFilterRadius[eResample] )
802 456 : dfXScale = 1;
803 583 : if( nSrcYSize >= nDstYSize && nSrcYSize <= nDstYSize + 1 + 2 * anGWKFilterRadius[eResample] )
804 462 : dfYScale = 1;
805 :
806 583 : dfXFilter = anGWKFilterRadius[eResample];
807 583 : dfYFilter = anGWKFilterRadius[eResample];
808 :
809 : nXRadius = ( dfXScale < 1.0 ) ?
810 583 : (int)ceil( dfXFilter / dfXScale ) :(int)dfXFilter;
811 : nYRadius = ( dfYScale < 1.0 ) ?
812 583 : (int)ceil( dfYFilter / dfYScale ) : (int)dfYFilter;
813 :
814 : // Filter window offset depends on the parity of the kernel radius
815 583 : nFiltInitX = ((anGWKFilterRadius[eResample] + 1) % 2) - nXRadius;
816 583 : nFiltInitY = ((anGWKFilterRadius[eResample] + 1) % 2) - nYRadius;
817 :
818 : /* -------------------------------------------------------------------- */
819 : /* Set up resampling functions. */
820 : /* -------------------------------------------------------------------- */
821 583 : if( CSLFetchBoolean( papszWarpOptions, "USE_GENERAL_CASE", FALSE ) )
822 0 : return GWKGeneralCase( this );
823 :
824 : #if defined(HAVE_OPENCL)
825 : if((eWorkingDataType == GDT_Byte
826 : || eWorkingDataType == GDT_CInt16
827 : || eWorkingDataType == GDT_UInt16
828 : || eWorkingDataType == GDT_Int16
829 : || eWorkingDataType == GDT_CFloat32
830 : || eWorkingDataType == GDT_Float32) &&
831 : (eResample == GRA_Bilinear
832 : || eResample == GRA_Cubic
833 : || eResample == GRA_CubicSpline
834 : || eResample == GRA_Lanczos) &&
835 : CSLFetchBoolean( papszWarpOptions, "USE_OPENCL", TRUE ))
836 : {
837 : CPLErr eResult = GWKOpenCLCase( this );
838 :
839 : // CE_Warning tells us a suitable OpenCL environment was not available
840 : // so we fall through to other CPU based methods.
841 : if( eResult != CE_Warning )
842 : return eResult;
843 : }
844 : #endif /* defined HAVE_OPENCL */
845 :
846 583 : if( eWorkingDataType == GDT_Byte
847 : && eResample == GRA_NearestNeighbour
848 : && papanBandSrcValid == NULL
849 : && panUnifiedSrcValid == NULL
850 : && pafUnifiedSrcDensity == NULL
851 : && panDstValid == NULL
852 : && pafDstDensity == NULL )
853 255 : return GWKNearestNoMasksByte( this );
854 :
855 328 : if( eWorkingDataType == GDT_Byte
856 : && eResample == GRA_Bilinear
857 : && papanBandSrcValid == NULL
858 : && panUnifiedSrcValid == NULL
859 : && pafUnifiedSrcDensity == NULL
860 : && panDstValid == NULL
861 : && pafDstDensity == NULL )
862 16 : return GWKBilinearNoMasksByte( this );
863 :
864 312 : if( eWorkingDataType == GDT_Byte
865 : && eResample == GRA_Cubic
866 : && papanBandSrcValid == NULL
867 : && panUnifiedSrcValid == NULL
868 : && pafUnifiedSrcDensity == NULL
869 : && panDstValid == NULL
870 : && pafDstDensity == NULL )
871 10 : return GWKCubicNoMasksByte( this );
872 :
873 302 : if( eWorkingDataType == GDT_Byte
874 : && eResample == GRA_CubicSpline
875 : && papanBandSrcValid == NULL
876 : && panUnifiedSrcValid == NULL
877 : && pafUnifiedSrcDensity == NULL
878 : && panDstValid == NULL
879 : && pafDstDensity == NULL )
880 10 : return GWKCubicSplineNoMasksByte( this );
881 :
882 292 : if( eWorkingDataType == GDT_Byte
883 : && eResample == GRA_NearestNeighbour )
884 28 : return GWKNearestByte( this );
885 :
886 264 : if( (eWorkingDataType == GDT_Int16 || eWorkingDataType == GDT_UInt16)
887 : && eResample == GRA_NearestNeighbour
888 : && papanBandSrcValid == NULL
889 : && panUnifiedSrcValid == NULL
890 : && pafUnifiedSrcDensity == NULL
891 : && panDstValid == NULL
892 : && pafDstDensity == NULL )
893 14 : return GWKNearestNoMasksShort( this );
894 :
895 250 : if( (eWorkingDataType == GDT_Int16 )
896 : && eResample == GRA_Cubic
897 : && papanBandSrcValid == NULL
898 : && panUnifiedSrcValid == NULL
899 : && pafUnifiedSrcDensity == NULL
900 : && panDstValid == NULL
901 : && pafDstDensity == NULL )
902 8 : return GWKCubicNoMasksShort( this );
903 :
904 242 : if( (eWorkingDataType == GDT_Int16 )
905 : && eResample == GRA_CubicSpline
906 : && papanBandSrcValid == NULL
907 : && panUnifiedSrcValid == NULL
908 : && pafUnifiedSrcDensity == NULL
909 : && panDstValid == NULL
910 : && pafDstDensity == NULL )
911 8 : return GWKCubicSplineNoMasksShort( this );
912 :
913 234 : if( (eWorkingDataType == GDT_Int16 )
914 : && eResample == GRA_Bilinear
915 : && papanBandSrcValid == NULL
916 : && panUnifiedSrcValid == NULL
917 : && pafUnifiedSrcDensity == NULL
918 : && panDstValid == NULL
919 : && pafDstDensity == NULL )
920 20 : return GWKBilinearNoMasksShort( this );
921 :
922 214 : if( (eWorkingDataType == GDT_Int16 || eWorkingDataType == GDT_UInt16)
923 : && eResample == GRA_NearestNeighbour )
924 7 : return GWKNearestShort( this );
925 :
926 207 : if( eWorkingDataType == GDT_Float32
927 : && eResample == GRA_NearestNeighbour
928 : && papanBandSrcValid == NULL
929 : && panUnifiedSrcValid == NULL
930 : && pafUnifiedSrcDensity == NULL
931 : && panDstValid == NULL
932 : && pafDstDensity == NULL )
933 8 : return GWKNearestNoMasksFloat( this );
934 :
935 199 : if( eWorkingDataType == GDT_Float32
936 : && eResample == GRA_NearestNeighbour )
937 6 : return GWKNearestFloat( this );
938 :
939 193 : return GWKGeneralCase( this );
940 : }
941 :
942 : /************************************************************************/
943 : /* Validate() */
944 : /************************************************************************/
945 :
946 : /**
947 : * \fn CPLErr GDALWarpKernel::Validate()
948 : *
949 : * Check the settings in the GDALWarpKernel, and issue a CPLError()
950 : * (and return CE_Failure) if the configuration is considered to be
951 : * invalid for some reason.
952 : *
953 : * This method will also do some standard defaulting such as setting
954 : * pfnProgress to GDALDummyProgress() if it is NULL.
955 : *
956 : * @return CE_None on success or CE_Failure if an error is detected.
957 : */
958 :
959 584 : CPLErr GDALWarpKernel::Validate()
960 :
961 : {
962 584 : if ( (size_t)eResample >=
963 : (sizeof(anGWKFilterRadius) / sizeof(anGWKFilterRadius[0])) )
964 : {
965 : CPLError( CE_Failure, CPLE_AppDefined,
966 0 : "Unsupported resampling method %d.", (int) eResample );
967 0 : return CE_Failure;
968 : }
969 :
970 : // Safety check for callers that would use GDALWarpKernel without using
971 : // GDALWarpOperation.
972 584 : if( (eResample == GRA_CubicSpline || eResample == GRA_Lanczos) &&
973 : atoi(CSLFetchNameValueDef(papszWarpOptions, "EXTRA_ELTS", "0") ) != WARP_EXTRA_ELTS )
974 : {
975 : CPLError( CE_Failure, CPLE_AppDefined,
976 : "Source arrays must have WARP_EXTRA_ELTS extra elements at their end. "
977 : "See GDALWarpKernel class definition. If this condition is fulfilled, "
978 0 : "define a EXTRA_ELTS=%d warp options", WARP_EXTRA_ELTS);
979 0 : return CE_Failure;
980 : }
981 :
982 584 : return CE_None;
983 : }
984 :
985 : /************************************************************************/
986 : /* GWKOverlayDensity() */
987 : /* */
988 : /* Compute the final density for the destination pixel. This */
989 : /* is a function of the overlay density (passed in) and the */
990 : /* original density. */
991 : /************************************************************************/
992 :
993 2238219 : static void GWKOverlayDensity( GDALWarpKernel *poWK, int iDstOffset,
994 : double dfDensity )
995 : {
996 2238219 : if( dfDensity < 0.0001 || poWK->pafDstDensity == NULL )
997 1789911 : return;
998 :
999 448308 : poWK->pafDstDensity[iDstOffset] = (float)
1000 448308 : ( 1.0 - (1.0 - dfDensity) * (1.0 - poWK->pafDstDensity[iDstOffset]) );
1001 : }
1002 :
1003 : /************************************************************************/
1004 : /* GWKSetPixelValue() */
1005 : /************************************************************************/
1006 :
1007 290867 : static int GWKSetPixelValue( GDALWarpKernel *poWK, int iBand,
1008 : int iDstOffset, double dfDensity,
1009 : double dfReal, double dfImag )
1010 :
1011 : {
1012 290867 : GByte *pabyDst = poWK->papabyDstImage[iBand];
1013 :
1014 : /* -------------------------------------------------------------------- */
1015 : /* If the source density is less than 100% we need to fetch the */
1016 : /* existing destination value, and mix it with the source to */
1017 : /* get the new "to apply" value. Also compute composite */
1018 : /* density. */
1019 : /* */
1020 : /* We avoid mixing if density is very near one or risk mixing */
1021 : /* in very extreme nodata values and causing odd results (#1610) */
1022 : /* -------------------------------------------------------------------- */
1023 290867 : if( dfDensity < 0.9999 )
1024 : {
1025 1472 : double dfDstReal, dfDstImag, dfDstDensity = 1.0;
1026 :
1027 1472 : if( dfDensity < 0.0001 )
1028 0 : return TRUE;
1029 :
1030 1472 : if( poWK->pafDstDensity != NULL )
1031 0 : dfDstDensity = poWK->pafDstDensity[iDstOffset];
1032 1472 : else if( poWK->panDstValid != NULL
1033 0 : && !((poWK->panDstValid[iDstOffset>>5]
1034 : & (0x01 << (iDstOffset & 0x1f))) ) )
1035 0 : dfDstDensity = 0.0;
1036 :
1037 : // It seems like we also ought to be testing panDstValid[] here!
1038 :
1039 1472 : switch( poWK->eWorkingDataType )
1040 : {
1041 : case GDT_Byte:
1042 1472 : dfDstReal = pabyDst[iDstOffset];
1043 1472 : dfDstImag = 0.0;
1044 1472 : break;
1045 :
1046 : case GDT_Int16:
1047 0 : dfDstReal = ((GInt16 *) pabyDst)[iDstOffset];
1048 0 : dfDstImag = 0.0;
1049 0 : break;
1050 :
1051 : case GDT_UInt16:
1052 0 : dfDstReal = ((GUInt16 *) pabyDst)[iDstOffset];
1053 0 : dfDstImag = 0.0;
1054 0 : break;
1055 :
1056 : case GDT_Int32:
1057 0 : dfDstReal = ((GInt32 *) pabyDst)[iDstOffset];
1058 0 : dfDstImag = 0.0;
1059 0 : break;
1060 :
1061 : case GDT_UInt32:
1062 0 : dfDstReal = ((GUInt32 *) pabyDst)[iDstOffset];
1063 0 : dfDstImag = 0.0;
1064 0 : break;
1065 :
1066 : case GDT_Float32:
1067 0 : dfDstReal = ((float *) pabyDst)[iDstOffset];
1068 0 : dfDstImag = 0.0;
1069 0 : break;
1070 :
1071 : case GDT_Float64:
1072 0 : dfDstReal = ((double *) pabyDst)[iDstOffset];
1073 0 : dfDstImag = 0.0;
1074 0 : break;
1075 :
1076 : case GDT_CInt16:
1077 0 : dfDstReal = ((GInt16 *) pabyDst)[iDstOffset*2];
1078 0 : dfDstImag = ((GInt16 *) pabyDst)[iDstOffset*2+1];
1079 0 : break;
1080 :
1081 : case GDT_CInt32:
1082 0 : dfDstReal = ((GInt32 *) pabyDst)[iDstOffset*2];
1083 0 : dfDstImag = ((GInt32 *) pabyDst)[iDstOffset*2+1];
1084 0 : break;
1085 :
1086 : case GDT_CFloat32:
1087 0 : dfDstReal = ((float *) pabyDst)[iDstOffset*2];
1088 0 : dfDstImag = ((float *) pabyDst)[iDstOffset*2+1];
1089 0 : break;
1090 :
1091 : case GDT_CFloat64:
1092 0 : dfDstReal = ((double *) pabyDst)[iDstOffset*2];
1093 0 : dfDstImag = ((double *) pabyDst)[iDstOffset*2+1];
1094 0 : break;
1095 :
1096 : default:
1097 0 : CPLAssert( FALSE );
1098 0 : dfDstDensity = 0.0;
1099 0 : return FALSE;
1100 : }
1101 :
1102 : // the destination density is really only relative to the portion
1103 : // not occluded by the overlay.
1104 1472 : double dfDstInfluence = (1.0 - dfDensity) * dfDstDensity;
1105 :
1106 : dfReal = (dfReal * dfDensity + dfDstReal * dfDstInfluence)
1107 1472 : / (dfDensity + dfDstInfluence);
1108 :
1109 : dfImag = (dfImag * dfDensity + dfDstImag * dfDstInfluence)
1110 1472 : / (dfDensity + dfDstInfluence);
1111 : }
1112 :
1113 : /* -------------------------------------------------------------------- */
1114 : /* Actually apply the destination value. */
1115 : /* */
1116 : /* Avoid using the destination nodata value for integer datatypes */
1117 : /* if by chance it is equal to the computed pixel value. */
1118 : /* -------------------------------------------------------------------- */
1119 :
1120 : #define CLAMP(type,minval,maxval) \
1121 : do { \
1122 : if (dfReal < minval) ((type *) pabyDst)[iDstOffset] = (type)minval; \
1123 : else if (dfReal > maxval) ((type *) pabyDst)[iDstOffset] = (type)maxval; \
1124 : else ((type *) pabyDst)[iDstOffset] = (minval < 0) ? (type)floor(dfReal + 0.5) : (type)(dfReal + 0.5); \
1125 : if (poWK->padfDstNoDataReal != NULL && \
1126 : poWK->padfDstNoDataReal[iBand] == (double)((type *) pabyDst)[iDstOffset]) \
1127 : { \
1128 : if (((type *) pabyDst)[iDstOffset] == minval) \
1129 : ((type *) pabyDst)[iDstOffset] = (type)(minval + 1); \
1130 : else \
1131 : ((type *) pabyDst)[iDstOffset] --; \
1132 : } } while(0)
1133 :
1134 290867 : switch( poWK->eWorkingDataType )
1135 : {
1136 : case GDT_Byte:
1137 287295 : CLAMP(GByte, 0.0, 255.0);
1138 287295 : break;
1139 :
1140 : case GDT_Int16:
1141 63 : CLAMP(GInt16, -32768.0, 32767.0);
1142 63 : break;
1143 :
1144 : case GDT_UInt16:
1145 252 : CLAMP(GUInt16, 0.0, 65535.0);
1146 252 : break;
1147 :
1148 : case GDT_UInt32:
1149 315 : CLAMP(GUInt32, 0.0, 4294967295.0);
1150 315 : break;
1151 :
1152 : case GDT_Int32:
1153 1115 : CLAMP(GInt32, -2147483648.0, 2147483647.0);
1154 1115 : break;
1155 :
1156 : case GDT_Float32:
1157 252 : ((float *) pabyDst)[iDstOffset] = (float) dfReal;
1158 252 : break;
1159 :
1160 : case GDT_Float64:
1161 315 : ((double *) pabyDst)[iDstOffset] = dfReal;
1162 315 : break;
1163 :
1164 : case GDT_CInt16:
1165 315 : if( dfReal < -32768 )
1166 0 : ((GInt16 *) pabyDst)[iDstOffset*2] = -32768;
1167 315 : else if( dfReal > 32767 )
1168 0 : ((GInt16 *) pabyDst)[iDstOffset*2] = 32767;
1169 : else
1170 315 : ((GInt16 *) pabyDst)[iDstOffset*2] = (GInt16) floor(dfReal+0.5);
1171 315 : if( dfImag < -32768 )
1172 0 : ((GInt16 *) pabyDst)[iDstOffset*2+1] = -32768;
1173 315 : else if( dfImag > 32767 )
1174 0 : ((GInt16 *) pabyDst)[iDstOffset*2+1] = 32767;
1175 : else
1176 315 : ((GInt16 *) pabyDst)[iDstOffset*2+1] = (GInt16) floor(dfImag+0.5);
1177 315 : break;
1178 :
1179 : case GDT_CInt32:
1180 315 : if( dfReal < -2147483648.0 )
1181 0 : ((GInt32 *) pabyDst)[iDstOffset*2] = (GInt32) -2147483648.0;
1182 315 : else if( dfReal > 2147483647.0 )
1183 0 : ((GInt32 *) pabyDst)[iDstOffset*2] = (GInt32) 2147483647.0;
1184 : else
1185 315 : ((GInt32 *) pabyDst)[iDstOffset*2] = (GInt32) floor(dfReal+0.5);
1186 315 : if( dfImag < -2147483648.0 )
1187 0 : ((GInt32 *) pabyDst)[iDstOffset*2+1] = (GInt32) -2147483648.0;
1188 315 : else if( dfImag > 2147483647.0 )
1189 0 : ((GInt32 *) pabyDst)[iDstOffset*2+1] = (GInt32) 2147483647.0;
1190 : else
1191 315 : ((GInt32 *) pabyDst)[iDstOffset*2+1] = (GInt32) floor(dfImag+0.5);
1192 315 : break;
1193 :
1194 : case GDT_CFloat32:
1195 315 : ((float *) pabyDst)[iDstOffset*2] = (float) dfReal;
1196 315 : ((float *) pabyDst)[iDstOffset*2+1] = (float) dfImag;
1197 315 : break;
1198 :
1199 : case GDT_CFloat64:
1200 315 : ((double *) pabyDst)[iDstOffset*2] = (double) dfReal;
1201 315 : ((double *) pabyDst)[iDstOffset*2+1] = (double) dfImag;
1202 315 : break;
1203 :
1204 : default:
1205 0 : return FALSE;
1206 : }
1207 :
1208 290867 : return TRUE;
1209 : }
1210 :
1211 : /************************************************************************/
1212 : /* GWKGetPixelValue() */
1213 : /************************************************************************/
1214 :
1215 1279 : static int GWKGetPixelValue( GDALWarpKernel *poWK, int iBand,
1216 : int iSrcOffset, double *pdfDensity,
1217 : double *pdfReal, double *pdfImag )
1218 :
1219 : {
1220 1279 : GByte *pabySrc = poWK->papabySrcImage[iBand];
1221 :
1222 1279 : if( poWK->panUnifiedSrcValid != NULL
1223 0 : && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
1224 : & (0x01 << (iSrcOffset & 0x1f))) ) )
1225 : {
1226 0 : *pdfDensity = 0.0;
1227 0 : return FALSE;
1228 : }
1229 :
1230 2879 : if( poWK->papanBandSrcValid != NULL
1231 800 : && poWK->papanBandSrcValid[iBand] != NULL
1232 800 : && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
1233 : & (0x01 << (iSrcOffset & 0x1f)))) )
1234 : {
1235 0 : *pdfDensity = 0.0;
1236 0 : return FALSE;
1237 : }
1238 :
1239 1279 : switch( poWK->eWorkingDataType )
1240 : {
1241 : case GDT_Byte:
1242 1 : *pdfReal = pabySrc[iSrcOffset];
1243 1 : *pdfImag = 0.0;
1244 1 : break;
1245 :
1246 : case GDT_Int16:
1247 1 : *pdfReal = ((GInt16 *) pabySrc)[iSrcOffset];
1248 1 : *pdfImag = 0.0;
1249 1 : break;
1250 :
1251 : case GDT_UInt16:
1252 4 : *pdfReal = ((GUInt16 *) pabySrc)[iSrcOffset];
1253 4 : *pdfImag = 0.0;
1254 4 : break;
1255 :
1256 : case GDT_Int32:
1257 867 : *pdfReal = ((GInt32 *) pabySrc)[iSrcOffset];
1258 867 : *pdfImag = 0.0;
1259 867 : break;
1260 :
1261 : case GDT_UInt32:
1262 67 : *pdfReal = ((GUInt32 *) pabySrc)[iSrcOffset];
1263 67 : *pdfImag = 0.0;
1264 67 : break;
1265 :
1266 : case GDT_Float32:
1267 4 : *pdfReal = ((float *) pabySrc)[iSrcOffset];
1268 4 : *pdfImag = 0.0;
1269 4 : break;
1270 :
1271 : case GDT_Float64:
1272 67 : *pdfReal = ((double *) pabySrc)[iSrcOffset];
1273 67 : *pdfImag = 0.0;
1274 67 : break;
1275 :
1276 : case GDT_CInt16:
1277 67 : *pdfReal = ((GInt16 *) pabySrc)[iSrcOffset*2];
1278 67 : *pdfImag = ((GInt16 *) pabySrc)[iSrcOffset*2+1];
1279 67 : break;
1280 :
1281 : case GDT_CInt32:
1282 67 : *pdfReal = ((GInt32 *) pabySrc)[iSrcOffset*2];
1283 67 : *pdfImag = ((GInt32 *) pabySrc)[iSrcOffset*2+1];
1284 67 : break;
1285 :
1286 : case GDT_CFloat32:
1287 67 : *pdfReal = ((float *) pabySrc)[iSrcOffset*2];
1288 67 : *pdfImag = ((float *) pabySrc)[iSrcOffset*2+1];
1289 67 : break;
1290 :
1291 : case GDT_CFloat64:
1292 67 : *pdfReal = ((double *) pabySrc)[iSrcOffset*2];
1293 67 : *pdfImag = ((double *) pabySrc)[iSrcOffset*2+1];
1294 67 : break;
1295 :
1296 : default:
1297 0 : *pdfDensity = 0.0;
1298 0 : return FALSE;
1299 : }
1300 :
1301 1279 : if( poWK->pafUnifiedSrcDensity != NULL )
1302 0 : *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
1303 : else
1304 1279 : *pdfDensity = 1.0;
1305 :
1306 1279 : return *pdfDensity != 0.0;
1307 : }
1308 :
1309 : /************************************************************************/
1310 : /* GWKGetPixelRow() */
1311 : /************************************************************************/
1312 :
1313 : /* It is assumed that adfImag[] is set to 0 by caller code for non-complex */
1314 : /* data-types. */
1315 :
1316 1675450 : static int GWKGetPixelRow( GDALWarpKernel *poWK, int iBand,
1317 : int iSrcOffset, int nHalfSrcLen,
1318 : double* padfDensity,
1319 : double adfReal[],
1320 : double* padfImag )
1321 : {
1322 : // We know that nSrcLen is even, so we can *always* unroll loops 2x
1323 1675450 : int nSrcLen = nHalfSrcLen * 2;
1324 1675450 : int bHasValid = FALSE;
1325 : int i;
1326 :
1327 1675450 : if( padfDensity != NULL )
1328 : {
1329 : // Init the density
1330 35648 : for ( i = 0; i < nSrcLen; i += 2 )
1331 : {
1332 18112 : padfDensity[i] = 1.0;
1333 18112 : padfDensity[i+1] = 1.0;
1334 : }
1335 :
1336 17536 : if ( poWK->panUnifiedSrcValid != NULL )
1337 : {
1338 0 : for ( i = 0; i < nSrcLen; i += 2 )
1339 : {
1340 0 : if(poWK->panUnifiedSrcValid[(iSrcOffset+i)>>5]
1341 : & (0x01 << ((iSrcOffset+i) & 0x1f)))
1342 0 : bHasValid = TRUE;
1343 : else
1344 0 : padfDensity[i] = 0.0;
1345 :
1346 0 : if(poWK->panUnifiedSrcValid[(iSrcOffset+i+1)>>5]
1347 : & (0x01 << ((iSrcOffset+i+1) & 0x1f)))
1348 0 : bHasValid = TRUE;
1349 : else
1350 0 : padfDensity[i+1] = 0.0;
1351 : }
1352 :
1353 : // Reset or fail as needed
1354 0 : if ( bHasValid )
1355 0 : bHasValid = FALSE;
1356 : else
1357 0 : return FALSE;
1358 : }
1359 :
1360 32536 : if ( poWK->papanBandSrcValid != NULL
1361 15000 : && poWK->papanBandSrcValid[iBand] != NULL)
1362 : {
1363 30000 : for ( i = 0; i < nSrcLen; i += 2 )
1364 : {
1365 15000 : if(poWK->papanBandSrcValid[iBand][(iSrcOffset+i)>>5]
1366 : & (0x01 << ((iSrcOffset+i) & 0x1f)))
1367 15000 : bHasValid = TRUE;
1368 : else
1369 0 : padfDensity[i] = 0.0;
1370 :
1371 15000 : if(poWK->papanBandSrcValid[iBand][(iSrcOffset+i+1)>>5]
1372 : & (0x01 << ((iSrcOffset+i+1) & 0x1f)))
1373 15000 : bHasValid = TRUE;
1374 : else
1375 0 : padfDensity[i+1] = 0.0;
1376 : }
1377 :
1378 : // Reset or fail as needed
1379 15000 : if ( bHasValid )
1380 15000 : bHasValid = FALSE;
1381 : else
1382 0 : return FALSE;
1383 : }
1384 : }
1385 :
1386 : // Fetch data
1387 1675450 : switch( poWK->eWorkingDataType )
1388 : {
1389 : case GDT_Byte:
1390 : {
1391 1668406 : GByte* pSrc = (GByte*) poWK->papabySrcImage[iBand];
1392 1668406 : pSrc += iSrcOffset;
1393 6611511 : for ( i = 0; i < nSrcLen; i += 2 )
1394 : {
1395 4943105 : adfReal[i] = pSrc[i];
1396 4943105 : adfReal[i+1] = pSrc[i+1];
1397 : }
1398 1668406 : break;
1399 : }
1400 :
1401 : case GDT_Int16:
1402 : {
1403 294 : GInt16* pSrc = (GInt16*) poWK->papabySrcImage[iBand];
1404 294 : pSrc += iSrcOffset;
1405 1096 : for ( i = 0; i < nSrcLen; i += 2 )
1406 : {
1407 802 : adfReal[i] = pSrc[i];
1408 802 : adfReal[i+1] = pSrc[i+1];
1409 : }
1410 294 : break;
1411 : }
1412 :
1413 : case GDT_UInt16:
1414 : {
1415 750 : GUInt16* pSrc = (GUInt16*) poWK->papabySrcImage[iBand];
1416 750 : pSrc += iSrcOffset;
1417 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1418 : {
1419 1482 : adfReal[i] = pSrc[i];
1420 1482 : adfReal[i+1] = pSrc[i+1];
1421 : }
1422 750 : break;
1423 : }
1424 :
1425 : case GDT_Int32:
1426 : {
1427 750 : GInt32* pSrc = (GInt32*) poWK->papabySrcImage[iBand];
1428 750 : pSrc += iSrcOffset;
1429 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1430 : {
1431 1482 : adfReal[i] = pSrc[i];
1432 1482 : adfReal[i+1] = pSrc[i+1];
1433 : }
1434 750 : break;
1435 : }
1436 :
1437 : case GDT_UInt32:
1438 : {
1439 750 : GUInt32* pSrc = (GUInt32*) poWK->papabySrcImage[iBand];
1440 750 : pSrc += iSrcOffset;
1441 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1442 : {
1443 1482 : adfReal[i] = pSrc[i];
1444 1482 : adfReal[i+1] = pSrc[i+1];
1445 : }
1446 750 : break;
1447 : }
1448 :
1449 : case GDT_Float32:
1450 : {
1451 750 : float* pSrc = (float*) poWK->papabySrcImage[iBand];
1452 750 : pSrc += iSrcOffset;
1453 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1454 : {
1455 1482 : adfReal[i] = pSrc[i];
1456 1482 : adfReal[i+1] = pSrc[i+1];
1457 : }
1458 750 : break;
1459 : }
1460 :
1461 : case GDT_Float64:
1462 : {
1463 750 : double* pSrc = (double*) poWK->papabySrcImage[iBand];
1464 750 : pSrc += iSrcOffset;
1465 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1466 : {
1467 1482 : adfReal[i] = pSrc[i];
1468 1482 : adfReal[i+1] = pSrc[i+1];
1469 : }
1470 750 : break;
1471 : }
1472 :
1473 : case GDT_CInt16:
1474 : {
1475 750 : GInt16* pSrc = (GInt16*) poWK->papabySrcImage[iBand];
1476 750 : pSrc += 2 * iSrcOffset;
1477 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1478 : {
1479 1482 : adfReal[i] = pSrc[2*i];
1480 1482 : padfImag[i] = pSrc[2*i+1];
1481 :
1482 1482 : adfReal[i+1] = pSrc[2*i+2];
1483 1482 : padfImag[i+1] = pSrc[2*i+3];
1484 : }
1485 750 : break;
1486 : }
1487 :
1488 : case GDT_CInt32:
1489 : {
1490 750 : GInt32* pSrc = (GInt32*) poWK->papabySrcImage[iBand];
1491 750 : pSrc += 2 * iSrcOffset;
1492 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1493 : {
1494 1482 : adfReal[i] = pSrc[2*i];
1495 1482 : padfImag[i] = pSrc[2*i+1];
1496 :
1497 1482 : adfReal[i+1] = pSrc[2*i+2];
1498 1482 : padfImag[i+1] = pSrc[2*i+3];
1499 : }
1500 750 : break;
1501 : }
1502 :
1503 : case GDT_CFloat32:
1504 : {
1505 750 : float* pSrc = (float*) poWK->papabySrcImage[iBand];
1506 750 : pSrc += 2 * iSrcOffset;
1507 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1508 : {
1509 1482 : adfReal[i] = pSrc[2*i];
1510 1482 : padfImag[i] = pSrc[2*i+1];
1511 :
1512 1482 : adfReal[i+1] = pSrc[2*i+2];
1513 1482 : padfImag[i+1] = pSrc[2*i+3];
1514 : }
1515 750 : break;
1516 : }
1517 :
1518 :
1519 : case GDT_CFloat64:
1520 : {
1521 750 : double* pSrc = (double*) poWK->papabySrcImage[iBand];
1522 750 : pSrc += 2 * iSrcOffset;
1523 2232 : for ( i = 0; i < nSrcLen; i += 2 )
1524 : {
1525 1482 : adfReal[i] = pSrc[2*i];
1526 1482 : padfImag[i] = pSrc[2*i+1];
1527 :
1528 1482 : adfReal[i+1] = pSrc[2*i+2];
1529 1482 : padfImag[i+1] = pSrc[2*i+3];
1530 : }
1531 750 : break;
1532 : }
1533 :
1534 : default:
1535 0 : CPLAssert(FALSE);
1536 0 : if( padfDensity )
1537 0 : memset( padfDensity, 0, nSrcLen * sizeof(double) );
1538 0 : return FALSE;
1539 : }
1540 :
1541 1675450 : if( padfDensity == NULL )
1542 1657914 : return TRUE;
1543 :
1544 17536 : if( poWK->pafUnifiedSrcDensity == NULL )
1545 : {
1546 35184 : for ( i = 0; i < nSrcLen; i += 2 )
1547 : {
1548 : // Take into account earlier calcs
1549 17880 : if(padfDensity[i] > 0.000000001)
1550 : {
1551 17880 : padfDensity[i] = 1.0;
1552 17880 : bHasValid = TRUE;
1553 : }
1554 :
1555 17880 : if(padfDensity[i+1] > 0.000000001)
1556 : {
1557 17880 : padfDensity[i+1] = 1.0;
1558 17880 : bHasValid = TRUE;
1559 : }
1560 : }
1561 : }
1562 : else
1563 : {
1564 464 : for ( i = 0; i < nSrcLen; i += 2 )
1565 : {
1566 232 : if(padfDensity[i] > 0.000000001)
1567 232 : padfDensity[i] = poWK->pafUnifiedSrcDensity[iSrcOffset+i];
1568 232 : if(padfDensity[i] > 0.000000001)
1569 176 : bHasValid = TRUE;
1570 :
1571 232 : if(padfDensity[i+1] > 0.000000001)
1572 232 : padfDensity[i+1] = poWK->pafUnifiedSrcDensity[iSrcOffset+i+1];
1573 232 : if(padfDensity[i+1] > 0.000000001)
1574 212 : bHasValid = TRUE;
1575 : }
1576 : }
1577 :
1578 17536 : return bHasValid;
1579 : }
1580 :
1581 : /************************************************************************/
1582 : /* GWKGetPixelByte() */
1583 : /************************************************************************/
1584 :
1585 725901 : static int GWKGetPixelByte( GDALWarpKernel *poWK, int iBand,
1586 : int iSrcOffset, double *pdfDensity,
1587 : GByte *pbValue )
1588 :
1589 : {
1590 725901 : GByte *pabySrc = poWK->papabySrcImage[iBand];
1591 :
1592 1101739 : if ( ( poWK->panUnifiedSrcValid != NULL
1593 375838 : && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
1594 : & (0x01 << (iSrcOffset & 0x1f))) ) )
1595 : || ( poWK->papanBandSrcValid != NULL
1596 0 : && poWK->papanBandSrcValid[iBand] != NULL
1597 0 : && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
1598 : & (0x01 << (iSrcOffset & 0x1f)))) ) )
1599 : {
1600 0 : *pdfDensity = 0.0;
1601 0 : return FALSE;
1602 : }
1603 :
1604 725901 : *pbValue = pabySrc[iSrcOffset];
1605 :
1606 725901 : if ( poWK->pafUnifiedSrcDensity == NULL )
1607 710798 : *pdfDensity = 1.0;
1608 : else
1609 15103 : *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
1610 :
1611 725901 : return *pdfDensity != 0.0;
1612 : }
1613 :
1614 : /************************************************************************/
1615 : /* GWKGetPixelShort() */
1616 : /************************************************************************/
1617 :
1618 1488467 : static int GWKGetPixelShort( GDALWarpKernel *poWK, int iBand,
1619 : int iSrcOffset, double *pdfDensity,
1620 : GInt16 *piValue )
1621 :
1622 : {
1623 1488467 : GInt16 *pabySrc = (GInt16 *)poWK->papabySrcImage[iBand];
1624 :
1625 4462995 : if ( ( poWK->panUnifiedSrcValid != NULL
1626 0 : && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
1627 : & (0x01 << (iSrcOffset & 0x1f))) ) )
1628 : || ( poWK->papanBandSrcValid != NULL
1629 1487264 : && poWK->papanBandSrcValid[iBand] != NULL
1630 1487264 : && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
1631 : & (0x01 << (iSrcOffset & 0x1f)))) ) )
1632 : {
1633 715 : *pdfDensity = 0.0;
1634 715 : return FALSE;
1635 : }
1636 :
1637 1487752 : *piValue = pabySrc[iSrcOffset];
1638 :
1639 1487752 : if ( poWK->pafUnifiedSrcDensity == NULL )
1640 1486549 : *pdfDensity = 1.0;
1641 : else
1642 1203 : *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
1643 :
1644 1487752 : return *pdfDensity != 0.0;
1645 : }
1646 :
1647 : /************************************************************************/
1648 : /* GWKGetPixelFloat() */
1649 : /************************************************************************/
1650 :
1651 1603 : static int GWKGetPixelFloat( GDALWarpKernel *poWK, int iBand,
1652 : int iSrcOffset, double *pdfDensity,
1653 : float *pfValue )
1654 :
1655 : {
1656 1603 : float *pabySrc = (float *)poWK->papabySrcImage[iBand];
1657 :
1658 2403 : if ( ( poWK->panUnifiedSrcValid != NULL
1659 0 : && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
1660 : & (0x01 << (iSrcOffset & 0x1f))) ) )
1661 : || ( poWK->papanBandSrcValid != NULL
1662 400 : && poWK->papanBandSrcValid[iBand] != NULL
1663 400 : && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
1664 : & (0x01 << (iSrcOffset & 0x1f)))) ) )
1665 : {
1666 40 : *pdfDensity = 0.0;
1667 40 : return FALSE;
1668 : }
1669 :
1670 1563 : *pfValue = pabySrc[iSrcOffset];
1671 :
1672 1563 : if ( poWK->pafUnifiedSrcDensity == NULL )
1673 360 : *pdfDensity = 1.0;
1674 : else
1675 1203 : *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
1676 :
1677 1563 : return *pdfDensity != 0.0;
1678 : }
1679 :
1680 : /************************************************************************/
1681 : /* GWKBilinearResample() */
1682 : /* Set of bilinear interpolators */
1683 : /************************************************************************/
1684 :
1685 8588 : static int GWKBilinearResample( GDALWarpKernel *poWK, int iBand,
1686 : double dfSrcX, double dfSrcY,
1687 : double *pdfDensity,
1688 : double *pdfReal, double *pdfImag )
1689 :
1690 : {
1691 : // Save as local variables to avoid following pointers
1692 8588 : int nSrcXSize = poWK->nSrcXSize;
1693 8588 : int nSrcYSize = poWK->nSrcYSize;
1694 :
1695 8588 : int iSrcX = (int) floor(dfSrcX - 0.5);
1696 8588 : int iSrcY = (int) floor(dfSrcY - 0.5);
1697 : int iSrcOffset;
1698 8588 : double dfRatioX = 1.5 - (dfSrcX - iSrcX);
1699 8588 : double dfRatioY = 1.5 - (dfSrcY - iSrcY);
1700 8588 : double adfDensity[2], adfReal[2], adfImag[2] = {0, 0};
1701 8588 : double dfAccumulatorReal = 0.0, dfAccumulatorImag = 0.0;
1702 8588 : double dfAccumulatorDensity = 0.0;
1703 8588 : double dfAccumulatorDivisor = 0.0;
1704 8588 : int bShifted = FALSE;
1705 :
1706 8588 : if (iSrcX == -1)
1707 : {
1708 0 : iSrcX = 0;
1709 0 : dfRatioX = 1;
1710 : }
1711 8588 : if (iSrcY == -1)
1712 : {
1713 150 : iSrcY = 0;
1714 150 : dfRatioY = 1;
1715 : }
1716 8588 : iSrcOffset = iSrcX + iSrcY * nSrcXSize;
1717 :
1718 : // Shift so we don't overrun the array
1719 8588 : if( nSrcXSize * nSrcYSize == iSrcOffset + 1
1720 : || nSrcXSize * nSrcYSize == iSrcOffset + nSrcXSize + 1 )
1721 : {
1722 111 : bShifted = TRUE;
1723 111 : --iSrcOffset;
1724 : }
1725 :
1726 : // Get pixel row
1727 8588 : if ( iSrcY >= 0 && iSrcY < nSrcYSize
1728 : && iSrcOffset >= 0 && iSrcOffset < nSrcXSize * nSrcYSize
1729 : && GWKGetPixelRow( poWK, iBand, iSrcOffset, 1,
1730 : adfDensity, adfReal, adfImag ) )
1731 : {
1732 8568 : double dfMult1 = dfRatioX * dfRatioY;
1733 8568 : double dfMult2 = (1.0-dfRatioX) * dfRatioY;
1734 :
1735 : // Shifting corrected
1736 8568 : if ( bShifted )
1737 : {
1738 111 : adfReal[0] = adfReal[1];
1739 111 : adfImag[0] = adfImag[1];
1740 111 : adfDensity[0] = adfDensity[1];
1741 : }
1742 :
1743 : // Upper Left Pixel
1744 17136 : if ( iSrcX >= 0 && iSrcX < nSrcXSize
1745 8568 : && adfDensity[0] > 0.000000001 )
1746 : {
1747 8552 : dfAccumulatorDivisor += dfMult1;
1748 :
1749 8552 : dfAccumulatorReal += adfReal[0] * dfMult1;
1750 8552 : dfAccumulatorImag += adfImag[0] * dfMult1;
1751 8552 : dfAccumulatorDensity += adfDensity[0] * dfMult1;
1752 : }
1753 :
1754 : // Upper Right Pixel
1755 16770 : if ( iSrcX+1 >= 0 && iSrcX+1 < nSrcXSize
1756 8202 : && adfDensity[1] > 0.000000001 )
1757 : {
1758 8202 : dfAccumulatorDivisor += dfMult2;
1759 :
1760 8202 : dfAccumulatorReal += adfReal[1] * dfMult2;
1761 8202 : dfAccumulatorImag += adfImag[1] * dfMult2;
1762 8202 : dfAccumulatorDensity += adfDensity[1] * dfMult2;
1763 : }
1764 : }
1765 :
1766 : // Get pixel row
1767 8588 : if ( iSrcY+1 >= 0 && iSrcY+1 < nSrcYSize
1768 : && iSrcOffset+nSrcXSize >= 0
1769 : && iSrcOffset+nSrcXSize < nSrcXSize * nSrcYSize
1770 : && GWKGetPixelRow( poWK, iBand, iSrcOffset+nSrcXSize, 1,
1771 : adfDensity, adfReal, adfImag ) )
1772 : {
1773 8372 : double dfMult1 = dfRatioX * (1.0-dfRatioY);
1774 8372 : double dfMult2 = (1.0-dfRatioX) * (1.0-dfRatioY);
1775 :
1776 : // Shifting corrected
1777 8372 : if ( bShifted )
1778 : {
1779 57 : adfReal[0] = adfReal[1];
1780 57 : adfImag[0] = adfImag[1];
1781 57 : adfDensity[0] = adfDensity[1];
1782 : }
1783 :
1784 : // Lower Left Pixel
1785 16744 : if ( iSrcX >= 0 && iSrcX < nSrcXSize
1786 8372 : && adfDensity[0] > 0.000000001 )
1787 : {
1788 8352 : dfAccumulatorDivisor += dfMult1;
1789 :
1790 8352 : dfAccumulatorReal += adfReal[0] * dfMult1;
1791 8352 : dfAccumulatorImag += adfImag[0] * dfMult1;
1792 8352 : dfAccumulatorDensity += adfDensity[0] * dfMult1;
1793 : }
1794 :
1795 : // Lower Right Pixel
1796 16432 : if ( iSrcX+1 >= 0 && iSrcX+1 < nSrcXSize
1797 8060 : && adfDensity[1] > 0.000000001 )
1798 : {
1799 8060 : dfAccumulatorDivisor += dfMult2;
1800 :
1801 8060 : dfAccumulatorReal += adfReal[1] * dfMult2;
1802 8060 : dfAccumulatorImag += adfImag[1] * dfMult2;
1803 8060 : dfAccumulatorDensity += adfDensity[1] * dfMult2;
1804 : }
1805 : }
1806 :
1807 : /* -------------------------------------------------------------------- */
1808 : /* Return result. */
1809 : /* -------------------------------------------------------------------- */
1810 8588 : if ( dfAccumulatorDivisor == 1.0 )
1811 : {
1812 8402 : *pdfReal = dfAccumulatorReal;
1813 8402 : *pdfImag = dfAccumulatorImag;
1814 8402 : *pdfDensity = dfAccumulatorDensity;
1815 8402 : return TRUE;
1816 : }
1817 186 : else if ( dfAccumulatorDivisor < 0.00001 )
1818 : {
1819 0 : *pdfReal = 0.0;
1820 0 : *pdfImag = 0.0;
1821 0 : *pdfDensity = 0.0;
1822 0 : return FALSE;
1823 : }
1824 : else
1825 : {
1826 186 : *pdfReal = dfAccumulatorReal / dfAccumulatorDivisor;
1827 186 : *pdfImag = dfAccumulatorImag / dfAccumulatorDivisor;
1828 186 : *pdfDensity = dfAccumulatorDensity / dfAccumulatorDivisor;
1829 186 : return TRUE;
1830 : }
1831 : }
1832 :
1833 289915 : static int GWKBilinearResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
1834 : double dfSrcX, double dfSrcY,
1835 : GByte *pbValue )
1836 :
1837 : {
1838 289915 : double dfAccumulator = 0.0;
1839 289915 : double dfAccumulatorDivisor = 0.0;
1840 :
1841 289915 : int iSrcX = (int) floor(dfSrcX - 0.5);
1842 289915 : int iSrcY = (int) floor(dfSrcY - 0.5);
1843 289915 : int iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
1844 289915 : double dfRatioX = 1.5 - (dfSrcX - iSrcX);
1845 289915 : double dfRatioY = 1.5 - (dfSrcY - iSrcY);
1846 :
1847 : // Upper Left Pixel
1848 289915 : if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
1849 : && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
1850 : {
1851 283063 : double dfMult = dfRatioX * dfRatioY;
1852 :
1853 283063 : dfAccumulatorDivisor += dfMult;
1854 :
1855 : dfAccumulator +=
1856 283063 : (double)poWK->papabySrcImage[iBand][iSrcOffset] * dfMult;
1857 : }
1858 :
1859 : // Upper Right Pixel
1860 289915 : if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
1861 : && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
1862 : {
1863 286086 : double dfMult = (1.0-dfRatioX) * dfRatioY;
1864 :
1865 286086 : dfAccumulatorDivisor += dfMult;
1866 :
1867 : dfAccumulator +=
1868 286086 : (double)poWK->papabySrcImage[iBand][iSrcOffset+1] * dfMult;
1869 : }
1870 :
1871 : // Lower Right Pixel
1872 289915 : if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
1873 : && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
1874 : {
1875 289188 : double dfMult = (1.0-dfRatioX) * (1.0-dfRatioY);
1876 :
1877 289188 : dfAccumulatorDivisor += dfMult;
1878 :
1879 : dfAccumulator +=
1880 289188 : (double)poWK->papabySrcImage[iBand][iSrcOffset+1+poWK->nSrcXSize]
1881 289188 : * dfMult;
1882 : }
1883 :
1884 : // Lower Left Pixel
1885 289915 : if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
1886 : && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
1887 : {
1888 286134 : double dfMult = dfRatioX * (1.0-dfRatioY);
1889 :
1890 286134 : dfAccumulatorDivisor += dfMult;
1891 :
1892 : dfAccumulator +=
1893 286134 : (double)poWK->papabySrcImage[iBand][iSrcOffset+poWK->nSrcXSize]
1894 286134 : * dfMult;
1895 : }
1896 :
1897 : /* -------------------------------------------------------------------- */
1898 : /* Return result. */
1899 : /* -------------------------------------------------------------------- */
1900 : double dfValue;
1901 :
1902 289915 : if( dfAccumulatorDivisor < 0.00001 )
1903 : {
1904 0 : *pbValue = 0;
1905 0 : return FALSE;
1906 : }
1907 289915 : else if( dfAccumulatorDivisor == 1.0 )
1908 : {
1909 274559 : dfValue = dfAccumulator;
1910 : }
1911 : else
1912 : {
1913 15356 : dfValue = dfAccumulator / dfAccumulatorDivisor;
1914 : }
1915 :
1916 289915 : if ( dfValue < 0.0 )
1917 0 : *pbValue = 0;
1918 289915 : else if ( dfValue > 255.0 )
1919 716 : *pbValue = 255;
1920 : else
1921 289199 : *pbValue = (GByte)(0.5 + dfValue);
1922 :
1923 289915 : return TRUE;
1924 : }
1925 :
1926 1714891 : static int GWKBilinearResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
1927 : double dfSrcX, double dfSrcY,
1928 : GInt16 *piValue )
1929 :
1930 : {
1931 1714891 : double dfAccumulator = 0.0;
1932 1714891 : double dfAccumulatorDivisor = 0.0;
1933 :
1934 1714891 : int iSrcX = (int) floor(dfSrcX - 0.5);
1935 1714891 : int iSrcY = (int) floor(dfSrcY - 0.5);
1936 1714891 : int iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
1937 1714891 : double dfRatioX = 1.5 - (dfSrcX - iSrcX);
1938 1714891 : double dfRatioY = 1.5 - (dfSrcY - iSrcY);
1939 :
1940 : // Upper Left Pixel
1941 1714891 : if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
1942 : && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
1943 : {
1944 1707355 : double dfMult = dfRatioX * dfRatioY;
1945 :
1946 1707355 : dfAccumulatorDivisor += dfMult;
1947 :
1948 : dfAccumulator +=
1949 1707355 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset]
1950 1707355 : * dfMult;
1951 : }
1952 :
1953 : // Upper Right Pixel
1954 1714891 : if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
1955 : && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
1956 : {
1957 1709182 : double dfMult = (1.0-dfRatioX) * dfRatioY;
1958 :
1959 1709182 : dfAccumulatorDivisor += dfMult;
1960 :
1961 : dfAccumulator +=
1962 1709182 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+1] * dfMult;
1963 : }
1964 :
1965 : // Lower Right Pixel
1966 1714891 : if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
1967 : && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
1968 : {
1969 1713535 : double dfMult = (1.0-dfRatioX) * (1.0-dfRatioY);
1970 :
1971 1713535 : dfAccumulatorDivisor += dfMult;
1972 :
1973 : dfAccumulator +=
1974 1713535 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+1+poWK->nSrcXSize]
1975 1713535 : * dfMult;
1976 : }
1977 :
1978 : // Lower Left Pixel
1979 1714891 : if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
1980 : && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
1981 : {
1982 1711682 : double dfMult = dfRatioX * (1.0-dfRatioY);
1983 :
1984 1711682 : dfAccumulatorDivisor += dfMult;
1985 :
1986 : dfAccumulator +=
1987 1711682 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+poWK->nSrcXSize]
1988 1711682 : * dfMult;
1989 : }
1990 :
1991 : /* -------------------------------------------------------------------- */
1992 : /* Return result. */
1993 : /* -------------------------------------------------------------------- */
1994 1714891 : if( dfAccumulatorDivisor == 1.0 )
1995 : {
1996 1698761 : *piValue = (GInt16)(0.5 + dfAccumulator);
1997 1698761 : return TRUE;
1998 : }
1999 16130 : else if( dfAccumulatorDivisor < 0.00001 )
2000 : {
2001 0 : *piValue = 0;
2002 0 : return FALSE;
2003 : }
2004 : else
2005 : {
2006 16130 : *piValue = (GInt16)(0.5 + dfAccumulator / dfAccumulatorDivisor);
2007 16130 : return TRUE;
2008 : }
2009 : }
2010 :
2011 : /************************************************************************/
2012 : /* GWKCubicResample() */
2013 : /* Set of bicubic interpolators using cubic convolution. */
2014 : /************************************************************************/
2015 :
2016 : #define CubicConvolution(distance1,distance2,distance3,f0,f1,f2,f3) \
2017 : ( ( -f0 + f1 - f2 + f3) * distance3 \
2018 : + (2.0*(f0 - f1) + f2 - f3) * distance2 \
2019 : + ( -f0 + f2 ) * distance1 \
2020 : + f1 )
2021 :
2022 558 : static int GWKCubicResample( GDALWarpKernel *poWK, int iBand,
2023 : double dfSrcX, double dfSrcY,
2024 : double *pdfDensity,
2025 : double *pdfReal, double *pdfImag )
2026 :
2027 : {
2028 558 : int iSrcX = (int) floor( dfSrcX - 0.5 );
2029 558 : int iSrcY = (int) floor( dfSrcY - 0.5 );
2030 558 : int iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
2031 558 : double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2032 558 : double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2033 558 : double dfDeltaX2 = dfDeltaX * dfDeltaX;
2034 558 : double dfDeltaY2 = dfDeltaY * dfDeltaY;
2035 558 : double dfDeltaX3 = dfDeltaX2 * dfDeltaX;
2036 558 : double dfDeltaY3 = dfDeltaY2 * dfDeltaY;
2037 : double adfValueDens[4], adfValueReal[4], adfValueImag[4];
2038 558 : double adfDensity[4], adfReal[4], adfImag[4] = {0, 0, 0, 0};
2039 : int i;
2040 :
2041 : // Get the bilinear interpolation at the image borders
2042 558 : if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
2043 : || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
2044 : return GWKBilinearResample( poWK, iBand, dfSrcX, dfSrcY,
2045 414 : pdfDensity, pdfReal, pdfImag );
2046 :
2047 720 : for ( i = -1; i < 3; i++ )
2048 : {
2049 2880 : if ( !GWKGetPixelRow(poWK, iBand, iSrcOffset + i * poWK->nSrcXSize - 1,
2050 : 2, adfDensity, adfReal, adfImag)
2051 576 : || adfDensity[0] < 0.000000001
2052 576 : || adfDensity[1] < 0.000000001
2053 576 : || adfDensity[2] < 0.000000001
2054 576 : || adfDensity[3] < 0.000000001 )
2055 : {
2056 : return GWKBilinearResample( poWK, iBand, dfSrcX, dfSrcY,
2057 0 : pdfDensity, pdfReal, pdfImag );
2058 : }
2059 :
2060 4608 : adfValueDens[i + 1] = CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
2061 4608 : adfDensity[0], adfDensity[1], adfDensity[2], adfDensity[3]);
2062 4608 : adfValueReal[i + 1] = CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
2063 4608 : adfReal[0], adfReal[1], adfReal[2], adfReal[3]);
2064 4608 : adfValueImag[i + 1] = CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
2065 4608 : adfImag[0], adfImag[1], adfImag[2], adfImag[3]);
2066 : }
2067 :
2068 :
2069 : /* -------------------------------------------------------------------- */
2070 : /* For now, if we have any pixels missing in the kernel area, */
2071 : /* we fallback on using bilinear interpolation. Ideally we */
2072 : /* should do "weight adjustment" of our results similarly to */
2073 : /* what is done for the cubic spline and lanc. interpolators. */
2074 : /* -------------------------------------------------------------------- */
2075 1152 : *pdfDensity = CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
2076 : adfValueDens[0], adfValueDens[1],
2077 1152 : adfValueDens[2], adfValueDens[3]);
2078 1152 : *pdfReal = CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
2079 : adfValueReal[0], adfValueReal[1],
2080 1152 : adfValueReal[2], adfValueReal[3]);
2081 1152 : *pdfImag = CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
2082 : adfValueImag[0], adfValueImag[1],
2083 1152 : adfValueImag[2], adfValueImag[3]);
2084 :
2085 144 : return TRUE;
2086 : }
2087 :
2088 278207 : static int GWKCubicResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
2089 : double dfSrcX, double dfSrcY,
2090 : GByte *pbValue )
2091 :
2092 : {
2093 278207 : int iSrcX = (int) floor( dfSrcX - 0.5 );
2094 278207 : int iSrcY = (int) floor( dfSrcY - 0.5 );
2095 278207 : int iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
2096 278207 : double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2097 278207 : double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2098 278207 : double dfDeltaX2 = dfDeltaX * dfDeltaX;
2099 278207 : double dfDeltaY2 = dfDeltaY * dfDeltaY;
2100 278207 : double dfDeltaX3 = dfDeltaX2 * dfDeltaX;
2101 278207 : double dfDeltaY3 = dfDeltaY2 * dfDeltaY;
2102 : double adfValue[4];
2103 : int i;
2104 :
2105 : // Get the bilinear interpolation at the image borders
2106 278207 : if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
2107 : || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
2108 : return GWKBilinearResampleNoMasksByte( poWK, iBand, dfSrcX, dfSrcY,
2109 10570 : pbValue);
2110 :
2111 1338185 : for ( i = -1; i < 3; i++ )
2112 : {
2113 1070548 : int iOffset = iSrcOffset + i * poWK->nSrcXSize;
2114 :
2115 11776028 : adfValue[i + 1] = CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
2116 : (double)poWK->papabySrcImage[iBand][iOffset - 1],
2117 : (double)poWK->papabySrcImage[iBand][iOffset],
2118 : (double)poWK->papabySrcImage[iBand][iOffset + 1],
2119 11776028 : (double)poWK->papabySrcImage[iBand][iOffset + 2]);
2120 : }
2121 :
2122 267637 : double dfValue = CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
2123 : adfValue[0], adfValue[1], adfValue[2], adfValue[3]);
2124 :
2125 267637 : if ( dfValue < 0.0 )
2126 8 : *pbValue = 0;
2127 267629 : else if ( dfValue > 255.0 )
2128 11506 : *pbValue = 255;
2129 : else
2130 256123 : *pbValue = (GByte)(0.5 + dfValue);
2131 :
2132 267637 : return TRUE;
2133 : }
2134 :
2135 262207 : static int GWKCubicResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
2136 : double dfSrcX, double dfSrcY,
2137 : GInt16 *piValue )
2138 :
2139 : {
2140 262207 : int iSrcX = (int) floor( dfSrcX - 0.5 );
2141 262207 : int iSrcY = (int) floor( dfSrcY - 0.5 );
2142 262207 : int iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
2143 262207 : double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2144 262207 : double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2145 262207 : double dfDeltaX2 = dfDeltaX * dfDeltaX;
2146 262207 : double dfDeltaY2 = dfDeltaY * dfDeltaY;
2147 262207 : double dfDeltaX3 = dfDeltaX2 * dfDeltaX;
2148 262207 : double dfDeltaY3 = dfDeltaY2 * dfDeltaY;
2149 : double adfValue[4];
2150 : int i;
2151 :
2152 : // Get the bilinear interpolation at the image borders
2153 262207 : if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
2154 : || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
2155 : return GWKBilinearResampleNoMasksShort( poWK, iBand, dfSrcX, dfSrcY,
2156 9182 : piValue);
2157 :
2158 1265125 : for ( i = -1; i < 3; i++ )
2159 : {
2160 1012100 : int iOffset = iSrcOffset + i * poWK->nSrcXSize;
2161 :
2162 11133100 : adfValue[i + 1] =CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
2163 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset - 1],
2164 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset],
2165 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset + 1],
2166 11133100 : (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset + 2]);
2167 : }
2168 :
2169 2024200 : *piValue = (GInt16)CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
2170 2024200 : adfValue[0], adfValue[1], adfValue[2], adfValue[3]);
2171 :
2172 253025 : return TRUE;
2173 : }
2174 :
2175 :
2176 : /************************************************************************/
2177 : /* GWKLanczosSinc() */
2178 : /************************************************************************/
2179 :
2180 : /*
2181 : * Lanczos windowed sinc interpolation kernel with radius r.
2182 : * /
2183 : * | sinc(x) * sinc(x/r), if |x| < r
2184 : * L(x) = | 1, if x = 0 ,
2185 : * | 0, otherwise
2186 : * \
2187 : *
2188 : * where sinc(x) = sin(PI * x) / (PI * x).
2189 : */
2190 :
2191 : #define GWK_PI 3.14159265358979323846
2192 :
2193 0 : static double GWKLanczosSinc( double dfX, double dfR )
2194 : {
2195 0 : if ( dfX == 0.0 )
2196 0 : return 1.0;
2197 :
2198 0 : const double dfPIX = GWK_PI * dfX;
2199 0 : const double dfPIXoverR = dfPIX / dfR;
2200 0 : const double dfPIX2overR = dfPIX * dfPIXoverR;
2201 0 : return sin(dfPIX) * sin(dfPIXoverR) / dfPIX2overR;
2202 : }
2203 :
2204 : //#undef GWK_PI
2205 :
2206 : /************************************************************************/
2207 : /* GWKBSpline() */
2208 : /************************************************************************/
2209 :
2210 4326896 : static double GWKBSpline( double x )
2211 : {
2212 4326896 : double xp2 = x + 2.0;
2213 4326896 : double xp1 = x + 1.0;
2214 4326896 : double xm1 = x - 1.0;
2215 :
2216 : // This will most likely be used, so we'll compute it ahead of time to
2217 : // avoid stalling the processor
2218 4326896 : double xp2c = xp2 * xp2 * xp2;
2219 :
2220 : // Note that the test is computed only if it is needed
2221 : return (((xp2 > 0.0)?((xp1 > 0.0)?((x > 0.0)?((xm1 > 0.0)?
2222 : -4.0 * xm1*xm1*xm1:0.0) +
2223 : 6.0 * x*x*x:0.0) +
2224 : -4.0 * xp1*xp1*xp1:0.0) +
2225 4326896 : xp2c:0.0) ) * 0.166666666666666666666;
2226 : }
2227 :
2228 :
2229 : /************************************************************************/
2230 : /* GWKResampleWrkStruct */
2231 : /************************************************************************/
2232 :
2233 : typedef struct _GWKResampleWrkStruct GWKResampleWrkStruct;
2234 :
2235 : typedef int (*pfnGWKResampleType) ( GDALWarpKernel *poWK, int iBand,
2236 : double dfSrcX, double dfSrcY,
2237 : double *pdfDensity,
2238 : double *pdfReal, double *pdfImag,
2239 : GWKResampleWrkStruct* psWrkStruct );
2240 :
2241 :
2242 : struct _GWKResampleWrkStruct
2243 : {
2244 : pfnGWKResampleType pfnGWKResample;
2245 :
2246 : // Space for saved X weights
2247 : double *padfWeightsX;
2248 : char *panCalcX;
2249 :
2250 : double *padfWeightsY; // only used by GWKResampleOptimizedLanczos
2251 : int iLastSrcX; // only used by GWKResampleOptimizedLanczos
2252 : int iLastSrcY; // only used by GWKResampleOptimizedLanczos
2253 : double dfLastDeltaX; // only used by GWKResampleOptimizedLanczos
2254 : double dfLastDeltaY; // only used by GWKResampleOptimizedLanczos
2255 :
2256 : // Space for saving a row of pixels
2257 : double *padfRowDensity;
2258 : double *padfRowReal;
2259 : double *padfRowImag;
2260 : };
2261 :
2262 : /************************************************************************/
2263 : /* GWKResampleCreateWrkStruct() */
2264 : /************************************************************************/
2265 :
2266 : static int GWKResample( GDALWarpKernel *poWK, int iBand,
2267 : double dfSrcX, double dfSrcY,
2268 : double *pdfDensity,
2269 : double *pdfReal, double *pdfImag,
2270 : GWKResampleWrkStruct* psWrkStruct );
2271 :
2272 : static int GWKResampleOptimizedLanczos( GDALWarpKernel *poWK, int iBand,
2273 : double dfSrcX, double dfSrcY,
2274 : double *pdfDensity,
2275 : double *pdfReal, double *pdfImag,
2276 : GWKResampleWrkStruct* psWrkStruct );
2277 :
2278 87 : static GWKResampleWrkStruct* GWKResampleCreateWrkStruct(GDALWarpKernel *poWK)
2279 : {
2280 87 : int nXDist = ( poWK->nXRadius + 1 ) * 2;
2281 :
2282 : GWKResampleWrkStruct* psWrkStruct =
2283 87 : (GWKResampleWrkStruct*)CPLMalloc(sizeof(GWKResampleWrkStruct));
2284 :
2285 : // Alloc space for saved X weights
2286 87 : psWrkStruct->padfWeightsX = (double *)CPLCalloc( nXDist, sizeof(double) );
2287 87 : psWrkStruct->panCalcX = (char *)CPLMalloc( nXDist * sizeof(char) );
2288 :
2289 87 : psWrkStruct->padfWeightsY = (double *)CPLCalloc( nXDist, sizeof(double) );
2290 87 : psWrkStruct->iLastSrcX = -10;
2291 87 : psWrkStruct->iLastSrcY = -10;
2292 87 : psWrkStruct->dfLastDeltaX = -10;
2293 87 : psWrkStruct->dfLastDeltaY = -10;
2294 :
2295 : // Alloc space for saving a row of pixels
2296 173 : if( poWK->pafUnifiedSrcDensity == NULL &&
2297 : poWK->panUnifiedSrcValid == NULL &&
2298 : poWK->papanBandSrcValid == NULL )
2299 : {
2300 86 : psWrkStruct->padfRowDensity = NULL;
2301 : }
2302 : else
2303 : {
2304 1 : psWrkStruct->padfRowDensity = (double *)CPLCalloc( nXDist, sizeof(double) );
2305 : }
2306 87 : psWrkStruct->padfRowReal = (double *)CPLCalloc( nXDist, sizeof(double) );
2307 87 : psWrkStruct->padfRowImag = (double *)CPLCalloc( nXDist, sizeof(double) );
2308 :
2309 137 : if( poWK->eResample == GRA_Lanczos &&
2310 : poWK->dfXFilter == 3.0 &&
2311 : poWK->dfYFilter == 3.0 )
2312 : {
2313 50 : psWrkStruct->pfnGWKResample = GWKResampleOptimizedLanczos;
2314 :
2315 50 : const double dfXScale = poWK->dfXScale;
2316 50 : if( dfXScale < 1.0 )
2317 : {
2318 0 : int iMin = poWK->nFiltInitX, iMax = poWK->nXRadius;
2319 0 : while( iMin * dfXScale < -3.0 )
2320 0 : iMin ++;
2321 0 : while( iMax * dfXScale > 3.0 )
2322 0 : iMax --;
2323 :
2324 0 : for(int i = iMin; i <= iMax; ++i)
2325 : {
2326 0 : psWrkStruct->padfWeightsX[i-poWK->nFiltInitX] =
2327 0 : GWKLanczosSinc(i * dfXScale, poWK->dfXFilter) * dfXScale;
2328 : }
2329 : }
2330 :
2331 50 : const double dfYScale = poWK->dfYScale;
2332 50 : if( dfYScale < 1.0 )
2333 : {
2334 0 : int jMin = poWK->nFiltInitY, jMax = poWK->nYRadius;
2335 0 : while( jMin * dfYScale < -3.0 )
2336 0 : jMin ++;
2337 0 : while( jMax * dfYScale > 3.0 )
2338 0 : jMax --;
2339 :
2340 0 : for(int j = jMin; j <= jMax; ++j)
2341 : {
2342 0 : psWrkStruct->padfWeightsY[j-poWK->nFiltInitY] =
2343 0 : GWKLanczosSinc(j * dfYScale, poWK->dfYFilter) * dfYScale;
2344 : }
2345 : }
2346 : }
2347 : else
2348 37 : psWrkStruct->pfnGWKResample = GWKResample;
2349 :
2350 87 : return psWrkStruct;
2351 : }
2352 :
2353 : /************************************************************************/
2354 : /* GWKResampleDeleteWrkStruct() */
2355 : /************************************************************************/
2356 :
2357 87 : static void GWKResampleDeleteWrkStruct(GWKResampleWrkStruct* psWrkStruct)
2358 : {
2359 87 : CPLFree( psWrkStruct->padfWeightsX );
2360 87 : CPLFree( psWrkStruct->padfWeightsY );
2361 87 : CPLFree( psWrkStruct->panCalcX );
2362 87 : CPLFree( psWrkStruct->padfRowDensity );
2363 87 : CPLFree( psWrkStruct->padfRowReal );
2364 87 : CPLFree( psWrkStruct->padfRowImag );
2365 87 : CPLFree( psWrkStruct );
2366 87 : }
2367 :
2368 : /************************************************************************/
2369 : /* GWKResample() */
2370 : /************************************************************************/
2371 :
2372 558 : static int GWKResample( GDALWarpKernel *poWK, int iBand,
2373 : double dfSrcX, double dfSrcY,
2374 : double *pdfDensity,
2375 : double *pdfReal, double *pdfImag,
2376 : GWKResampleWrkStruct* psWrkStruct )
2377 :
2378 : {
2379 : // Save as local variables to avoid following pointers in loops
2380 558 : const int nSrcXSize = poWK->nSrcXSize;
2381 558 : const int nSrcYSize = poWK->nSrcYSize;
2382 :
2383 558 : double dfAccumulatorReal = 0.0, dfAccumulatorImag = 0.0;
2384 558 : double dfAccumulatorDensity = 0.0;
2385 558 : double dfAccumulatorWeight = 0.0;
2386 558 : const int iSrcX = (int) floor( dfSrcX - 0.5 );
2387 558 : const int iSrcY = (int) floor( dfSrcY - 0.5 );
2388 558 : const int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
2389 558 : const double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2390 558 : const double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2391 558 : const int eResample = poWK->eResample;
2392 :
2393 558 : const double dfXScale = poWK->dfXScale, dfYScale = poWK->dfYScale;
2394 558 : const double dfXFilter = poWK->dfXFilter, dfYFilter = poWK->dfYFilter;
2395 :
2396 : int i, j;
2397 558 : const int nXDist = ( poWK->nXRadius + 1 ) * 2;
2398 :
2399 : // Space for saved X weights
2400 558 : double *padfWeightsX = psWrkStruct->padfWeightsX;
2401 558 : char *panCalcX = psWrkStruct->panCalcX;
2402 :
2403 : // Space for saving a row of pixels
2404 558 : double *padfRowDensity = psWrkStruct->padfRowDensity;
2405 558 : double *padfRowReal = psWrkStruct->padfRowReal;
2406 558 : double *padfRowImag = psWrkStruct->padfRowImag;
2407 :
2408 : // Mark as needing calculation (don't calculate the weights yet,
2409 : // because a mask may render it unnecessary)
2410 558 : memset( panCalcX, FALSE, nXDist * sizeof(char) );
2411 :
2412 558 : CPLAssert( eResample == GRA_CubicSpline || eResample == GRA_Lanczos );
2413 :
2414 : // Skip sampling over edge of image
2415 558 : j = poWK->nFiltInitY;
2416 558 : int jMax= poWK->nYRadius;
2417 558 : if( iSrcY + j < 0 )
2418 108 : j = -iSrcY;
2419 558 : if( iSrcY + jMax >= nSrcYSize )
2420 216 : jMax = nSrcYSize - iSrcY - 1;
2421 :
2422 558 : int iMin = poWK->nFiltInitX, iMax = poWK->nXRadius;
2423 558 : if( iSrcX + iMin < 0 )
2424 108 : iMin = -iSrcX;
2425 558 : if( iSrcX + iMax >= nSrcXSize )
2426 216 : iMax = nSrcXSize - iSrcX - 1;
2427 :
2428 558 : const int bXScaleBelow1 = ( dfXScale < 1.0 );
2429 558 : const int bYScaleBelow1 = ( dfYScale < 1.0 );
2430 :
2431 558 : int iRowOffset = iSrcOffset + (j - 1) * nSrcXSize + iMin;
2432 :
2433 : // Loop over pixel rows in the kernel
2434 2358 : for ( ; j <= jMax; ++j )
2435 : {
2436 : double dfWeight1;
2437 :
2438 1800 : iRowOffset += nSrcXSize;
2439 :
2440 : // Get pixel values
2441 : // We can potentially read extra elements after the "normal" end of the source arrays,
2442 : // but the contract of papabySrcImage[iBand], papanBandSrcValid[iBand],
2443 : // panUnifiedSrcValid and pafUnifiedSrcDensity is to have WARP_EXTRA_ELTS
2444 : // reserved at their end.
2445 1800 : if ( !GWKGetPixelRow( poWK, iBand, iRowOffset, (iMax-iMin+2)/2,
2446 : padfRowDensity, padfRowReal, padfRowImag ) )
2447 0 : continue;
2448 :
2449 : // Select the resampling algorithm
2450 1800 : if ( eResample == GRA_CubicSpline )
2451 : // Calculate the Y weight
2452 : dfWeight1 = ( bYScaleBelow1 ) ?
2453 : GWKBSpline(((double)j) * dfYScale) * dfYScale :
2454 1800 : GWKBSpline(((double)j) - dfDeltaY);
2455 : else /*if ( eResample == GRA_Lanczos )*/
2456 : {
2457 0 : if( bYScaleBelow1 )
2458 0 : dfWeight1 = GWKLanczosSinc(j * dfYScale, dfYFilter) * dfYScale;
2459 : else
2460 0 : dfWeight1 = GWKLanczosSinc(j - dfDeltaY, dfYFilter);
2461 : }
2462 :
2463 : // Iterate over pixels in row
2464 7704 : for (i = iMin; i <= iMax; ++i )
2465 : {
2466 : double dfWeight2;
2467 :
2468 : // Skip sampling if pixel has zero density
2469 5904 : if ( padfRowDensity != NULL &&
2470 0 : padfRowDensity[i-iMin] < 0.000000001 )
2471 0 : continue;
2472 :
2473 : // Make or use a cached set of weights for this row
2474 5904 : if ( panCalcX[i-iMin] )
2475 : // Use saved weight value instead of recomputing it
2476 4104 : dfWeight2 = dfWeight1 * padfWeightsX[i-iMin];
2477 : else
2478 : {
2479 : // Choose among possible algorithms
2480 1800 : if ( eResample == GRA_CubicSpline )
2481 : // Calculate & save the X weight
2482 1800 : padfWeightsX[i-iMin] = dfWeight2 = ( bXScaleBelow1 ) ?
2483 : GWKBSpline((double)i * dfXScale) * dfXScale :
2484 1800 : GWKBSpline(dfDeltaX - (double)i);
2485 : else /*if ( eResample == GRA_Lanczos )*/
2486 : {
2487 : // Calculate & save the X weight
2488 0 : if( bXScaleBelow1 )
2489 0 : padfWeightsX[i-iMin] = dfWeight2 =
2490 0 : GWKLanczosSinc(i * dfXScale, dfXFilter) * dfXScale;
2491 : else
2492 0 : padfWeightsX[i-iMin] = dfWeight2 =
2493 0 : GWKLanczosSinc(i - dfDeltaX, dfXFilter);
2494 : }
2495 :
2496 1800 : dfWeight2 *= dfWeight1;
2497 1800 : panCalcX[i-iMin] = TRUE;
2498 : }
2499 :
2500 : // Accumulate!
2501 5904 : dfAccumulatorReal += padfRowReal[i-iMin] * dfWeight2;
2502 5904 : dfAccumulatorImag += padfRowImag[i-iMin] * dfWeight2;
2503 5904 : if( padfRowDensity != NULL )
2504 0 : dfAccumulatorDensity += padfRowDensity[i-iMin] * dfWeight2;
2505 5904 : dfAccumulatorWeight += dfWeight2;
2506 : }
2507 : }
2508 :
2509 558 : if ( dfAccumulatorWeight < 0.000001 ||
2510 : (padfRowDensity != NULL && dfAccumulatorDensity < 0.000001) )
2511 : {
2512 0 : *pdfDensity = 0.0;
2513 0 : return FALSE;
2514 : }
2515 :
2516 : // Calculate the output taking into account weighting
2517 882 : if ( dfAccumulatorWeight < 0.99999 || dfAccumulatorWeight > 1.00001 )
2518 : {
2519 324 : *pdfReal = dfAccumulatorReal / dfAccumulatorWeight;
2520 324 : *pdfImag = dfAccumulatorImag / dfAccumulatorWeight;
2521 324 : if( padfRowDensity != NULL )
2522 0 : *pdfDensity = dfAccumulatorDensity / dfAccumulatorWeight;
2523 : else
2524 324 : *pdfDensity = 1.0;
2525 : }
2526 : else
2527 : {
2528 234 : *pdfReal = dfAccumulatorReal;
2529 234 : *pdfImag = dfAccumulatorImag;
2530 234 : if( padfRowDensity != NULL )
2531 0 : *pdfDensity = dfAccumulatorDensity;
2532 : else
2533 234 : *pdfDensity = 1.0;
2534 : }
2535 :
2536 558 : return TRUE;
2537 : }
2538 :
2539 : /************************************************************************/
2540 : /* GWKResampleOptimizedLanczos() */
2541 : /************************************************************************/
2542 :
2543 278826 : static int GWKResampleOptimizedLanczos( GDALWarpKernel *poWK, int iBand,
2544 : double dfSrcX, double dfSrcY,
2545 : double *pdfDensity,
2546 : double *pdfReal, double *pdfImag,
2547 : GWKResampleWrkStruct* psWrkStruct )
2548 :
2549 : {
2550 : // Save as local variables to avoid following pointers in loops
2551 278826 : const int nSrcXSize = poWK->nSrcXSize;
2552 278826 : const int nSrcYSize = poWK->nSrcYSize;
2553 :
2554 278826 : double dfAccumulatorReal = 0.0, dfAccumulatorImag = 0.0;
2555 278826 : double dfAccumulatorDensity = 0.0;
2556 278826 : double dfAccumulatorWeight = 0.0;
2557 278826 : const int iSrcX = (int) floor( dfSrcX - 0.5 );
2558 278826 : const int iSrcY = (int) floor( dfSrcY - 0.5 );
2559 278826 : const int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
2560 278826 : const double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2561 278826 : const double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2562 :
2563 278826 : const double dfXScale = poWK->dfXScale, dfYScale = poWK->dfYScale;
2564 :
2565 : // Space for saved X weights
2566 278826 : double *padfWeightsX = psWrkStruct->padfWeightsX;
2567 278826 : double *padfWeightsY = psWrkStruct->padfWeightsY;
2568 :
2569 : // Space for saving a row of pixels
2570 278826 : double *padfRowDensity = psWrkStruct->padfRowDensity;
2571 278826 : double *padfRowReal = psWrkStruct->padfRowReal;
2572 278826 : double *padfRowImag = psWrkStruct->padfRowImag;
2573 :
2574 : // Skip sampling over edge of image
2575 278826 : int jMin = poWK->nFiltInitY, jMax= poWK->nYRadius;
2576 278826 : if( iSrcY + jMin < 0 )
2577 12398 : jMin = -iSrcY;
2578 278826 : if( iSrcY + jMax >= nSrcYSize )
2579 934 : jMax = nSrcYSize - iSrcY - 1;
2580 :
2581 278826 : int iMin = poWK->nFiltInitX, iMax = poWK->nXRadius;
2582 278826 : if( iSrcX + iMin < 0 )
2583 11886 : iMin = -iSrcX;
2584 278826 : if( iSrcX + iMax >= nSrcXSize )
2585 934 : iMax = nSrcXSize - iSrcX - 1;
2586 :
2587 278826 : if( dfXScale < 1.0 )
2588 : {
2589 0 : while( iMin * dfXScale < -3.0 )
2590 0 : iMin ++;
2591 0 : while( iMax * dfXScale > 3.0 )
2592 0 : iMax --;
2593 : // padfWeightsX computed in GWKResampleCreateWrkStruct
2594 : }
2595 : else
2596 : {
2597 824284 : while( iMin - dfDeltaX < -3.0 )
2598 266632 : iMin ++;
2599 557652 : while( iMax - dfDeltaX > 3.0 )
2600 0 : iMax --;
2601 :
2602 278826 : if( iSrcX != psWrkStruct->iLastSrcX ||
2603 : dfDeltaX != psWrkStruct->dfLastDeltaX )
2604 : {
2605 : // Optimisation of GWKLanczosSinc(i - dfDeltaX) based on the following
2606 : // trigonometric formulas.
2607 :
2608 : //sin(GWK_PI * (dfBase + k)) = sin(GWK_PI * dfBase) * cos(GWK_PI * k) + cos(GWK_PI * dfBase) * sin(GWK_PI * k)
2609 : //sin(GWK_PI * (dfBase + k)) = dfSinPIBase * cos(GWK_PI * k) + dfCosPIBase * sin(GWK_PI * k)
2610 : //sin(GWK_PI * (dfBase + k)) = dfSinPIBase * cos(GWK_PI * k)
2611 : //sin(GWK_PI * (dfBase + k)) = dfSinPIBase * (((k % 2) == 0) ? 1 : -1)
2612 :
2613 : //sin(GWK_PI / dfR * (dfBase + k)) = sin(GWK_PI / dfR * dfBase) * cos(GWK_PI / dfR * k) + cos(GWK_PI / dfR * dfBase) * sin(GWK_PI / dfR * k)
2614 : //sin(GWK_PI / dfR * (dfBase + k)) = dfSinPIBaseOverR * cos(GWK_PI / dfR * k) + dfCosPIBaseOverR * sin(GWK_PI / dfR * k)
2615 :
2616 278826 : double dfSinPIDeltaXOver3 = sin((-GWK_PI / 3) * dfDeltaX);
2617 278826 : double dfSin2PIDeltaXOver3 = dfSinPIDeltaXOver3 * dfSinPIDeltaXOver3;
2618 : /* ok to use sqrt(1-sin^2) since GWK_PI / 3 * dfDeltaX < PI/2 */
2619 278826 : double dfCosPIDeltaXOver3 = sqrt(1 - dfSin2PIDeltaXOver3);
2620 278826 : double dfSinPIDeltaX = (3-4*dfSin2PIDeltaXOver3)*dfSinPIDeltaXOver3;
2621 278826 : const double dfInvPI2Over3 = 3.0 / (GWK_PI * GWK_PI);
2622 278826 : double dfInvPI2Over3xSinPIDeltaX = dfInvPI2Over3 * dfSinPIDeltaX;
2623 : double dfInvPI2Over3xSinPIDeltaXxm0d5SinPIDeltaXOver3 =
2624 278826 : -0.5 * dfInvPI2Over3xSinPIDeltaX * dfSinPIDeltaXOver3;
2625 278826 : const double dfSinPIOver3 = 0.8660254037844386;
2626 : double dfInvPI2Over3xSinPIDeltaXxSinPIOver3xCosPIDeltaXOver3 =
2627 278826 : dfSinPIOver3 * dfInvPI2Over3xSinPIDeltaX * dfCosPIDeltaXOver3;
2628 : double padfCst[] = {
2629 : dfInvPI2Over3xSinPIDeltaX * dfSinPIDeltaXOver3,
2630 : dfInvPI2Over3xSinPIDeltaXxm0d5SinPIDeltaXOver3 -
2631 : dfInvPI2Over3xSinPIDeltaXxSinPIOver3xCosPIDeltaXOver3,
2632 : dfInvPI2Over3xSinPIDeltaXxm0d5SinPIDeltaXOver3 +
2633 278826 : dfInvPI2Over3xSinPIDeltaXxSinPIOver3xCosPIDeltaXOver3 };
2634 :
2635 1934940 : for (int i = iMin; i <= iMax; ++i )
2636 : {
2637 1656114 : const double dfX = i - dfDeltaX;
2638 1656114 : if (dfX == 0.0)
2639 682 : padfWeightsX[i-poWK->nFiltInitX] = 1.0;
2640 : else
2641 1655432 : padfWeightsX[i-poWK->nFiltInitX] =
2642 1655432 : padfCst[(i + 3) % 3] / (dfX * dfX);
2643 : //CPLAssert(fabs(padfWeightsX[i-poWK->nFiltInitX] - GWKLanczosSinc(dfX, 3.0)) < 1e-10);
2644 : }
2645 :
2646 278826 : psWrkStruct->iLastSrcX = iSrcX;
2647 278826 : psWrkStruct->dfLastDeltaX = dfDeltaX;
2648 : }
2649 : }
2650 :
2651 278826 : if( dfYScale < 1.0 )
2652 : {
2653 0 : while( jMin * dfYScale < -3.0 )
2654 0 : jMin ++;
2655 0 : while( jMax * dfYScale > 3.0 )
2656 0 : jMax --;
2657 : // padfWeightsY computed in GWKResampleCreateWrkStruct
2658 : }
2659 : else
2660 : {
2661 823772 : while( jMin - dfDeltaY < -3.0 )
2662 266120 : jMin ++;
2663 557652 : while( jMax - dfDeltaY > 3.0 )
2664 0 : jMax --;
2665 :
2666 278826 : if( iSrcY != psWrkStruct->iLastSrcY ||
2667 : dfDeltaY != psWrkStruct->dfLastDeltaY )
2668 : {
2669 2364 : double dfSinPIDeltaYOver3 = sin((-GWK_PI / 3) * dfDeltaY);
2670 2364 : double dfSin2PIDeltaYOver3 = dfSinPIDeltaYOver3 * dfSinPIDeltaYOver3;
2671 : /* ok to use sqrt(1-sin^2) since GWK_PI / 3 * dfDeltaY < PI/2 */
2672 2364 : double dfCosPIDeltaYOver3 = sqrt(1 - dfSin2PIDeltaYOver3);
2673 2364 : double dfSinPIDeltaY = (3-4*dfSin2PIDeltaYOver3)*dfSinPIDeltaYOver3;
2674 2364 : const double dfInvPI2Over3 = 3.0 / (GWK_PI * GWK_PI);
2675 2364 : double dfInvPI2Over3xSinPIDeltaY = dfInvPI2Over3 * dfSinPIDeltaY;
2676 : double dfInvPI2Over3xSinPIDeltaYxm0d5SinPIDeltaYOver3 =
2677 2364 : -0.5 * dfInvPI2Over3xSinPIDeltaY * dfSinPIDeltaYOver3;
2678 2364 : const double dfSinPIOver3 = 0.8660254037844386;
2679 : double dfInvPI2Over3xSinPIDeltaYxSinPIOver3xCosPIDeltaYOver3 =
2680 2364 : dfSinPIOver3 * dfInvPI2Over3xSinPIDeltaY * dfCosPIDeltaYOver3;
2681 : double padfCst[] = {
2682 : dfInvPI2Over3xSinPIDeltaY * dfSinPIDeltaYOver3,
2683 : dfInvPI2Over3xSinPIDeltaYxm0d5SinPIDeltaYOver3 -
2684 : dfInvPI2Over3xSinPIDeltaYxSinPIOver3xCosPIDeltaYOver3,
2685 : dfInvPI2Over3xSinPIDeltaYxm0d5SinPIDeltaYOver3 +
2686 2364 : dfInvPI2Over3xSinPIDeltaYxSinPIOver3xCosPIDeltaYOver3 };
2687 :
2688 15547 : for ( int j = jMin; j <= jMax; ++j )
2689 : {
2690 13183 : const double dfY = j - dfDeltaY;
2691 13183 : if (dfY == 0.0)
2692 132 : padfWeightsY[j-poWK->nFiltInitY] = 1.0;
2693 : else
2694 13051 : padfWeightsY[j-poWK->nFiltInitY] =
2695 13051 : padfCst[(j + 3) % 3] / (dfY * dfY);
2696 : //CPLAssert(fabs(padfWeightsY[j-poWK->nFiltInitY] - GWKLanczosSinc(dfY, 3.0)) < 1e-10);
2697 : }
2698 :
2699 2364 : psWrkStruct->iLastSrcY = iSrcY;
2700 2364 : psWrkStruct->dfLastDeltaY = dfDeltaY;
2701 : }
2702 : }
2703 :
2704 278826 : int iRowOffset = iSrcOffset + (jMin - 1) * nSrcXSize + iMin;
2705 :
2706 : // If we have no density information, we can simply compute the
2707 : // accumulated weight.
2708 278826 : if( padfRowDensity == NULL )
2709 : {
2710 278826 : double dfRowAccWeight = 0.0;
2711 1934940 : for (int i = iMin; i <= iMax; ++i )
2712 : {
2713 1656114 : dfRowAccWeight += padfWeightsX[i-poWK->nFiltInitX];
2714 : }
2715 278826 : double dfColAccWeight = 0.0;
2716 1934940 : for ( int j = jMin; j <= jMax; ++j )
2717 : {
2718 1656114 : dfColAccWeight += padfWeightsY[j-poWK->nFiltInitY];
2719 : }
2720 278826 : dfAccumulatorWeight = dfRowAccWeight * dfColAccWeight;
2721 :
2722 278826 : if( !GDALDataTypeIsComplex(poWK->eWorkingDataType) )
2723 278578 : padfRowImag = NULL;
2724 : }
2725 :
2726 : // Loop over pixel rows in the kernel
2727 1934940 : for ( int j = jMin; j <= jMax; ++j )
2728 : {
2729 : double dfWeight1;
2730 :
2731 1656114 : iRowOffset += nSrcXSize;
2732 :
2733 : // Get pixel values
2734 : // We can potentially read extra elements after the "normal" end of the source arrays,
2735 : // but the contract of papabySrcImage[iBand], papanBandSrcValid[iBand],
2736 : // panUnifiedSrcValid and pafUnifiedSrcDensity is to have WARP_EXTRA_ELTS
2737 : // reserved at their end.
2738 1656114 : if ( !GWKGetPixelRow( poWK, iBand, iRowOffset, (iMax-iMin+2)/2,
2739 : padfRowDensity, padfRowReal, padfRowImag ) )
2740 0 : continue;
2741 :
2742 1656114 : dfWeight1 = padfWeightsY[j-poWK->nFiltInitY];
2743 :
2744 : // Iterate over pixels in row
2745 1656114 : if ( padfRowDensity != NULL )
2746 : {
2747 0 : for (int i = iMin; i <= iMax; ++i )
2748 : {
2749 : double dfWeight2;
2750 :
2751 : // Skip sampling if pixel has zero density
2752 0 : if ( padfRowDensity[i - iMin] < 0.000000001 )
2753 0 : continue;
2754 :
2755 : // Use a cached set of weights for this row
2756 0 : dfWeight2 = dfWeight1 * padfWeightsX[i- poWK->nFiltInitX];
2757 :
2758 : // Accumulate!
2759 0 : dfAccumulatorReal += padfRowReal[i - iMin] * dfWeight2;
2760 0 : dfAccumulatorImag += padfRowImag[i - iMin] * dfWeight2;
2761 0 : dfAccumulatorDensity += padfRowDensity[i - iMin] * dfWeight2;
2762 0 : dfAccumulatorWeight += dfWeight2;
2763 : }
2764 : }
2765 1656114 : else if( padfRowImag == NULL )
2766 : {
2767 1654938 : double dfRowAccReal = 0.0;
2768 11487773 : for (int i = iMin; i <= iMax; ++i )
2769 : {
2770 9832835 : double dfWeight2 = padfWeightsX[i- poWK->nFiltInitX];
2771 :
2772 : // Accumulate!
2773 9832835 : dfRowAccReal += padfRowReal[i - iMin] * dfWeight2;
2774 : }
2775 :
2776 1654938 : dfAccumulatorReal += dfRowAccReal * dfWeight1;
2777 : }
2778 : else
2779 : {
2780 1176 : double dfRowAccReal = 0.0;
2781 1176 : double dfRowAccImag = 0.0;
2782 7040 : for (int i = iMin; i <= iMax; ++i )
2783 : {
2784 5864 : double dfWeight2 = padfWeightsX[i- poWK->nFiltInitX];
2785 :
2786 : // Accumulate!
2787 5864 : dfRowAccReal += padfRowReal[i - iMin] * dfWeight2;
2788 5864 : dfRowAccImag += padfRowImag[i - iMin] * dfWeight2;
2789 : }
2790 :
2791 1176 : dfAccumulatorReal += dfRowAccReal * dfWeight1;
2792 1176 : dfAccumulatorImag += dfRowAccImag * dfWeight1;
2793 : }
2794 : }
2795 :
2796 278826 : if ( dfAccumulatorWeight < 0.000001 ||
2797 : (padfRowDensity != NULL && dfAccumulatorDensity < 0.000001) )
2798 : {
2799 0 : *pdfDensity = 0.0;
2800 0 : return FALSE;
2801 : }
2802 :
2803 : // Calculate the output taking into account weighting
2804 556970 : if ( dfAccumulatorWeight < 0.99999 || dfAccumulatorWeight > 1.00001 )
2805 : {
2806 278144 : const double dfInvAcc = 1.0 / dfAccumulatorWeight;
2807 278144 : *pdfReal = dfAccumulatorReal * dfInvAcc;
2808 278144 : *pdfImag = dfAccumulatorImag * dfInvAcc;
2809 278144 : if( padfRowDensity != NULL )
2810 0 : *pdfDensity = dfAccumulatorDensity * dfInvAcc;
2811 : else
2812 278144 : *pdfDensity = 1.0;
2813 : }
2814 : else
2815 : {
2816 682 : *pdfReal = dfAccumulatorReal;
2817 682 : *pdfImag = dfAccumulatorImag;
2818 682 : if( padfRowDensity != NULL )
2819 0 : *pdfDensity = dfAccumulatorDensity;
2820 : else
2821 682 : *pdfDensity = 1.0;
2822 : }
2823 :
2824 278826 : return TRUE;
2825 : }
2826 :
2827 278207 : static int GWKCubicSplineResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
2828 : double dfSrcX, double dfSrcY,
2829 : GByte *pbValue, double *padfBSpline )
2830 :
2831 : {
2832 : // Commonly used; save locally
2833 278207 : int nSrcXSize = poWK->nSrcXSize;
2834 278207 : int nSrcYSize = poWK->nSrcYSize;
2835 :
2836 278207 : double dfAccumulator = 0.0;
2837 278207 : int iSrcX = (int) floor( dfSrcX - 0.5 );
2838 278207 : int iSrcY = (int) floor( dfSrcY - 0.5 );
2839 278207 : int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
2840 278207 : double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2841 278207 : double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2842 :
2843 278207 : double dfXScale = poWK->dfXScale;
2844 278207 : double dfYScale = poWK->dfYScale;
2845 278207 : int nXRadius = poWK->nXRadius;
2846 278207 : int nYRadius = poWK->nYRadius;
2847 :
2848 278207 : GByte* pabySrcBand = poWK->papabySrcImage[iBand];
2849 :
2850 : // Politely refusing to process invalid coordinates or obscenely small image
2851 278207 : if ( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize
2852 : || nXRadius > nSrcXSize || nYRadius > nSrcYSize )
2853 1 : return GWKBilinearResampleNoMasksByte( poWK, iBand, dfSrcX, dfSrcY, pbValue);
2854 :
2855 : // Loop over all rows in the kernel
2856 : int j, jC;
2857 1391030 : for ( jC = 0, j = 1 - nYRadius; j <= nYRadius; ++j, ++jC )
2858 : {
2859 : int iSampJ;
2860 : // Calculate the Y weight
2861 : double dfWeight1 = ( dfYScale < 1.0 ) ?
2862 : GWKBSpline((double)j * dfYScale) * dfYScale :
2863 1112824 : GWKBSpline((double)j - dfDeltaY);
2864 :
2865 : // Flip sampling over edge of image
2866 1112824 : if ( iSrcY + j < 0 )
2867 6676 : iSampJ = iSrcOffset - (iSrcY + j) * nSrcXSize;
2868 1106148 : else if ( iSrcY + j >= nSrcYSize )
2869 556 : iSampJ = iSrcOffset + (2*nSrcYSize - 2*iSrcY - j - 1) * nSrcXSize;
2870 : else
2871 1105592 : iSampJ = iSrcOffset + j * nSrcXSize;
2872 :
2873 : // Loop over all pixels in the row
2874 : int i, iC;
2875 5564120 : for ( iC = 0, i = 1 - nXRadius; i <= nXRadius; ++i, ++iC )
2876 : {
2877 : int iSampI;
2878 : double dfWeight2;
2879 :
2880 : // Flip sampling over edge of image
2881 4451296 : if ( iSrcX + i < 0 )
2882 26704 : iSampI = -iSrcX - i;
2883 4424592 : else if ( iSrcX + i >= nSrcXSize )
2884 2224 : iSampI = 2*nSrcXSize - 2*iSrcX - i - 1;
2885 : else
2886 4422368 : iSampI = i;
2887 :
2888 : // Make a cached set of GWKBSpline values
2889 4451296 : if( jC == 0 )
2890 : {
2891 : // Calculate & save the X weight
2892 1112824 : dfWeight2 = padfBSpline[iC] = ((dfXScale < 1.0 ) ?
2893 : GWKBSpline((double)i * dfXScale) * dfXScale :
2894 1112824 : GWKBSpline(dfDeltaX - (double)i));
2895 1112824 : dfWeight2 *= dfWeight1;
2896 : }
2897 : else
2898 3338472 : dfWeight2 = dfWeight1 * padfBSpline[iC];
2899 :
2900 : // Retrieve the pixel & accumulate
2901 4451296 : dfAccumulator += (double)pabySrcBand[iSampI+iSampJ] * dfWeight2;
2902 : }
2903 : }
2904 :
2905 278206 : if ( dfAccumulator < 0.0 )
2906 0 : *pbValue = 0;
2907 278206 : else if ( dfAccumulator > 255.0 )
2908 19 : *pbValue = 255;
2909 : else
2910 278187 : *pbValue = (GByte)(0.5 + dfAccumulator);
2911 :
2912 278206 : return TRUE;
2913 : }
2914 :
2915 262207 : static int GWKCubicSplineResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
2916 : double dfSrcX, double dfSrcY,
2917 : GInt16 *piValue, double *padfBSpline )
2918 :
2919 : {
2920 : //Save src size to local var
2921 262207 : int nSrcXSize = poWK->nSrcXSize;
2922 262207 : int nSrcYSize = poWK->nSrcYSize;
2923 :
2924 262207 : double dfAccumulator = 0.0;
2925 262207 : int iSrcX = (int) floor( dfSrcX - 0.5 );
2926 262207 : int iSrcY = (int) floor( dfSrcY - 0.5 );
2927 262207 : int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
2928 262207 : double dfDeltaX = dfSrcX - 0.5 - iSrcX;
2929 262207 : double dfDeltaY = dfSrcY - 0.5 - iSrcY;
2930 :
2931 262207 : double dfXScale = poWK->dfXScale;
2932 262207 : double dfYScale = poWK->dfYScale;
2933 262207 : int nXRadius = poWK->nXRadius;
2934 262207 : int nYRadius = poWK->nYRadius;
2935 :
2936 : // Save band array pointer to local var; cast here instead of later
2937 262207 : GInt16* pabySrcBand = ((GInt16 *)poWK->papabySrcImage[iBand]);
2938 :
2939 : // Politely refusing to process invalid coordinates or obscenely small image
2940 262207 : if ( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize
2941 : || nXRadius > nSrcXSize || nYRadius > nSrcYSize )
2942 1 : return GWKBilinearResampleNoMasksShort( poWK, iBand, dfSrcX, dfSrcY, piValue);
2943 :
2944 : // Loop over all pixels in the kernel
2945 : int j, jC;
2946 1311030 : for ( jC = 0, j = 1 - nYRadius; j <= nYRadius; ++j, ++jC )
2947 : {
2948 : int iSampJ;
2949 :
2950 : // Calculate the Y weight
2951 : double dfWeight1 = ( dfYScale < 1.0 ) ?
2952 : GWKBSpline((double)j * dfYScale) * dfYScale :
2953 1048824 : GWKBSpline((double)j - dfDeltaY);
2954 :
2955 : // Flip sampling over edge of image
2956 1048824 : if ( iSrcY + j < 0 )
2957 6156 : iSampJ = iSrcOffset - (iSrcY + j) * nSrcXSize;
2958 1042668 : else if ( iSrcY + j >= nSrcYSize )
2959 36 : iSampJ = iSrcOffset + (2*nSrcYSize - 2*iSrcY - j - 1) * nSrcXSize;
2960 : else
2961 1042632 : iSampJ = iSrcOffset + j * nSrcXSize;
2962 :
2963 : // Loop over all pixels in row
2964 : int i, iC;
2965 5244120 : for ( iC = 0, i = 1 - nXRadius; i <= nXRadius; ++i, ++iC )
2966 : {
2967 : int iSampI;
2968 : double dfWeight2;
2969 :
2970 : // Flip sampling over edge of image
2971 4195296 : if ( iSrcX + i < 0 )
2972 24624 : iSampI = -iSrcX - i;
2973 4170672 : else if(iSrcX + i >= nSrcXSize)
2974 144 : iSampI = 2*nSrcXSize - 2*iSrcX - i - 1;
2975 : else
2976 4170528 : iSampI = i;
2977 :
2978 : // Make a cached set of GWKBSpline values
2979 4195296 : if ( jC == 0 )
2980 : {
2981 : // Calculate & save the X weight
2982 1048824 : dfWeight2 = padfBSpline[iC] = ((dfXScale < 1.0 ) ?
2983 : GWKBSpline((double)i * dfXScale) * dfXScale :
2984 1048824 : GWKBSpline(dfDeltaX - (double)i));
2985 1048824 : dfWeight2 *= dfWeight1;
2986 : } else
2987 3146472 : dfWeight2 = dfWeight1 * padfBSpline[iC];
2988 :
2989 4195296 : dfAccumulator += (double)pabySrcBand[iSampI + iSampJ] * dfWeight2;
2990 : }
2991 : }
2992 :
2993 262206 : *piValue = (GInt16)(0.5 + dfAccumulator);
2994 :
2995 262206 : return TRUE;
2996 : }
2997 :
2998 : /************************************************************************/
2999 : /* GWKOpenCLCase() */
3000 : /* */
3001 : /* This is identical to GWKGeneralCase(), but functions via */
3002 : /* OpenCL. This means we have vector optimization (SSE) and/or */
3003 : /* GPU optimization depending on our prefs. The code itsef is */
3004 : /* general and not optimized, but by defining constants we can */
3005 : /* make some pretty darn good code on the fly. */
3006 : /************************************************************************/
3007 :
3008 : #if defined(HAVE_OPENCL)
3009 : static CPLErr GWKOpenCLCase( GDALWarpKernel *poWK )
3010 : {
3011 : int iDstY, iBand;
3012 : int nDstXSize = poWK->nDstXSize, nDstYSize = poWK->nDstYSize;
3013 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3014 : int nDstXOff = poWK->nDstXOff , nDstYOff = poWK->nDstYOff;
3015 : int nSrcXOff = poWK->nSrcXOff , nSrcYOff = poWK->nSrcYOff;
3016 : CPLErr eErr = CE_None;
3017 : struct oclWarper *warper;
3018 : cl_channel_type imageFormat;
3019 : int useImag = FALSE;
3020 : OCLResampAlg resampAlg;
3021 : cl_int err;
3022 :
3023 : switch ( poWK->eWorkingDataType )
3024 : {
3025 : case GDT_Byte:
3026 : imageFormat = CL_UNORM_INT8;
3027 : break;
3028 : case GDT_UInt16:
3029 : imageFormat = CL_UNORM_INT16;
3030 : break;
3031 : case GDT_CInt16:
3032 : useImag = TRUE;
3033 : case GDT_Int16:
3034 : imageFormat = CL_SNORM_INT16;
3035 : break;
3036 : case GDT_CFloat32:
3037 : useImag = TRUE;
3038 : case GDT_Float32:
3039 : imageFormat = CL_FLOAT;
3040 : break;
3041 : default:
3042 : // We don't support higher precision formats
3043 : CPLDebug( "OpenCL",
3044 : "Unsupported resampling OpenCL data type %d.",
3045 : (int) poWK->eWorkingDataType );
3046 : return CE_Warning;
3047 : }
3048 :
3049 : switch (poWK->eResample)
3050 : {
3051 : case GRA_Bilinear:
3052 : resampAlg = OCL_Bilinear;
3053 : break;
3054 : case GRA_Cubic:
3055 : resampAlg = OCL_Cubic;
3056 : break;
3057 : case GRA_CubicSpline:
3058 : resampAlg = OCL_CubicSpline;
3059 : break;
3060 : case GRA_Lanczos:
3061 : resampAlg = OCL_Lanczos;
3062 : break;
3063 : default:
3064 : // We don't support higher precision formats
3065 : CPLDebug( "OpenCL",
3066 : "Unsupported resampling OpenCL resampling alg %d.",
3067 : (int) poWK->eResample );
3068 : return CE_Warning;
3069 : }
3070 :
3071 : // Using a factor of 2 or 4 seems to have much less rounding error than 3 on the GPU.
3072 : // Then the rounding error can cause strange artifacting under the right conditions.
3073 : warper = GDALWarpKernelOpenCL_createEnv(nSrcXSize, nSrcYSize,
3074 : nDstXSize, nDstYSize,
3075 : imageFormat, poWK->nBands, 4,
3076 : useImag, poWK->papanBandSrcValid != NULL,
3077 : poWK->pafDstDensity,
3078 : poWK->padfDstNoDataReal,
3079 : resampAlg, &err );
3080 :
3081 : if(err != CL_SUCCESS || warper == NULL)
3082 : {
3083 : eErr = CE_Warning;
3084 : if (warper != NULL)
3085 : goto free_warper;
3086 : return eErr;
3087 : }
3088 :
3089 : CPLDebug( "GDAL", "GDALWarpKernel()::GWKOpenCLCase()\n"
3090 : "Src=%d,%d,%dx%d Dst=%d,%d,%dx%d",
3091 : nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
3092 : nDstXOff, nDstYOff, nDstXSize, nDstYSize );
3093 :
3094 : if( !poWK->pfnProgress( poWK->dfProgressBase, "", poWK->pProgress ) )
3095 : {
3096 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
3097 : eErr = CE_Failure;
3098 : goto free_warper;
3099 : }
3100 :
3101 : /* ==================================================================== */
3102 : /* Loop over bands. */
3103 : /* ==================================================================== */
3104 : for( iBand = 0; iBand < poWK->nBands; iBand++ ) {
3105 : if( poWK->papanBandSrcValid != NULL && poWK->papanBandSrcValid[iBand] != NULL) {
3106 : GDALWarpKernelOpenCL_setSrcValid(warper, (int *)poWK->papanBandSrcValid[iBand], iBand);
3107 : if(err != CL_SUCCESS)
3108 : {
3109 : CPLError( CE_Failure, CPLE_AppDefined,
3110 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3111 : eErr = CE_Failure;
3112 : goto free_warper;
3113 : }
3114 : }
3115 :
3116 : err = GDALWarpKernelOpenCL_setSrcImg(warper, poWK->papabySrcImage[iBand], iBand);
3117 : if(err != CL_SUCCESS)
3118 : {
3119 : CPLError( CE_Failure, CPLE_AppDefined,
3120 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3121 : eErr = CE_Failure;
3122 : goto free_warper;
3123 : }
3124 :
3125 : err = GDALWarpKernelOpenCL_setDstImg(warper, poWK->papabyDstImage[iBand], iBand);
3126 : if(err != CL_SUCCESS)
3127 : {
3128 : CPLError( CE_Failure, CPLE_AppDefined,
3129 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3130 : eErr = CE_Failure;
3131 : goto free_warper;
3132 : }
3133 : }
3134 :
3135 : /* -------------------------------------------------------------------- */
3136 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3137 : /* scanlines worth of positions. */
3138 : /* -------------------------------------------------------------------- */
3139 : double *padfX, *padfY, *padfZ;
3140 : int *pabSuccess;
3141 :
3142 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3143 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3144 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3145 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3146 :
3147 : /* ==================================================================== */
3148 : /* Loop over output lines. */
3149 : /* ==================================================================== */
3150 : for( iDstY = 0; iDstY < nDstYSize && eErr == CE_None; ++iDstY )
3151 : {
3152 : int iDstX;
3153 :
3154 : /* ---------------------------------------------------------------- */
3155 : /* Setup points to transform to source image space. */
3156 : /* ---------------------------------------------------------------- */
3157 : for( iDstX = 0; iDstX < nDstXSize; ++iDstX )
3158 : {
3159 : padfX[iDstX] = iDstX + 0.5 + nDstXOff;
3160 : padfY[iDstX] = iDstY + 0.5 + nDstYOff;
3161 : padfZ[iDstX] = 0.0;
3162 : }
3163 :
3164 : /* ---------------------------------------------------------------- */
3165 : /* Transform the points from destination pixel/line coordinates*/
3166 : /* to source pixel/line coordinates. */
3167 : /* ---------------------------------------------------------------- */
3168 : poWK->pfnTransformer( poWK->pTransformerArg, TRUE, nDstXSize,
3169 : padfX, padfY, padfZ, pabSuccess );
3170 :
3171 : err = GDALWarpKernelOpenCL_setCoordRow(warper, padfX, padfY,
3172 : nSrcXOff, nSrcYOff,
3173 : pabSuccess, iDstY);
3174 : if(err != CL_SUCCESS)
3175 : {
3176 : CPLError( CE_Failure, CPLE_AppDefined,
3177 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3178 : return CE_Failure;
3179 : }
3180 :
3181 : //Update the valid & density masks because we don't do so in the kernel
3182 : for( iDstX = 0; iDstX < nDstXSize && eErr == CE_None; iDstX++ )
3183 : {
3184 : double dfX = padfX[iDstX];
3185 : double dfY = padfY[iDstX];
3186 : int iDstOffset = iDstX + iDstY * nDstXSize;
3187 :
3188 : //See GWKGeneralCase() for appropriate commenting
3189 : if( !pabSuccess[iDstX] || dfX < nSrcXOff || dfY < nSrcYOff )
3190 : continue;
3191 :
3192 : int iSrcX = ((int) dfX) - nSrcXOff;
3193 : int iSrcY = ((int) dfY) - nSrcYOff;
3194 :
3195 : if( iSrcX < 0 || iSrcX >= nSrcXSize || iSrcY < 0 || iSrcY >= nSrcYSize )
3196 : continue;
3197 :
3198 : int iSrcOffset = iSrcX + iSrcY * nSrcXSize;
3199 : double dfDensity = 1.0;
3200 :
3201 : if( poWK->pafUnifiedSrcDensity != NULL
3202 : && iSrcX >= 0 && iSrcY >= 0
3203 : && iSrcX < nSrcXSize && iSrcY < nSrcYSize )
3204 : dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
3205 :
3206 : GWKOverlayDensity( poWK, iDstOffset, dfDensity );
3207 :
3208 : //Because this is on the bit-wise level, it can't be done well in OpenCL
3209 : if( poWK->panDstValid != NULL )
3210 : poWK->panDstValid[iDstOffset>>5] |= 0x01 << (iDstOffset & 0x1f);
3211 : }
3212 : }
3213 :
3214 : CPLFree( padfX );
3215 : CPLFree( padfY );
3216 : CPLFree( padfZ );
3217 : CPLFree( pabSuccess );
3218 :
3219 : err = GDALWarpKernelOpenCL_runResamp(warper,
3220 : poWK->pafUnifiedSrcDensity,
3221 : poWK->panUnifiedSrcValid,
3222 : poWK->pafDstDensity,
3223 : poWK->panDstValid,
3224 : poWK->dfXScale, poWK->dfYScale,
3225 : poWK->dfXFilter, poWK->dfYFilter,
3226 : poWK->nXRadius, poWK->nYRadius,
3227 : poWK->nFiltInitX, poWK->nFiltInitY);
3228 :
3229 : if(err != CL_SUCCESS)
3230 : {
3231 : CPLError( CE_Failure, CPLE_AppDefined,
3232 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3233 : eErr = CE_Failure;
3234 : goto free_warper;
3235 : }
3236 :
3237 : /* ==================================================================== */
3238 : /* Loop over output lines. */
3239 : /* ==================================================================== */
3240 : for( iDstY = 0; iDstY < nDstYSize && eErr == CE_None; iDstY++ )
3241 : {
3242 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3243 : {
3244 : int iDstX;
3245 : void *rowReal, *rowImag;
3246 : GByte *pabyDst = poWK->papabyDstImage[iBand];
3247 :
3248 : err = GDALWarpKernelOpenCL_getRow(warper, &rowReal, &rowImag, iDstY, iBand);
3249 : if(err != CL_SUCCESS)
3250 : {
3251 : CPLError( CE_Failure, CPLE_AppDefined,
3252 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3253 : eErr = CE_Failure;
3254 : goto free_warper;
3255 : }
3256 :
3257 : //Copy the data from the warper to GDAL's memory
3258 : switch ( poWK->eWorkingDataType )
3259 : {
3260 : case GDT_Byte:
3261 : memcpy((void **)&(((GByte *)pabyDst)[iDstY*nDstXSize]),
3262 : rowReal, sizeof(GByte)*nDstXSize);
3263 : break;
3264 : case GDT_Int16:
3265 : memcpy((void **)&(((GInt16 *)pabyDst)[iDstY*nDstXSize]),
3266 : rowReal, sizeof(GInt16)*nDstXSize);
3267 : break;
3268 : case GDT_UInt16:
3269 : memcpy((void **)&(((GUInt16 *)pabyDst)[iDstY*nDstXSize]),
3270 : rowReal, sizeof(GUInt16)*nDstXSize);
3271 : break;
3272 : case GDT_Float32:
3273 : memcpy((void **)&(((float *)pabyDst)[iDstY*nDstXSize]),
3274 : rowReal, sizeof(float)*nDstXSize);
3275 : break;
3276 : case GDT_CInt16:
3277 : {
3278 : GInt16 *pabyDstI16 = &(((GInt16 *)pabyDst)[iDstY*nDstXSize]);
3279 : for (iDstX = 0; iDstX < nDstXSize; iDstX++) {
3280 : pabyDstI16[iDstX*2 ] = ((GInt16 *)rowReal)[iDstX];
3281 : pabyDstI16[iDstX*2+1] = ((GInt16 *)rowImag)[iDstX];
3282 : }
3283 : }
3284 : break;
3285 : case GDT_CFloat32:
3286 : {
3287 : float *pabyDstF32 = &(((float *)pabyDst)[iDstY*nDstXSize]);
3288 : for (iDstX = 0; iDstX < nDstXSize; iDstX++) {
3289 : pabyDstF32[iDstX*2 ] = ((float *)rowReal)[iDstX];
3290 : pabyDstF32[iDstX*2+1] = ((float *)rowImag)[iDstX];
3291 : }
3292 : }
3293 : break;
3294 : default:
3295 : // We don't support higher precision formats
3296 : CPLError( CE_Failure, CPLE_AppDefined,
3297 : "Unsupported resampling OpenCL data type %d.", (int) poWK->eWorkingDataType );
3298 : eErr = CE_Failure;
3299 : goto free_warper;
3300 : }
3301 : }
3302 : }
3303 : free_warper:
3304 : if((err = GDALWarpKernelOpenCL_deleteEnv(warper)) != CL_SUCCESS)
3305 : {
3306 : CPLError( CE_Failure, CPLE_AppDefined,
3307 : "OpenCL routines reported failure (%d) on line %d.", (int) err, __LINE__ );
3308 : return CE_Failure;
3309 : }
3310 :
3311 : return eErr;
3312 : }
3313 : #endif /* defined(HAVE_OPENCL) */
3314 :
3315 :
3316 : #define COMPUTE_iSrcOffset(_pabSuccess, _iDstX, _padfX, _padfY, _poWK, _nSrcXSize, _nSrcYSize) \
3317 : if( !_pabSuccess[_iDstX] ) \
3318 : continue; \
3319 : \
3320 : /* -------------------------------------------------------------------- */ \
3321 : /* Figure out what pixel we want in our source raster, and skip */ \
3322 : /* further processing if it is well off the source image. */ \
3323 : /* -------------------------------------------------------------------- */ \
3324 : /* We test against the value before casting to avoid the */ \
3325 : /* problem of asymmetric truncation effects around zero. That is */ \
3326 : /* -0.5 will be 0 when cast to an int. */ \
3327 : if( _padfX[_iDstX] < _poWK->nSrcXOff \
3328 : || _padfY[_iDstX] < _poWK->nSrcYOff ) \
3329 : continue; \
3330 : \
3331 : int iSrcX, iSrcY, iSrcOffset;\
3332 : \
3333 : iSrcX = ((int) (_padfX[_iDstX] + 1e-10)) - _poWK->nSrcXOff;\
3334 : iSrcY = ((int) (_padfY[_iDstX] + 1e-10)) - _poWK->nSrcYOff;\
3335 : \
3336 : /* If operating outside natural projection area, padfX/Y can be */ \
3337 : /* a very huge positive number, that becomes -2147483648 in the */ \
3338 : /* int trucation. So it is necessary to test now for non negativeness. */ \
3339 : if( iSrcX < 0 || iSrcX >= _nSrcXSize || iSrcY < 0 || iSrcY >= _nSrcYSize )\
3340 : continue;\
3341 : \
3342 : iSrcOffset = iSrcX + iSrcY * _nSrcXSize;
3343 :
3344 : /************************************************************************/
3345 : /* GWKGeneralCase() */
3346 : /* */
3347 : /* This is the most general case. It attempts to handle all */
3348 : /* possible features with relatively little concern for */
3349 : /* efficiency. */
3350 : /************************************************************************/
3351 :
3352 : static void GWKGeneralCaseThread(void* pData);
3353 :
3354 193 : static CPLErr GWKGeneralCase( GDALWarpKernel *poWK )
3355 : {
3356 193 : return GWKRun( poWK, "GWKGeneralCase", GWKGeneralCaseThread );
3357 : }
3358 :
3359 193 : static void GWKGeneralCaseThread( void* pData)
3360 :
3361 : {
3362 193 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3363 193 : GDALWarpKernel *poWK = psJob->poWK;
3364 193 : int iYMin = psJob->iYMin;
3365 193 : int iYMax = psJob->iYMax;
3366 :
3367 : int iDstY;
3368 193 : int nDstXSize = poWK->nDstXSize;
3369 193 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3370 :
3371 : /* -------------------------------------------------------------------- */
3372 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3373 : /* scanlines worth of positions. */
3374 : /* -------------------------------------------------------------------- */
3375 : double *padfX, *padfY, *padfZ;
3376 : int *pabSuccess;
3377 :
3378 193 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3379 193 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3380 193 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3381 193 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3382 :
3383 193 : GWKResampleWrkStruct* psWrkStruct = NULL;
3384 193 : if (poWK->eResample == GRA_CubicSpline
3385 : || poWK->eResample == GRA_Lanczos )
3386 : {
3387 87 : psWrkStruct = GWKResampleCreateWrkStruct(poWK);
3388 : }
3389 :
3390 : /* ==================================================================== */
3391 : /* Loop over output lines. */
3392 : /* ==================================================================== */
3393 1917 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3394 : {
3395 : int iDstX;
3396 :
3397 : /* -------------------------------------------------------------------- */
3398 : /* Setup points to transform to source image space. */
3399 : /* -------------------------------------------------------------------- */
3400 533172 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3401 : {
3402 531448 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
3403 531448 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
3404 531448 : padfZ[iDstX] = 0.0;
3405 : }
3406 :
3407 : /* -------------------------------------------------------------------- */
3408 : /* Transform the points from destination pixel/line coordinates */
3409 : /* to source pixel/line coordinates. */
3410 : /* -------------------------------------------------------------------- */
3411 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
3412 1724 : padfX, padfY, padfZ, pabSuccess );
3413 :
3414 : /* ==================================================================== */
3415 : /* Loop over pixels in output scanline. */
3416 : /* ==================================================================== */
3417 533172 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3418 : {
3419 : int iDstOffset;
3420 :
3421 531448 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
3422 :
3423 : /* -------------------------------------------------------------------- */
3424 : /* Do not try to apply transparent/invalid source pixels to the */
3425 : /* destination. This currently ignores the multi-pixel input */
3426 : /* of bilinear and cubic resamples. */
3427 : /* -------------------------------------------------------------------- */
3428 284907 : double dfDensity = 1.0;
3429 :
3430 284907 : if( poWK->pafUnifiedSrcDensity != NULL )
3431 : {
3432 1328 : dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
3433 1328 : if( dfDensity < 0.00001 )
3434 1299 : continue;
3435 : }
3436 :
3437 283608 : if( poWK->panUnifiedSrcValid != NULL
3438 0 : && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
3439 : & (0x01 << (iSrcOffset & 0x1f))) )
3440 0 : continue;
3441 :
3442 : /* ==================================================================== */
3443 : /* Loop processing each band. */
3444 : /* ==================================================================== */
3445 : int iBand;
3446 283608 : int bHasFoundDensity = FALSE;
3447 :
3448 283608 : iDstOffset = iDstX + iDstY * nDstXSize;
3449 573003 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3450 : {
3451 289395 : double dfBandDensity = 0.0;
3452 289395 : double dfValueReal = 0.0;
3453 289395 : double dfValueImag = 0.0;
3454 :
3455 : /* -------------------------------------------------------------------- */
3456 : /* Collect the source value. */
3457 : /* -------------------------------------------------------------------- */
3458 290674 : if ( poWK->eResample == GRA_NearestNeighbour ||
3459 : nSrcXSize == 1 || nSrcYSize == 1)
3460 : {
3461 : GWKGetPixelValue( poWK, iBand, iSrcOffset,
3462 1279 : &dfBandDensity, &dfValueReal, &dfValueImag );
3463 : }
3464 288116 : else if ( poWK->eResample == GRA_Bilinear )
3465 : {
3466 : GWKBilinearResample( poWK, iBand,
3467 8174 : padfX[iDstX]-poWK->nSrcXOff,
3468 8174 : padfY[iDstX]-poWK->nSrcYOff,
3469 : &dfBandDensity,
3470 16348 : &dfValueReal, &dfValueImag );
3471 : }
3472 279942 : else if ( poWK->eResample == GRA_Cubic )
3473 : {
3474 : GWKCubicResample( poWK, iBand,
3475 558 : padfX[iDstX]-poWK->nSrcXOff,
3476 558 : padfY[iDstX]-poWK->nSrcYOff,
3477 : &dfBandDensity,
3478 1116 : &dfValueReal, &dfValueImag );
3479 : }
3480 279384 : else if ( poWK->eResample == GRA_CubicSpline
3481 : || poWK->eResample == GRA_Lanczos )
3482 : {
3483 : psWrkStruct->pfnGWKResample( poWK, iBand,
3484 279384 : padfX[iDstX]-poWK->nSrcXOff,
3485 279384 : padfY[iDstX]-poWK->nSrcYOff,
3486 : &dfBandDensity,
3487 838152 : &dfValueReal, &dfValueImag, psWrkStruct );
3488 : }
3489 :
3490 :
3491 : // If we didn't find any valid inputs skip to next band.
3492 289395 : if ( dfBandDensity < 0.0000000001 )
3493 0 : continue;
3494 :
3495 289395 : bHasFoundDensity = TRUE;
3496 :
3497 : /* -------------------------------------------------------------------- */
3498 : /* We have a computed value from the source. Now apply it to */
3499 : /* the destination pixel. */
3500 : /* -------------------------------------------------------------------- */
3501 : GWKSetPixelValue( poWK, iBand, iDstOffset,
3502 : dfBandDensity,
3503 289395 : dfValueReal, dfValueImag );
3504 :
3505 : }
3506 :
3507 283608 : if (!bHasFoundDensity)
3508 0 : continue;
3509 :
3510 : /* -------------------------------------------------------------------- */
3511 : /* Update destination density/validity masks. */
3512 : /* -------------------------------------------------------------------- */
3513 283608 : GWKOverlayDensity( poWK, iDstOffset, dfDensity );
3514 :
3515 283608 : if( poWK->panDstValid != NULL )
3516 : {
3517 : poWK->panDstValid[iDstOffset>>5] |=
3518 0 : 0x01 << (iDstOffset & 0x1f);
3519 : }
3520 :
3521 : } /* Next iDstX */
3522 :
3523 : /* -------------------------------------------------------------------- */
3524 : /* Report progress to the user, and optionally cancel out. */
3525 : /* -------------------------------------------------------------------- */
3526 1724 : if (psJob->pfnProgress(psJob))
3527 0 : break;
3528 : }
3529 :
3530 : /* -------------------------------------------------------------------- */
3531 : /* Cleanup and return. */
3532 : /* -------------------------------------------------------------------- */
3533 193 : CPLFree( padfX );
3534 193 : CPLFree( padfY );
3535 193 : CPLFree( padfZ );
3536 193 : CPLFree( pabSuccess );
3537 193 : if (psWrkStruct)
3538 87 : GWKResampleDeleteWrkStruct(psWrkStruct);
3539 193 : }
3540 :
3541 : /************************************************************************/
3542 : /* GWKNearestNoMasksByte() */
3543 : /* */
3544 : /* Case for 8bit input data with nearest neighbour resampling */
3545 : /* without concerning about masking. Should be as fast as */
3546 : /* possible for this particular transformation type. */
3547 : /************************************************************************/
3548 :
3549 : static void GWKNearestNoMasksByteThread(void* pData);
3550 :
3551 255 : static CPLErr GWKNearestNoMasksByte( GDALWarpKernel *poWK )
3552 : {
3553 255 : return GWKRun( poWK, "GWKNearestNoMasksByte", GWKNearestNoMasksByteThread );
3554 : }
3555 :
3556 255 : static void GWKNearestNoMasksByteThread(void* pData)
3557 : {
3558 255 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3559 255 : GDALWarpKernel *poWK = psJob->poWK;
3560 255 : int iYMin = psJob->iYMin;
3561 255 : int iYMax = psJob->iYMax;
3562 :
3563 : int iDstY;
3564 255 : int nDstXSize = poWK->nDstXSize;
3565 255 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3566 :
3567 : /* -------------------------------------------------------------------- */
3568 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3569 : /* scanlines worth of positions. */
3570 : /* -------------------------------------------------------------------- */
3571 : double *padfX, *padfY, *padfZ;
3572 : int *pabSuccess;
3573 :
3574 255 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3575 255 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3576 255 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3577 255 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3578 :
3579 : /* ==================================================================== */
3580 : /* Loop over output lines. */
3581 : /* ==================================================================== */
3582 30684 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3583 : {
3584 : int iDstX;
3585 :
3586 : /* -------------------------------------------------------------------- */
3587 : /* Setup points to transform to source image space. */
3588 : /* -------------------------------------------------------------------- */
3589 8647071 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3590 : {
3591 8616642 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
3592 8616642 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
3593 8616642 : padfZ[iDstX] = 0.0;
3594 : }
3595 :
3596 : /* -------------------------------------------------------------------- */
3597 : /* Transform the points from destination pixel/line coordinates */
3598 : /* to source pixel/line coordinates. */
3599 : /* -------------------------------------------------------------------- */
3600 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
3601 30429 : padfX, padfY, padfZ, pabSuccess );
3602 :
3603 : /* ==================================================================== */
3604 : /* Loop over pixels in output scanline. */
3605 : /* ==================================================================== */
3606 8647071 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3607 : {
3608 8616642 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
3609 :
3610 : /* ==================================================================== */
3611 : /* Loop processing each band. */
3612 : /* ==================================================================== */
3613 : int iBand;
3614 : int iDstOffset;
3615 :
3616 8331963 : iDstOffset = iDstX + iDstY * nDstXSize;
3617 :
3618 20252470 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3619 : {
3620 11920507 : poWK->papabyDstImage[iBand][iDstOffset] =
3621 11920507 : poWK->papabySrcImage[iBand][iSrcOffset];
3622 : }
3623 : }
3624 :
3625 : /* -------------------------------------------------------------------- */
3626 : /* Report progress to the user, and optionally cancel out. */
3627 : /* -------------------------------------------------------------------- */
3628 30429 : if (psJob->pfnProgress(psJob))
3629 0 : break;
3630 : }
3631 :
3632 : /* -------------------------------------------------------------------- */
3633 : /* Cleanup and return. */
3634 : /* -------------------------------------------------------------------- */
3635 255 : CPLFree( padfX );
3636 255 : CPLFree( padfY );
3637 255 : CPLFree( padfZ );
3638 255 : CPLFree( pabSuccess );
3639 255 : }
3640 :
3641 : /************************************************************************/
3642 : /* GWKBilinearNoMasksByte() */
3643 : /* */
3644 : /* Case for 8bit input data with bilinear resampling without */
3645 : /* concerning about masking. Should be as fast as possible */
3646 : /* for this particular transformation type. */
3647 : /************************************************************************/
3648 :
3649 : static void GWKBilinearNoMasksByteThread(void* pData);
3650 :
3651 16 : static CPLErr GWKBilinearNoMasksByte( GDALWarpKernel *poWK )
3652 : {
3653 16 : return GWKRun( poWK, "GWKBilinearNoMasksByte", GWKBilinearNoMasksByteThread );
3654 : }
3655 :
3656 17 : static void GWKBilinearNoMasksByteThread(void* pData)
3657 : {
3658 17 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3659 17 : GDALWarpKernel *poWK = psJob->poWK;
3660 17 : int iYMin = psJob->iYMin;
3661 17 : int iYMax = psJob->iYMax;
3662 :
3663 : int iDstY;
3664 17 : int nDstXSize = poWK->nDstXSize;
3665 17 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3666 :
3667 : /* -------------------------------------------------------------------- */
3668 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3669 : /* scanlines worth of positions. */
3670 : /* -------------------------------------------------------------------- */
3671 : double *padfX, *padfY, *padfZ;
3672 : int *pabSuccess;
3673 :
3674 17 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3675 17 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3676 17 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3677 17 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3678 :
3679 : /* ==================================================================== */
3680 : /* Loop over output lines. */
3681 : /* ==================================================================== */
3682 768 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3683 : {
3684 : int iDstX;
3685 :
3686 : /* -------------------------------------------------------------------- */
3687 : /* Setup points to transform to source image space. */
3688 : /* -------------------------------------------------------------------- */
3689 331234 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3690 : {
3691 330480 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
3692 330480 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
3693 330480 : padfZ[iDstX] = 0.0;
3694 : }
3695 :
3696 : /* -------------------------------------------------------------------- */
3697 : /* Transform the points from destination pixel/line coordinates */
3698 : /* to source pixel/line coordinates. */
3699 : /* -------------------------------------------------------------------- */
3700 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
3701 754 : padfX, padfY, padfZ, pabSuccess );
3702 :
3703 : /* ==================================================================== */
3704 : /* Loop over pixels in output scanline. */
3705 : /* ==================================================================== */
3706 331234 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3707 : {
3708 330480 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
3709 :
3710 : /* ==================================================================== */
3711 : /* Loop processing each band. */
3712 : /* ==================================================================== */
3713 : int iBand;
3714 : int iDstOffset;
3715 :
3716 279344 : iDstOffset = iDstX + iDstY * nDstXSize;
3717 :
3718 558688 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3719 : {
3720 : GWKBilinearResampleNoMasksByte( poWK, iBand,
3721 279344 : padfX[iDstX]-poWK->nSrcXOff,
3722 279344 : padfY[iDstX]-poWK->nSrcYOff,
3723 838032 : &poWK->papabyDstImage[iBand][iDstOffset] );
3724 : }
3725 : }
3726 :
3727 : /* -------------------------------------------------------------------- */
3728 : /* Report progress to the user, and optionally cancel out. */
3729 : /* -------------------------------------------------------------------- */
3730 754 : if (psJob->pfnProgress(psJob))
3731 3 : break;
3732 : }
3733 :
3734 : /* -------------------------------------------------------------------- */
3735 : /* Cleanup and return. */
3736 : /* -------------------------------------------------------------------- */
3737 17 : CPLFree( padfX );
3738 17 : CPLFree( padfY );
3739 17 : CPLFree( padfZ );
3740 17 : CPLFree( pabSuccess );
3741 17 : }
3742 :
3743 : /************************************************************************/
3744 : /* GWKCubicNoMasksByte() */
3745 : /* */
3746 : /* Case for 8bit input data with cubic resampling without */
3747 : /* concerning about masking. Should be as fast as possible */
3748 : /* for this particular transformation type. */
3749 : /************************************************************************/
3750 :
3751 : static void GWKCubicNoMasksByteThread(void* pData);
3752 :
3753 10 : static CPLErr GWKCubicNoMasksByte( GDALWarpKernel *poWK )
3754 : {
3755 10 : return GWKRun( poWK, "GWKCubicNoMasksByte", GWKCubicNoMasksByteThread );
3756 : }
3757 :
3758 10 : static void GWKCubicNoMasksByteThread( void* pData )
3759 :
3760 : {
3761 10 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3762 10 : GDALWarpKernel *poWK = psJob->poWK;
3763 10 : int iYMin = psJob->iYMin;
3764 10 : int iYMax = psJob->iYMax;
3765 :
3766 : int iDstY;
3767 10 : int nDstXSize = poWK->nDstXSize;
3768 10 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3769 :
3770 : /* -------------------------------------------------------------------- */
3771 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3772 : /* scanlines worth of positions. */
3773 : /* -------------------------------------------------------------------- */
3774 : double *padfX, *padfY, *padfZ;
3775 : int *pabSuccess;
3776 :
3777 10 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3778 10 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3779 10 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3780 10 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3781 :
3782 : /* ==================================================================== */
3783 : /* Loop over output lines. */
3784 : /* ==================================================================== */
3785 703 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3786 : {
3787 : int iDstX;
3788 :
3789 : /* -------------------------------------------------------------------- */
3790 : /* Setup points to transform to source image space. */
3791 : /* -------------------------------------------------------------------- */
3792 330036 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3793 : {
3794 329343 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
3795 329343 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
3796 329343 : padfZ[iDstX] = 0.0;
3797 : }
3798 :
3799 : /* -------------------------------------------------------------------- */
3800 : /* Transform the points from destination pixel/line coordinates */
3801 : /* to source pixel/line coordinates. */
3802 : /* -------------------------------------------------------------------- */
3803 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
3804 693 : padfX, padfY, padfZ, pabSuccess );
3805 :
3806 : /* ==================================================================== */
3807 : /* Loop over pixels in output scanline. */
3808 : /* ==================================================================== */
3809 330036 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3810 : {
3811 329343 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
3812 :
3813 : /* ==================================================================== */
3814 : /* Loop processing each band. */
3815 : /* ==================================================================== */
3816 : int iBand;
3817 : int iDstOffset;
3818 :
3819 278207 : iDstOffset = iDstX + iDstY * nDstXSize;
3820 :
3821 556414 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3822 : {
3823 : GWKCubicResampleNoMasksByte( poWK, iBand,
3824 278207 : padfX[iDstX]-poWK->nSrcXOff,
3825 278207 : padfY[iDstX]-poWK->nSrcYOff,
3826 834621 : &poWK->papabyDstImage[iBand][iDstOffset] );
3827 : }
3828 : }
3829 :
3830 : /* -------------------------------------------------------------------- */
3831 : /* Report progress to the user, and optionally cancel out. */
3832 : /* -------------------------------------------------------------------- */
3833 693 : if (psJob->pfnProgress(psJob))
3834 0 : break;
3835 : }
3836 :
3837 : /* -------------------------------------------------------------------- */
3838 : /* Cleanup and return. */
3839 : /* -------------------------------------------------------------------- */
3840 10 : CPLFree( padfX );
3841 10 : CPLFree( padfY );
3842 10 : CPLFree( padfZ );
3843 10 : CPLFree( pabSuccess );
3844 10 : }
3845 :
3846 : /************************************************************************/
3847 : /* GWKCubicSplineNoMasksByte() */
3848 : /* */
3849 : /* Case for 8bit input data with cubic spline resampling without */
3850 : /* concerning about masking. Should be as fast as possible */
3851 : /* for this particular transformation type. */
3852 : /************************************************************************/
3853 :
3854 : static void GWKCubicSplineNoMasksByteThread(void* pData);
3855 :
3856 10 : static CPLErr GWKCubicSplineNoMasksByte( GDALWarpKernel *poWK )
3857 : {
3858 10 : return GWKRun( poWK, "GWKCubicSplineNoMasksByte", GWKCubicSplineNoMasksByteThread );
3859 : }
3860 :
3861 10 : static void GWKCubicSplineNoMasksByteThread( void* pData )
3862 :
3863 : {
3864 10 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3865 10 : GDALWarpKernel *poWK = psJob->poWK;
3866 10 : int iYMin = psJob->iYMin;
3867 10 : int iYMax = psJob->iYMax;
3868 :
3869 : int iDstY;
3870 10 : int nDstXSize = poWK->nDstXSize;
3871 10 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3872 :
3873 : /* -------------------------------------------------------------------- */
3874 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3875 : /* scanlines worth of positions. */
3876 : /* -------------------------------------------------------------------- */
3877 : double *padfX, *padfY, *padfZ;
3878 : int *pabSuccess;
3879 :
3880 10 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3881 10 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3882 10 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3883 10 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3884 :
3885 10 : int nXRadius = poWK->nXRadius;
3886 10 : double *padfBSpline = (double *)CPLCalloc( nXRadius * 2, sizeof(double) );
3887 :
3888 : /* ==================================================================== */
3889 : /* Loop over output lines. */
3890 : /* ==================================================================== */
3891 703 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3892 : {
3893 : int iDstX;
3894 :
3895 : /* -------------------------------------------------------------------- */
3896 : /* Setup points to transform to source image space. */
3897 : /* -------------------------------------------------------------------- */
3898 330036 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3899 : {
3900 329343 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
3901 329343 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
3902 329343 : padfZ[iDstX] = 0.0;
3903 : }
3904 :
3905 : /* -------------------------------------------------------------------- */
3906 : /* Transform the points from destination pixel/line coordinates */
3907 : /* to source pixel/line coordinates. */
3908 : /* -------------------------------------------------------------------- */
3909 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
3910 693 : padfX, padfY, padfZ, pabSuccess );
3911 :
3912 : /* ==================================================================== */
3913 : /* Loop over pixels in output scanline. */
3914 : /* ==================================================================== */
3915 330036 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
3916 : {
3917 329343 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
3918 :
3919 : /* ==================================================================== */
3920 : /* Loop processing each band. */
3921 : /* ==================================================================== */
3922 : int iBand;
3923 : int iDstOffset;
3924 :
3925 278207 : iDstOffset = iDstX + iDstY * nDstXSize;
3926 :
3927 556414 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
3928 : {
3929 : GWKCubicSplineResampleNoMasksByte( poWK, iBand,
3930 278207 : padfX[iDstX]-poWK->nSrcXOff,
3931 278207 : padfY[iDstX]-poWK->nSrcYOff,
3932 278207 : &poWK->papabyDstImage[iBand][iDstOffset],
3933 834621 : padfBSpline);
3934 : }
3935 : }
3936 :
3937 : /* -------------------------------------------------------------------- */
3938 : /* Report progress to the user, and optionally cancel out. */
3939 : /* -------------------------------------------------------------------- */
3940 693 : if (psJob->pfnProgress(psJob))
3941 0 : break;
3942 : }
3943 :
3944 : /* -------------------------------------------------------------------- */
3945 : /* Cleanup and return. */
3946 : /* -------------------------------------------------------------------- */
3947 10 : CPLFree( padfX );
3948 10 : CPLFree( padfY );
3949 10 : CPLFree( padfZ );
3950 10 : CPLFree( pabSuccess );
3951 10 : CPLFree( padfBSpline );
3952 10 : }
3953 :
3954 : /************************************************************************/
3955 : /* GWKNearestByte() */
3956 : /* */
3957 : /* Case for 8bit input data with nearest neighbour resampling */
3958 : /* using valid flags. Should be as fast as possible for this */
3959 : /* particular transformation type. */
3960 : /************************************************************************/
3961 :
3962 : static void GWKNearestByteThread(void* pData);
3963 :
3964 28 : static CPLErr GWKNearestByte( GDALWarpKernel *poWK )
3965 : {
3966 28 : return GWKRun( poWK, "GWKNearestByte", GWKNearestByteThread );
3967 : }
3968 :
3969 32 : static void GWKNearestByteThread( void* pData )
3970 :
3971 : {
3972 32 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
3973 32 : GDALWarpKernel *poWK = psJob->poWK;
3974 32 : int iYMin = psJob->iYMin;
3975 32 : int iYMax = psJob->iYMax;
3976 :
3977 : int iDstY;
3978 32 : int nDstXSize = poWK->nDstXSize;
3979 32 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
3980 :
3981 : /* -------------------------------------------------------------------- */
3982 : /* Allocate x,y,z coordinate arrays for transformation ... one */
3983 : /* scanlines worth of positions. */
3984 : /* -------------------------------------------------------------------- */
3985 : double *padfX, *padfY, *padfZ;
3986 : int *pabSuccess;
3987 :
3988 32 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3989 32 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3990 32 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
3991 32 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
3992 :
3993 : /* ==================================================================== */
3994 : /* Loop over output lines. */
3995 : /* ==================================================================== */
3996 3572 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
3997 : {
3998 : int iDstX;
3999 :
4000 : /* -------------------------------------------------------------------- */
4001 : /* Setup points to transform to source image space. */
4002 : /* -------------------------------------------------------------------- */
4003 1596029 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4004 : {
4005 1592489 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4006 1592489 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4007 1592489 : padfZ[iDstX] = 0.0;
4008 : }
4009 :
4010 : /* -------------------------------------------------------------------- */
4011 : /* Transform the points from destination pixel/line coordinates */
4012 : /* to source pixel/line coordinates. */
4013 : /* -------------------------------------------------------------------- */
4014 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4015 3540 : padfX, padfY, padfZ, pabSuccess );
4016 :
4017 : /* ==================================================================== */
4018 : /* Loop over pixels in output scanline. */
4019 : /* ==================================================================== */
4020 1571262 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4021 : {
4022 : int iDstOffset;
4023 :
4024 1567723 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4025 :
4026 : /* -------------------------------------------------------------------- */
4027 : /* Do not try to apply invalid source pixels to the dest. */
4028 : /* -------------------------------------------------------------------- */
4029 732326 : if( poWK->panUnifiedSrcValid != NULL
4030 158681 : && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
4031 : & (0x01 << (iSrcOffset & 0x1f))) )
4032 32599 : continue;
4033 :
4034 : /* -------------------------------------------------------------------- */
4035 : /* Do not try to apply transparent source pixels to the destination.*/
4036 : /* -------------------------------------------------------------------- */
4037 541046 : double dfDensity = 1.0;
4038 :
4039 541046 : if( poWK->pafUnifiedSrcDensity != NULL )
4040 : {
4041 90000 : dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
4042 90000 : if( dfDensity < 0.00001 )
4043 74897 : continue;
4044 : }
4045 :
4046 : /* ==================================================================== */
4047 : /* Loop processing each band. */
4048 : /* ==================================================================== */
4049 : int iBand;
4050 :
4051 466149 : iDstOffset = iDstX + iDstY * nDstXSize;
4052 :
4053 1192046 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4054 : {
4055 725901 : GByte bValue = 0;
4056 725901 : double dfBandDensity = 0.0;
4057 :
4058 : /* -------------------------------------------------------------------- */
4059 : /* Collect the source value. */
4060 : /* -------------------------------------------------------------------- */
4061 725901 : if ( GWKGetPixelByte( poWK, iBand, iSrcOffset, &dfBandDensity,
4062 : &bValue ) )
4063 : {
4064 725901 : if( dfBandDensity < 1.0 )
4065 : {
4066 1472 : if( dfBandDensity == 0.0 )
4067 : /* do nothing */;
4068 : else
4069 : {
4070 : /* let the general code take care of mixing */
4071 : GWKSetPixelValue( poWK, iBand, iDstOffset,
4072 : dfBandDensity, (double) bValue,
4073 1472 : 0.0 );
4074 : }
4075 : }
4076 : else
4077 : {
4078 724429 : poWK->papabyDstImage[iBand][iDstOffset] = bValue;
4079 : }
4080 : }
4081 : }
4082 :
4083 : /* -------------------------------------------------------------------- */
4084 : /* Mark this pixel valid/opaque in the output. */
4085 : /* -------------------------------------------------------------------- */
4086 466145 : GWKOverlayDensity( poWK, iDstOffset, dfDensity );
4087 :
4088 466145 : if( poWK->panDstValid != NULL )
4089 : {
4090 : poWK->panDstValid[iDstOffset>>5] |=
4091 1605 : 0x01 << (iDstOffset & 0x1f);
4092 : }
4093 : } /* Next iDstX */
4094 :
4095 : /* -------------------------------------------------------------------- */
4096 : /* Report progress to the user, and optionally cancel out. */
4097 : /* -------------------------------------------------------------------- */
4098 3539 : if (psJob->pfnProgress(psJob))
4099 0 : break;
4100 : } /* Next iDstY */
4101 :
4102 : /* -------------------------------------------------------------------- */
4103 : /* Cleanup and return. */
4104 : /* -------------------------------------------------------------------- */
4105 32 : CPLFree( padfX );
4106 32 : CPLFree( padfY );
4107 32 : CPLFree( padfZ );
4108 32 : CPLFree( pabSuccess );
4109 32 : }
4110 :
4111 : /************************************************************************/
4112 : /* GWKNearestNoMasksShort() */
4113 : /* */
4114 : /* Case for 16bit signed and unsigned integer input data with */
4115 : /* nearest neighbour resampling without concerning about masking. */
4116 : /* Should be as fast as possible for this particular */
4117 : /* transformation type. */
4118 : /************************************************************************/
4119 :
4120 : static void GWKNearestNoMasksShortThread(void* pData);
4121 :
4122 14 : static CPLErr GWKNearestNoMasksShort( GDALWarpKernel *poWK )
4123 : {
4124 14 : return GWKRun( poWK, "GWKNearestNoMasksShort", GWKNearestNoMasksShortThread );
4125 : }
4126 :
4127 14 : static void GWKNearestNoMasksShortThread( void* pData )
4128 :
4129 : {
4130 14 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4131 14 : GDALWarpKernel *poWK = psJob->poWK;
4132 14 : int iYMin = psJob->iYMin;
4133 14 : int iYMax = psJob->iYMax;
4134 :
4135 : int iDstY;
4136 14 : int nDstXSize = poWK->nDstXSize;
4137 14 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4138 :
4139 : /* -------------------------------------------------------------------- */
4140 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4141 : /* scanlines worth of positions. */
4142 : /* -------------------------------------------------------------------- */
4143 : double *padfX, *padfY, *padfZ;
4144 : int *pabSuccess;
4145 :
4146 14 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4147 14 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4148 14 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4149 14 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4150 :
4151 : /* ==================================================================== */
4152 : /* Loop over output lines. */
4153 : /* ==================================================================== */
4154 700 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4155 : {
4156 : int iDstX;
4157 :
4158 : /* -------------------------------------------------------------------- */
4159 : /* Setup points to transform to source image space. */
4160 : /* -------------------------------------------------------------------- */
4161 328892 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4162 : {
4163 328206 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4164 328206 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4165 328206 : padfZ[iDstX] = 0.0;
4166 : }
4167 :
4168 : /* -------------------------------------------------------------------- */
4169 : /* Transform the points from destination pixel/line coordinates */
4170 : /* to source pixel/line coordinates. */
4171 : /* -------------------------------------------------------------------- */
4172 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4173 686 : padfX, padfY, padfZ, pabSuccess );
4174 :
4175 : /* ==================================================================== */
4176 : /* Loop over pixels in output scanline. */
4177 : /* ==================================================================== */
4178 328892 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4179 : {
4180 : int iDstOffset;
4181 :
4182 328206 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4183 :
4184 : /* ==================================================================== */
4185 : /* Loop processing each band. */
4186 : /* ==================================================================== */
4187 : int iBand;
4188 :
4189 264948 : iDstOffset = iDstX + iDstY * nDstXSize;
4190 :
4191 529896 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4192 : {
4193 264948 : ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] =
4194 264948 : ((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset];
4195 : }
4196 : }
4197 :
4198 : /* -------------------------------------------------------------------- */
4199 : /* Report progress to the user, and optionally cancel out. */
4200 : /* -------------------------------------------------------------------- */
4201 686 : if (psJob->pfnProgress(psJob))
4202 0 : break;
4203 : }
4204 :
4205 : /* -------------------------------------------------------------------- */
4206 : /* Cleanup and return. */
4207 : /* -------------------------------------------------------------------- */
4208 14 : CPLFree( padfX );
4209 14 : CPLFree( padfY );
4210 14 : CPLFree( padfZ );
4211 14 : CPLFree( pabSuccess );
4212 14 : }
4213 :
4214 : /************************************************************************/
4215 : /* GWKBilinearNoMasksShort() */
4216 : /* */
4217 : /* Case for 16bit input data with cubic resampling without */
4218 : /* concerning about masking. Should be as fast as possible */
4219 : /* for this particular transformation type. */
4220 : /************************************************************************/
4221 :
4222 : static void GWKBilinearNoMasksShortThread(void* pData);
4223 :
4224 20 : static CPLErr GWKBilinearNoMasksShort( GDALWarpKernel *poWK )
4225 : {
4226 20 : return GWKRun( poWK, "GWKBilinearNoMasksShort", GWKBilinearNoMasksShortThread );
4227 : }
4228 :
4229 20 : static void GWKBilinearNoMasksShortThread( void* pData )
4230 :
4231 : {
4232 20 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4233 20 : GDALWarpKernel *poWK = psJob->poWK;
4234 20 : int iYMin = psJob->iYMin;
4235 20 : int iYMax = psJob->iYMax;
4236 :
4237 : int iDstY;
4238 20 : int nDstXSize = poWK->nDstXSize;
4239 20 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4240 :
4241 : /* -------------------------------------------------------------------- */
4242 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4243 : /* scanlines worth of positions. */
4244 : /* -------------------------------------------------------------------- */
4245 : double *padfX, *padfY, *padfZ;
4246 : int *pabSuccess;
4247 :
4248 20 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4249 20 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4250 20 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4251 20 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4252 :
4253 : /* ==================================================================== */
4254 : /* Loop over output lines. */
4255 : /* ==================================================================== */
4256 1856 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4257 : {
4258 : int iDstX;
4259 :
4260 : /* -------------------------------------------------------------------- */
4261 : /* Setup points to transform to source image space. */
4262 : /* -------------------------------------------------------------------- */
4263 1707544 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4264 : {
4265 1705708 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4266 1705708 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4267 1705708 : padfZ[iDstX] = 0.0;
4268 : }
4269 :
4270 : /* -------------------------------------------------------------------- */
4271 : /* Transform the points from destination pixel/line coordinates */
4272 : /* to source pixel/line coordinates. */
4273 : /* -------------------------------------------------------------------- */
4274 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4275 1836 : padfX, padfY, padfZ, pabSuccess );
4276 :
4277 : /* ==================================================================== */
4278 : /* Loop over pixels in output scanline. */
4279 : /* ==================================================================== */
4280 1707544 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4281 : {
4282 1705708 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4283 :
4284 : /* ==================================================================== */
4285 : /* Loop processing each band. */
4286 : /* ==================================================================== */
4287 : int iBand;
4288 : int iDstOffset;
4289 :
4290 1705708 : iDstOffset = iDstX + iDstY * nDstXSize;
4291 :
4292 3411416 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4293 : {
4294 1705708 : GInt16 iValue = 0;
4295 : GWKBilinearResampleNoMasksShort( poWK, iBand,
4296 1705708 : padfX[iDstX]-poWK->nSrcXOff,
4297 1705708 : padfY[iDstX]-poWK->nSrcYOff,
4298 3411416 : &iValue );
4299 1705708 : ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
4300 : }
4301 : }
4302 :
4303 : /* -------------------------------------------------------------------- */
4304 : /* Report progress to the user, and optionally cancel out. */
4305 : /* -------------------------------------------------------------------- */
4306 1836 : if (psJob->pfnProgress(psJob))
4307 0 : break;
4308 : }
4309 :
4310 : /* -------------------------------------------------------------------- */
4311 : /* Cleanup and return. */
4312 : /* -------------------------------------------------------------------- */
4313 20 : CPLFree( padfX );
4314 20 : CPLFree( padfY );
4315 20 : CPLFree( padfZ );
4316 20 : CPLFree( pabSuccess );
4317 20 : }
4318 :
4319 : /************************************************************************/
4320 : /* GWKCubicNoMasksShort() */
4321 : /* */
4322 : /* Case for 16bit input data with cubic resampling without */
4323 : /* concerning about masking. Should be as fast as possible */
4324 : /* for this particular transformation type. */
4325 : /************************************************************************/
4326 :
4327 : static void GWKCubicNoMasksShortThread(void* pData);
4328 :
4329 8 : static CPLErr GWKCubicNoMasksShort( GDALWarpKernel *poWK )
4330 : {
4331 8 : return GWKRun( poWK, "GWKCubicNoMasksShort", GWKCubicNoMasksShortThread );
4332 : }
4333 :
4334 8 : static void GWKCubicNoMasksShortThread( void* pData )
4335 :
4336 : {
4337 8 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4338 8 : GDALWarpKernel *poWK = psJob->poWK;
4339 8 : int iYMin = psJob->iYMin;
4340 8 : int iYMax = psJob->iYMax;
4341 :
4342 : int iDstY;
4343 8 : int nDstXSize = poWK->nDstXSize;
4344 8 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4345 :
4346 : /* -------------------------------------------------------------------- */
4347 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4348 : /* scanlines worth of positions. */
4349 : /* -------------------------------------------------------------------- */
4350 : double *padfX, *padfY, *padfZ;
4351 : int *pabSuccess;
4352 :
4353 8 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4354 8 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4355 8 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4356 8 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4357 :
4358 : /* ==================================================================== */
4359 : /* Loop over output lines. */
4360 : /* ==================================================================== */
4361 533 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4362 : {
4363 : int iDstX;
4364 :
4365 : /* -------------------------------------------------------------------- */
4366 : /* Setup points to transform to source image space. */
4367 : /* -------------------------------------------------------------------- */
4368 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4369 : {
4370 262207 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4371 262207 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4372 262207 : padfZ[iDstX] = 0.0;
4373 : }
4374 :
4375 : /* -------------------------------------------------------------------- */
4376 : /* Transform the points from destination pixel/line coordinates */
4377 : /* to source pixel/line coordinates. */
4378 : /* -------------------------------------------------------------------- */
4379 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4380 525 : padfX, padfY, padfZ, pabSuccess );
4381 :
4382 : /* ==================================================================== */
4383 : /* Loop over pixels in output scanline. */
4384 : /* ==================================================================== */
4385 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4386 : {
4387 262207 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4388 :
4389 : /* ==================================================================== */
4390 : /* Loop processing each band. */
4391 : /* ==================================================================== */
4392 : int iBand;
4393 : int iDstOffset;
4394 :
4395 262207 : iDstOffset = iDstX + iDstY * nDstXSize;
4396 :
4397 524414 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4398 : {
4399 262207 : GInt16 iValue = 0;
4400 : GWKCubicResampleNoMasksShort( poWK, iBand,
4401 262207 : padfX[iDstX]-poWK->nSrcXOff,
4402 262207 : padfY[iDstX]-poWK->nSrcYOff,
4403 524414 : &iValue );
4404 262207 : ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
4405 : }
4406 : }
4407 :
4408 : /* -------------------------------------------------------------------- */
4409 : /* Report progress to the user, and optionally cancel out. */
4410 : /* -------------------------------------------------------------------- */
4411 525 : if (psJob->pfnProgress(psJob))
4412 0 : break;
4413 : }
4414 :
4415 : /* -------------------------------------------------------------------- */
4416 : /* Cleanup and return. */
4417 : /* -------------------------------------------------------------------- */
4418 8 : CPLFree( padfX );
4419 8 : CPLFree( padfY );
4420 8 : CPLFree( padfZ );
4421 8 : CPLFree( pabSuccess );
4422 8 : }
4423 :
4424 : /************************************************************************/
4425 : /* GWKCubicSplineNoMasksShort() */
4426 : /* */
4427 : /* Case for 16bit input data with cubic resampling without */
4428 : /* concerning about masking. Should be as fast as possible */
4429 : /* for this particular transformation type. */
4430 : /************************************************************************/
4431 :
4432 : static void GWKCubicSplineNoMasksShortThread(void* pData);
4433 :
4434 8 : static CPLErr GWKCubicSplineNoMasksShort( GDALWarpKernel *poWK )
4435 : {
4436 8 : return GWKRun( poWK, "GWKCubicSplineNoMasksShort", GWKCubicSplineNoMasksShortThread );
4437 : }
4438 :
4439 8 : static void GWKCubicSplineNoMasksShortThread( void* pData )
4440 :
4441 : {
4442 8 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4443 8 : GDALWarpKernel *poWK = psJob->poWK;
4444 8 : int iYMin = psJob->iYMin;
4445 8 : int iYMax = psJob->iYMax;
4446 :
4447 : int iDstY;
4448 8 : int nDstXSize = poWK->nDstXSize;
4449 8 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4450 :
4451 : /* -------------------------------------------------------------------- */
4452 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4453 : /* scanlines worth of positions. */
4454 : /* -------------------------------------------------------------------- */
4455 : double *padfX, *padfY, *padfZ;
4456 : int *pabSuccess;
4457 :
4458 8 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4459 8 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4460 8 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4461 8 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4462 :
4463 8 : int nXRadius = poWK->nXRadius;
4464 : // Make space to save weights
4465 8 : double *padfBSpline = (double *)CPLCalloc( nXRadius * 2, sizeof(double) );
4466 :
4467 : /* ==================================================================== */
4468 : /* Loop over output lines. */
4469 : /* ==================================================================== */
4470 533 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4471 : {
4472 : int iDstX;
4473 :
4474 : /* -------------------------------------------------------------------- */
4475 : /* Setup points to transform to source image space. */
4476 : /* -------------------------------------------------------------------- */
4477 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4478 : {
4479 262207 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4480 262207 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4481 262207 : padfZ[iDstX] = 0.0;
4482 : }
4483 :
4484 : /* -------------------------------------------------------------------- */
4485 : /* Transform the points from destination pixel/line coordinates */
4486 : /* to source pixel/line coordinates. */
4487 : /* -------------------------------------------------------------------- */
4488 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4489 525 : padfX, padfY, padfZ, pabSuccess );
4490 :
4491 : /* ==================================================================== */
4492 : /* Loop over pixels in output scanline. */
4493 : /* ==================================================================== */
4494 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4495 : {
4496 262207 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4497 :
4498 : /* ==================================================================== */
4499 : /* Loop processing each band. */
4500 : /* ==================================================================== */
4501 : int iBand;
4502 : int iDstOffset;
4503 :
4504 262207 : iDstOffset = iDstX + iDstY * nDstXSize;
4505 :
4506 524414 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4507 : {
4508 262207 : GInt16 iValue = 0;
4509 : GWKCubicSplineResampleNoMasksShort( poWK, iBand,
4510 262207 : padfX[iDstX]-poWK->nSrcXOff,
4511 262207 : padfY[iDstX]-poWK->nSrcYOff,
4512 : &iValue,
4513 524414 : padfBSpline);
4514 262207 : ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
4515 : }
4516 : }
4517 :
4518 : /* -------------------------------------------------------------------- */
4519 : /* Report progress to the user, and optionally cancel out. */
4520 : /* -------------------------------------------------------------------- */
4521 525 : if (psJob->pfnProgress(psJob))
4522 0 : break;
4523 : }
4524 :
4525 : /* -------------------------------------------------------------------- */
4526 : /* Cleanup and return. */
4527 : /* -------------------------------------------------------------------- */
4528 8 : CPLFree( padfX );
4529 8 : CPLFree( padfY );
4530 8 : CPLFree( padfZ );
4531 8 : CPLFree( pabSuccess );
4532 8 : CPLFree( padfBSpline );
4533 8 : }
4534 :
4535 : /************************************************************************/
4536 : /* GWKNearestShort() */
4537 : /* */
4538 : /* Case for 32bit float input data with nearest neighbour */
4539 : /* resampling using valid flags. Should be as fast as possible */
4540 : /* for this particular transformation type. */
4541 : /************************************************************************/
4542 :
4543 : static void GWKNearestShortThread(void* pData);
4544 :
4545 7 : static CPLErr GWKNearestShort( GDALWarpKernel *poWK )
4546 : {
4547 7 : return GWKRun( poWK, "GWKNearestShort", GWKNearestShortThread );
4548 : }
4549 :
4550 7 : static void GWKNearestShortThread(void* pData)
4551 : {
4552 7 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4553 7 : GDALWarpKernel *poWK = psJob->poWK;
4554 7 : int iYMin = psJob->iYMin;
4555 7 : int iYMax = psJob->iYMax;
4556 :
4557 : int iDstY;
4558 7 : int nDstXSize = poWK->nDstXSize;
4559 7 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4560 :
4561 : /* -------------------------------------------------------------------- */
4562 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4563 : /* scanlines worth of positions. */
4564 : /* -------------------------------------------------------------------- */
4565 : double *padfX, *padfY, *padfZ;
4566 : int *pabSuccess;
4567 :
4568 7 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4569 7 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4570 7 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4571 7 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4572 :
4573 : /* ==================================================================== */
4574 : /* Loop over output lines. */
4575 : /* ==================================================================== */
4576 2297 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4577 : {
4578 : int iDstX;
4579 :
4580 : /* -------------------------------------------------------------------- */
4581 : /* Setup points to transform to source image space. */
4582 : /* -------------------------------------------------------------------- */
4583 1620626 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4584 : {
4585 1618336 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4586 1618336 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4587 1618336 : padfZ[iDstX] = 0.0;
4588 : }
4589 :
4590 : /* -------------------------------------------------------------------- */
4591 : /* Transform the points from destination pixel/line coordinates */
4592 : /* to source pixel/line coordinates. */
4593 : /* -------------------------------------------------------------------- */
4594 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4595 2290 : padfX, padfY, padfZ, pabSuccess );
4596 :
4597 : /* ==================================================================== */
4598 : /* Loop over pixels in output scanline. */
4599 : /* ==================================================================== */
4600 1620626 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4601 : {
4602 : int iDstOffset;
4603 :
4604 1618336 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4605 :
4606 : /* -------------------------------------------------------------------- */
4607 : /* Don't generate output pixels for which the source valid */
4608 : /* mask exists and is invalid. */
4609 : /* -------------------------------------------------------------------- */
4610 1488066 : if( poWK->panUnifiedSrcValid != NULL
4611 0 : && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
4612 : & (0x01 << (iSrcOffset & 0x1f))) )
4613 0 : continue;
4614 :
4615 : /* -------------------------------------------------------------------- */
4616 : /* Do not try to apply transparent source pixels to the destination.*/
4617 : /* -------------------------------------------------------------------- */
4618 1488066 : double dfDensity = 1.0;
4619 :
4620 1488066 : if( poWK->pafUnifiedSrcDensity != NULL )
4621 : {
4622 802 : dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
4623 802 : if( dfDensity < 0.00001 )
4624 401 : continue;
4625 : }
4626 :
4627 : /* ==================================================================== */
4628 : /* Loop processing each band. */
4629 : /* ==================================================================== */
4630 : int iBand;
4631 1487665 : iDstOffset = iDstX + iDstY * nDstXSize;
4632 :
4633 2976132 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4634 : {
4635 1488467 : GInt16 iValue = 0;
4636 1488467 : double dfBandDensity = 0.0;
4637 :
4638 : /* -------------------------------------------------------------------- */
4639 : /* Collect the source value. */
4640 : /* -------------------------------------------------------------------- */
4641 1488467 : if ( GWKGetPixelShort( poWK, iBand, iSrcOffset, &dfBandDensity,
4642 : &iValue ) )
4643 : {
4644 1487752 : if( dfBandDensity < 1.0 )
4645 : {
4646 0 : if( dfBandDensity == 0.0 )
4647 : /* do nothing */;
4648 : else
4649 : {
4650 : /* let the general code take care of mixing */
4651 : GWKSetPixelValue( poWK, iBand, iDstOffset,
4652 : dfBandDensity, (double) iValue,
4653 0 : 0.0 );
4654 : }
4655 : }
4656 : else
4657 : {
4658 1487752 : ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
4659 : }
4660 : }
4661 : }
4662 :
4663 : /* -------------------------------------------------------------------- */
4664 : /* Mark this pixel valid/opaque in the output. */
4665 : /* -------------------------------------------------------------------- */
4666 1487665 : GWKOverlayDensity( poWK, iDstOffset, dfDensity );
4667 :
4668 1487665 : if( poWK->panDstValid != NULL )
4669 : {
4670 : poWK->panDstValid[iDstOffset>>5] |=
4671 0 : 0x01 << (iDstOffset & 0x1f);
4672 : }
4673 : } /* Next iDstX */
4674 :
4675 : /* -------------------------------------------------------------------- */
4676 : /* Report progress to the user, and optionally cancel out. */
4677 : /* -------------------------------------------------------------------- */
4678 2290 : if (psJob->pfnProgress(psJob))
4679 0 : break;
4680 : } /* Next iDstY */
4681 :
4682 : /* -------------------------------------------------------------------- */
4683 : /* Cleanup and return. */
4684 : /* -------------------------------------------------------------------- */
4685 7 : CPLFree( padfX );
4686 7 : CPLFree( padfY );
4687 7 : CPLFree( padfZ );
4688 7 : CPLFree( pabSuccess );
4689 7 : }
4690 :
4691 : /************************************************************************/
4692 : /* GWKNearestNoMasksFloat() */
4693 : /* */
4694 : /* Case for 32bit float input data with nearest neighbour */
4695 : /* resampling without concerning about masking. Should be as fast */
4696 : /* as possible for this particular transformation type. */
4697 : /************************************************************************/
4698 :
4699 : static void GWKNearestNoMasksFloatThread(void* pData);
4700 :
4701 8 : static CPLErr GWKNearestNoMasksFloat( GDALWarpKernel *poWK )
4702 : {
4703 8 : return GWKRun( poWK, "GWKNearestNoMasksFloat", GWKNearestNoMasksFloatThread );
4704 : }
4705 :
4706 8 : static void GWKNearestNoMasksFloatThread( void* pData )
4707 :
4708 : {
4709 8 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4710 8 : GDALWarpKernel *poWK = psJob->poWK;
4711 8 : int iYMin = psJob->iYMin;
4712 8 : int iYMax = psJob->iYMax;
4713 :
4714 : int iDstY;
4715 8 : int nDstXSize = poWK->nDstXSize;
4716 8 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4717 :
4718 : /* -------------------------------------------------------------------- */
4719 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4720 : /* scanlines worth of positions. */
4721 : /* -------------------------------------------------------------------- */
4722 : double *padfX, *padfY, *padfZ;
4723 : int *pabSuccess;
4724 :
4725 8 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4726 8 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4727 8 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4728 8 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4729 :
4730 : /* ==================================================================== */
4731 : /* Loop over output lines. */
4732 : /* ==================================================================== */
4733 533 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4734 : {
4735 : int iDstX;
4736 :
4737 : /* -------------------------------------------------------------------- */
4738 : /* Setup points to transform to source image space. */
4739 : /* -------------------------------------------------------------------- */
4740 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4741 : {
4742 262207 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4743 262207 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4744 262207 : padfZ[iDstX] = 0.0;
4745 : }
4746 :
4747 : /* -------------------------------------------------------------------- */
4748 : /* Transform the points from destination pixel/line coordinates */
4749 : /* to source pixel/line coordinates. */
4750 : /* -------------------------------------------------------------------- */
4751 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4752 525 : padfX, padfY, padfZ, pabSuccess );
4753 :
4754 : /* ==================================================================== */
4755 : /* Loop over pixels in output scanline. */
4756 : /* ==================================================================== */
4757 262732 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4758 : {
4759 : int iDstOffset;
4760 :
4761 262207 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4762 :
4763 : /* ==================================================================== */
4764 : /* Loop processing each band. */
4765 : /* ==================================================================== */
4766 : int iBand;
4767 :
4768 262207 : iDstOffset = iDstX + iDstY * nDstXSize;
4769 :
4770 524414 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4771 : {
4772 262207 : ((float *)poWK->papabyDstImage[iBand])[iDstOffset] =
4773 262207 : ((float *)poWK->papabySrcImage[iBand])[iSrcOffset];
4774 : }
4775 : }
4776 :
4777 : /* -------------------------------------------------------------------- */
4778 : /* Report progress to the user, and optionally cancel out. */
4779 : /* -------------------------------------------------------------------- */
4780 525 : if (psJob->pfnProgress(psJob))
4781 0 : break;
4782 : }
4783 :
4784 : /* -------------------------------------------------------------------- */
4785 : /* Cleanup and return. */
4786 : /* -------------------------------------------------------------------- */
4787 8 : CPLFree( padfX );
4788 8 : CPLFree( padfY );
4789 8 : CPLFree( padfZ );
4790 8 : CPLFree( pabSuccess );
4791 8 : }
4792 :
4793 : /************************************************************************/
4794 : /* GWKNearestFloat() */
4795 : /* */
4796 : /* Case for 32bit float input data with nearest neighbour */
4797 : /* resampling using valid flags. Should be as fast as possible */
4798 : /* for this particular transformation type. */
4799 : /************************************************************************/
4800 :
4801 : static void GWKNearestFloatThread(void* pData);
4802 :
4803 6 : static CPLErr GWKNearestFloat( GDALWarpKernel *poWK )
4804 : {
4805 6 : return GWKRun( poWK, "GWKNearestFloat", GWKNearestFloatThread );
4806 : }
4807 :
4808 6 : static void GWKNearestFloatThread( void* pData )
4809 :
4810 : {
4811 6 : GWKJobStruct* psJob = (GWKJobStruct*) pData;
4812 6 : GDALWarpKernel *poWK = psJob->poWK;
4813 6 : int iYMin = psJob->iYMin;
4814 6 : int iYMax = psJob->iYMax;
4815 :
4816 : int iDstY;
4817 6 : int nDstXSize = poWK->nDstXSize;
4818 6 : int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
4819 :
4820 : /* -------------------------------------------------------------------- */
4821 : /* Allocate x,y,z coordinate arrays for transformation ... one */
4822 : /* scanlines worth of positions. */
4823 : /* -------------------------------------------------------------------- */
4824 : double *padfX, *padfY, *padfZ;
4825 : int *pabSuccess;
4826 :
4827 6 : padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4828 6 : padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4829 6 : padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
4830 6 : pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
4831 :
4832 : /* ==================================================================== */
4833 : /* Loop over output lines. */
4834 : /* ==================================================================== */
4835 774 : for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
4836 : {
4837 : int iDstX;
4838 :
4839 : /* -------------------------------------------------------------------- */
4840 : /* Setup points to transform to source image space. */
4841 : /* -------------------------------------------------------------------- */
4842 393984 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4843 : {
4844 393216 : padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
4845 393216 : padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
4846 393216 : padfZ[iDstX] = 0.0;
4847 : }
4848 :
4849 : /* -------------------------------------------------------------------- */
4850 : /* Transform the points from destination pixel/line coordinates */
4851 : /* to source pixel/line coordinates. */
4852 : /* -------------------------------------------------------------------- */
4853 : poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
4854 768 : padfX, padfY, padfZ, pabSuccess );
4855 :
4856 : /* ==================================================================== */
4857 : /* Loop over pixels in output scanline. */
4858 : /* ==================================================================== */
4859 393984 : for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
4860 : {
4861 : int iDstOffset;
4862 :
4863 393216 : COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
4864 :
4865 : /* -------------------------------------------------------------------- */
4866 : /* Do not try to apply invalid source pixels to the dest. */
4867 : /* -------------------------------------------------------------------- */
4868 1202 : if( poWK->panUnifiedSrcValid != NULL
4869 0 : && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
4870 : & (0x01 << (iSrcOffset & 0x1f))) )
4871 0 : continue;
4872 :
4873 : /* -------------------------------------------------------------------- */
4874 : /* Do not try to apply transparent source pixels to the destination.*/
4875 : /* -------------------------------------------------------------------- */
4876 1202 : double dfDensity = 1.0;
4877 :
4878 1202 : if( poWK->pafUnifiedSrcDensity != NULL )
4879 : {
4880 802 : dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
4881 802 : if( dfDensity < 0.00001 )
4882 401 : continue;
4883 : }
4884 :
4885 : /* ==================================================================== */
4886 : /* Loop processing each band. */
4887 : /* ==================================================================== */
4888 : int iBand;
4889 :
4890 801 : iDstOffset = iDstX + iDstY * nDstXSize;
4891 :
4892 2404 : for( iBand = 0; iBand < poWK->nBands; iBand++ )
4893 : {
4894 1603 : float fValue = 0;
4895 1603 : double dfBandDensity = 0.0;
4896 :
4897 : /* -------------------------------------------------------------------- */
4898 : /* Collect the source value. */
4899 : /* -------------------------------------------------------------------- */
4900 1603 : if ( GWKGetPixelFloat( poWK, iBand, iSrcOffset, &dfBandDensity,
4901 : &fValue ) )
4902 : {
4903 1563 : if( dfBandDensity < 1.0 )
4904 : {
4905 0 : if( dfBandDensity == 0.0 )
4906 : /* do nothing */;
4907 : else
4908 : {
4909 : /* let the general code take care of mixing */
4910 : GWKSetPixelValue( poWK, iBand, iDstOffset,
4911 : dfBandDensity, (double) fValue,
4912 0 : 0.0 );
4913 : }
4914 : }
4915 : else
4916 : {
4917 1563 : ((float *)poWK->papabyDstImage[iBand])[iDstOffset]
4918 1563 : = fValue;
4919 : }
4920 : }
4921 : }
4922 :
4923 : /* -------------------------------------------------------------------- */
4924 : /* Mark this pixel valid/opaque in the output. */
4925 : /* -------------------------------------------------------------------- */
4926 801 : GWKOverlayDensity( poWK, iDstOffset, dfDensity );
4927 :
4928 801 : if( poWK->panDstValid != NULL )
4929 : {
4930 : poWK->panDstValid[iDstOffset>>5] |=
4931 400 : 0x01 << (iDstOffset & 0x1f);
4932 : }
4933 : }
4934 :
4935 : /* -------------------------------------------------------------------- */
4936 : /* Report progress to the user, and optionally cancel out. */
4937 : /* -------------------------------------------------------------------- */
4938 768 : if (psJob->pfnProgress(psJob))
4939 0 : break;
4940 : }
4941 :
4942 : /* -------------------------------------------------------------------- */
4943 : /* Cleanup and return. */
4944 : /* -------------------------------------------------------------------- */
4945 6 : CPLFree( padfX );
4946 6 : CPLFree( padfY );
4947 6 : CPLFree( padfZ );
4948 6 : CPLFree( pabSuccess );
4949 6 : }
4950 :
|