GRASS 8 Programmer's Manual 8.6.0dev(2026)-c83afef6d3
Loading...
Searching...
No Matches
georef.c
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * MODULE: imagery library
4 * AUTHOR(S): Original author(s) name(s) unknown - written by CERL
5 * Written By: Brian J. Buckley
6 *
7 * At: The Center for Remote Sensing
8 * Michigan State University
9 *
10 * PURPOSE: Image processing library
11 * SPDX-FileCopyrightText: 1999, 2005 GRASS Development Team
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 *
14 *****************************************************************************/
15
16/*
17 * Written: 12/19/91
18 *
19 * Last Update: 12/26/91 Brian J. Buckley
20 * Last Update: 1/24/92 Brian J. Buckley
21 * Added printout of trnfile. Triggered by BDEBUG.
22 * Last Update: 1/27/92 Brian J. Buckley
23 * Fixed bug so that only the active control points were used.
24 *
25 */
26
27#include <stdlib.h>
28#include <math.h>
29#include <grass/gis.h>
30#include <grass/imagery.h>
31#include <signal.h>
32
33/* STRUCTURE FOR USE INTERNALLY WITH THESE FUNCTIONS. THESE FUNCTIONS EXPECT
34 SQUARE MATRICES SO ONLY ONE VARIABLE IS GIVEN (N) FOR THE MATRIX SIZE */
35
36struct MATRIX {
37 int n; /* SIZE OF THIS MATRIX (N x N) */
38 double *v;
39};
40
41/* CALCULATE OFFSET INTO ARRAY BASED ON R/C */
42
43#define M(row, col) m->v[(((row) - 1) * (m->n)) + (col) - 1]
44
45#define MSUCCESS 1 /* SUCCESS */
46#define MNPTERR 0 /* NOT ENOUGH POINTS */
47#define MUNSOLVABLE -1 /* NOT SOLVABLE */
48#define MMEMERR -2 /* NOT ENOUGH MEMORY */
49#define MPARMERR -3 /* PARAMETER ERROR */
50#define MINTERR -4 /* INTERNAL ERROR */
51
52#define MAXORDER 3 /* HIGHEST SUPPORTED ORDER OF TRANSFORMATION */
53
54/***********************************************************************
55
56 FUNCTION PROTOTYPES FOR STATIC (INTERNAL) FUNCTIONS
57
58************************************************************************/
59
60static int calccoef(struct Control_Points *, double *, double *, int);
61static int calcls(struct Control_Points *, struct MATRIX *, double *, double *,
62 double *, double *);
63static int exactdet(struct Control_Points *, struct MATRIX *, double *,
64 double *, double *, double *);
65static int solvemat(struct MATRIX *, double *, double *, double *, double *);
66static double term(int, double, double);
67
68/***********************************************************************
69
70 TRANSFORM A SINGLE COORDINATE PAIR.
71
72************************************************************************/
73
74int I_georef(double e1, /* EASTING TO BE TRANSFORMED */
75 double n1, /* NORTHING TO BE TRANSFORMED */
76 double *e, /* EASTING, TRANSFORMED */
77 double *n, /* NORTHING, TRANSFORMED */
78 double E[], /* EASTING COEFFICIENTS */
79 double N[], /* NORTHING COEFFICIENTS */
80 int order /* ORDER OF TRANSFORMATION TO BE PERFORMED, MUST MATCH
81 THE ORDER USED TO CALCULATE THE COEFFICIENTS */
82)
83{
84 double e3, e2n, en2, n3, e2, en, n2;
85
86 switch (order) {
87 case 1:
88 *e = E[0] + E[1] * e1 + E[2] * n1;
89 *n = N[0] + N[1] * e1 + N[2] * n1;
90 break;
91
92 case 2:
93 e2 = e1 * e1;
94 n2 = n1 * n1;
95 en = e1 * n1;
96
97 *e = E[0] + E[1] * e1 + E[2] * n1 + E[3] * e2 + E[4] * en + E[5] * n2;
98 *n = N[0] + N[1] * e1 + N[2] * n1 + N[3] * e2 + N[4] * en + N[5] * n2;
99 break;
100
101 case 3:
102 e2 = e1 * e1;
103 en = e1 * n1;
104 n2 = n1 * n1;
105 e3 = e1 * e2;
106 e2n = e2 * n1;
107 en2 = e1 * n2;
108 n3 = n1 * n2;
109
110 *e = E[0] + E[1] * e1 + E[2] * n1 + E[3] * e2 + E[4] * en + E[5] * n2 +
111 E[6] * e3 + E[7] * e2n + E[8] * en2 + E[9] * n3;
112 *n = N[0] + N[1] * e1 + N[2] * n1 + N[3] * e2 + N[4] * en + N[5] * n2 +
113 N[6] * e3 + N[7] * e2n + N[8] * en2 + N[9] * n3;
114 break;
115
116 default:
117 return MPARMERR;
118 }
119
120 return MSUCCESS;
121}
122
123/***********************************************************************
124
125 COMPUTE THE FORWARD AND BACKWARD GEOREFFERENCING COEFFICIENTS
126 BASED ON A SET OF CONTROL POINTS
127
128************************************************************************/
129
131 double N12[], double E21[], double N21[],
132 int order)
133{
134 double *tempptr;
135 int status;
136
138 return MPARMERR;
139
140 /* CALCULATE THE FORWARD TRANSFORMATION COEFFICIENTS */
141
142 status = calccoef(cp, E12, N12, order);
143
144 if (status != MSUCCESS)
145 return status;
146
147 /* SWITCH THE 1 AND 2 EASTING AND NORTHING ARRAYS */
148
149 tempptr = cp->e1;
150 cp->e1 = cp->e2;
151 cp->e2 = tempptr;
152 tempptr = cp->n1;
153 cp->n1 = cp->n2;
154 cp->n2 = tempptr;
155
156 /* CALCULATE THE BACKWARD TRANSFORMATION COEFFICIENTS */
157
158 status = calccoef(cp, E21, N21, order);
159
160 /* SWITCH THE 1 AND 2 EASTING AND NORTHING ARRAYS BACK */
161
162 tempptr = cp->e1;
163 cp->e1 = cp->e2;
164 cp->e2 = tempptr;
165 tempptr = cp->n1;
166 cp->n1 = cp->n2;
167 cp->n2 = tempptr;
168
169 return status;
170}
171
172/***********************************************************************
173
174 COMPUTE THE GEOREFFERENCING COEFFICIENTS
175 BASED ON A SET OF CONTROL POINTS
176
177************************************************************************/
178
179static int calccoef(struct Control_Points *cp, double E[], double N[],
180 int order)
181{
182 struct MATRIX m;
183 double *a;
184 double *b;
185 int numactive; /* NUMBER OF ACTIVE CONTROL POINTS */
186 int status, i;
187
188 /* CALCULATE THE NUMBER OF VALID CONTROL POINTS */
189
190 for (i = numactive = 0; i < cp->count; i++) {
191 if (cp->status[i] > 0)
192 numactive++;
193 }
194
195 /* CALCULATE THE MINIMUM NUMBER OF CONTROL POINTS NEEDED TO DETERMINE
196 A TRANSFORMATION OF THIS ORDER */
197
198 m.n = ((order + 1) * (order + 2)) / 2;
199
200 if (numactive < m.n)
201 return MNPTERR;
202
203 /* INITIALIZE MATRIX */
204
205 m.v = G_calloc(m.n * m.n, sizeof(double));
206 a = G_calloc(m.n, sizeof(double));
207 b = G_calloc(m.n, sizeof(double));
208
209 if (numactive == m.n)
210 status = exactdet(cp, &m, a, b, E, N);
211 else
212 status = calcls(cp, &m, a, b, E, N);
213
214 G_free(m.v);
215 G_free(a);
216 G_free(b);
217
218 return status;
219}
220
221/***********************************************************************
222
223 CALCULATE THE TRANSFORMATION COEFFICIENTS WITH EXACTLY THE MINIMUM
224 NUMBER OF CONTROL POINTS REQUIRED FOR THIS TRANSFORMATION.
225
226************************************************************************/
227
228static int exactdet(struct Control_Points *cp, struct MATRIX *m, double a[],
229 double b[], double E[], /* EASTING COEFFICIENTS */
230 double N[] /* NORTHING COEFFICIENTS */
231)
232{
233 int pntnow, currow, j;
234
235 currow = 1;
236 for (pntnow = 0; pntnow < cp->count; pntnow++) {
237 if (cp->status[pntnow] > 0) {
238 /* POPULATE MATRIX M */
239
240 for (j = 1; j <= m->n; j++)
241 M(currow, j) = term(j, cp->e1[pntnow], cp->n1[pntnow]);
242
243 /* POPULATE MATRIX A AND B */
244
245 a[currow - 1] = cp->e2[pntnow];
246 b[currow - 1] = cp->n2[pntnow];
247
248 currow++;
249 }
250 }
251
252 if (currow - 1 != m->n)
253 return MINTERR;
254
255 return solvemat(m, a, b, E, N);
256}
257
258/***********************************************************************
259
260 CALCULATE THE TRANSFORMATION COEFFICIENTS WITH MORE THAN THE MINIMUM
261 NUMBER OF CONTROL POINTS REQUIRED FOR THIS TRANSFORMATION. THIS
262 ROUTINE USES THE LEAST SQUARES METHOD TO COMPUTE THE COEFFICIENTS.
263
264************************************************************************/
265
266static int calcls(struct Control_Points *cp, struct MATRIX *m, double a[],
267 double b[], double E[], /* EASTING COEFFICIENTS */
268 double N[] /* NORTHING COEFFICIENTS */
269)
270{
271 int i, j, n, numactive = 0;
272
273 /* INITIALIZE THE UPPER HALF OF THE MATRIX AND THE TWO COLUMN VECTORS */
274
275 for (i = 1; i <= m->n; i++) {
276 for (j = i; j <= m->n; j++)
277 M(i, j) = 0.0;
278 a[i - 1] = b[i - 1] = 0.0;
279 }
280
281 /* SUM THE UPPER HALF OF THE MATRIX AND THE COLUMN VECTORS ACCORDING TO
282 THE LEAST SQUARES METHOD OF SOLVING OVER DETERMINED SYSTEMS */
283
284 for (n = 0; n < cp->count; n++) {
285 if (cp->status[n] > 0) {
286 numactive++;
287 for (i = 1; i <= m->n; i++) {
288 for (j = i; j <= m->n; j++)
289 M(i, j) += term(i, cp->e1[n], cp->n1[n]) *
290 term(j, cp->e1[n], cp->n1[n]);
291
292 a[i - 1] += cp->e2[n] * term(i, cp->e1[n], cp->n1[n]);
293 b[i - 1] += cp->n2[n] * term(i, cp->e1[n], cp->n1[n]);
294 }
295 }
296 }
297
298 if (numactive <= m->n)
299 return MINTERR;
300
301 /* TRANSPOSE VALUES IN UPPER HALF OF M TO OTHER HALF */
302
303 for (i = 2; i <= m->n; i++)
304 for (j = 1; j < i; j++)
305 M(i, j) = M(j, i);
306
307 return solvemat(m, a, b, E, N);
308}
309
310/***********************************************************************
311
312 CALCULATE THE X/Y TERM BASED ON THE TERM NUMBER
313
314 ORDER\TERM 1 2 3 4 5 6 7 8 9 10
315 1 e0n0 e1n0 e0n1
316 2 e0n0 e1n0 e0n1 e2n0 e1n1 e0n2
317 3 e0n0 e1n0 e0n1 e2n0 e1n1 e0n2 e3n0 e2n1 e1n2 e0n3
318
319************************************************************************/
320
321static double term(int term, double e, double n)
322{
323 switch (term) {
324 case 1:
325 return 1.0;
326 case 2:
327 return e;
328 case 3:
329 return n;
330 case 4:
331 return e * e;
332 case 5:
333 return e * n;
334 case 6:
335 return n * n;
336 case 7:
337 return e * e * e;
338 case 8:
339 return e * e * n;
340 case 9:
341 return e * n * n;
342 case 10:
343 return n * n * n;
344 }
345
346 return 0.0;
347}
348
349/***********************************************************************
350
351 SOLVE FOR THE 'E' AND 'N' COEFFICIENTS BY USING A SOMEWHAT MODIFIED
352 GAUSSIAN ELIMINATION METHOD.
353
354 | M11 M12 ... M1n | | E0 | | a0 |
355 | M21 M22 ... M2n | | E1 | = | a1 |
356 | . . . . | | . | | . |
357 | Mn1 Mn2 ... Mnn | | En-1 | | an-1 |
358
359 and
360
361 | M11 M12 ... M1n | | N0 | | b0 |
362 | M21 M22 ... M2n | | N1 | = | b1 |
363 | . . . . | | . | | . |
364 | Mn1 Mn2 ... Mnn | | Nn-1 | | bn-1 |
365
366************************************************************************/
367
368static int solvemat(struct MATRIX *m, double a[], double b[], double E[],
369 double N[])
370{
371 int i, j, i2, j2, imark;
372 double factor, temp;
373 double pivot; /* ACTUAL VALUE OF THE LARGEST PIVOT CANDIDATE */
374
375 for (i = 1; i <= m->n; i++) {
376 j = i;
377
378 /* find row with largest magnitude value for pivot value */
379
380 pivot = M(i, j);
381 imark = i;
382 for (i2 = i + 1; i2 <= m->n; i2++) {
383 temp = fabs(M(i2, j));
384 if (temp > fabs(pivot)) {
385 pivot = M(i2, j);
386 imark = i2;
387 }
388 }
389
390 /* if the pivot is very small then the points are nearly co-linear */
391 /* co-linear points result in an undefined matrix, and nearly */
392 /* co-linear points results in a solution with rounding error */
393
394 if (pivot == 0.0)
395 return MUNSOLVABLE;
396
397 /* if row with highest pivot is not the current row, switch them */
398
399 if (imark != i) {
400 for (j2 = 1; j2 <= m->n; j2++) {
401 temp = M(imark, j2);
402 M(imark, j2) = M(i, j2);
403 M(i, j2) = temp;
404 }
405
406 temp = a[imark - 1];
407 a[imark - 1] = a[i - 1];
408 a[i - 1] = temp;
409
410 temp = b[imark - 1];
411 b[imark - 1] = b[i - 1];
412 b[i - 1] = temp;
413 }
414
415 /* compute zeros above and below the pivot, and compute
416 values for the rest of the row as well */
417
418 for (i2 = 1; i2 <= m->n; i2++) {
419 if (i2 != i) {
420 factor = M(i2, j) / pivot;
421 for (j2 = j; j2 <= m->n; j2++)
422 M(i2, j2) -= factor * M(i, j2);
423 a[i2 - 1] -= factor * a[i - 1];
424 b[i2 - 1] -= factor * b[i - 1];
425 }
426 }
427 }
428
429 /* SINCE ALL OTHER VALUES IN THE MATRIX ARE ZERO NOW, CALCULATE THE
430 COEFFICIENTS BY DIVIDING THE COLUMN VECTORS BY THE DIAGONAL VALUES. */
431
432 for (i = 1; i <= m->n; i++) {
433 E[i - 1] = a[i - 1] / M(i, i);
434 N[i - 1] = b[i - 1] / M(i, i);
435 }
436
437 return MSUCCESS;
438}
int order(int i_x, int i_y, int yNum)
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_calloc(m, n)
Definition defs/gis.h:137
#define N
int I_georef(double e1, double n1, double *e, double *n, double E[], double N[], int order)
Definition georef.c:74
#define MAXORDER
Definition georef.c:52
#define MNPTERR
Definition georef.c:46
int I_compute_georef_equations(struct Control_Points *cp, double E12[], double N12[], double E21[], double N21[], int order)
Definition georef.c:130
#define MINTERR
Definition georef.c:50
#define MSUCCESS
Definition georef.c:45
#define MPARMERR
Definition georef.c:49
#define MUNSOLVABLE
Definition georef.c:47
#define M(row, col)
Definition georef.c:43
double b
Definition r_raster.c:37