1 : /******************************************************************************
2 : * $Id: gdaltransformer.cpp 25707 2013-03-08 04:33:06Z warmerdam $
3 : *
4 : * Project: Mapinfo Image Warper
5 : * Purpose: Implementation of one or more GDALTrasformerFunc types, including
6 : * the GenImgProj (general image reprojector) transformer.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2002, i3 - information integration and imaging
11 : * Fort Collin, CO
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 "gdal_priv.h"
33 : #include "gdal_alg.h"
34 : #include "ogr_spatialref.h"
35 : #include "cpl_string.h"
36 : #include "gdal_alg_priv.h"
37 : #include "cpl_list.h"
38 : #include "cpl_multiproc.h"
39 :
40 : CPL_CVSID("$Id: gdaltransformer.cpp 25707 2013-03-08 04:33:06Z warmerdam $");
41 : CPL_C_START
42 : void *GDALDeserializeGCPTransformer( CPLXMLNode *psTree );
43 : void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
44 : void *GDALDeserializeGeoLocTransformer( CPLXMLNode *psTree );
45 : void *GDALDeserializeRPCTransformer( CPLXMLNode *psTree );
46 : CPL_C_END
47 :
48 : static CPLXMLNode *GDALSerializeReprojectionTransformer( void *pTransformArg );
49 : static void *GDALDeserializeReprojectionTransformer( CPLXMLNode *psTree );
50 :
51 : static CPLXMLNode *GDALSerializeGenImgProjTransformer( void *pTransformArg );
52 : static void *GDALDeserializeGenImgProjTransformer( CPLXMLNode *psTree );
53 :
54 : static void GDALRefreshGenImgProjTransformer(void* hTransformArg);
55 :
56 : /************************************************************************/
57 : /* GDALTransformFunc */
58 : /* */
59 : /* Documentation for GDALTransformFunc typedef. */
60 : /************************************************************************/
61 :
62 : /*!
63 :
64 : \typedef int GDALTransformerFunc
65 :
66 : Generic signature for spatial point transformers.
67 :
68 : This function signature is used for a variety of functions that accept
69 : passed in functions used to transform point locations between two coordinate
70 : spaces.
71 :
72 : The GDALCreateGenImgProjTransformer(), GDALCreateReprojectionTransformer(),
73 : GDALCreateGCPTransformer() and GDALCreateApproxTransformer() functions can
74 : be used to prepare argument data for some built-in transformers. As well,
75 : applications can implement their own transformers to the following signature.
76 :
77 : \code
78 : typedef int
79 : (*GDALTransformerFunc)( void *pTransformerArg,
80 : int bDstToSrc, int nPointCount,
81 : double *x, double *y, double *z, int *panSuccess );
82 : \endcode
83 :
84 : @param pTransformerArg application supplied callback data used by the
85 : transformer.
86 :
87 : @param bDstToSrc if TRUE the transformation will be from the destination
88 : coordinate space to the source coordinate system, otherwise the transformation
89 : will be from the source coordinate system to the destination coordinate system.
90 :
91 : @param nPointCount number of points in the x, y and z arrays.
92 :
93 : @param x input X coordinates. Results returned in same array.
94 :
95 : @param y input Y coordinates. Results returned in same array.
96 :
97 : @param z input Z coordinates. Results returned in same array.
98 :
99 : @param panSuccess array of ints in which success (TRUE) or failure (FALSE)
100 : flags are returned for the translation of each point.
101 :
102 : @return TRUE if the overall transformation succeeds (though some individual
103 : points may have failed) or FALSE if the overall transformation fails.
104 :
105 : */
106 :
107 : /************************************************************************/
108 : /* GDALSuggestedWarpOutput() */
109 : /************************************************************************/
110 :
111 : /**
112 : * Suggest output file size.
113 : *
114 : * This function is used to suggest the size, and georeferenced extents
115 : * appropriate given the indicated transformation and input file. It walks
116 : * the edges of the input file (approximately 20 sample points along each
117 : * edge) transforming into output coordinates in order to get an extents box.
118 : *
119 : * Then a resolution is computed with the intent that the length of the
120 : * distance from the top left corner of the output imagery to the bottom right
121 : * corner would represent the same number of pixels as in the source image.
122 : * Note that if the image is somewhat rotated the diagonal taken isnt of the
123 : * whole output bounding rectangle, but instead of the locations where the
124 : * top/left and bottom/right corners transform. The output pixel size is
125 : * always square. This is intended to approximately preserve the resolution
126 : * of the input data in the output file.
127 : *
128 : * The values returned in padfGeoTransformOut, pnPixels and pnLines are
129 : * the suggested number of pixels and lines for the output file, and the
130 : * geotransform relating those pixels to the output georeferenced coordinates.
131 : *
132 : * The trickiest part of using the function is ensuring that the
133 : * transformer created is from source file pixel/line coordinates to
134 : * output file georeferenced coordinates. This can be accomplished with
135 : * GDALCreateGenImgProjTransformer() by passing a NULL for the hDstDS.
136 : *
137 : * @param hSrcDS the input image (it is assumed the whole input images is
138 : * being transformed).
139 : * @param pfnTransformer the transformer function.
140 : * @param pTransformArg the callback data for the transformer function.
141 : * @param padfGeoTransformOut the array of six doubles in which the suggested
142 : * geotransform is returned.
143 : * @param pnPixels int in which the suggest pixel width of output is returned.
144 : * @param pnLines int in which the suggest pixel height of output is returned.
145 : *
146 : * @return CE_None if successful or CE_Failure otherwise.
147 : */
148 :
149 :
150 : CPLErr CPL_STDCALL
151 14 : GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
152 : GDALTransformerFunc pfnTransformer,
153 : void *pTransformArg,
154 : double *padfGeoTransformOut,
155 : int *pnPixels, int *pnLines )
156 :
157 : {
158 14 : VALIDATE_POINTER1( hSrcDS, "GDALSuggestedWarpOutput", CE_Failure );
159 :
160 14 : double adfExtent[4] = { 0 };
161 :
162 : return GDALSuggestedWarpOutput2( hSrcDS, pfnTransformer, pTransformArg,
163 : padfGeoTransformOut, pnPixels, pnLines,
164 14 : adfExtent, 0 );
165 : }
166 :
167 :
168 318 : static int GDALSuggestedWarpOutput2_MustAdjustForRightBorder(
169 : GDALTransformerFunc pfnTransformer, void *pTransformArg,
170 : double* padfExtent, int nPixels, int nLines,
171 : double dfPixelSizeX, double dfPixelSizeY)
172 : {
173 : int nSamplePoints;
174 : double dfRatio;
175 : int bErr;
176 : int nBadCount;
177 318 : int abSuccess[21] = { 0 };
178 318 : double adfX[21] = { 0 };
179 318 : double adfY[21] = { 0 };
180 318 : double adfZ[21] = { 0 };
181 :
182 : //double dfMinXOut = padfExtent[0];
183 : //double dfMinYOut = padfExtent[1];
184 318 : double dfMaxXOut = padfExtent[2];
185 318 : double dfMaxYOut = padfExtent[3];
186 :
187 : // Take 20 steps
188 318 : nSamplePoints = 0;
189 6996 : for( dfRatio = 0.0; dfRatio <= 1.01; dfRatio += 0.05 )
190 : {
191 : // Ensure we end exactly at the end.
192 6678 : if( dfRatio > 0.99 )
193 318 : dfRatio = 1.0;
194 :
195 : // Along right
196 6678 : adfX[nSamplePoints] = dfMaxXOut;
197 6678 : adfY[nSamplePoints] = dfMaxYOut - dfPixelSizeY * dfRatio * nLines;
198 6678 : adfZ[nSamplePoints++] = 0.0;
199 : }
200 :
201 318 : bErr = FALSE;
202 318 : if( !pfnTransformer( pTransformArg, TRUE, nSamplePoints,
203 : adfX, adfY, adfZ, abSuccess ) )
204 : {
205 0 : bErr = TRUE;
206 : }
207 :
208 318 : if( !bErr && !pfnTransformer( pTransformArg, FALSE, nSamplePoints,
209 : adfX, adfY, adfZ, abSuccess ) )
210 : {
211 0 : bErr = TRUE;
212 : }
213 :
214 318 : nSamplePoints = 0;
215 318 : nBadCount = 0;
216 6996 : for( dfRatio = 0.0; !bErr && dfRatio <= 1.01; dfRatio += 0.05 )
217 : {
218 6678 : double expected_x = dfMaxXOut;
219 6678 : double expected_y = dfMaxYOut - dfPixelSizeY * dfRatio * nLines;
220 12524 : if (fabs(adfX[nSamplePoints] - expected_x) > dfPixelSizeX ||
221 5846 : fabs(adfY[nSamplePoints] - expected_y) > dfPixelSizeY)
222 832 : nBadCount ++;
223 6678 : nSamplePoints ++;
224 : }
225 :
226 318 : return (nBadCount == nSamplePoints);
227 : }
228 :
229 :
230 312 : static int GDALSuggestedWarpOutput2_MustAdjustForBottomBorder(
231 : GDALTransformerFunc pfnTransformer, void *pTransformArg,
232 : double* padfExtent, int nPixels, int nLines,
233 : double dfPixelSizeX, double dfPixelSizeY)
234 : {
235 : int nSamplePoints;
236 : double dfRatio;
237 : int bErr;
238 : int nBadCount;
239 312 : int abSuccess[21] = { 0 };
240 312 : double adfX[21] = { 0 };
241 312 : double adfY[21] = { 0 };
242 312 : double adfZ[21] = { 0 };
243 :
244 312 : double dfMinXOut = padfExtent[0];
245 312 : double dfMinYOut = padfExtent[1];
246 : //double dfMaxXOut = padfExtent[2];
247 : //double dfMaxYOut = padfExtent[3];
248 :
249 : // Take 20 steps
250 312 : nSamplePoints = 0;
251 6864 : for( dfRatio = 0.0; dfRatio <= 1.01; dfRatio += 0.05 )
252 : {
253 : // Ensure we end exactly at the end.
254 6552 : if( dfRatio > 0.99 )
255 312 : dfRatio = 1.0;
256 :
257 : // Along right
258 6552 : adfX[nSamplePoints] = dfMinXOut + dfPixelSizeX * dfRatio * nPixels;
259 6552 : adfY[nSamplePoints] = dfMinYOut;
260 6552 : adfZ[nSamplePoints++] = 0.0;
261 : }
262 :
263 312 : bErr = FALSE;
264 312 : if( !pfnTransformer( pTransformArg, TRUE, nSamplePoints,
265 : adfX, adfY, adfZ, abSuccess ) )
266 : {
267 0 : bErr = TRUE;
268 : }
269 :
270 312 : if( !bErr && !pfnTransformer( pTransformArg, FALSE, nSamplePoints,
271 : adfX, adfY, adfZ, abSuccess ) )
272 : {
273 0 : bErr = TRUE;
274 : }
275 :
276 312 : nSamplePoints = 0;
277 312 : nBadCount = 0;
278 6864 : for( dfRatio = 0.0; !bErr && dfRatio <= 1.01; dfRatio += 0.05 )
279 : {
280 6552 : double expected_x = dfMinXOut + dfPixelSizeX * dfRatio * nPixels;
281 6552 : double expected_y = dfMinYOut;
282 12422 : if (fabs(adfX[nSamplePoints] - expected_x) > dfPixelSizeX ||
283 5870 : fabs(adfY[nSamplePoints] - expected_y) > dfPixelSizeY)
284 682 : nBadCount ++;
285 6552 : nSamplePoints ++;
286 : }
287 :
288 312 : return (nBadCount == nSamplePoints);
289 : }
290 :
291 : /************************************************************************/
292 : /* GDALSuggestedWarpOutput2() */
293 : /************************************************************************/
294 :
295 : /**
296 : * Suggest output file size.
297 : *
298 : * This function is used to suggest the size, and georeferenced extents
299 : * appropriate given the indicated transformation and input file. It walks
300 : * the edges of the input file (approximately 20 sample points along each
301 : * edge) transforming into output coordinates in order to get an extents box.
302 : *
303 : * Then a resolution is computed with the intent that the length of the
304 : * distance from the top left corner of the output imagery to the bottom right
305 : * corner would represent the same number of pixels as in the source image.
306 : * Note that if the image is somewhat rotated the diagonal taken isnt of the
307 : * whole output bounding rectangle, but instead of the locations where the
308 : * top/left and bottom/right corners transform. The output pixel size is
309 : * always square. This is intended to approximately preserve the resolution
310 : * of the input data in the output file.
311 : *
312 : * The values returned in padfGeoTransformOut, pnPixels and pnLines are
313 : * the suggested number of pixels and lines for the output file, and the
314 : * geotransform relating those pixels to the output georeferenced coordinates.
315 : *
316 : * The trickiest part of using the function is ensuring that the
317 : * transformer created is from source file pixel/line coordinates to
318 : * output file georeferenced coordinates. This can be accomplished with
319 : * GDALCreateGenImgProjTransformer() by passing a NULL for the hDstDS.
320 : *
321 : * @param hSrcDS the input image (it is assumed the whole input images is
322 : * being transformed).
323 : * @param pfnTransformer the transformer function.
324 : * @param pTransformArg the callback data for the transformer function.
325 : * @param padfGeoTransformOut the array of six doubles in which the suggested
326 : * geotransform is returned.
327 : * @param pnPixels int in which the suggest pixel width of output is returned.
328 : * @param pnLines int in which the suggest pixel height of output is returned.
329 : * @param padfExtent Four entry array to return extents as (xmin, ymin, xmax, ymax).
330 : * @param nOptions Options, currently always zero.
331 : *
332 : * @return CE_None if successful or CE_Failure otherwise.
333 : */
334 :
335 : CPLErr CPL_STDCALL
336 288 : GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS,
337 : GDALTransformerFunc pfnTransformer,
338 : void *pTransformArg,
339 : double *padfGeoTransformOut,
340 : int *pnPixels, int *pnLines,
341 : double *padfExtent, int nOptions )
342 :
343 : {
344 288 : VALIDATE_POINTER1( hSrcDS, "GDALSuggestedWarpOutput2", CE_Failure );
345 :
346 : /* -------------------------------------------------------------------- */
347 : /* Setup sample points all around the edge of the input raster. */
348 : /* -------------------------------------------------------------------- */
349 288 : int nSamplePoints = 0;
350 288 : int nInXSize = GDALGetRasterXSize( hSrcDS );
351 288 : int nInYSize = GDALGetRasterYSize( hSrcDS );
352 :
353 288 : if (pfnTransformer == GDALGenImgProjTransform)
354 : {
355 : /* In case CHECK_WITH_INVERT_PROJ has been modified */
356 288 : GDALRefreshGenImgProjTransformer(pTransformArg);
357 : }
358 :
359 : #define N_PIXELSTEP 50
360 288 : int nSteps = (int) (double(MIN(nInYSize, nInXSize)) / N_PIXELSTEP + .5);
361 288 : if (nSteps < 20)
362 282 : nSteps = 20;
363 288 : nSteps = MIN(nSteps,100);
364 :
365 : retry:
366 288 : int nSampleMax = (nSteps + 1)*(nSteps + 1);
367 288 : int *pabSuccess = NULL;
368 : double *padfX, *padfY, *padfZ;
369 : double *padfXRevert, *padfYRevert, *padfZRevert;
370 :
371 288 : double dfRatio = 0.0;
372 288 : double dfStep = 1. / nSteps;
373 :
374 288 : pabSuccess = (int *) VSIMalloc3(sizeof(int), nSteps + 1, nSteps + 1);
375 288 : padfX = (double *) VSIMalloc3(sizeof(double) * 3, nSteps + 1, nSteps + 1);
376 288 : padfXRevert = (double *) VSIMalloc3(sizeof(double) * 3, nSteps + 1, nSteps + 1);
377 288 : if (pabSuccess == NULL || padfX == NULL || padfXRevert == NULL)
378 : {
379 0 : CPLFree( padfX );
380 0 : CPLFree( padfXRevert );
381 0 : CPLFree( pabSuccess );
382 0 : if (nSteps > 20)
383 : {
384 0 : nSteps = 20;
385 0 : goto retry;
386 : }
387 0 : return CE_Failure;
388 : }
389 288 : padfY = padfX + nSampleMax;
390 288 : padfZ = padfX + nSampleMax * 2;
391 288 : padfYRevert = padfXRevert + nSampleMax;
392 288 : padfZRevert = padfXRevert + nSampleMax * 2;
393 :
394 :
395 : // Take N_STEPS steps
396 : int iStep;
397 6336 : for( iStep = 0; iStep <= nSteps; iStep ++ )
398 : {
399 6048 : dfRatio = (iStep == nSteps) ? 1.0 : iStep * dfStep;
400 :
401 : // Along top
402 6048 : padfX[nSamplePoints] = dfRatio * nInXSize;
403 6048 : padfY[nSamplePoints] = 0.0;
404 6048 : padfZ[nSamplePoints++] = 0.0;
405 :
406 : // Along bottom
407 6048 : padfX[nSamplePoints] = dfRatio * nInXSize;
408 6048 : padfY[nSamplePoints] = nInYSize;
409 6048 : padfZ[nSamplePoints++] = 0.0;
410 :
411 : // Along left
412 6048 : padfX[nSamplePoints] = 0.0;
413 6048 : padfY[nSamplePoints] = dfRatio * nInYSize;
414 6048 : padfZ[nSamplePoints++] = 0.0;
415 :
416 : // Along right
417 6048 : padfX[nSamplePoints] = nInXSize;
418 6048 : padfY[nSamplePoints] = dfRatio * nInYSize;
419 6048 : padfZ[nSamplePoints++] = 0.0;
420 : }
421 :
422 288 : CPLAssert( nSamplePoints == 4 * (nSteps + 1) );
423 :
424 288 : memset( pabSuccess, 1, sizeof(int) * nSampleMax );
425 :
426 : /* -------------------------------------------------------------------- */
427 : /* Transform them to the output coordinate system. */
428 : /* -------------------------------------------------------------------- */
429 288 : int nFailedCount = 0, i;
430 :
431 288 : if( !pfnTransformer( pTransformArg, FALSE, nSamplePoints,
432 : padfX, padfY, padfZ, pabSuccess ) )
433 : {
434 : CPLError( CE_Failure, CPLE_AppDefined,
435 : "GDALSuggestedWarpOutput() failed because the passed\n"
436 0 : "transformer failed." );
437 0 : CPLFree( padfX );
438 0 : CPLFree( padfXRevert );
439 0 : CPLFree( pabSuccess );
440 0 : return CE_Failure;
441 : }
442 :
443 24480 : for( i = 0; i < nSamplePoints; i++ )
444 : {
445 24192 : if( !pabSuccess[i] )
446 299 : nFailedCount++;
447 : }
448 :
449 : /* -------------------------------------------------------------------- */
450 : /* Check if the computed target coordinates are revertable. */
451 : /* If not, try the detailed grid sampling. */
452 : /* -------------------------------------------------------------------- */
453 288 : if (nFailedCount == 0 )
454 : {
455 282 : memcpy(padfXRevert, padfX, nSamplePoints * sizeof(double));
456 282 : memcpy(padfYRevert, padfY, nSamplePoints * sizeof(double));
457 282 : memcpy(padfZRevert, padfZ, nSamplePoints * sizeof(double));
458 282 : if( !pfnTransformer( pTransformArg, TRUE, nSamplePoints,
459 : padfXRevert, padfYRevert, padfZRevert, pabSuccess ) )
460 : {
461 0 : nFailedCount = 1;
462 : }
463 : else
464 : {
465 5964 : for( i = 0; nFailedCount == 0 && i < nSamplePoints; i++ )
466 : {
467 5682 : if( !pabSuccess[i] )
468 0 : nFailedCount++;
469 :
470 5682 : dfRatio = 0.0 + (i/4) * dfStep;
471 5682 : if (dfRatio>0.99)
472 216 : dfRatio = 1.0;
473 :
474 : double dfExpectedX, dfExpectedY;
475 5682 : if ((i % 4) == 0)
476 : {
477 1591 : dfExpectedX = dfRatio * nInXSize;
478 1591 : dfExpectedY = 0.0;
479 : }
480 4091 : else if ((i % 4) == 1)
481 : {
482 1364 : dfExpectedX = dfRatio * nInXSize;
483 1364 : dfExpectedY = nInYSize;
484 : }
485 2727 : else if ((i % 4) == 2)
486 : {
487 1364 : dfExpectedX = 0.0;
488 1364 : dfExpectedY = dfRatio * nInYSize;
489 : }
490 : else
491 : {
492 1363 : dfExpectedX = nInXSize;
493 1363 : dfExpectedY = dfRatio * nInYSize;
494 : }
495 :
496 11137 : if (fabs(padfXRevert[i] - dfExpectedX) > nInXSize / nSteps ||
497 5455 : fabs(padfYRevert[i] - dfExpectedY) > nInYSize / nSteps)
498 228 : nFailedCount ++;
499 : }
500 : }
501 : }
502 :
503 : /* -------------------------------------------------------------------- */
504 : /* If any of the edge points failed to transform, we need to */
505 : /* build a fairly detailed internal grid of points instead to */
506 : /* help identify the area that is transformable. */
507 : /* -------------------------------------------------------------------- */
508 288 : if( nFailedCount > 0 )
509 : {
510 : int iStep2;
511 : double dfRatio2;
512 234 : nSamplePoints = 0;
513 :
514 : // Take N_STEPS steps
515 5148 : for( iStep = 0; iStep <= nSteps; iStep ++ )
516 : {
517 4914 : dfRatio = (iStep == nSteps) ? 1.0 : iStep * dfStep;
518 :
519 108108 : for( iStep2 = 0; iStep2 <= nSteps; iStep2 ++ )
520 : {
521 103194 : dfRatio2 = (iStep2 == nSteps) ? 1.0 : iStep2 * dfStep;
522 :
523 : // Along top
524 103194 : padfX[nSamplePoints] = dfRatio2 * nInXSize;
525 103194 : padfY[nSamplePoints] = dfRatio * nInYSize;
526 103194 : padfZ[nSamplePoints++] = 0.0;
527 : }
528 : }
529 :
530 234 : CPLAssert( nSamplePoints == nSampleMax );
531 :
532 234 : if( !pfnTransformer( pTransformArg, FALSE, nSamplePoints,
533 : padfX, padfY, padfZ, pabSuccess ) )
534 : {
535 : CPLError( CE_Failure, CPLE_AppDefined,
536 : "GDALSuggestedWarpOutput() failed because the passed\n"
537 0 : "transformer failed." );
538 :
539 0 : CPLFree( padfX );
540 0 : CPLFree( padfXRevert );
541 0 : CPLFree( pabSuccess );
542 :
543 0 : return CE_Failure;
544 : }
545 : }
546 :
547 : /* -------------------------------------------------------------------- */
548 : /* Collect the bounds, ignoring any failed points. */
549 : /* -------------------------------------------------------------------- */
550 288 : double dfMinXOut=0, dfMinYOut=0, dfMaxXOut=0, dfMaxYOut=0;
551 288 : int bGotInitialPoint = FALSE;
552 :
553 288 : nFailedCount = 0;
554 108018 : for( i = 0; i < nSamplePoints; i++ )
555 : {
556 :
557 107730 : int x_i = i % (nSteps + 1);
558 107730 : int y_i = i / (nSteps + 1);
559 :
560 107730 : if (x_i > 0 && (pabSuccess[i-1] || pabSuccess[i]))
561 : {
562 102138 : double x_out_before = padfX[i-1];
563 102138 : double x_out_after = padfX[i];
564 102138 : int nIter = 0;
565 102138 : double x_in_before = (x_i - 1) * nInXSize * 1.0 / nSteps;
566 102138 : double x_in_after = x_i * nInXSize * 1.0 / nSteps;
567 102138 : int valid_before = pabSuccess[i-1];
568 102138 : int valid_after = pabSuccess[i];
569 :
570 : /* Detect discontinuity in target coordinates when the target x coordinates */
571 : /* change sign. This may be a false positive when the targe tx is around 0 */
572 : /* Dichotomic search to reduce the interval to near the discontinuity and */
573 : /* get a better out extent */
574 207380 : while ( (!valid_before || !valid_after ||
575 : x_out_before * x_out_after < 0) && nIter < 16 )
576 : {
577 3104 : double x = (x_in_before + x_in_after) / 2;
578 3104 : double y = y_i * nInYSize * 1.0 / nSteps;
579 3104 : double z= 0;
580 : //fprintf(stderr, "[%d] (%f, %f) -> ", nIter, x, y);
581 3104 : int bSuccess = TRUE;
582 3104 : if( !pfnTransformer( pTransformArg, FALSE, 1,
583 : &x, &y, &z, &bSuccess ) || !bSuccess )
584 : {
585 : //fprintf(stderr, "invalid\n");
586 243 : if (!valid_before)
587 : {
588 171 : x_in_before = (x_in_before + x_in_after) / 2;
589 : }
590 72 : else if (!valid_after)
591 : {
592 72 : x_in_after = (x_in_before + x_in_after) / 2;
593 : }
594 : else
595 0 : break;
596 : }
597 : else
598 : {
599 : //fprintf(stderr, "(%f, %f)\n", x, y);
600 :
601 2861 : if( !bGotInitialPoint )
602 : {
603 3 : bGotInitialPoint = TRUE;
604 3 : dfMinXOut = dfMaxXOut = x;
605 3 : dfMinYOut = dfMaxYOut = y;
606 : }
607 : else
608 : {
609 2858 : dfMinXOut = MIN(dfMinXOut,x);
610 2858 : dfMinYOut = MIN(dfMinYOut,y);
611 2858 : dfMaxXOut = MAX(dfMaxXOut,x);
612 2858 : dfMaxYOut = MAX(dfMaxYOut,y);
613 : }
614 :
615 4205 : if (!valid_before || x_out_before * x < 0)
616 : {
617 1344 : valid_after = TRUE;
618 1344 : x_in_after = (x_in_before + x_in_after) / 2;
619 1344 : x_out_after = x;
620 : }
621 : else
622 : {
623 1517 : valid_before = TRUE;
624 1517 : x_out_before = x;
625 1517 : x_in_before = (x_in_before + x_in_after) / 2;
626 : }
627 : }
628 3104 : nIter ++;
629 : }
630 : }
631 :
632 107730 : if( !pabSuccess[i] )
633 : {
634 503 : nFailedCount++;
635 503 : continue;
636 : }
637 :
638 107227 : if( !bGotInitialPoint )
639 : {
640 285 : bGotInitialPoint = TRUE;
641 285 : dfMinXOut = dfMaxXOut = padfX[i];
642 285 : dfMinYOut = dfMaxYOut = padfY[i];
643 : }
644 : else
645 : {
646 106942 : dfMinXOut = MIN(dfMinXOut, padfX[i]);
647 106942 : dfMinYOut = MIN(dfMinYOut, padfY[i]);
648 106942 : dfMaxXOut = MAX(dfMaxXOut, padfX[i]);
649 106942 : dfMaxYOut = MAX(dfMaxYOut, padfY[i]);
650 : }
651 : }
652 :
653 288 : if( nFailedCount > nSamplePoints - 10 )
654 : {
655 : CPLError( CE_Failure, CPLE_AppDefined,
656 : "Too many points (%d out of %d) failed to transform,\n"
657 : "unable to compute output bounds.",
658 0 : nFailedCount, nSamplePoints );
659 :
660 0 : CPLFree( padfX );
661 0 : CPLFree( padfXRevert );
662 0 : CPLFree( pabSuccess );
663 :
664 0 : return CE_Failure;
665 : }
666 :
667 288 : if( nFailedCount > 0 )
668 : CPLDebug( "GDAL",
669 : "GDALSuggestedWarpOutput(): %d out of %d points failed to transform.",
670 6 : nFailedCount, nSamplePoints );
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Compute the distance in "georeferenced" units from the top */
674 : /* corner of the transformed input image to the bottom left */
675 : /* corner of the transformed input. Use this distance to */
676 : /* compute an approximate pixel size in the output */
677 : /* georeferenced coordinates. */
678 : /* -------------------------------------------------------------------- */
679 : double dfDiagonalDist, dfDeltaX, dfDeltaY;
680 :
681 570 : if( pabSuccess[0] && pabSuccess[nSamplePoints - 1] )
682 : {
683 282 : dfDeltaX = padfX[nSamplePoints-1] - padfX[0];
684 282 : dfDeltaY = padfY[nSamplePoints-1] - padfY[0];
685 : }
686 : else
687 : {
688 6 : dfDeltaX = dfMaxXOut - dfMinXOut;
689 6 : dfDeltaY = dfMaxYOut - dfMinYOut;
690 : }
691 :
692 288 : dfDiagonalDist = sqrt( dfDeltaX * dfDeltaX + dfDeltaY * dfDeltaY );
693 :
694 : /* -------------------------------------------------------------------- */
695 : /* Compute a pixel size from this. */
696 : /* -------------------------------------------------------------------- */
697 : double dfPixelSize;
698 :
699 : dfPixelSize = dfDiagonalDist
700 288 : / sqrt(((double)nInXSize)*nInXSize + ((double)nInYSize)*nInYSize);
701 :
702 288 : double dfPixels = (dfMaxXOut - dfMinXOut) / dfPixelSize;
703 288 : double dfLines = (dfMaxYOut - dfMinYOut) / dfPixelSize;
704 :
705 288 : if( dfPixels > INT_MAX - 1 || dfLines > INT_MAX - 1 )
706 : {
707 : CPLError( CE_Failure, CPLE_AppDefined,
708 : "Computed dimensions are too big : %.0f x %.0f",
709 0 : dfPixels + 0.5, dfLines + 0.5 );
710 :
711 0 : CPLFree( padfX );
712 0 : CPLFree( padfXRevert );
713 0 : CPLFree( pabSuccess );
714 :
715 0 : return CE_Failure;
716 : }
717 :
718 288 : *pnPixels = (int) (dfPixels + 0.5);
719 288 : *pnLines = (int) (dfLines + 0.5);
720 :
721 288 : double dfPixelSizeX = dfPixelSize;
722 288 : double dfPixelSizeY = dfPixelSize;
723 :
724 : double adfExtent[4];
725 288 : const double adfRatioArray[] = { 0, 0.001, 0.01, 0.1, 1 };
726 : size_t nRetry;
727 :
728 : #define N_ELEMENTS(x) (sizeof(x) / sizeof(x[0]))
729 :
730 : /* -------------------------------------------------------------------- */
731 : /* Check that the right border is not completely out of source */
732 : /* image. If so, adjust the x pixel size a bit in the hope it will */
733 : /* fit. */
734 : /* -------------------------------------------------------------------- */
735 320 : for( nRetry = 0; nRetry < N_ELEMENTS(adfRatioArray); nRetry ++ )
736 : {
737 : double dfTryPixelSizeX =
738 318 : dfPixelSizeX - dfPixelSizeX * adfRatioArray[nRetry] / *pnPixels;
739 318 : adfExtent[0] = dfMinXOut;
740 318 : adfExtent[1] = dfMaxYOut - (*pnLines) * dfPixelSizeY;
741 318 : adfExtent[2] = dfMinXOut + (*pnPixels) * dfTryPixelSizeX;
742 318 : adfExtent[3] = dfMaxYOut;
743 318 : if (!GDALSuggestedWarpOutput2_MustAdjustForRightBorder(
744 : pfnTransformer, pTransformArg,
745 : adfExtent, *pnPixels, *pnLines,
746 : dfTryPixelSizeX, dfPixelSizeY))
747 : {
748 286 : dfPixelSizeX = dfTryPixelSizeX;
749 286 : break;
750 : }
751 : }
752 :
753 : /* -------------------------------------------------------------------- */
754 : /* Check that the bottom border is not completely out of source */
755 : /* image. If so, adjust the y pixel size a bit in the hope it will */
756 : /* fit. */
757 : /* -------------------------------------------------------------------- */
758 314 : for( nRetry = 0; nRetry < N_ELEMENTS(adfRatioArray); nRetry ++ )
759 : {
760 : double dfTryPixelSizeY =
761 312 : dfPixelSizeY - dfPixelSizeY * adfRatioArray[nRetry] / *pnLines;
762 312 : adfExtent[0] = dfMinXOut;
763 312 : adfExtent[1] = dfMaxYOut - (*pnLines) * dfTryPixelSizeY;
764 312 : adfExtent[2] = dfMinXOut + (*pnPixels) * dfPixelSizeX;
765 312 : adfExtent[3] = dfMaxYOut;
766 312 : if (!GDALSuggestedWarpOutput2_MustAdjustForBottomBorder(
767 : pfnTransformer, pTransformArg,
768 : adfExtent, *pnPixels, *pnLines,
769 : dfPixelSizeX, dfTryPixelSizeY))
770 : {
771 286 : dfPixelSizeY = dfTryPixelSizeY;
772 286 : break;
773 : }
774 : }
775 :
776 :
777 : /* -------------------------------------------------------------------- */
778 : /* Recompute some bounds so that all return values are consistant */
779 : /* -------------------------------------------------------------------- */
780 288 : dfMaxXOut = dfMinXOut + (*pnPixels) * dfPixelSizeX;
781 288 : dfMinYOut = dfMaxYOut - (*pnLines) * dfPixelSizeY;
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Return raw extents. */
785 : /* -------------------------------------------------------------------- */
786 288 : padfExtent[0] = dfMinXOut;
787 288 : padfExtent[1] = dfMinYOut;
788 288 : padfExtent[2] = dfMaxXOut;
789 288 : padfExtent[3] = dfMaxYOut;
790 :
791 : /* -------------------------------------------------------------------- */
792 : /* Set the output geotransform. */
793 : /* -------------------------------------------------------------------- */
794 288 : padfGeoTransformOut[0] = dfMinXOut;
795 288 : padfGeoTransformOut[1] = dfPixelSizeX;
796 288 : padfGeoTransformOut[2] = 0.0;
797 288 : padfGeoTransformOut[3] = dfMaxYOut;
798 288 : padfGeoTransformOut[4] = 0.0;
799 288 : padfGeoTransformOut[5] = - dfPixelSizeY;
800 :
801 288 : CPLFree( padfX );
802 288 : CPLFree( padfXRevert );
803 288 : CPLFree( pabSuccess );
804 :
805 288 : return CE_None;
806 : }
807 :
808 : /************************************************************************/
809 : /* ==================================================================== */
810 : /* GDALGenImgProjTransformer */
811 : /* ==================================================================== */
812 : /************************************************************************/
813 :
814 : typedef struct {
815 :
816 : GDALTransformerInfo sTI;
817 :
818 : double adfSrcGeoTransform[6];
819 : double adfSrcInvGeoTransform[6];
820 :
821 : void *pSrcGCPTransformArg;
822 : void *pSrcRPCTransformArg;
823 : void *pSrcTPSTransformArg;
824 : void *pSrcGeoLocTransformArg;
825 :
826 : void *pReprojectArg;
827 :
828 : double adfDstGeoTransform[6];
829 : double adfDstInvGeoTransform[6];
830 :
831 : void *pDstGCPTransformArg;
832 :
833 : } GDALGenImgProjTransformInfo;
834 :
835 : /************************************************************************/
836 : /* GDALCloneGenImgProjTransformer() */
837 : /************************************************************************/
838 :
839 8 : void* GDALCloneGenImgProjTransformer( void *hTransformArg )
840 : {
841 8 : VALIDATE_POINTER1( hTransformArg, "GDALCloneGenImgProjTransformer", NULL );
842 :
843 : GDALGenImgProjTransformInfo *psInfo =
844 8 : (GDALGenImgProjTransformInfo *) hTransformArg;
845 :
846 : GDALGenImgProjTransformInfo *psClonedInfo = (GDALGenImgProjTransformInfo *)
847 8 : CPLMalloc(sizeof(GDALGenImgProjTransformInfo));
848 :
849 8 : memcpy(psClonedInfo, psInfo, sizeof(GDALGenImgProjTransformInfo));
850 8 : if( psClonedInfo->pSrcGCPTransformArg )
851 0 : psClonedInfo->pSrcGCPTransformArg = GDALCloneTransformer( psInfo->pSrcGCPTransformArg );
852 8 : if( psClonedInfo->pSrcRPCTransformArg )
853 0 : psClonedInfo->pSrcRPCTransformArg = GDALCloneTransformer( psInfo->pSrcRPCTransformArg );
854 8 : if( psClonedInfo->pSrcTPSTransformArg )
855 0 : psClonedInfo->pSrcTPSTransformArg = GDALCloneTransformer( psInfo->pSrcTPSTransformArg );
856 8 : if( psClonedInfo->pSrcGeoLocTransformArg )
857 0 : psClonedInfo->pSrcGeoLocTransformArg = GDALCloneTransformer( psInfo->pSrcGeoLocTransformArg );
858 8 : if( psClonedInfo->pReprojectArg )
859 8 : psClonedInfo->pReprojectArg = GDALCloneTransformer( psInfo->pReprojectArg );
860 8 : if( psClonedInfo->pDstGCPTransformArg )
861 0 : psClonedInfo->pDstGCPTransformArg = GDALCloneTransformer( psInfo->pDstGCPTransformArg );
862 :
863 8 : return psClonedInfo;
864 : }
865 :
866 : /************************************************************************/
867 : /* GDALCreateGenImgProjTransformer() */
868 : /************************************************************************/
869 :
870 : /**
871 : * Create image to image transformer.
872 : *
873 : * This function creates a transformation object that maps from pixel/line
874 : * coordinates on one image to pixel/line coordinates on another image. The
875 : * images may potentially be georeferenced in different coordinate systems,
876 : * and may used GCPs to map between their pixel/line coordinates and
877 : * georeferenced coordinates (as opposed to the default assumption that their
878 : * geotransform should be used).
879 : *
880 : * This transformer potentially performs three concatenated transformations.
881 : *
882 : * The first stage is from source image pixel/line coordinates to source
883 : * image georeferenced coordinates, and may be done using the geotransform,
884 : * or if not defined using a polynomial model derived from GCPs. If GCPs
885 : * are used this stage is accomplished using GDALGCPTransform().
886 : *
887 : * The second stage is to change projections from the source coordinate system
888 : * to the destination coordinate system, assuming they differ. This is
889 : * accomplished internally using GDALReprojectionTransform().
890 : *
891 : * The third stage is converting from destination image georeferenced
892 : * coordinates to destination image coordinates. This is done using the
893 : * destination image geotransform, or if not available, using a polynomial
894 : * model derived from GCPs. If GCPs are used this stage is accomplished using
895 : * GDALGCPTransform(). This stage is skipped if hDstDS is NULL when the
896 : * transformation is created.
897 : *
898 : * @param hSrcDS source dataset, or NULL.
899 : * @param pszSrcWKT the coordinate system for the source dataset. If NULL,
900 : * it will be read from the dataset itself.
901 : * @param hDstDS destination dataset (or NULL).
902 : * @param pszDstWKT the coordinate system for the destination dataset. If
903 : * NULL, and hDstDS not NULL, it will be read from the destination dataset.
904 : * @param bGCPUseOK TRUE if GCPs should be used if the geotransform is not
905 : * available on the source dataset (not destination).
906 : * @param dfGCPErrorThreshold ignored/deprecated.
907 : * @param nOrder the maximum order to use for GCP derived polynomials if
908 : * possible. Use 0 to autoselect, or -1 for thin plate splines.
909 : *
910 : * @return handle suitable for use GDALGenImgProjTransform(), and to be
911 : * deallocated with GDALDestroyGenImgProjTransformer().
912 : */
913 :
914 : void *
915 50 : GDALCreateGenImgProjTransformer( GDALDatasetH hSrcDS, const char *pszSrcWKT,
916 : GDALDatasetH hDstDS, const char *pszDstWKT,
917 : int bGCPUseOK, double dfGCPErrorThreshold,
918 : int nOrder )
919 :
920 : {
921 50 : char **papszOptions = NULL;
922 : void *pRet;
923 :
924 50 : if( pszSrcWKT != NULL )
925 33 : papszOptions = CSLSetNameValue( papszOptions, "SRC_SRS", pszSrcWKT );
926 50 : if( pszDstWKT != NULL )
927 32 : papszOptions = CSLSetNameValue( papszOptions, "DST_SRS", pszDstWKT );
928 50 : if( !bGCPUseOK )
929 9 : papszOptions = CSLSetNameValue( papszOptions, "GCPS_OK", "FALSE" );
930 50 : if( nOrder != 0 )
931 : papszOptions = CSLSetNameValue( papszOptions, "MAX_GCP_ORDER",
932 0 : CPLString().Printf("%d",nOrder) );
933 :
934 50 : pRet = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
935 50 : CSLDestroy( papszOptions );
936 :
937 50 : return pRet;
938 : }
939 :
940 :
941 :
942 : /************************************************************************/
943 : /* InsertCenterLong() */
944 : /* */
945 : /* Insert a CENTER_LONG Extension entry on a GEOGCS to indicate */
946 : /* the center longitude of the dataset for wrapping purposes. */
947 : /************************************************************************/
948 :
949 48 : static CPLString InsertCenterLong( GDALDatasetH hDS, CPLString osWKT )
950 :
951 : {
952 48 : if( !EQUALN(osWKT.c_str(), "GEOGCS[", 7) )
953 24 : return osWKT;
954 :
955 24 : if( strstr(osWKT,"EXTENSION[\"CENTER_LONG") != NULL )
956 0 : return osWKT;
957 :
958 : /* -------------------------------------------------------------------- */
959 : /* For now we only do this if we have a geotransform since */
960 : /* other forms require a bunch of extra work. */
961 : /* -------------------------------------------------------------------- */
962 : double adfGeoTransform[6];
963 :
964 24 : if( GDALGetGeoTransform( hDS, adfGeoTransform ) != CE_None )
965 0 : return osWKT;
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Compute min/max longitude based on testing the four corners. */
969 : /* -------------------------------------------------------------------- */
970 : double dfMinLong, dfMaxLong;
971 24 : int nXSize = GDALGetRasterXSize( hDS );
972 24 : int nYSize = GDALGetRasterYSize( hDS );
973 :
974 : dfMinLong =
975 504 : MIN(MIN(adfGeoTransform[0] + 0 * adfGeoTransform[1]
976 : + 0 * adfGeoTransform[2],
977 : adfGeoTransform[0] + nXSize * adfGeoTransform[1]
978 : + 0 * adfGeoTransform[2]),
979 : MIN(adfGeoTransform[0] + 0 * adfGeoTransform[1]
980 : + nYSize * adfGeoTransform[2],
981 : adfGeoTransform[0] + nXSize * adfGeoTransform[1]
982 504 : + nYSize * adfGeoTransform[2]));
983 : dfMaxLong =
984 576 : MAX(MAX(adfGeoTransform[0] + 0 * adfGeoTransform[1]
985 : + 0 * adfGeoTransform[2],
986 : adfGeoTransform[0] + nXSize * adfGeoTransform[1]
987 : + 0 * adfGeoTransform[2]),
988 : MAX(adfGeoTransform[0] + 0 * adfGeoTransform[1]
989 : + nYSize * adfGeoTransform[2],
990 : adfGeoTransform[0] + nXSize * adfGeoTransform[1]
991 576 : + nYSize * adfGeoTransform[2]));
992 :
993 24 : if( dfMaxLong - dfMinLong > 360.0 )
994 0 : return osWKT;
995 :
996 : /* -------------------------------------------------------------------- */
997 : /* Insert center long. */
998 : /* -------------------------------------------------------------------- */
999 24 : OGRSpatialReference oSRS( osWKT );
1000 24 : double dfCenterLong = (dfMaxLong + dfMinLong) / 2.0;
1001 : OGR_SRSNode *poExt;
1002 :
1003 24 : poExt = new OGR_SRSNode( "EXTENSION" );
1004 48 : poExt->AddChild( new OGR_SRSNode( "CENTER_LONG" ) );
1005 24 : poExt->AddChild( new OGR_SRSNode( CPLString().Printf("%g",dfCenterLong) ));
1006 :
1007 24 : oSRS.GetRoot()->AddChild( poExt->Clone() );
1008 24 : delete poExt;
1009 :
1010 : /* -------------------------------------------------------------------- */
1011 : /* Convert back to wkt. */
1012 : /* -------------------------------------------------------------------- */
1013 24 : char *pszWKT = NULL;
1014 24 : oSRS.exportToWkt( &pszWKT );
1015 :
1016 24 : osWKT = pszWKT;
1017 24 : CPLFree( pszWKT );
1018 :
1019 24 : return osWKT;
1020 : }
1021 :
1022 : /************************************************************************/
1023 : /* GDALCreateGenImgProjTransformer2() */
1024 : /************************************************************************/
1025 :
1026 : /**
1027 : * Create image to image transformer.
1028 : *
1029 : * This function creates a transformation object that maps from pixel/line
1030 : * coordinates on one image to pixel/line coordinates on another image. The
1031 : * images may potentially be georeferenced in different coordinate systems,
1032 : * and may used GCPs to map between their pixel/line coordinates and
1033 : * georeferenced coordinates (as opposed to the default assumption that their
1034 : * geotransform should be used).
1035 : *
1036 : * This transformer potentially performs three concatenated transformations.
1037 : *
1038 : * The first stage is from source image pixel/line coordinates to source
1039 : * image georeferenced coordinates, and may be done using the geotransform,
1040 : * or if not defined using a polynomial model derived from GCPs. If GCPs
1041 : * are used this stage is accomplished using GDALGCPTransform().
1042 : *
1043 : * The second stage is to change projections from the source coordinate system
1044 : * to the destination coordinate system, assuming they differ. This is
1045 : * accomplished internally using GDALReprojectionTransform().
1046 : *
1047 : * The third stage is converting from destination image georeferenced
1048 : * coordinates to destination image coordinates. This is done using the
1049 : * destination image geotransform, or if not available, using a polynomial
1050 : * model derived from GCPs. If GCPs are used this stage is accomplished using
1051 : * GDALGCPTransform(). This stage is skipped if hDstDS is NULL when the
1052 : * transformation is created.
1053 : *
1054 : * Supported Options:
1055 : * <ul>
1056 : * <li> SRC_SRS: WKT SRS to be used as an override for hSrcDS.
1057 : * <li> DST_SRS: WKT SRS to be used as an override for hDstDS.
1058 : * <li> GCPS_OK: If false, GCPs will not be used, default is TRUE.
1059 : * <li> REFINE_MINIMUM_GCPS: The minimum amount of GCPs that should be available after the refinement.
1060 : * <li> REFINE_TOLERANCE: The tolernace that specifies when a GCP will be eliminated.
1061 : * <li> MAX_GCP_ORDER: the maximum order to use for GCP derived polynomials if
1062 : * possible. The default is to autoselect based on the number of GCPs.
1063 : * A value of -1 triggers use of Thin Plate Spline instead of polynomials.
1064 : * <li> METHOD: may have a value which is one of GEOTRANSFORM, GCP_POLYNOMIAL,
1065 : * GCP_TPS, GEOLOC_ARRAY, RPC to force only one geolocation method to be
1066 : * considered on the source dataset.
1067 : * <li> RPC_HEIGHT: A fixed height to be used with RPC calculations.
1068 : * <li> RPC_DEM: The name of a DEM file to be used with RPC calculations.
1069 : * <li> INSERT_CENTER_LONG: May be set to FALSE to disable setting up a
1070 : * CENTER_LONG value on the coordinate system to rewrap things around the
1071 : * center of the image.
1072 : * </ul>
1073 : *
1074 : * @param hSrcDS source dataset, or NULL.
1075 : * @param hDstDS destination dataset (or NULL).
1076 : * @param papszOptions NULL-terminated list of string options (or NULL).
1077 : *
1078 : * @return handle suitable for use GDALGenImgProjTransform(), and to be
1079 : * deallocated with GDALDestroyGenImgProjTransformer() or NULL on failure.
1080 : */
1081 :
1082 : void *
1083 342 : GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
1084 : char **papszOptions )
1085 :
1086 : {
1087 : GDALGenImgProjTransformInfo *psInfo;
1088 : char **papszMD;
1089 : GDALRPCInfo sRPCInfo;
1090 342 : const char *pszMethod = CSLFetchNameValue( papszOptions, "METHOD" );
1091 : const char *pszValue;
1092 342 : int nOrder = 0, bGCPUseOK = TRUE, nMinimumGcps = -1, bRefine = FALSE;
1093 342 : double dfTolerance = 0.0;
1094 342 : const char *pszSrcWKT = CSLFetchNameValue( papszOptions, "SRC_SRS" );
1095 342 : const char *pszDstWKT = CSLFetchNameValue( papszOptions, "DST_SRS" );
1096 :
1097 342 : pszValue = CSLFetchNameValue( papszOptions, "MAX_GCP_ORDER" );
1098 342 : if( pszValue )
1099 0 : nOrder = atoi(pszValue);
1100 :
1101 342 : pszValue = CSLFetchNameValue( papszOptions, "GCPS_OK" );
1102 342 : if( pszValue )
1103 9 : bGCPUseOK = CSLTestBoolean(pszValue);
1104 :
1105 342 : pszValue = CSLFetchNameValue( papszOptions, "REFINE_MINIMUM_GCPS" );
1106 342 : if( pszValue )
1107 : {
1108 0 : if( atoi(pszValue) != -1)
1109 0 : nMinimumGcps = atoi(pszValue);
1110 : }
1111 :
1112 342 : pszValue = CSLFetchNameValue( papszOptions, "REFINE_TOLERANCE" );
1113 342 : if( pszValue )
1114 : {
1115 0 : dfTolerance = atof(pszValue);
1116 0 : bRefine = TRUE;
1117 : }
1118 :
1119 : /* -------------------------------------------------------------------- */
1120 : /* Initialize the transform info. */
1121 : /* -------------------------------------------------------------------- */
1122 : psInfo = (GDALGenImgProjTransformInfo *)
1123 342 : CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
1124 :
1125 342 : strcpy( psInfo->sTI.szSignature, "GTI" );
1126 342 : psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
1127 342 : psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
1128 342 : psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
1129 342 : psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
1130 :
1131 : /* -------------------------------------------------------------------- */
1132 : /* Get forward and inverse geotransform for the source image. */
1133 : /* -------------------------------------------------------------------- */
1134 342 : if( hSrcDS == NULL )
1135 : {
1136 12 : psInfo->adfSrcGeoTransform[0] = 0.0;
1137 12 : psInfo->adfSrcGeoTransform[1] = 1.0;
1138 12 : psInfo->adfSrcGeoTransform[2] = 0.0;
1139 12 : psInfo->adfSrcGeoTransform[3] = 0.0;
1140 12 : psInfo->adfSrcGeoTransform[4] = 0.0;
1141 12 : psInfo->adfSrcGeoTransform[5] = 1.0;
1142 : memcpy( psInfo->adfSrcInvGeoTransform, psInfo->adfSrcGeoTransform,
1143 12 : sizeof(double) * 6 );
1144 : }
1145 :
1146 637 : else if( (pszMethod == NULL || EQUAL(pszMethod,"GEOTRANSFORM"))
1147 : && GDALGetGeoTransform( hSrcDS, psInfo->adfSrcGeoTransform )
1148 : == CE_None
1149 307 : && (psInfo->adfSrcGeoTransform[0] != 0.0
1150 0 : || psInfo->adfSrcGeoTransform[1] != 1.0
1151 0 : || psInfo->adfSrcGeoTransform[2] != 0.0
1152 0 : || psInfo->adfSrcGeoTransform[3] != 0.0
1153 0 : || psInfo->adfSrcGeoTransform[4] != 0.0
1154 0 : || ABS(psInfo->adfSrcGeoTransform[5]) != 1.0) )
1155 : {
1156 : GDALInvGeoTransform( psInfo->adfSrcGeoTransform,
1157 307 : psInfo->adfSrcInvGeoTransform );
1158 307 : if( pszSrcWKT == NULL )
1159 277 : pszSrcWKT = GDALGetProjectionRef( hSrcDS );
1160 : }
1161 :
1162 23 : else if( bGCPUseOK
1163 : && (pszMethod == NULL || EQUAL(pszMethod,"GCP_POLYNOMIAL") )
1164 : && GDALGetGCPCount( hSrcDS ) > 0 && nOrder >= 0 )
1165 : {
1166 16 : if(bRefine)
1167 : {
1168 : psInfo->pSrcGCPTransformArg =
1169 : GDALCreateGCPRefineTransformer( GDALGetGCPCount( hSrcDS ),
1170 : GDALGetGCPs( hSrcDS ), nOrder,
1171 0 : FALSE, dfTolerance, nMinimumGcps );
1172 : }
1173 : else
1174 : {
1175 : psInfo->pSrcGCPTransformArg =
1176 : GDALCreateGCPTransformer( GDALGetGCPCount( hSrcDS ),
1177 : GDALGetGCPs( hSrcDS ), nOrder,
1178 16 : FALSE );
1179 : }
1180 :
1181 16 : if( psInfo->pSrcGCPTransformArg == NULL )
1182 : {
1183 0 : GDALDestroyGenImgProjTransformer( psInfo );
1184 0 : return NULL;
1185 : }
1186 :
1187 16 : if( pszSrcWKT == NULL )
1188 16 : pszSrcWKT = GDALGetGCPProjection( hSrcDS );
1189 : }
1190 :
1191 7 : else if( bGCPUseOK
1192 : && GDALGetGCPCount( hSrcDS ) > 0
1193 : && nOrder <= 0
1194 : && (pszMethod == NULL || EQUAL(pszMethod,"GCP_TPS")) )
1195 : {
1196 : psInfo->pSrcTPSTransformArg =
1197 : GDALCreateTPSTransformer( GDALGetGCPCount( hSrcDS ),
1198 3 : GDALGetGCPs( hSrcDS ), FALSE );
1199 3 : if( psInfo->pSrcTPSTransformArg == NULL )
1200 : {
1201 0 : GDALDestroyGenImgProjTransformer( psInfo );
1202 0 : return NULL;
1203 : }
1204 :
1205 3 : if( pszSrcWKT == NULL )
1206 3 : pszSrcWKT = GDALGetGCPProjection( hSrcDS );
1207 : }
1208 :
1209 4 : else if( (pszMethod == NULL || EQUAL(pszMethod,"RPC"))
1210 : && (papszMD = GDALGetMetadata( hSrcDS, "RPC" )) != NULL
1211 : && GDALExtractRPCInfo( papszMD, &sRPCInfo ) )
1212 : {
1213 : psInfo->pSrcRPCTransformArg =
1214 3 : GDALCreateRPCTransformer( &sRPCInfo, FALSE, 0.1, papszOptions );
1215 3 : if( psInfo->pSrcRPCTransformArg == NULL )
1216 : {
1217 0 : GDALDestroyGenImgProjTransformer( psInfo );
1218 0 : return NULL;
1219 : }
1220 3 : if( pszSrcWKT == NULL )
1221 3 : pszSrcWKT = SRS_WKT_WGS84;
1222 : }
1223 :
1224 1 : else if( (pszMethod == NULL || EQUAL(pszMethod,"GEOLOC_ARRAY"))
1225 : && (papszMD = GDALGetMetadata( hSrcDS, "GEOLOCATION" )) != NULL )
1226 : {
1227 : psInfo->pSrcGeoLocTransformArg =
1228 1 : GDALCreateGeoLocTransformer( hSrcDS, papszMD, FALSE );
1229 :
1230 1 : if( psInfo->pSrcGeoLocTransformArg == NULL )
1231 : {
1232 0 : GDALDestroyGenImgProjTransformer( psInfo );
1233 0 : return NULL;
1234 : }
1235 1 : if( pszSrcWKT == NULL )
1236 1 : pszSrcWKT = CSLFetchNameValue( papszMD, "SRS" );
1237 : }
1238 :
1239 0 : else if( pszMethod != NULL )
1240 : {
1241 : CPLError( CE_Failure, CPLE_AppDefined,
1242 : "Unable to compute a %s based transformation between pixel/line\n"
1243 : "and georeferenced coordinates for %s.\n",
1244 0 : pszMethod, GDALGetDescription( hSrcDS ) );
1245 :
1246 0 : GDALDestroyGenImgProjTransformer( psInfo );
1247 0 : return NULL;
1248 : }
1249 :
1250 : else
1251 : {
1252 : CPLError( CE_Failure, CPLE_AppDefined,
1253 : "Unable to compute a transformation between pixel/line\n"
1254 : "and georeferenced coordinates for %s.\n"
1255 : "There is no affine transformation and no GCPs.",
1256 0 : GDALGetDescription( hSrcDS ) );
1257 :
1258 0 : GDALDestroyGenImgProjTransformer( psInfo );
1259 0 : return NULL;
1260 : }
1261 :
1262 : /* -------------------------------------------------------------------- */
1263 : /* Setup reprojection. */
1264 : /* -------------------------------------------------------------------- */
1265 342 : if( pszDstWKT == NULL && hDstDS != NULL )
1266 21 : pszDstWKT = GDALGetProjectionRef( hDstDS );
1267 :
1268 342 : if( pszSrcWKT != NULL && strlen(pszSrcWKT) > 0
1269 : && pszDstWKT != NULL && strlen(pszDstWKT) > 0
1270 : && !EQUAL(pszSrcWKT,pszDstWKT) )
1271 : {
1272 49 : CPLString osSrcWKT = pszSrcWKT;
1273 49 : if (hSrcDS
1274 : && CSLFetchBoolean( papszOptions, "INSERT_CENTER_LONG", TRUE ) )
1275 48 : osSrcWKT = InsertCenterLong( hSrcDS, osSrcWKT );
1276 :
1277 : psInfo->pReprojectArg =
1278 49 : GDALCreateReprojectionTransformer( osSrcWKT.c_str(), pszDstWKT );
1279 : }
1280 :
1281 : /* -------------------------------------------------------------------- */
1282 : /* Get forward and inverse geotransform for destination image. */
1283 : /* If we have no destination use a unit transform. */
1284 : /* -------------------------------------------------------------------- */
1285 342 : if( hDstDS )
1286 : {
1287 41 : GDALGetGeoTransform( hDstDS, psInfo->adfDstGeoTransform );
1288 : GDALInvGeoTransform( psInfo->adfDstGeoTransform,
1289 41 : psInfo->adfDstInvGeoTransform );
1290 : }
1291 : else
1292 : {
1293 301 : psInfo->adfDstGeoTransform[0] = 0.0;
1294 301 : psInfo->adfDstGeoTransform[1] = 1.0;
1295 301 : psInfo->adfDstGeoTransform[2] = 0.0;
1296 301 : psInfo->adfDstGeoTransform[3] = 0.0;
1297 301 : psInfo->adfDstGeoTransform[4] = 0.0;
1298 301 : psInfo->adfDstGeoTransform[5] = 1.0;
1299 : memcpy( psInfo->adfDstInvGeoTransform, psInfo->adfDstGeoTransform,
1300 301 : sizeof(double) * 6 );
1301 : }
1302 :
1303 342 : return psInfo;
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* GDALRefreshGenImgProjTransformer() */
1308 : /************************************************************************/
1309 :
1310 288 : void GDALRefreshGenImgProjTransformer(void* hTransformArg)
1311 : {
1312 : GDALGenImgProjTransformInfo *psInfo =
1313 288 : static_cast<GDALGenImgProjTransformInfo *>( hTransformArg );
1314 :
1315 288 : if (psInfo->pReprojectArg)
1316 : {
1317 29 : CPLXMLNode* psXML = GDALSerializeReprojectionTransformer(psInfo->pReprojectArg);
1318 29 : GDALDestroyReprojectionTransformer(psInfo->pReprojectArg);
1319 29 : psInfo->pReprojectArg = GDALDeserializeReprojectionTransformer(psXML);
1320 29 : CPLDestroyXMLNode(psXML);
1321 : }
1322 288 : }
1323 :
1324 : /************************************************************************/
1325 : /* GDALCreateGenImgProjTransformer3() */
1326 : /************************************************************************/
1327 :
1328 : /**
1329 : * Create image to image transformer.
1330 : *
1331 : * This function creates a transformation object that maps from pixel/line
1332 : * coordinates on one image to pixel/line coordinates on another image. The
1333 : * images may potentially be georeferenced in different coordinate systems,
1334 : * and may used GCPs to map between their pixel/line coordinates and
1335 : * georeferenced coordinates (as opposed to the default assumption that their
1336 : * geotransform should be used).
1337 : *
1338 : * This transformer potentially performs three concatenated transformations.
1339 : *
1340 : * The first stage is from source image pixel/line coordinates to source
1341 : * image georeferenced coordinates, and may be done using the geotransform,
1342 : * or if not defined using a polynomial model derived from GCPs. If GCPs
1343 : * are used this stage is accomplished using GDALGCPTransform().
1344 : *
1345 : * The second stage is to change projections from the source coordinate system
1346 : * to the destination coordinate system, assuming they differ. This is
1347 : * accomplished internally using GDALReprojectionTransform().
1348 : *
1349 : * The third stage is converting from destination image georeferenced
1350 : * coordinates to destination image coordinates. This is done using the
1351 : * destination image geotransform, or if not available, using a polynomial
1352 : * model derived from GCPs. If GCPs are used this stage is accomplished using
1353 : * GDALGCPTransform(). This stage is skipped if hDstDS is NULL when the
1354 : * transformation is created.
1355 : *
1356 : * @param pszSrcWKT source WKT (or NULL).
1357 : * @param padfSrcGeoTransform source geotransform (or NULL).
1358 : * @param pszDstWKT destination WKT (or NULL).
1359 : * @param padfDstGeoTransform destination geotransform (or NULL).
1360 : *
1361 : * @return handle suitable for use GDALGenImgProjTransform(), and to be
1362 : * deallocated with GDALDestroyGenImgProjTransformer() or NULL on failure.
1363 : */
1364 :
1365 : void *
1366 0 : GDALCreateGenImgProjTransformer3( const char *pszSrcWKT,
1367 : const double *padfSrcGeoTransform,
1368 : const char *pszDstWKT,
1369 : const double *padfDstGeoTransform )
1370 :
1371 : {
1372 : GDALGenImgProjTransformInfo *psInfo;
1373 :
1374 : /* -------------------------------------------------------------------- */
1375 : /* Initialize the transform info. */
1376 : /* -------------------------------------------------------------------- */
1377 : psInfo = (GDALGenImgProjTransformInfo *)
1378 0 : CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
1379 :
1380 0 : strcpy( psInfo->sTI.szSignature, "GTI" );
1381 0 : psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
1382 0 : psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
1383 0 : psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
1384 0 : psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
1385 :
1386 : /* -------------------------------------------------------------------- */
1387 : /* Get forward and inverse geotransform for the source image. */
1388 : /* -------------------------------------------------------------------- */
1389 0 : if( padfSrcGeoTransform )
1390 : {
1391 : memcpy( psInfo->adfSrcGeoTransform, padfSrcGeoTransform,
1392 0 : sizeof(psInfo->adfSrcGeoTransform) );
1393 : GDALInvGeoTransform( psInfo->adfSrcGeoTransform,
1394 0 : psInfo->adfSrcInvGeoTransform );
1395 : }
1396 : else
1397 : {
1398 0 : psInfo->adfSrcGeoTransform[0] = 0.0;
1399 0 : psInfo->adfSrcGeoTransform[1] = 1.0;
1400 0 : psInfo->adfSrcGeoTransform[2] = 0.0;
1401 0 : psInfo->adfSrcGeoTransform[3] = 0.0;
1402 0 : psInfo->adfSrcGeoTransform[4] = 0.0;
1403 0 : psInfo->adfSrcGeoTransform[5] = 1.0;
1404 : memcpy( psInfo->adfSrcInvGeoTransform, psInfo->adfSrcGeoTransform,
1405 0 : sizeof(double) * 6 );
1406 : }
1407 :
1408 : /* -------------------------------------------------------------------- */
1409 : /* Setup reprojection. */
1410 : /* -------------------------------------------------------------------- */
1411 0 : if( pszSrcWKT != NULL && strlen(pszSrcWKT) > 0
1412 : && pszDstWKT != NULL && strlen(pszDstWKT) > 0
1413 : && !EQUAL(pszSrcWKT, pszDstWKT) )
1414 : {
1415 : psInfo->pReprojectArg =
1416 0 : GDALCreateReprojectionTransformer( pszSrcWKT, pszDstWKT );
1417 : }
1418 :
1419 : /* -------------------------------------------------------------------- */
1420 : /* Get forward and inverse geotransform for destination image. */
1421 : /* If we have no destination matrix use a unit transform. */
1422 : /* -------------------------------------------------------------------- */
1423 0 : if( padfDstGeoTransform )
1424 : {
1425 : memcpy( psInfo->adfDstGeoTransform, padfDstGeoTransform,
1426 0 : sizeof(psInfo->adfDstGeoTransform) );
1427 : GDALInvGeoTransform( psInfo->adfDstGeoTransform,
1428 0 : psInfo->adfDstInvGeoTransform );
1429 : }
1430 : else
1431 : {
1432 0 : psInfo->adfDstGeoTransform[0] = 0.0;
1433 0 : psInfo->adfDstGeoTransform[1] = 1.0;
1434 0 : psInfo->adfDstGeoTransform[2] = 0.0;
1435 0 : psInfo->adfDstGeoTransform[3] = 0.0;
1436 0 : psInfo->adfDstGeoTransform[4] = 0.0;
1437 0 : psInfo->adfDstGeoTransform[5] = 1.0;
1438 : memcpy( psInfo->adfDstInvGeoTransform, psInfo->adfDstGeoTransform,
1439 0 : sizeof(double) * 6 );
1440 : }
1441 :
1442 0 : return psInfo;
1443 : }
1444 :
1445 : /************************************************************************/
1446 : /* GDALSetGenImgProjTransformerDstGeoTransform() */
1447 : /************************************************************************/
1448 :
1449 : /**
1450 : * Set GenImgProj output geotransform.
1451 : *
1452 : * Normally the "destination geotransform", or transformation between
1453 : * georeferenced output coordinates and pixel/line coordinates on the
1454 : * destination file is extracted from the destination file by
1455 : * GDALCreateGenImgProjTransformer() and stored in the GenImgProj private
1456 : * info. However, sometimes it is inconvenient to have an output file
1457 : * handle with appropriate geotransform information when creating the
1458 : * transformation. For these cases, this function can be used to apply
1459 : * the destination geotransform.
1460 : *
1461 : * @param hTransformArg the handle to update.
1462 : * @param padfGeoTransform the destination geotransform to apply (six doubles).
1463 : */
1464 :
1465 283 : void GDALSetGenImgProjTransformerDstGeoTransform(
1466 : void *hTransformArg, const double *padfGeoTransform )
1467 :
1468 : {
1469 283 : VALIDATE_POINTER0( hTransformArg, "GDALSetGenImgProjTransformerDstGeoTransform" );
1470 :
1471 : GDALGenImgProjTransformInfo *psInfo =
1472 283 : static_cast<GDALGenImgProjTransformInfo *>( hTransformArg );
1473 :
1474 283 : memcpy( psInfo->adfDstGeoTransform, padfGeoTransform, sizeof(double) * 6 );
1475 : GDALInvGeoTransform( psInfo->adfDstGeoTransform,
1476 283 : psInfo->adfDstInvGeoTransform );
1477 : }
1478 :
1479 : /************************************************************************/
1480 : /* GDALDestroyGenImgProjTransformer() */
1481 : /************************************************************************/
1482 :
1483 : /**
1484 : * GenImgProjTransformer deallocator.
1485 : *
1486 : * This function is used to deallocate the handle created with
1487 : * GDALCreateGenImgProjTransformer().
1488 : *
1489 : * @param hTransformArg the handle to deallocate.
1490 : */
1491 :
1492 395 : void GDALDestroyGenImgProjTransformer( void *hTransformArg )
1493 :
1494 : {
1495 395 : VALIDATE_POINTER0( hTransformArg, "GDALDestroyGenImgProjTransformer" );
1496 :
1497 : GDALGenImgProjTransformInfo *psInfo =
1498 395 : (GDALGenImgProjTransformInfo *) hTransformArg;
1499 :
1500 395 : if( psInfo->pSrcGCPTransformArg != NULL )
1501 21 : GDALDestroyGCPTransformer( psInfo->pSrcGCPTransformArg );
1502 :
1503 395 : if( psInfo->pSrcTPSTransformArg != NULL )
1504 4 : GDALDestroyTPSTransformer( psInfo->pSrcTPSTransformArg );
1505 :
1506 395 : if( psInfo->pSrcRPCTransformArg != NULL )
1507 3 : GDALDestroyRPCTransformer( psInfo->pSrcRPCTransformArg );
1508 :
1509 395 : if( psInfo->pSrcGeoLocTransformArg != NULL )
1510 2 : GDALDestroyGeoLocTransformer( psInfo->pSrcGeoLocTransformArg );
1511 :
1512 395 : if( psInfo->pDstGCPTransformArg != NULL )
1513 0 : GDALDestroyGCPTransformer( psInfo->pDstGCPTransformArg );
1514 :
1515 395 : if( psInfo->pReprojectArg != NULL )
1516 69 : GDALDestroyReprojectionTransformer( psInfo->pReprojectArg );
1517 :
1518 395 : CPLFree( psInfo );
1519 : }
1520 :
1521 : /************************************************************************/
1522 : /* GDALGenImgProjTransform() */
1523 : /************************************************************************/
1524 :
1525 : /**
1526 : * Perform general image reprojection transformation.
1527 : *
1528 : * Actually performs the transformation setup in
1529 : * GDALCreateGenImgProjTransformer(). This function matches the signature
1530 : * required by the GDALTransformerFunc(), and more details on the arguments
1531 : * can be found in that topic.
1532 : */
1533 :
1534 301911 : int GDALGenImgProjTransform( void *pTransformArg, int bDstToSrc,
1535 : int nPointCount,
1536 : double *padfX, double *padfY, double *padfZ,
1537 : int *panSuccess )
1538 : {
1539 : GDALGenImgProjTransformInfo *psInfo =
1540 301911 : (GDALGenImgProjTransformInfo *) pTransformArg;
1541 : int i;
1542 : double *padfGeoTransform;
1543 : void *pGCPTransformArg;
1544 : void *pRPCTransformArg;
1545 : void *pTPSTransformArg;
1546 : void *pGeoLocTransformArg;
1547 :
1548 : /* -------------------------------------------------------------------- */
1549 : /* Convert from src (dst) pixel/line to src (dst) */
1550 : /* georeferenced coordinates. */
1551 : /* -------------------------------------------------------------------- */
1552 301911 : if( bDstToSrc )
1553 : {
1554 179949 : padfGeoTransform = psInfo->adfDstGeoTransform;
1555 179949 : pGCPTransformArg = psInfo->pDstGCPTransformArg;
1556 179949 : pRPCTransformArg = NULL;
1557 179949 : pTPSTransformArg = NULL;
1558 179949 : pGeoLocTransformArg = NULL;
1559 : }
1560 : else
1561 : {
1562 121962 : padfGeoTransform = psInfo->adfSrcGeoTransform;
1563 121962 : pGCPTransformArg = psInfo->pSrcGCPTransformArg;
1564 121962 : pRPCTransformArg = psInfo->pSrcRPCTransformArg;
1565 121962 : pTPSTransformArg = psInfo->pSrcTPSTransformArg;
1566 121962 : pGeoLocTransformArg = psInfo->pSrcGeoLocTransformArg;
1567 : }
1568 :
1569 301911 : if( pGCPTransformArg != NULL )
1570 : {
1571 5801 : if( !GDALGCPTransform( pGCPTransformArg, FALSE,
1572 : nPointCount, padfX, padfY, padfZ,
1573 : panSuccess ) )
1574 0 : return FALSE;
1575 : }
1576 296110 : else if( pTPSTransformArg != NULL )
1577 : {
1578 889 : if( !GDALTPSTransform( pTPSTransformArg, FALSE,
1579 : nPointCount, padfX, padfY, padfZ,
1580 : panSuccess ) )
1581 0 : return FALSE;
1582 : }
1583 295221 : else if( pRPCTransformArg != NULL )
1584 : {
1585 4 : if( !GDALRPCTransform( pRPCTransformArg, FALSE,
1586 : nPointCount, padfX, padfY, padfZ,
1587 : panSuccess ) )
1588 0 : return FALSE;
1589 : }
1590 295217 : else if( pGeoLocTransformArg != NULL )
1591 : {
1592 1 : if( !GDALGeoLocTransform( pGeoLocTransformArg, FALSE,
1593 : nPointCount, padfX, padfY, padfZ,
1594 : panSuccess ) )
1595 0 : return FALSE;
1596 : }
1597 : else
1598 : {
1599 8788540 : for( i = 0; i < nPointCount; i++ )
1600 : {
1601 : double dfNewX, dfNewY;
1602 :
1603 8493324 : if( padfX[i] == HUGE_VAL || padfY[i] == HUGE_VAL )
1604 : {
1605 657 : panSuccess[i] = FALSE;
1606 657 : continue;
1607 : }
1608 :
1609 8492667 : dfNewX = padfGeoTransform[0]
1610 8492667 : + padfX[i] * padfGeoTransform[1]
1611 8492667 : + padfY[i] * padfGeoTransform[2];
1612 8492667 : dfNewY = padfGeoTransform[3]
1613 8492667 : + padfX[i] * padfGeoTransform[4]
1614 8492667 : + padfY[i] * padfGeoTransform[5];
1615 :
1616 8492667 : padfX[i] = dfNewX;
1617 8492667 : padfY[i] = dfNewY;
1618 : }
1619 : }
1620 :
1621 : /* -------------------------------------------------------------------- */
1622 : /* Reproject if needed. */
1623 : /* -------------------------------------------------------------------- */
1624 301910 : if( psInfo->pReprojectArg )
1625 : {
1626 37819 : if( !GDALReprojectionTransform( psInfo->pReprojectArg, bDstToSrc,
1627 : nPointCount, padfX, padfY, padfZ,
1628 : panSuccess ) )
1629 0 : return FALSE;
1630 : }
1631 : else
1632 : {
1633 3994072 : for( i = 0; i < nPointCount; i++ )
1634 3729981 : panSuccess[i] = 1;
1635 : }
1636 :
1637 : /* -------------------------------------------------------------------- */
1638 : /* Convert dst (src) georef coordinates back to pixel/line. */
1639 : /* -------------------------------------------------------------------- */
1640 301911 : if( bDstToSrc )
1641 : {
1642 179949 : padfGeoTransform = psInfo->adfSrcInvGeoTransform;
1643 179949 : pGCPTransformArg = psInfo->pSrcGCPTransformArg;
1644 179949 : pRPCTransformArg = psInfo->pSrcRPCTransformArg;
1645 179949 : pTPSTransformArg = psInfo->pSrcTPSTransformArg;
1646 179949 : pGeoLocTransformArg = psInfo->pSrcGeoLocTransformArg;
1647 : }
1648 : else
1649 : {
1650 121962 : padfGeoTransform = psInfo->adfDstInvGeoTransform;
1651 121962 : pGCPTransformArg = psInfo->pDstGCPTransformArg;
1652 121962 : pRPCTransformArg = NULL;
1653 121962 : pTPSTransformArg = NULL;
1654 121962 : pGeoLocTransformArg = NULL;
1655 : }
1656 :
1657 301911 : if( pGCPTransformArg != NULL )
1658 : {
1659 6406 : if( !GDALGCPTransform( pGCPTransformArg, TRUE,
1660 : nPointCount, padfX, padfY, padfZ,
1661 : panSuccess ) )
1662 0 : return FALSE;
1663 : }
1664 295505 : else if( pTPSTransformArg != NULL )
1665 : {
1666 931 : if( !GDALTPSTransform( pTPSTransformArg, TRUE,
1667 : nPointCount, padfX, padfY, padfZ,
1668 : panSuccess ) )
1669 0 : return FALSE;
1670 : }
1671 294574 : else if( pRPCTransformArg != NULL )
1672 : {
1673 4 : if( !GDALRPCTransform( pRPCTransformArg, TRUE,
1674 : nPointCount, padfX, padfY, padfZ,
1675 : panSuccess ) )
1676 0 : return FALSE;
1677 : }
1678 294570 : else if( pGeoLocTransformArg != NULL )
1679 : {
1680 259 : if( !GDALGeoLocTransform( pGeoLocTransformArg, TRUE,
1681 : nPointCount, padfX, padfY, padfZ,
1682 : panSuccess ) )
1683 0 : return FALSE;
1684 : }
1685 : else
1686 : {
1687 8647973 : for( i = 0; i < nPointCount; i++ )
1688 : {
1689 : double dfNewX, dfNewY;
1690 :
1691 8353662 : if( !panSuccess[i] )
1692 159983 : continue;
1693 :
1694 8193679 : dfNewX = padfGeoTransform[0]
1695 8193679 : + padfX[i] * padfGeoTransform[1]
1696 8193679 : + padfY[i] * padfGeoTransform[2];
1697 8193679 : dfNewY = padfGeoTransform[3]
1698 8193679 : + padfX[i] * padfGeoTransform[4]
1699 8193679 : + padfY[i] * padfGeoTransform[5];
1700 :
1701 8193679 : padfX[i] = dfNewX;
1702 8193679 : padfY[i] = dfNewY;
1703 : }
1704 : }
1705 :
1706 301911 : return TRUE;
1707 : }
1708 :
1709 : /************************************************************************/
1710 : /* GDALSerializeGenImgProjTransformer() */
1711 : /************************************************************************/
1712 :
1713 : static CPLXMLNode *
1714 6 : GDALSerializeGenImgProjTransformer( void *pTransformArg )
1715 :
1716 : {
1717 : char szWork[200];
1718 : CPLXMLNode *psTree;
1719 : GDALGenImgProjTransformInfo *psInfo =
1720 6 : (GDALGenImgProjTransformInfo *) pTransformArg;
1721 :
1722 6 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "GenImgProjTransformer" );
1723 :
1724 : /* -------------------------------------------------------------------- */
1725 : /* Handle GCP transformation. */
1726 : /* -------------------------------------------------------------------- */
1727 6 : if( psInfo->pSrcGCPTransformArg != NULL )
1728 : {
1729 : CPLXMLNode *psTransformerContainer;
1730 : CPLXMLNode *psTransformer;
1731 :
1732 : psTransformerContainer =
1733 3 : CPLCreateXMLNode( psTree, CXT_Element, "SrcGCPTransformer" );
1734 :
1735 : psTransformer = GDALSerializeTransformer( GDALGCPTransform,
1736 3 : psInfo->pSrcGCPTransformArg);
1737 3 : if( psTransformer != NULL )
1738 3 : CPLAddXMLChild( psTransformerContainer, psTransformer );
1739 : }
1740 :
1741 : /* -------------------------------------------------------------------- */
1742 : /* Handle TPS transformation. */
1743 : /* -------------------------------------------------------------------- */
1744 3 : else if( psInfo->pSrcTPSTransformArg != NULL )
1745 : {
1746 : CPLXMLNode *psTransformerContainer;
1747 : CPLXMLNode *psTransformer;
1748 :
1749 : psTransformerContainer =
1750 1 : CPLCreateXMLNode( psTree, CXT_Element, "SrcTPSTransformer" );
1751 :
1752 : psTransformer =
1753 1 : GDALSerializeTransformer( NULL, psInfo->pSrcTPSTransformArg);
1754 1 : if( psTransformer != NULL )
1755 1 : CPLAddXMLChild( psTransformerContainer, psTransformer );
1756 : }
1757 :
1758 : /* -------------------------------------------------------------------- */
1759 : /* Handle GeoLoc transformation. */
1760 : /* -------------------------------------------------------------------- */
1761 2 : else if( psInfo->pSrcGeoLocTransformArg != NULL )
1762 : {
1763 : CPLXMLNode *psTransformerContainer;
1764 : CPLXMLNode *psTransformer;
1765 :
1766 : psTransformerContainer =
1767 0 : CPLCreateXMLNode( psTree, CXT_Element, "SrcGeoLocTransformer" );
1768 :
1769 : psTransformer =
1770 0 : GDALSerializeTransformer( NULL, psInfo->pSrcGeoLocTransformArg);
1771 0 : if( psTransformer != NULL )
1772 0 : CPLAddXMLChild( psTransformerContainer, psTransformer );
1773 : }
1774 :
1775 : /* -------------------------------------------------------------------- */
1776 : /* Handle RPC transformation. */
1777 : /* -------------------------------------------------------------------- */
1778 2 : else if( psInfo->pSrcRPCTransformArg != NULL )
1779 : {
1780 : CPLXMLNode *psTransformerContainer;
1781 : CPLXMLNode *psTransformer;
1782 :
1783 : psTransformerContainer =
1784 0 : CPLCreateXMLNode( psTree, CXT_Element, "SrcRPCTransformer" );
1785 :
1786 : psTransformer =
1787 0 : GDALSerializeTransformer( NULL, psInfo->pSrcRPCTransformArg);
1788 0 : if( psTransformer != NULL )
1789 0 : CPLAddXMLChild( psTransformerContainer, psTransformer );
1790 : }
1791 :
1792 : /* -------------------------------------------------------------------- */
1793 : /* Handle source geotransforms. */
1794 : /* -------------------------------------------------------------------- */
1795 : else
1796 : {
1797 : sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
1798 : psInfo->adfSrcGeoTransform[0],
1799 : psInfo->adfSrcGeoTransform[1],
1800 : psInfo->adfSrcGeoTransform[2],
1801 : psInfo->adfSrcGeoTransform[3],
1802 : psInfo->adfSrcGeoTransform[4],
1803 2 : psInfo->adfSrcGeoTransform[5] );
1804 2 : CPLCreateXMLElementAndValue( psTree, "SrcGeoTransform", szWork );
1805 :
1806 : sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
1807 : psInfo->adfSrcInvGeoTransform[0],
1808 : psInfo->adfSrcInvGeoTransform[1],
1809 : psInfo->adfSrcInvGeoTransform[2],
1810 : psInfo->adfSrcInvGeoTransform[3],
1811 : psInfo->adfSrcInvGeoTransform[4],
1812 2 : psInfo->adfSrcInvGeoTransform[5] );
1813 2 : CPLCreateXMLElementAndValue( psTree, "SrcInvGeoTransform", szWork );
1814 : }
1815 :
1816 : /* -------------------------------------------------------------------- */
1817 : /* Handle destination geotransforms. */
1818 : /* -------------------------------------------------------------------- */
1819 : sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
1820 : psInfo->adfDstGeoTransform[0],
1821 : psInfo->adfDstGeoTransform[1],
1822 : psInfo->adfDstGeoTransform[2],
1823 : psInfo->adfDstGeoTransform[3],
1824 : psInfo->adfDstGeoTransform[4],
1825 6 : psInfo->adfDstGeoTransform[5] );
1826 6 : CPLCreateXMLElementAndValue( psTree, "DstGeoTransform", szWork );
1827 :
1828 : sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
1829 : psInfo->adfDstInvGeoTransform[0],
1830 : psInfo->adfDstInvGeoTransform[1],
1831 : psInfo->adfDstInvGeoTransform[2],
1832 : psInfo->adfDstInvGeoTransform[3],
1833 : psInfo->adfDstInvGeoTransform[4],
1834 6 : psInfo->adfDstInvGeoTransform[5] );
1835 6 : CPLCreateXMLElementAndValue( psTree, "DstInvGeoTransform", szWork );
1836 :
1837 : /* -------------------------------------------------------------------- */
1838 : /* Do we have a reprojection transformer? */
1839 : /* -------------------------------------------------------------------- */
1840 6 : if( psInfo->pReprojectArg != NULL )
1841 : {
1842 : CPLXMLNode *psTransformerContainer;
1843 : CPLXMLNode *psTransformer;
1844 :
1845 : psTransformerContainer =
1846 0 : CPLCreateXMLNode( psTree, CXT_Element, "ReprojectTransformer" );
1847 :
1848 : psTransformer = GDALSerializeTransformer( GDALReprojectionTransform,
1849 0 : psInfo->pReprojectArg );
1850 0 : if( psTransformer != NULL )
1851 0 : CPLAddXMLChild( psTransformerContainer, psTransformer );
1852 : }
1853 :
1854 6 : return psTree;
1855 : }
1856 :
1857 : /************************************************************************/
1858 : /* GDALDeserializeGenImgProjTransformer() */
1859 : /************************************************************************/
1860 :
1861 45 : void *GDALDeserializeGenImgProjTransformer( CPLXMLNode *psTree )
1862 :
1863 : {
1864 : GDALGenImgProjTransformInfo *psInfo;
1865 : CPLXMLNode *psSubtree;
1866 :
1867 : /* -------------------------------------------------------------------- */
1868 : /* Initialize the transform info. */
1869 : /* -------------------------------------------------------------------- */
1870 : psInfo = (GDALGenImgProjTransformInfo *)
1871 45 : CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
1872 :
1873 45 : strcpy( psInfo->sTI.szSignature, "GTI" );
1874 45 : psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
1875 45 : psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
1876 45 : psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
1877 45 : psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
1878 :
1879 : /* -------------------------------------------------------------------- */
1880 : /* SrcGeotransform */
1881 : /* -------------------------------------------------------------------- */
1882 45 : if( CPLGetXMLNode( psTree, "SrcGeoTransform" ) != NULL )
1883 : {
1884 : sscanf( CPLGetXMLValue( psTree, "SrcGeoTransform", "" ),
1885 : "%lg,%lg,%lg,%lg,%lg,%lg",
1886 : psInfo->adfSrcGeoTransform + 0,
1887 : psInfo->adfSrcGeoTransform + 1,
1888 : psInfo->adfSrcGeoTransform + 2,
1889 : psInfo->adfSrcGeoTransform + 3,
1890 : psInfo->adfSrcGeoTransform + 4,
1891 38 : psInfo->adfSrcGeoTransform + 5 );
1892 :
1893 38 : if( CPLGetXMLNode( psTree, "SrcInvGeoTransform" ) != NULL )
1894 : {
1895 : sscanf( CPLGetXMLValue( psTree, "SrcInvGeoTransform", "" ),
1896 : "%lg,%lg,%lg,%lg,%lg,%lg",
1897 : psInfo->adfSrcInvGeoTransform + 0,
1898 : psInfo->adfSrcInvGeoTransform + 1,
1899 : psInfo->adfSrcInvGeoTransform + 2,
1900 : psInfo->adfSrcInvGeoTransform + 3,
1901 : psInfo->adfSrcInvGeoTransform + 4,
1902 38 : psInfo->adfSrcInvGeoTransform + 5 );
1903 :
1904 : }
1905 : else
1906 : GDALInvGeoTransform( psInfo->adfSrcGeoTransform,
1907 0 : psInfo->adfSrcInvGeoTransform );
1908 : }
1909 :
1910 : /* -------------------------------------------------------------------- */
1911 : /* Src GCP Transform */
1912 : /* -------------------------------------------------------------------- */
1913 45 : psSubtree = CPLGetXMLNode( psTree, "SrcGCPTransformer" );
1914 45 : if( psSubtree != NULL && psSubtree->psChild != NULL )
1915 : {
1916 : psInfo->pSrcGCPTransformArg =
1917 5 : GDALDeserializeGCPTransformer( psSubtree->psChild );
1918 : }
1919 :
1920 : /* -------------------------------------------------------------------- */
1921 : /* Src TPS Transform */
1922 : /* -------------------------------------------------------------------- */
1923 45 : psSubtree = CPLGetXMLNode( psTree, "SrcTPSTransformer" );
1924 45 : if( psSubtree != NULL && psSubtree->psChild != NULL )
1925 : {
1926 : psInfo->pSrcTPSTransformArg =
1927 1 : GDALDeserializeTPSTransformer( psSubtree->psChild );
1928 : }
1929 :
1930 : /* -------------------------------------------------------------------- */
1931 : /* Src GeoLoc Transform */
1932 : /* -------------------------------------------------------------------- */
1933 45 : psSubtree = CPLGetXMLNode( psTree, "SrcGeoLocTransformer" );
1934 45 : if( psSubtree != NULL && psSubtree->psChild != NULL )
1935 : {
1936 : psInfo->pSrcGeoLocTransformArg =
1937 1 : GDALDeserializeGeoLocTransformer( psSubtree->psChild );
1938 : }
1939 :
1940 : /* -------------------------------------------------------------------- */
1941 : /* Src RPC Transform */
1942 : /* -------------------------------------------------------------------- */
1943 45 : psSubtree = CPLGetXMLNode( psTree, "SrcRPCTransformer" );
1944 45 : if( psSubtree != NULL && psSubtree->psChild != NULL )
1945 : {
1946 : psInfo->pSrcRPCTransformArg =
1947 0 : GDALDeserializeRPCTransformer( psSubtree->psChild );
1948 : }
1949 :
1950 : /* -------------------------------------------------------------------- */
1951 : /* DstGeotransform */
1952 : /* -------------------------------------------------------------------- */
1953 45 : if( CPLGetXMLNode( psTree, "DstGeoTransform" ) != NULL )
1954 : {
1955 : sscanf( CPLGetXMLValue( psTree, "DstGeoTransform", "" ),
1956 : "%lg,%lg,%lg,%lg,%lg,%lg",
1957 : psInfo->adfDstGeoTransform + 0,
1958 : psInfo->adfDstGeoTransform + 1,
1959 : psInfo->adfDstGeoTransform + 2,
1960 : psInfo->adfDstGeoTransform + 3,
1961 : psInfo->adfDstGeoTransform + 4,
1962 45 : psInfo->adfDstGeoTransform + 5 );
1963 :
1964 45 : if( CPLGetXMLNode( psTree, "DstInvGeoTransform" ) != NULL )
1965 : {
1966 : sscanf( CPLGetXMLValue( psTree, "DstInvGeoTransform", "" ),
1967 : "%lg,%lg,%lg,%lg,%lg,%lg",
1968 : psInfo->adfDstInvGeoTransform + 0,
1969 : psInfo->adfDstInvGeoTransform + 1,
1970 : psInfo->adfDstInvGeoTransform + 2,
1971 : psInfo->adfDstInvGeoTransform + 3,
1972 : psInfo->adfDstInvGeoTransform + 4,
1973 29 : psInfo->adfDstInvGeoTransform + 5 );
1974 :
1975 : }
1976 : else
1977 : GDALInvGeoTransform( psInfo->adfDstGeoTransform,
1978 16 : psInfo->adfDstInvGeoTransform );
1979 : }
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* Reproject transformer */
1983 : /* -------------------------------------------------------------------- */
1984 45 : psSubtree = CPLGetXMLNode( psTree, "ReprojectTransformer" );
1985 45 : if( psSubtree != NULL && psSubtree->psChild != NULL )
1986 : {
1987 : psInfo->pReprojectArg =
1988 12 : GDALDeserializeReprojectionTransformer( psSubtree->psChild );
1989 : }
1990 :
1991 45 : return psInfo;
1992 : }
1993 :
1994 : /************************************************************************/
1995 : /* ==================================================================== */
1996 : /* GDALReprojectionTransformer */
1997 : /* ==================================================================== */
1998 : /************************************************************************/
1999 :
2000 : typedef struct {
2001 : GDALTransformerInfo sTI;
2002 :
2003 : OGRCoordinateTransformation *poForwardTransform;
2004 : OGRCoordinateTransformation *poReverseTransform;
2005 : } GDALReprojectionTransformInfo;
2006 :
2007 : /************************************************************************/
2008 : /* GDALCreateReprojectionTransformer() */
2009 : /************************************************************************/
2010 :
2011 : /**
2012 : * Create reprojection transformer.
2013 : *
2014 : * Creates a callback data structure suitable for use with
2015 : * GDALReprojectionTransformation() to represent a transformation from
2016 : * one geographic or projected coordinate system to another. On input
2017 : * the coordinate systems are described in OpenGIS WKT format.
2018 : *
2019 : * Internally the OGRCoordinateTransformation object is used to implement
2020 : * the reprojection.
2021 : *
2022 : * @param pszSrcWKT the coordinate system for the source coordinate system.
2023 : * @param pszDstWKT the coordinate system for the destination coordinate
2024 : * system.
2025 : *
2026 : * @return Handle for use with GDALReprojectionTransform(), or NULL if the
2027 : * system fails to initialize the reprojection.
2028 : **/
2029 :
2030 98 : void *GDALCreateReprojectionTransformer( const char *pszSrcWKT,
2031 : const char *pszDstWKT )
2032 :
2033 : {
2034 98 : OGRSpatialReference oSrcSRS, oDstSRS;
2035 : OGRCoordinateTransformation *poForwardTransform;
2036 :
2037 : /* -------------------------------------------------------------------- */
2038 : /* Ingest the SRS definitions. */
2039 : /* -------------------------------------------------------------------- */
2040 98 : if( oSrcSRS.importFromWkt( (char **) &pszSrcWKT ) != OGRERR_NONE )
2041 : {
2042 : CPLError( CE_Failure, CPLE_AppDefined,
2043 : "Failed to import coordinate system `%s'.",
2044 0 : pszSrcWKT );
2045 0 : return NULL;
2046 : }
2047 98 : if( oDstSRS.importFromWkt( (char **) &pszDstWKT ) != OGRERR_NONE )
2048 : {
2049 : CPLError( CE_Failure, CPLE_AppDefined,
2050 : "Failed to import coordinate system `%s'.",
2051 0 : pszSrcWKT );
2052 0 : return NULL;
2053 : }
2054 :
2055 : /* -------------------------------------------------------------------- */
2056 : /* Build the forward coordinate transformation. */
2057 : /* -------------------------------------------------------------------- */
2058 98 : poForwardTransform = OGRCreateCoordinateTransformation(&oSrcSRS,&oDstSRS);
2059 :
2060 98 : if( poForwardTransform == NULL )
2061 : // OGRCreateCoordinateTransformation() will report errors on its own.
2062 0 : return NULL;
2063 :
2064 : /* -------------------------------------------------------------------- */
2065 : /* Create a structure to hold the transform info, and also */
2066 : /* build reverse transform. We assume that if the forward */
2067 : /* transform can be created, then so can the reverse one. */
2068 : /* -------------------------------------------------------------------- */
2069 : GDALReprojectionTransformInfo *psInfo;
2070 :
2071 : psInfo = (GDALReprojectionTransformInfo *)
2072 98 : CPLCalloc(sizeof(GDALReprojectionTransformInfo),1);
2073 :
2074 98 : psInfo->poForwardTransform = poForwardTransform;
2075 : psInfo->poReverseTransform =
2076 98 : OGRCreateCoordinateTransformation(&oDstSRS,&oSrcSRS);
2077 :
2078 98 : strcpy( psInfo->sTI.szSignature, "GTI" );
2079 98 : psInfo->sTI.pszClassName = "GDALReprojectionTransformer";
2080 98 : psInfo->sTI.pfnTransform = GDALReprojectionTransform;
2081 98 : psInfo->sTI.pfnCleanup = GDALDestroyReprojectionTransformer;
2082 98 : psInfo->sTI.pfnSerialize = GDALSerializeReprojectionTransformer;
2083 :
2084 98 : return psInfo;
2085 : }
2086 :
2087 : /************************************************************************/
2088 : /* GDALDestroyReprojectionTransformer() */
2089 : /************************************************************************/
2090 :
2091 : /**
2092 : * Destroy reprojection transformation.
2093 : *
2094 : * @param pTransformArg the transformation handle returned by
2095 : * GDALCreateReprojectionTransformer().
2096 : */
2097 :
2098 98 : void GDALDestroyReprojectionTransformer( void *pTransformArg )
2099 :
2100 : {
2101 98 : VALIDATE_POINTER0( pTransformArg, "GDALDestroyReprojectionTransformer" );
2102 :
2103 : GDALReprojectionTransformInfo *psInfo =
2104 98 : (GDALReprojectionTransformInfo *) pTransformArg;
2105 :
2106 98 : if( psInfo->poForwardTransform )
2107 98 : delete psInfo->poForwardTransform;
2108 :
2109 98 : if( psInfo->poReverseTransform )
2110 98 : delete psInfo->poReverseTransform;
2111 :
2112 98 : CPLFree( psInfo );
2113 : }
2114 :
2115 : /************************************************************************/
2116 : /* GDALReprojectionTransform() */
2117 : /************************************************************************/
2118 :
2119 : /**
2120 : * Perform reprojection transformation.
2121 : *
2122 : * Actually performs the reprojection transformation described in
2123 : * GDALCreateReprojectionTransformer(). This function matches the
2124 : * GDALTransformerFunc() signature. Details of the arguments are described
2125 : * there.
2126 : */
2127 :
2128 37818 : int GDALReprojectionTransform( void *pTransformArg, int bDstToSrc,
2129 : int nPointCount,
2130 : double *padfX, double *padfY, double *padfZ,
2131 : int *panSuccess )
2132 :
2133 : {
2134 : GDALReprojectionTransformInfo *psInfo =
2135 37818 : (GDALReprojectionTransformInfo *) pTransformArg;
2136 : int bSuccess;
2137 :
2138 37818 : if( bDstToSrc )
2139 : bSuccess = psInfo->poReverseTransform->TransformEx(
2140 31685 : nPointCount, padfX, padfY, padfZ, panSuccess );
2141 : else
2142 : bSuccess = psInfo->poForwardTransform->TransformEx(
2143 6133 : nPointCount, padfX, padfY, padfZ, panSuccess );
2144 :
2145 37820 : return bSuccess;
2146 : }
2147 :
2148 : /************************************************************************/
2149 : /* GDALSerializeReprojectionTransformer() */
2150 : /************************************************************************/
2151 :
2152 : static CPLXMLNode *
2153 37 : GDALSerializeReprojectionTransformer( void *pTransformArg )
2154 :
2155 : {
2156 : CPLXMLNode *psTree;
2157 : GDALReprojectionTransformInfo *psInfo =
2158 37 : (GDALReprojectionTransformInfo *) pTransformArg;
2159 :
2160 37 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "ReprojectionTransformer" );
2161 :
2162 : /* -------------------------------------------------------------------- */
2163 : /* Handle SourceCS. */
2164 : /* -------------------------------------------------------------------- */
2165 : OGRSpatialReference *poSRS;
2166 37 : char *pszWKT = NULL;
2167 :
2168 37 : poSRS = psInfo->poForwardTransform->GetSourceCS();
2169 37 : poSRS->exportToWkt( &pszWKT );
2170 37 : CPLCreateXMLElementAndValue( psTree, "SourceSRS", pszWKT );
2171 37 : CPLFree( pszWKT );
2172 :
2173 : /* -------------------------------------------------------------------- */
2174 : /* Handle DestinationCS. */
2175 : /* -------------------------------------------------------------------- */
2176 37 : poSRS = psInfo->poForwardTransform->GetTargetCS();
2177 37 : poSRS->exportToWkt( &pszWKT );
2178 37 : CPLCreateXMLElementAndValue( psTree, "TargetSRS", pszWKT );
2179 37 : CPLFree( pszWKT );
2180 :
2181 37 : return psTree;
2182 : }
2183 :
2184 : /************************************************************************/
2185 : /* GDALDeserializeReprojectionTransformer() */
2186 : /************************************************************************/
2187 :
2188 : static void *
2189 49 : GDALDeserializeReprojectionTransformer( CPLXMLNode *psTree )
2190 :
2191 : {
2192 49 : const char *pszSourceSRS = CPLGetXMLValue( psTree, "SourceSRS", NULL );
2193 49 : const char *pszTargetSRS= CPLGetXMLValue( psTree, "TargetSRS", NULL );
2194 49 : char *pszSourceWKT = NULL, *pszTargetWKT = NULL;
2195 49 : void *pResult = NULL;
2196 :
2197 49 : if( pszSourceSRS != NULL )
2198 : {
2199 49 : OGRSpatialReference oSRS;
2200 :
2201 49 : if( oSRS.SetFromUserInput( pszSourceSRS ) == OGRERR_NONE )
2202 49 : oSRS.exportToWkt( &pszSourceWKT );
2203 : }
2204 :
2205 49 : if( pszTargetSRS != NULL )
2206 : {
2207 49 : OGRSpatialReference oSRS;
2208 :
2209 49 : if( oSRS.SetFromUserInput( pszTargetSRS ) == OGRERR_NONE )
2210 49 : oSRS.exportToWkt( &pszTargetWKT );
2211 : }
2212 :
2213 98 : if( pszSourceWKT != NULL && pszTargetWKT != NULL )
2214 : {
2215 : pResult = GDALCreateReprojectionTransformer( pszSourceWKT,
2216 49 : pszTargetWKT );
2217 : }
2218 : else
2219 : {
2220 : CPLError( CE_Failure, CPLE_AppDefined,
2221 : "ReprojectionTransformer definition missing either\n"
2222 0 : "SourceSRS or TargetSRS definition." );
2223 : }
2224 :
2225 49 : CPLFree( pszSourceWKT );
2226 49 : CPLFree( pszTargetWKT );
2227 :
2228 49 : return pResult;
2229 : }
2230 :
2231 : /************************************************************************/
2232 : /* ==================================================================== */
2233 : /* Approximate transformer. */
2234 : /* ==================================================================== */
2235 : /************************************************************************/
2236 :
2237 : typedef struct
2238 : {
2239 : GDALTransformerInfo sTI;
2240 :
2241 : GDALTransformerFunc pfnBaseTransformer;
2242 : void *pBaseCBData;
2243 : double dfMaxError;
2244 :
2245 : int bOwnSubtransformer;
2246 : } ApproxTransformInfo;
2247 :
2248 : /************************************************************************/
2249 : /* GDALCloneApproxTransformer() */
2250 : /************************************************************************/
2251 :
2252 8 : void* GDALCloneApproxTransformer( void *hTransformArg )
2253 : {
2254 8 : VALIDATE_POINTER1( hTransformArg, "GDALCloneApproxTransformer", NULL );
2255 :
2256 : ApproxTransformInfo *psInfo =
2257 8 : (ApproxTransformInfo *) hTransformArg;
2258 :
2259 : ApproxTransformInfo *psClonedInfo = (ApproxTransformInfo *)
2260 8 : CPLMalloc(sizeof(ApproxTransformInfo));
2261 :
2262 8 : memcpy(psClonedInfo, psInfo, sizeof(ApproxTransformInfo));
2263 8 : if( psClonedInfo->pBaseCBData )
2264 : {
2265 8 : psClonedInfo->pBaseCBData = GDALCloneTransformer( psInfo->pBaseCBData );
2266 8 : if( psClonedInfo->pBaseCBData == NULL )
2267 : {
2268 0 : CPLFree(psClonedInfo);
2269 0 : return NULL;
2270 : }
2271 : }
2272 8 : psClonedInfo->bOwnSubtransformer = TRUE;
2273 :
2274 8 : return psClonedInfo;
2275 : }
2276 :
2277 : /************************************************************************/
2278 : /* GDALSerializeApproxTransformer() */
2279 : /************************************************************************/
2280 :
2281 : static CPLXMLNode *
2282 3 : GDALSerializeApproxTransformer( void *pTransformArg )
2283 :
2284 : {
2285 : CPLXMLNode *psTree;
2286 3 : ApproxTransformInfo *psInfo = (ApproxTransformInfo *) pTransformArg;
2287 :
2288 3 : psTree = CPLCreateXMLNode( NULL, CXT_Element, "ApproxTransformer" );
2289 :
2290 : /* -------------------------------------------------------------------- */
2291 : /* Attach max error. */
2292 : /* -------------------------------------------------------------------- */
2293 : CPLCreateXMLElementAndValue( psTree, "MaxError",
2294 3 : CPLString().Printf("%g",psInfo->dfMaxError) );
2295 :
2296 : /* -------------------------------------------------------------------- */
2297 : /* Capture underlying transformer. */
2298 : /* -------------------------------------------------------------------- */
2299 : CPLXMLNode *psTransformerContainer;
2300 : CPLXMLNode *psTransformer;
2301 :
2302 : psTransformerContainer =
2303 3 : CPLCreateXMLNode( psTree, CXT_Element, "BaseTransformer" );
2304 :
2305 : psTransformer = GDALSerializeTransformer( psInfo->pfnBaseTransformer,
2306 3 : psInfo->pBaseCBData );
2307 3 : if( psTransformer != NULL )
2308 3 : CPLAddXMLChild( psTransformerContainer, psTransformer );
2309 :
2310 3 : return psTree;
2311 : }
2312 :
2313 : /************************************************************************/
2314 : /* GDALCreateApproxTransformer() */
2315 : /************************************************************************/
2316 :
2317 : /**
2318 : * Create an approximating transformer.
2319 : *
2320 : * This function creates a context for an approximated transformer. Basically
2321 : * a high precision transformer is supplied as input and internally linear
2322 : * approximations are computed to generate results to within a defined
2323 : * precision.
2324 : *
2325 : * The approximation is actually done at the point where GDALApproxTransform()
2326 : * calls are made, and depend on the assumption that the roughly linear. The
2327 : * first and last point passed in must be the extreme values and the
2328 : * intermediate values should describe a curve between the end points. The
2329 : * approximator transforms and center using the approximate transformer, and
2330 : * then compares the true middle transformed value to a linear approximation
2331 : * based on the end points. If the error is within the supplied threshold
2332 : * then the end points are used to linearly approximate all the values
2333 : * otherwise the inputs points are split into two smaller sets, and the
2334 : * function recursively called till a sufficiently small set of points if found
2335 : * that the linear approximation is OK, or that all the points are exactly
2336 : * computed.
2337 : *
2338 : * This function is very suitable for approximating transformation results
2339 : * from output pixel/line space to input coordinates for warpers that operate
2340 : * on one input scanline at a time. Care should be taken using it in other
2341 : * circumstances as little internal validation is done, in order to keep things
2342 : * fast.
2343 : *
2344 : * @param pfnBaseTransformer the high precision transformer which should be
2345 : * approximated.
2346 : * @param pBaseTransformArg the callback argument for the high precision
2347 : * transformer.
2348 : * @param dfMaxError the maximum cartesian error in the "output" space that
2349 : * is to be accepted in the linear approximation.
2350 : *
2351 : * @return callback pointer suitable for use with GDALApproxTransform(). It
2352 : * should be deallocated with GDALDestroyApproxTransformer().
2353 : */
2354 :
2355 299 : void *GDALCreateApproxTransformer( GDALTransformerFunc pfnBaseTransformer,
2356 : void *pBaseTransformArg, double dfMaxError)
2357 :
2358 : {
2359 : ApproxTransformInfo *psATInfo;
2360 :
2361 299 : psATInfo = (ApproxTransformInfo*) CPLMalloc(sizeof(ApproxTransformInfo));
2362 299 : psATInfo->pfnBaseTransformer = pfnBaseTransformer;
2363 299 : psATInfo->pBaseCBData = pBaseTransformArg;
2364 299 : psATInfo->dfMaxError = dfMaxError;
2365 299 : psATInfo->bOwnSubtransformer = FALSE;
2366 :
2367 299 : strcpy( psATInfo->sTI.szSignature, "GTI" );
2368 299 : psATInfo->sTI.pszClassName = "GDALApproxTransformer";
2369 299 : psATInfo->sTI.pfnTransform = GDALApproxTransform;
2370 299 : psATInfo->sTI.pfnCleanup = GDALDestroyApproxTransformer;
2371 299 : psATInfo->sTI.pfnSerialize = GDALSerializeApproxTransformer;
2372 :
2373 299 : return psATInfo;
2374 : }
2375 :
2376 : /************************************************************************/
2377 : /* GDALApproxTransformerOwnsSubtransformer() */
2378 : /************************************************************************/
2379 :
2380 26 : void GDALApproxTransformerOwnsSubtransformer( void *pCBData, int bOwnFlag )
2381 :
2382 : {
2383 26 : ApproxTransformInfo *psATInfo = (ApproxTransformInfo *) pCBData;
2384 :
2385 26 : psATInfo->bOwnSubtransformer = bOwnFlag;
2386 26 : }
2387 :
2388 : /************************************************************************/
2389 : /* GDALDestroyApproxTransformer() */
2390 : /************************************************************************/
2391 :
2392 : /**
2393 : * Cleanup approximate transformer.
2394 : *
2395 : * Deallocates the resources allocated by GDALCreateApproxTransformer().
2396 : *
2397 : * @param pCBData callback data originally returned by
2398 : * GDALCreateApproxTransformer().
2399 : */
2400 :
2401 307 : void GDALDestroyApproxTransformer( void * pCBData )
2402 :
2403 : {
2404 307 : VALIDATE_POINTER0( pCBData, "GDALDestroyApproxTransformer" );
2405 :
2406 307 : ApproxTransformInfo *psATInfo = (ApproxTransformInfo *) pCBData;
2407 :
2408 307 : if( psATInfo->bOwnSubtransformer )
2409 34 : GDALDestroyTransformer( psATInfo->pBaseCBData );
2410 :
2411 307 : CPLFree( pCBData );
2412 : }
2413 :
2414 : /************************************************************************/
2415 : /* GDALApproxTransform() */
2416 : /************************************************************************/
2417 :
2418 : /**
2419 : * Perform approximate transformation.
2420 : *
2421 : * Actually performs the approximate transformation described in
2422 : * GDALCreateApproxTransformer(). This function matches the
2423 : * GDALTransformerFunc() signature. Details of the arguments are described
2424 : * there.
2425 : */
2426 :
2427 48731 : int GDALApproxTransform( void *pCBData, int bDstToSrc, int nPoints,
2428 : double *x, double *y, double *z, int *panSuccess )
2429 :
2430 : {
2431 48731 : ApproxTransformInfo *psATInfo = (ApproxTransformInfo *) pCBData;
2432 : double x2[3], y2[3], z2[3], dfDeltaX, dfDeltaY, dfError, dfDist, dfDeltaZ;
2433 : int nMiddle, anSuccess2[3], i, bSuccess;
2434 :
2435 48731 : nMiddle = (nPoints-1)/2;
2436 :
2437 : /* -------------------------------------------------------------------- */
2438 : /* Bail if our preconditions are not met, or if error is not */
2439 : /* acceptable. */
2440 : /* -------------------------------------------------------------------- */
2441 144770 : if( y[0] != y[nPoints-1] || y[0] != y[nMiddle]
2442 96039 : || x[0] == x[nPoints-1] || x[0] == x[nMiddle]
2443 : || psATInfo->dfMaxError == 0.0 || nPoints <= 5 )
2444 : {
2445 : return psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
2446 1014 : nPoints, x, y, z, panSuccess );
2447 : }
2448 :
2449 : /* -------------------------------------------------------------------- */
2450 : /* Transform first, last and middle point. */
2451 : /* -------------------------------------------------------------------- */
2452 47717 : x2[0] = x[0];
2453 47717 : y2[0] = y[0];
2454 47717 : z2[0] = z[0];
2455 47717 : x2[1] = x[nMiddle];
2456 47717 : y2[1] = y[nMiddle];
2457 47717 : z2[1] = z[nMiddle];
2458 47717 : x2[2] = x[nPoints-1];
2459 47717 : y2[2] = y[nPoints-1];
2460 47717 : z2[2] = z[nPoints-1];
2461 :
2462 : bSuccess =
2463 : psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 3,
2464 47717 : x2, y2, z2, anSuccess2 );
2465 47717 : if( !bSuccess || !anSuccess2[0] || !anSuccess2[1] || !anSuccess2[2] )
2466 : return psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
2467 1446 : nPoints, x, y, z, panSuccess );
2468 :
2469 : /* -------------------------------------------------------------------- */
2470 : /* Is the error at the middle acceptable relative to an */
2471 : /* interpolation of the middle position? */
2472 : /* -------------------------------------------------------------------- */
2473 46271 : dfDeltaX = (x2[2] - x2[0]) / (x[nPoints-1] - x[0]);
2474 46271 : dfDeltaY = (y2[2] - y2[0]) / (x[nPoints-1] - x[0]);
2475 46271 : dfDeltaZ = (z2[2] - z2[0]) / (x[nPoints-1] - x[0]);
2476 :
2477 92542 : dfError = fabs((x2[0] + dfDeltaX * (x[nMiddle] - x[0])) - x2[1])
2478 92542 : + fabs((y2[0] + dfDeltaY * (x[nMiddle] - x[0])) - y2[1]);
2479 :
2480 46271 : if( dfError > psATInfo->dfMaxError )
2481 : {
2482 : #ifdef notdef
2483 : CPLDebug( "GDAL", "ApproxTransformer - "
2484 : "error %g over threshold %g, subdivide %d points.",
2485 : dfError, psATInfo->dfMaxError, nPoints );
2486 : #endif
2487 :
2488 : bSuccess =
2489 : GDALApproxTransform( psATInfo, bDstToSrc, nMiddle,
2490 7679 : x, y, z, panSuccess );
2491 :
2492 7679 : if( !bSuccess )
2493 0 : return FALSE;
2494 :
2495 : bSuccess =
2496 : GDALApproxTransform( psATInfo, bDstToSrc, nPoints - nMiddle,
2497 : x+nMiddle, y+nMiddle, z+nMiddle,
2498 7679 : panSuccess+nMiddle );
2499 :
2500 7679 : if( !bSuccess )
2501 0 : return FALSE;
2502 :
2503 7679 : return TRUE;
2504 : }
2505 :
2506 : /* -------------------------------------------------------------------- */
2507 : /* Error is OK since this is just used to compute output bounds */
2508 : /* of newly created file for gdalwarper. So just use affine */
2509 : /* approximation of the reverse transform. Eventually we */
2510 : /* should implement iterative searching to find a result within */
2511 : /* our error threshold. */
2512 : /* -------------------------------------------------------------------- */
2513 8756195 : for( i = nPoints-1; i >= 0; i-- )
2514 : {
2515 8717603 : dfDist = (x[i] - x[0]);
2516 8717603 : y[i] = y2[0] + dfDeltaY * dfDist;
2517 8717603 : x[i] = x2[0] + dfDeltaX * dfDist;
2518 8717603 : z[i] = z2[0] + dfDeltaZ * dfDist;
2519 8717603 : panSuccess[i] = TRUE;
2520 : }
2521 :
2522 38592 : return TRUE;
2523 : }
2524 :
2525 : /************************************************************************/
2526 : /* GDALDeserializeApproxTransformer() */
2527 : /************************************************************************/
2528 :
2529 : static void *
2530 24 : GDALDeserializeApproxTransformer( CPLXMLNode *psTree )
2531 :
2532 : {
2533 24 : double dfMaxError = atof(CPLGetXMLValue( psTree, "MaxError", "0.25" ));
2534 : CPLXMLNode *psContainer;
2535 24 : GDALTransformerFunc pfnBaseTransform = NULL;
2536 24 : void *pBaseCBData = NULL;
2537 :
2538 24 : psContainer = CPLGetXMLNode( psTree, "BaseTransformer" );
2539 :
2540 24 : if( psContainer != NULL && psContainer->psChild != NULL )
2541 : {
2542 : GDALDeserializeTransformer( psContainer->psChild,
2543 : &pfnBaseTransform,
2544 24 : &pBaseCBData );
2545 :
2546 : }
2547 :
2548 24 : if( pfnBaseTransform == NULL )
2549 : {
2550 : CPLError( CE_Failure, CPLE_AppDefined,
2551 0 : "Cannot get base transform for approx transformer." );
2552 0 : return NULL;
2553 : }
2554 : else
2555 : {
2556 : void *pApproxCBData = GDALCreateApproxTransformer( pfnBaseTransform,
2557 : pBaseCBData,
2558 24 : dfMaxError );
2559 24 : GDALApproxTransformerOwnsSubtransformer( pApproxCBData, TRUE );
2560 :
2561 24 : return pApproxCBData;
2562 : }
2563 : }
2564 :
2565 : /************************************************************************/
2566 : /* GDALApplyGeoTransform() */
2567 : /************************************************************************/
2568 :
2569 : /**
2570 : * Apply GeoTransform to x/y coordinate.
2571 : *
2572 : * Applies the following computation, converting a (pixel,line) coordinate
2573 : * into a georeferenced (geo_x,geo_y) location.
2574 : *
2575 : * *pdfGeoX = padfGeoTransform[0] + dfPixel * padfGeoTransform[1]
2576 : * + dfLine * padfGeoTransform[2];
2577 : * *pdfGeoY = padfGeoTransform[3] + dfPixel * padfGeoTransform[4]
2578 : * + dfLine * padfGeoTransform[5];
2579 : *
2580 : * @param padfGeoTransform Six coefficient GeoTransform to apply.
2581 : * @param dfPixel Input pixel position.
2582 : * @param dfLine Input line position.
2583 : * @param pdfGeoX output location where geo_x (easting/longitude) location is placed.
2584 : * @param pdfGeoY output location where geo_y (northing/latitude) location is placed.
2585 : */
2586 :
2587 3 : void CPL_STDCALL GDALApplyGeoTransform( double *padfGeoTransform,
2588 : double dfPixel, double dfLine,
2589 : double *pdfGeoX, double *pdfGeoY )
2590 : {
2591 3 : *pdfGeoX = padfGeoTransform[0] + dfPixel * padfGeoTransform[1]
2592 3 : + dfLine * padfGeoTransform[2];
2593 3 : *pdfGeoY = padfGeoTransform[3] + dfPixel * padfGeoTransform[4]
2594 3 : + dfLine * padfGeoTransform[5];
2595 3 : }
2596 :
2597 : /************************************************************************/
2598 : /* GDALInvGeoTransform() */
2599 : /************************************************************************/
2600 :
2601 : /**
2602 : * Invert Geotransform.
2603 : *
2604 : * This function will invert a standard 3x2 set of GeoTransform coefficients.
2605 : * This converts the equation from being pixel to geo to being geo to pixel.
2606 : *
2607 : * @param gt_in Input geotransform (six doubles - unaltered).
2608 : * @param gt_out Output geotransform (six doubles - updated).
2609 : *
2610 : * @return TRUE on success or FALSE if the equation is uninvertable.
2611 : */
2612 :
2613 662 : int CPL_STDCALL GDALInvGeoTransform( double *gt_in, double *gt_out )
2614 :
2615 : {
2616 : double det, inv_det;
2617 :
2618 : /* we assume a 3rd row that is [1 0 0] */
2619 :
2620 : /* Compute determinate */
2621 :
2622 662 : det = gt_in[1] * gt_in[5] - gt_in[2] * gt_in[4];
2623 :
2624 662 : if( fabs(det) < 0.000000000000001 )
2625 0 : return 0;
2626 :
2627 662 : inv_det = 1.0 / det;
2628 :
2629 : /* compute adjoint, and devide by determinate */
2630 :
2631 662 : gt_out[1] = gt_in[5] * inv_det;
2632 662 : gt_out[4] = -gt_in[4] * inv_det;
2633 :
2634 662 : gt_out[2] = -gt_in[2] * inv_det;
2635 662 : gt_out[5] = gt_in[1] * inv_det;
2636 :
2637 662 : gt_out[0] = ( gt_in[2] * gt_in[3] - gt_in[0] * gt_in[5]) * inv_det;
2638 662 : gt_out[3] = (-gt_in[1] * gt_in[3] + gt_in[0] * gt_in[4]) * inv_det;
2639 :
2640 662 : return 1;
2641 : }
2642 :
2643 : /************************************************************************/
2644 : /* GDALSerializeTransformer() */
2645 : /************************************************************************/
2646 :
2647 13 : CPLXMLNode *GDALSerializeTransformer( GDALTransformerFunc pfnFunc,
2648 : void *pTransformArg )
2649 :
2650 : {
2651 13 : VALIDATE_POINTER1( pTransformArg, "GDALSerializeTransformer", NULL );
2652 :
2653 13 : GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
2654 :
2655 13 : if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
2656 : {
2657 : CPLError( CE_Failure, CPLE_AppDefined,
2658 0 : "Attempt to serialize non-GTI transformer." );
2659 0 : return NULL;
2660 : }
2661 13 : else if ( psInfo->pfnSerialize == NULL )
2662 : {
2663 : CPLError( CE_Failure, CPLE_AppDefined,
2664 0 : "No serialization function available for this transformer." );
2665 0 : return NULL;
2666 : }
2667 : else
2668 : {
2669 13 : return psInfo->pfnSerialize( pTransformArg );
2670 : }
2671 : }
2672 :
2673 : /************************************************************************/
2674 : /* GDALRegisterTransformDeserializer() */
2675 : /************************************************************************/
2676 :
2677 : static CPLList* psListDeserializer = NULL;
2678 : static void* hDeserializerMutex = NULL;
2679 :
2680 : typedef struct
2681 : {
2682 : char* pszTransformName;
2683 : GDALTransformerFunc pfnTransformerFunc;
2684 : GDALTransformDeserializeFunc pfnDeserializeFunc;
2685 : } TransformDeserializerInfo;
2686 :
2687 588 : void* GDALRegisterTransformDeserializer(const char* pszTransformName,
2688 : GDALTransformerFunc pfnTransformerFunc,
2689 : GDALTransformDeserializeFunc pfnDeserializeFunc)
2690 : {
2691 : TransformDeserializerInfo* psInfo =
2692 588 : (TransformDeserializerInfo*)CPLMalloc(sizeof(TransformDeserializerInfo));
2693 588 : psInfo->pszTransformName = CPLStrdup(pszTransformName);
2694 588 : psInfo->pfnTransformerFunc = pfnTransformerFunc;
2695 588 : psInfo->pfnDeserializeFunc = pfnDeserializeFunc;
2696 :
2697 588 : CPLMutexHolderD(&hDeserializerMutex);
2698 588 : psListDeserializer = CPLListInsert(psListDeserializer, psInfo, 0);
2699 :
2700 588 : return psInfo;
2701 : }
2702 :
2703 : /************************************************************************/
2704 : /* GDALUnregisterTransformDeserializer() */
2705 : /************************************************************************/
2706 :
2707 550 : void GDALUnregisterTransformDeserializer(void* pData)
2708 : {
2709 550 : CPLMutexHolderD(&hDeserializerMutex);
2710 550 : CPLList* psList = psListDeserializer;
2711 550 : CPLList* psLast = NULL;
2712 1100 : while(psList)
2713 : {
2714 550 : if (psList->pData == pData)
2715 : {
2716 : TransformDeserializerInfo* psInfo =
2717 550 : (TransformDeserializerInfo*)pData;
2718 550 : CPLFree(psInfo->pszTransformName);
2719 550 : CPLFree(pData);
2720 550 : if (psLast)
2721 0 : psLast->psNext = psList->psNext;
2722 : else
2723 550 : psListDeserializer = NULL;
2724 550 : CPLFree(psList);
2725 550 : break;
2726 : }
2727 0 : psLast = psList;
2728 0 : psList = psList->psNext;
2729 550 : }
2730 550 : }
2731 :
2732 : /************************************************************************/
2733 : /* GDALUnregisterTransformDeserializer() */
2734 : /************************************************************************/
2735 :
2736 550 : void GDALCleanupTransformDeserializerMutex()
2737 : {
2738 550 : if( hDeserializerMutex != NULL )
2739 : {
2740 550 : CPLDestroyMutex(hDeserializerMutex);
2741 550 : hDeserializerMutex = NULL;
2742 : }
2743 550 : }
2744 :
2745 : /************************************************************************/
2746 : /* GDALDeserializeTransformer() */
2747 : /************************************************************************/
2748 :
2749 77 : CPLErr GDALDeserializeTransformer( CPLXMLNode *psTree,
2750 : GDALTransformerFunc *ppfnFunc,
2751 : void **ppTransformArg )
2752 :
2753 : {
2754 77 : *ppfnFunc = NULL;
2755 77 : *ppTransformArg = NULL;
2756 :
2757 77 : CPLErrorReset();
2758 :
2759 77 : if( psTree == NULL || psTree->eType != CXT_Element )
2760 : CPLError( CE_Failure, CPLE_AppDefined,
2761 0 : "Malformed element in GDALDeserializeTransformer" );
2762 77 : else if( EQUAL(psTree->pszValue,"GenImgProjTransformer") )
2763 : {
2764 45 : *ppfnFunc = GDALGenImgProjTransform;
2765 45 : *ppTransformArg = GDALDeserializeGenImgProjTransformer( psTree );
2766 : }
2767 32 : else if( EQUAL(psTree->pszValue,"ReprojectionTransformer") )
2768 : {
2769 8 : *ppfnFunc = GDALReprojectionTransform;
2770 8 : *ppTransformArg = GDALDeserializeReprojectionTransformer( psTree );
2771 : }
2772 24 : else if( EQUAL(psTree->pszValue,"GCPTransformer") )
2773 : {
2774 0 : *ppfnFunc = GDALGCPTransform;
2775 0 : *ppTransformArg = GDALDeserializeGCPTransformer( psTree );
2776 : }
2777 24 : else if( EQUAL(psTree->pszValue,"TPSTransformer") )
2778 : {
2779 0 : *ppfnFunc = GDALTPSTransform;
2780 0 : *ppTransformArg = GDALDeserializeTPSTransformer( psTree );
2781 : }
2782 24 : else if( EQUAL(psTree->pszValue,"GeoLocTransformer") )
2783 : {
2784 0 : *ppfnFunc = GDALGeoLocTransform;
2785 0 : *ppTransformArg = GDALDeserializeGeoLocTransformer( psTree );
2786 : }
2787 24 : else if( EQUAL(psTree->pszValue,"RPCTransformer") )
2788 : {
2789 0 : *ppfnFunc = GDALRPCTransform;
2790 0 : *ppTransformArg = GDALDeserializeRPCTransformer( psTree );
2791 : }
2792 24 : else if( EQUAL(psTree->pszValue,"ApproxTransformer") )
2793 : {
2794 24 : *ppfnFunc = GDALApproxTransform;
2795 24 : *ppTransformArg = GDALDeserializeApproxTransformer( psTree );
2796 : }
2797 : else
2798 : {
2799 0 : GDALTransformDeserializeFunc pfnDeserializeFunc = NULL;
2800 : {
2801 0 : CPLMutexHolderD(&hDeserializerMutex);
2802 0 : CPLList* psList = psListDeserializer;
2803 0 : while(psList)
2804 : {
2805 : TransformDeserializerInfo* psInfo =
2806 0 : (TransformDeserializerInfo*)psList->pData;
2807 0 : if (strcmp(psInfo->pszTransformName, psTree->pszValue) == 0)
2808 : {
2809 0 : *ppfnFunc = psInfo->pfnTransformerFunc;
2810 0 : pfnDeserializeFunc = psInfo->pfnDeserializeFunc;
2811 0 : break;
2812 : }
2813 0 : psList = psList->psNext;
2814 0 : }
2815 : }
2816 :
2817 0 : if (pfnDeserializeFunc != NULL)
2818 : {
2819 0 : *ppTransformArg = pfnDeserializeFunc( psTree );
2820 : }
2821 : else
2822 : {
2823 : CPLError( CE_Failure, CPLE_AppDefined,
2824 : "Unrecognised element '%s' GDALDeserializeTransformer",
2825 0 : psTree->pszValue );
2826 : }
2827 : }
2828 :
2829 77 : return CPLGetLastErrorType();
2830 : }
2831 :
2832 : /************************************************************************/
2833 : /* GDALDestroyTransformer() */
2834 : /************************************************************************/
2835 :
2836 125 : void GDALDestroyTransformer( void *pTransformArg )
2837 :
2838 : {
2839 125 : GDALTransformerInfo *psInfo = (GDALTransformerInfo *) pTransformArg;
2840 :
2841 125 : if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
2842 : {
2843 : CPLError( CE_Failure, CPLE_AppDefined,
2844 0 : "Attempt to destroy non-GTI transformer." );
2845 : }
2846 : else
2847 125 : psInfo->pfnCleanup( pTransformArg );
2848 125 : }
2849 :
2850 : /************************************************************************/
2851 : /* GDALUseTransformer() */
2852 : /************************************************************************/
2853 :
2854 19 : int GDALUseTransformer( void *pTransformArg,
2855 : int bDstToSrc, int nPointCount,
2856 : double *x, double *y, double *z,
2857 : int *panSuccess )
2858 : {
2859 19 : GDALTransformerInfo *psInfo = (GDALTransformerInfo *) pTransformArg;
2860 :
2861 19 : if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
2862 : {
2863 : CPLError( CE_Failure, CPLE_AppDefined,
2864 0 : "Attempt to use non-GTI transformer." );
2865 0 : return FALSE;
2866 : }
2867 : else
2868 : return psInfo->pfnTransform( pTransformArg, bDstToSrc, nPointCount,
2869 19 : x, y, z, panSuccess );
2870 : }
2871 :
2872 : /************************************************************************/
2873 : /* GDALCloneTransformer() */
2874 : /************************************************************************/
2875 :
2876 : /* TODO GDAL 2.0 : use a void* (*pfnClone) (void *) member */
2877 24 : void *GDALCloneTransformer( void *pTransformArg )
2878 : {
2879 24 : VALIDATE_POINTER1( pTransformArg, "GDALCloneTransformer", NULL );
2880 :
2881 24 : GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
2882 :
2883 24 : if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
2884 : {
2885 : CPLError( CE_Failure, CPLE_AppDefined,
2886 0 : "Attempt to clone non-GTI transformer." );
2887 0 : return NULL;
2888 : }
2889 :
2890 24 : void* (*pfnClone)(void*) = NULL;
2891 24 : if( EQUAL(psInfo->pszClassName,"GDALTPSTransformer") )
2892 : {
2893 0 : pfnClone = GDALCloneTPSTransformer;
2894 : }
2895 : /* TODO
2896 : else if( EQUAL(psInfo->pszClassName,"GDALGeoLocTransformer") )
2897 : {
2898 : pfnClone = GDALCloneGeoLocTransformer;
2899 : }
2900 : else if( EQUAL(psInfo->pszClassName,"GDALRPCTransformer") )
2901 : {
2902 : pfnClone = GDALCloneRPCTransformer;
2903 : }
2904 : */
2905 24 : else if( EQUAL(psInfo->pszClassName,"GDALGenImgProjTransformer") )
2906 : {
2907 8 : pfnClone = GDALCloneGenImgProjTransformer;
2908 : }
2909 : /* Useless : serialization/deserialization is fine */
2910 : /*
2911 : else if( EQUAL(psInfo->pszClassName,"GDALReprojectionTransformer") )
2912 : {
2913 : pfnClone = GDALCloneReprojectionTransformer;
2914 : }
2915 : */
2916 16 : else if( EQUAL(psInfo->pszClassName,"GDALApproxTransformer") )
2917 : {
2918 8 : pfnClone = GDALCloneApproxTransformer;
2919 : }
2920 :
2921 24 : if( pfnClone != NULL )
2922 : {
2923 16 : void* pRet = pfnClone(pTransformArg);
2924 16 : if( pRet != NULL )
2925 16 : return pRet;
2926 : }
2927 :
2928 8 : if ( psInfo->pfnSerialize == NULL )
2929 : {
2930 : CPLError( CE_Failure, CPLE_AppDefined,
2931 0 : "No serialization function available for this transformer." );
2932 0 : return NULL;
2933 : }
2934 : else
2935 : {
2936 8 : CPLXMLNode* pSerialized = psInfo->pfnSerialize( pTransformArg );
2937 8 : if( pSerialized == NULL )
2938 0 : return NULL;
2939 8 : GDALTransformerFunc pfnTransformer = NULL;
2940 8 : void *pClonedTransformArg = NULL;
2941 8 : if( GDALDeserializeTransformer( pSerialized, &pfnTransformer, &pClonedTransformArg ) !=
2942 : CE_None )
2943 : {
2944 0 : CPLDestroyXMLNode(pSerialized);
2945 0 : return NULL;
2946 : }
2947 8 : CPLDestroyXMLNode(pSerialized);
2948 8 : return pClonedTransformArg;
2949 : }
2950 : }
|