1 /******************************************************************************
2  * $Id: geo_trans.c 8e5eeb35bf76390e3134a4ea7076dab7d478ea0e 2018-11-14 22:55:13 +0100 Even Rouault $
3  *
4  * Project:  libgeotiff
5  * Purpose:  Code to abstract translation between pixel/line and PCS
6  *           coordinates.
7  * Author:   Frank Warmerdam, warmerda@home.com
8  *
9  ******************************************************************************
10  * Copyright (c) 1999, Frank Warmerdam
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  *****************************************************************************/
30 
31 #include "geotiff.h"
32 #include "geo_tiffp.h" /* external TIFF interface */
33 #include "geo_keyp.h"  /* private interface       */
34 #include "geokeys.h"
35 
36 /************************************************************************/
37 /*                          inv_geotransform()                          */
38 /*                                                                      */
39 /*      Invert a 6 term geotransform style matrix.                      */
40 /************************************************************************/
41 
inv_geotransform(double * gt_in,double * gt_out)42 static int inv_geotransform( double *gt_in, double *gt_out )
43 
44 {
45     double	det, inv_det;
46 
47     /* we assume a 3rd row that is [0 0 1] */
48 
49     /* Compute determinate */
50 
51     det = gt_in[0] * gt_in[4] - gt_in[1] * gt_in[3];
52 
53     if( fabs(det) < 0.000000000000001 )
54         return 0;
55 
56     inv_det = 1.0 / det;
57 
58     /* compute adjoint, and divide by determinate */
59 
60     gt_out[0] =  gt_in[4] * inv_det;
61     gt_out[3] = -gt_in[3] * inv_det;
62 
63     gt_out[1] = -gt_in[1] * inv_det;
64     gt_out[4] =  gt_in[0] * inv_det;
65 
66     gt_out[2] = ( gt_in[1] * gt_in[5] - gt_in[2] * gt_in[4]) * inv_det;
67     gt_out[5] = (-gt_in[0] * gt_in[5] + gt_in[2] * gt_in[3]) * inv_det;
68 
69     return 1;
70 }
71 
72 /************************************************************************/
73 /*                       GTIFTiepointTranslate()                        */
74 /************************************************************************/
75 
76 static
GTIFTiepointTranslate(int gcp_count,double * gcps_in,double * gcps_out,double x_in,double y_in,double * x_out,double * y_out)77 int GTIFTiepointTranslate( int gcp_count, double * gcps_in, double * gcps_out,
78                            double x_in, double y_in,
79                            double *x_out, double *y_out )
80 
81 {
82     (void) gcp_count;
83     (void) gcps_in;
84     (void) gcps_out;
85     (void) x_in;
86     (void) y_in;
87     (void) x_out;
88     (void) y_out;
89 
90     /* I would appreciate a _brief_ block of code for doing second order
91        polynomial regression here! */
92     return FALSE;
93 }
94 
95 
96 /************************************************************************/
97 /*                           GTIFImageToPCS()                           */
98 /************************************************************************/
99 
100 /**
101  * Translate a pixel/line coordinate to projection coordinates.
102  *
103  * At this time this function does not support image to PCS translations for
104  * tiepoints-only definitions,  only pixelscale and transformation matrix
105  * formulations.
106  *
107  * @param gtif The handle from GTIFNew() indicating the target file.
108  * @param x A pointer to the double containing the pixel offset on input,
109  * and into which the easting/longitude will be put on completion.
110  * @param y A pointer to the double containing the line offset on input,
111  * and into which the northing/latitude will be put on completion.
112  *
113  * @return TRUE if the transformation succeeds, or FALSE if it fails.  It may
114  * fail if the file doesn't have properly setup transformation information,
115  * or it is in a form unsupported by this function.
116  */
117 
GTIFImageToPCS(GTIF * gtif,double * x,double * y)118 int GTIFImageToPCS( GTIF *gtif, double *x, double *y )
119 
120 {
121     int     res = FALSE;
122     int     tiepoint_count, count, transform_count;
123     tiff_t *tif=gtif->gt_tif;
124     double *tiepoints   = 0;
125     double *pixel_scale = 0;
126     double *transform   = 0;
127 
128 
129     if (!(gtif->gt_methods.get)(tif, GTIFF_TIEPOINTS,
130                               &tiepoint_count, &tiepoints ))
131         tiepoint_count = 0;
132 
133     if (!(gtif->gt_methods.get)(tif, GTIFF_PIXELSCALE, &count, &pixel_scale ))
134         count = 0;
135 
136     if (!(gtif->gt_methods.get)(tif, GTIFF_TRANSMATRIX,
137                                 &transform_count, &transform ))
138         transform_count = 0;
139 
140 /* -------------------------------------------------------------------- */
141 /*      If the pixelscale count is zero, but we have tiepoints use      */
142 /*      the tiepoint based approach.                                    */
143 /* -------------------------------------------------------------------- */
144     if( tiepoint_count > 6 && count == 0 )
145     {
146         res = GTIFTiepointTranslate( tiepoint_count / 6,
147                                      tiepoints, tiepoints + 3,
148                                      *x, *y, x, y );
149     }
150 
151 /* -------------------------------------------------------------------- */
152 /*	If we have a transformation matrix, use it. 			*/
153 /* -------------------------------------------------------------------- */
154     else if( transform_count == 16 )
155     {
156         double x_in = *x, y_in = *y;
157 
158         *x = x_in * transform[0] + y_in * transform[1] + transform[3];
159         *y = x_in * transform[4] + y_in * transform[5] + transform[7];
160 
161         res = TRUE;
162     }
163 
164 /* -------------------------------------------------------------------- */
165 /*      For now we require one tie point, and a valid pixel scale.      */
166 /* -------------------------------------------------------------------- */
167     else if( count < 3 || tiepoint_count < 6 )
168     {
169         res = FALSE;
170     }
171 
172     else
173     {
174         *x = (*x - tiepoints[0]) * pixel_scale[0] + tiepoints[3];
175         *y = (*y - tiepoints[1]) * (-1 * pixel_scale[1]) + tiepoints[4];
176 
177         res = TRUE;
178     }
179 
180 /* -------------------------------------------------------------------- */
181 /*      Cleanup                                                         */
182 /* -------------------------------------------------------------------- */
183     if(tiepoints)
184         _GTIFFree(tiepoints);
185     if(pixel_scale)
186         _GTIFFree(pixel_scale);
187     if(transform)
188         _GTIFFree(transform);
189 
190     return res;
191 }
192 
193 /************************************************************************/
194 /*                           GTIFPCSToImage()                           */
195 /************************************************************************/
196 
197 /**
198  * Translate a projection coordinate to pixel/line coordinates.
199  *
200  * At this time this function does not support PCS to image translations for
201  * tiepoints-only based definitions, only matrix and pixelscale/tiepoints
202  * formulations are supposed.
203  *
204  * @param gtif The handle from GTIFNew() indicating the target file.
205  * @param x A pointer to the double containing the pixel offset on input,
206  * and into which the easting/longitude will be put on completion.
207  * @param y A pointer to the double containing the line offset on input,
208  * and into which the northing/latitude will be put on completion.
209  *
210  * @return TRUE if the transformation succeeds, or FALSE if it fails.  It may
211  * fail if the file doesn't have properly setup transformation information,
212  * or it is in a form unsupported by this function.
213  */
214 
GTIFPCSToImage(GTIF * gtif,double * x,double * y)215 int GTIFPCSToImage( GTIF *gtif, double *x, double *y )
216 
217 {
218     double 	*tiepoints = NULL;
219     int 	tiepoint_count, count, transform_count = 0;
220     double	*pixel_scale = NULL;
221     double 	*transform   = NULL;
222     tiff_t 	*tif=gtif->gt_tif;
223     int		result = FALSE;
224 
225 /* -------------------------------------------------------------------- */
226 /*      Fetch tiepoints and pixel scale.                                */
227 /* -------------------------------------------------------------------- */
228     if (!(gtif->gt_methods.get)(tif, GTIFF_TIEPOINTS,
229                               &tiepoint_count, &tiepoints ))
230         tiepoint_count = 0;
231 
232     if (!(gtif->gt_methods.get)(tif, GTIFF_PIXELSCALE, &count, &pixel_scale ))
233         count = 0;
234 
235     if (!(gtif->gt_methods.get)(tif, GTIFF_TRANSMATRIX,
236                                 &transform_count, &transform ))
237         transform_count = 0;
238 
239 /* -------------------------------------------------------------------- */
240 /*      If the pixelscale count is zero, but we have tiepoints use      */
241 /*      the tiepoint based approach.                                    */
242 /* -------------------------------------------------------------------- */
243     if( tiepoint_count > 6 && count == 0 )
244     {
245         result = GTIFTiepointTranslate( tiepoint_count / 6,
246                                         tiepoints + 3, tiepoints,
247                                         *x, *y, x, y );
248     }
249 
250 /* -------------------------------------------------------------------- */
251 /*      Handle matrix - convert to "geotransform" format, invert and    */
252 /*      apply.                                                          */
253 /* -------------------------------------------------------------------- */
254     else if( transform_count == 16 )
255     {
256         double  x_in = *x, y_in = *y;
257         double	gt_in[6], gt_out[6];
258 
259         gt_in[0] = transform[0];
260         gt_in[1] = transform[1];
261         gt_in[2] = transform[3];
262         gt_in[3] = transform[4];
263         gt_in[4] = transform[5];
264         gt_in[5] = transform[7];
265 
266         if( !inv_geotransform( gt_in, gt_out ) )
267             result = FALSE;
268         else
269         {
270             *x = x_in * gt_out[0] + y_in * gt_out[1] + gt_out[2];
271             *y = x_in * gt_out[3] + y_in * gt_out[4] + gt_out[5];
272 
273             result = TRUE;
274         }
275     }
276 
277 /* -------------------------------------------------------------------- */
278 /*      For now we require one tie point, and a valid pixel scale.      */
279 /* -------------------------------------------------------------------- */
280     else if( count >= 3 && tiepoint_count >= 6 )
281     {
282         *x = (*x - tiepoints[3]) / pixel_scale[0] + tiepoints[0];
283         *y = (*y - tiepoints[4]) / (-1 * pixel_scale[1]) + tiepoints[1];
284 
285         result = TRUE;
286     }
287 
288 /* -------------------------------------------------------------------- */
289 /*      Cleanup.                                                        */
290 /* -------------------------------------------------------------------- */
291     if(tiepoints)
292         _GTIFFree(tiepoints);
293     if(pixel_scale)
294         _GTIFFree(pixel_scale);
295     if(transform)
296         _GTIFFree(transform);
297 
298     return result;
299 }
300