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