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