123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- /***********************************************************************
- orthorot.c
- written by: Markus Metz
- loosely based on crs3d.c
- 2D/3D Transformation with orthogonal rotation
- ************************************************************************/
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- #include <limits.h>
- #include <grass/gis.h>
- #include <grass/gmath.h>
- #include <grass/imagery.h>
- #include <grass/glocale.h>
- #include "crs.h"
- #define MSUCCESS 1 /* SUCCESS */
- #define MNPTERR 0 /* NOT ENOUGH POINTS */
- #define MUNSOLVABLE -1 /* NOT SOLVABLE */
- #define MMEMERR -2 /* NOT ENOUGH MEMORY */
- #define MPARMERR -3 /* PARAMETER ERROR */
- #define MINTERR -4 /* INTERNAL ERROR */
- /***********************************************************************
- FUNCTION PROTOTYPES FOR STATIC (INTERNAL) FUNCTIONS
- ************************************************************************/
- static int calccoef(struct Control_Points_3D *, double *, int);
- static int calcscale(struct Control_Points_3D *, double *);
- void transpose_matrix(int, int, double **, double **);
- void matmult(int, int, int, double **, double **, double **);
- void copy_matrix(int, int, double **, double **);
- void init_matrix(int, int, double **);
- void scale_matrix(int, int, double, double **, double **);
- void matrix_multiply(int, int, double **, double *, double *);
- void subtract_matrix(int, int, double **, double **, double **);
- double trace(int, int, double **);
- /***********************************************************************
- TRANSFORM A SINGLE COORDINATE PAIR.
- ************************************************************************/
- int CRS_georef_or(double e1, /* EASTING TO BE TRANSFORMED */
- double n1, /* NORTHING TO BE TRANSFORMED */
- double z1, /* HEIGHT TO BE TRANSFORMED */
- double *e, /* EASTING, TRANSFORMED */
- double *n, /* NORTHING, TRANSFORMED */
- double *z, /* HEIGHT, TRANSFORMED */
- double OR[] /* TRANSFORMATION COEFFICIENTS */
- )
- {
- *e = OR[9] + OR[12] * (OR[0] * e1 + OR[1] * n1 + OR[2] * z1);
- *n = OR[10] + OR[13] * (OR[3] * e1 + OR[4] * n1 + OR[5] * z1);
- *z = OR[11] + OR[14] * (OR[6] * e1 + OR[7] * n1 + OR[8] * z1);
- return MSUCCESS;
- }
- /***********************************************************************
- COMPUTE THE FORWARD AND BACKWARD GEOREFFERENCING COEFFICIENTS
- BASED ON A SET OF CONTROL POINTS
-
- ORTHOGONAL TRANSFORMATION (ORTHOGONAL ROTATION MATRIX)
-
- Rotation matrix
- OR[0] OR[1] OR[2]
- OR[3] OR[4] OR[5]
- OR[6] OR[7] OR[8]
- OR[9] x shift
- OR[10] y shift
- OR[11] z shift
- OR[12] x or global scale
- OR[13] y scale
- OR[14] z scale
- ************************************************************************/
- int CRS_compute_georef_equations_or(struct Control_Points_3D *cp,
- double OR12[], double OR21[])
- {
- double *tempptr, *OR;
- int status, i, numactive;
- struct Control_Points_3D cpc, /* center points */
- cpr; /* reduced to center */
- cpc.count = 1;
- cpc.e1 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.e2 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.n1 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.n2 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.z1 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.z2 = (double *)G_calloc(cpc.count, sizeof(double));
- cpc.status = (int *)G_calloc(cpc.count, sizeof(int));
- cpc.e1[0] = 0.0;
- cpc.e2[0] = 0.0;
- cpc.n1[0] = 0.0;
- cpc.n2[0] = 0.0;
- cpc.z1[0] = 0.0;
- cpc.z2[0] = 0.0;
- cpc.status[0] = 1;
- /* center points */
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- numactive++;
- cpc.e1[0] += cp->e1[i];
- cpc.e2[0] += cp->e2[i];
- cpc.n1[0] += cp->n1[i];
- cpc.n2[0] += cp->n2[i];
- cpc.z1[0] += cp->z1[i];
- cpc.z2[0] += cp->z2[i];
- }
- }
- /* this version of 3D transformation needs 3 control points */
- if (numactive < 3)
- return MNPTERR;
- cpc.e1[0] /= numactive;
- cpc.e2[0] /= numactive;
- cpc.n1[0] /= numactive;
- cpc.n2[0] /= numactive;
- cpc.z1[0] /= numactive;
- cpc.z2[0] /= numactive;
- /* shift to center points */
- cpr.count = numactive;
- cpr.e1 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.e2 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.n1 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.n2 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.z1 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.z2 = (double *)G_calloc(cpr.count, sizeof(double));
- cpr.status = (int *)G_calloc(cpr.count, sizeof(int));
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- cpr.e1[numactive] = cp->e1[i] - cpc.e1[0];
- cpr.e2[numactive] = cp->e2[i] - cpc.e2[0];
- cpr.n1[numactive] = cp->n1[i] - cpc.n1[0];
- cpr.n2[numactive] = cp->n2[i] - cpc.n2[0];
- cpr.z1[numactive] = cp->z1[i] - cpc.z1[0];
- cpr.z2[numactive] = cp->z2[i] - cpc.z2[0];
- cpr.status[numactive] = 1;
- numactive++;
- }
- }
-
- /* CALCULATE THE FORWARD TRANSFORMATION COEFFICIENTS */
- OR = OR12;
- status = calccoef(&cpr, OR, 3);
- calcscale(&cpr, OR);
- /* CALCULATE FORWARD SHIFTS */
- OR[9] = OR[10] = OR[11] = 0.0;
-
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- OR[9] += cp->e2[i] - OR[12] *
- (OR[0] * cp->e1[i] +
- OR[1] * cp->n1[i] +
- OR[2] * cp->z1[i]);
- OR[10] += cp->n2[i] - OR[13] *
- (OR[3] * cp->e1[i] +
- OR[4] * cp->n1[i] +
- OR[5] * cp->z1[i]);
- OR[11] += cp->z2[i] - OR[14] *
- (OR[6] * cp->e1[i] +
- OR[7] * cp->n1[i] +
- OR[8] * cp->z1[i]);
-
- numactive++;
- }
- }
- OR[9] /= numactive;
- OR[10] /= numactive;
- OR[11] /= numactive;
-
- /* SWITCH THE 1 AND 2 EASTING, NORTHING, AND HEIGHT ARRAYS */
- tempptr = cpr.e1;
- cpr.e1 = cpr.e2;
- cpr.e2 = tempptr;
- tempptr = cpr.n1;
- cpr.n1 = cpr.n2;
- cpr.n2 = tempptr;
- tempptr = cpr.z1;
- cpr.z1 = cpr.z2;
- cpr.z2 = tempptr;
- /* CALCULATE THE BACKWARD TRANSFORMATION COEFFICIENTS */
- OR = OR21;
- status = calccoef(&cpr, OR, 3);
- if (status != MSUCCESS)
- return status;
- calcscale(&cpr, OR);
- /* SWITCH THE 1 AND 2 EASTING, NORTHING, AND HEIGHT ARRAYS BACK */
- tempptr = cpr.e1;
- cpr.e1 = cpr.e2;
- cpr.e2 = tempptr;
- tempptr = cpr.n1;
- cpr.n1 = cpr.n2;
- cpr.n2 = tempptr;
- tempptr = cpr.z1;
- cpr.z1 = cpr.z2;
- cpr.z2 = tempptr;
- /* CALCULATE BACKWARD SHIFTS */
- OR[9] = OR[10] = OR[11] = 0.0;
-
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- OR[9] += cp->e1[i] - OR[12] *
- (OR[0] * cp->e2[i] +
- OR[1] * cp->n2[i] +
- OR[2] * cp->z2[i]);
- OR[10] += cp->n1[i] - OR[13] *
- (OR[3] * cp->e2[i] +
- OR[4] * cp->n2[i] +
- OR[5] * cp->z2[i]);
- OR[11] += cp->z1[i] - OR[14] *
- (OR[6] * cp->e2[i] +
- OR[7] * cp->n2[i] +
- OR[8] * cp->z2[i]);
- numactive++;
- }
- }
- OR[9] /= numactive;
- OR[10] /= numactive;
- OR[11] /= numactive;
-
- OR = OR12;
- G_debug(1, "********************************");
- G_debug(1, "Forward transformation:");
- G_debug(1, "Orthogonal rotation matrix:");
- G_debug(1, "%.4f %.4f %.4f", OR[0], OR[1], OR[2]);
- G_debug(1, "%.4f %.4f %.4f", OR[3], OR[4], OR[5]);
- G_debug(1, "%.4f %.4f %.4f", OR[6], OR[7], OR[8]);
- G_debug(1, "x, y, z shift: %.4f %.4f %.4f", OR[9], OR[10], OR[11]);
- G_debug(1, "x, y, z scale: %.4f %.4f %.4f", OR[12], OR[13], OR[14]);
- OR = OR21;
- G_debug(1, "********************************");
- G_debug(1, "Backward transformation:");
- G_debug(1, "Orthogonal rotation matrix:");
- G_debug(1, "%.4f %.4f %.4f", OR[0], OR[1], OR[2]);
- G_debug(1, "%.4f %.4f %.4f", OR[3], OR[4], OR[5]);
- G_debug(1, "%.4f %.4f %.4f", OR[6], OR[7], OR[8]);
- G_debug(1, "x, y, z shift: %.4f %.4f %.4f", OR[9], OR[10], OR[11]);
- G_debug(1, "x, y, z scale: %.4f %.4f %.4f", OR[12], OR[13], OR[14]);
- return status;
- }
- /***********************************************************************
- COMPUTE THE GEOREFFERENCING COEFFICIENTS
- BASED ON A SET OF CONTROL POINTS
- ************************************************************************/
- static int calccoef(struct Control_Points_3D *cp, double OR[], int ndims)
- {
- double **src_mat = NULL;
- double **src_mat_T = NULL;
- double **dest_mat = NULL;
- double **dest_mat_T = NULL;
- double **src_dest_mat = NULL;
- double *S_vec = NULL;
- double **R_mat = NULL;
- double **R_mat_T = NULL;
- double **mat_mn1 = NULL;
- double **mat_mn2 = NULL;
- double **mat_nm1 = NULL;
- double **mat_nm2 = NULL;
- double **mat_nn1 = NULL;
- double **E_mat = NULL;
- double **P_mat = NULL;
- double **Q_mat = NULL;
- double *D_vec = NULL;
- double *one_vec = NULL;
- double trace1 = 0.0;
- double trace2 = 0.0;
- int numactive; /* NUMBER OF ACTIVE CONTROL POINTS */
- int m, n, i, j;
- int status;
- /* CALCULATE THE NUMBER OF VALID CONTROL POINTS */
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0)
- numactive++;
- }
- m = numactive;
- n = ndims;
- src_mat = G_alloc_matrix(m, n);
- dest_mat = G_alloc_matrix(m, n);
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- src_mat[numactive][0] = cp->e1[i];
- src_mat[numactive][1] = cp->n1[i];
- src_mat[numactive][2] = cp->z1[i];
- dest_mat[numactive][0] = cp->e2[i];
- dest_mat[numactive][1] = cp->n2[i];
- dest_mat[numactive][2] = cp->z2[i];
- numactive++;
- }
- }
- D_vec = G_alloc_vector(ndims);
- src_mat_T = G_alloc_matrix(n, m);
- dest_mat_T = G_alloc_matrix(n, m);
- src_dest_mat = G_alloc_matrix(n, n);
- R_mat = G_alloc_matrix(n, n);
- R_mat_T = G_alloc_matrix(n, n);
- mat_mn1 = G_alloc_matrix(m, n);
- mat_mn2 = G_alloc_matrix(m, n);
- mat_nm1 = G_alloc_matrix(n, m);
- mat_nm2 = G_alloc_matrix(n, m);
- mat_nn1 = G_alloc_matrix(n, n);
- E_mat = G_alloc_matrix(m, m);
- P_mat = G_alloc_matrix(ndims, ndims);
- Q_mat = G_alloc_matrix(ndims, ndims);
- transpose_matrix(m, n, dest_mat, dest_mat_T);
- for (i = 0; i < m; i++) {
- for (j = 0; j < m; j++) {
- if (i != j) {
- E_mat[i][j] = -1.0 / (double)m;
- }
- else{
- E_mat[i][j] = 1.0 - 1.0 / (double)m;
- }
- }
- }
- matmult(n, m, m, dest_mat_T, E_mat, mat_nm1);
- matmult(n, m, n, mat_nm1, src_mat, src_dest_mat);
- copy_matrix(n, n, src_dest_mat, P_mat);
- copy_matrix(n, n, src_dest_mat, mat_nn1);
- status = G_math_svduv(D_vec, mat_nn1, P_mat, n, Q_mat, n);
- if (status == 0)
- status = MSUCCESS;
- transpose_matrix(n, n, P_mat, mat_nn1);
- /* rotation matrix */
- matmult(n, n, n, Q_mat, mat_nn1, R_mat_T);
- transpose_matrix(n, n, R_mat_T, R_mat);
- /* scale */
- matmult(n, n, n, src_dest_mat, R_mat_T, mat_nn1);
- trace1 = trace(n, n, mat_nn1);
- transpose_matrix(m, n, src_mat, src_mat_T);
- matmult(n, m, m, src_mat_T, E_mat, mat_nm1);
- matmult(n, m, n, mat_nm1, src_mat, mat_nn1);
- trace2 = trace(n, n, mat_nn1);
- OR[14] = trace1 / trace2;
- /* shifts */
- matmult(m, n, n, src_mat, R_mat_T, mat_mn1);
- scale_matrix(m, n, OR[14], mat_mn1, mat_mn2);
- subtract_matrix(m, n, dest_mat, mat_mn2, mat_mn1);
- scale_matrix(m, n, 1.0 / m, mat_mn1, mat_mn2);
- transpose_matrix(m, n, mat_mn2, mat_nm1);
- S_vec = G_alloc_vector(n);
- one_vec = G_alloc_vector(m);
- for (i = 0; i < m; i++){
- one_vec[i] = 1.0;
- }
- matrix_multiply(n, m, mat_nm1, one_vec, S_vec);
- /* matrix to vector */
- for (i = 0; i < ndims; i++) {
- for (j = 0; j < ndims; j++) {
- OR[i * ndims + j] = R_mat[i][j];
- }
- }
-
- G_free_matrix(src_mat);
- G_free_matrix(src_mat_T);
- G_free_matrix(dest_mat);
- G_free_matrix(dest_mat_T);
- G_free_matrix(src_dest_mat);
- G_free_vector(D_vec);
- G_free_matrix(E_mat);
- G_free_matrix(P_mat);
- G_free_matrix(Q_mat);
- G_free_matrix(R_mat);
- G_free_matrix(R_mat_T);
- G_free_matrix(mat_mn1);
- G_free_matrix(mat_mn2);
- G_free_matrix(mat_nm1);
- G_free_matrix(mat_nm2);
- G_free_matrix(mat_nn1);
- G_free_vector(S_vec);
- G_free_vector(one_vec);
- return status;
- }
- /***********************************************************************
- CALCULATE SCALE
- ************************************************************************/
- static int calcscale(struct Control_Points_3D *cp, double OR[])
- {
- double sumX, sumY, sumsqX, sumsqY, sumXY;
- int numactive; /* NUMBER OF ACTIVE CONTROL POINTS */
- int i;
- /* CALCULATE SCALE */
- sumX = sumY = sumsqX = sumsqY = sumXY = 0.0;
-
- for (i = numactive = 0; i < cp->count; i++) {
- if (cp->status[i] > 0) {
- double c1, c2;
-
- c1 = OR[0] * cp->e1[i] + OR[1] * cp->n1[i] + OR[2] * cp->z1[i];
- c2 = cp->e2[i];
- sumX += c1;
- sumY += c2;
- sumsqX += c1 * c1;
- sumsqY += c2 * c2;
- sumXY += c1 * c2;
- c1 = OR[3] * cp->e1[i] + OR[4] * cp->n1[i] + OR[5] * cp->z1[i];
- c2 = cp->n2[i];
- sumX += c1;
- sumY += c2;
- sumsqX += c1 * c1;
- sumsqY += c2 * c2;
- sumXY += c1 * c2;
- c1 = OR[6] * cp->e1[i] + OR[7] * cp->n1[i] + OR[8] * cp->z1[i];
- c2 = cp->z2[i];
- sumX += c1;
- sumY += c2;
- sumsqX += c1 * c1;
- sumsqY += c2 * c2;
- sumXY += c1 * c2;
-
- numactive++;
- }
- }
- OR[12] = (sumXY - sumX * sumY / numactive) /
- (sumsqX - sumX * sumX / numactive);
-
- if (fabs(OR[12] - OR[14]) > 10 * GRASS_EPSILON) {
- G_debug(1, "Scale mismatch: %.4f %.4f", OR[12], OR[14]);
- OR[12] = OR[14];
- }
- OR[13] = OR[14] = OR[12];
- return MSUCCESS;
- }
- void transpose_matrix(int m, int n, double **src_matrix, double **dest_matrix)
- {
- int i, j;
- for(i = 0; i < m; i++) {
- for(j = 0; j < n; j++) {
- dest_matrix[j][i] = src_matrix[i][j];
- }
- }
- }
- void matmult(int m, int n, int p, double **mat1, double **mat2, double **mat3)
- {
- int i, j, k;
- double sum;
- /* input mat1: m x n */
- /* input mat2: n x p */
- /* output mat3: m x p */
- for (i = 0; i < m; i++) {
- for (j = 0; j < p; j++) {
- sum = 0.0;
- for (k = 0; k < n; k++) {
- sum += mat1[i][k] * mat2[k][j];
- }
- mat3[i][j] = sum;
- }
- }
- }
- void copy_matrix(int n, int m, double **src_matrix, double **dest_matrix)
- {
- int i, j;
- for (i = 0; i < n; i++) {
- for (j = 0; j < m; j++) {
- dest_matrix[i][j] = src_matrix[i][j];
- }
- }
- }
- double trace(int n, int m, double **matrix)
- {
- int i;
- double t = 0.0;
- for (i = 0; i < n; i++) {
- t += matrix[i][i];
- }
- return t;
- }
- void init_matrix(int n, int m, double **matrix)
- {
- int i, j;
- for (i = 0; i < n; i++) {
- for (j = 0; j < m; j++) {
- matrix[i][j] = 0.0;
- }
- }
- }
- void scale_matrix(int n, int m, double scal, double **src_matrix,
- double **dest_matrix)
- {
- int i, j;
- for (i = 0; i < n; i++) {
- for (j = 0; j < m; j++) {
- dest_matrix[i][j] = scal * src_matrix[i][j];
- }
- }
- }
- void subtract_matrix(int n, int m, double **mat1, double **mat2,
- double **mat3)
- {
- int i, j;
- for (i = 0; i < n; i++) {
- for (j = 0; j < m; j++) {
- mat3[i][j] = mat1[i][j] - mat2[i][j];
- }
- }
- }
- void matrix_multiply(int n, int m, double **mat, double *iv,
- double *ov)
- {
- int i, j;
- for (i = 0; i < n; i++) {
- ov[i] = 0.0;
- for(j = 0; j < m; j++) {
- ov[i] += mat[i][j] * iv[j];
- }
- }
- }
|