#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#include "config-msvc.h"
#else
#include "config.h"
#endif
#ifdef ENABLE_GCP
#include "grass_crs.h"
#ifndef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#endif
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
static int calccoef (struct Control_Points *, double **, double **);
static int calcls (struct Control_Points *, struct MATRIX *, double *,
double *, double *, double *);
static double tps_base_func (const double x1, const double y1,
const double x2, const double y2);
static int solvemat (struct MATRIX *, double *, double *, double *, double *);
GCP_PRIVATE int
gcp_I_georef_tps (double e1,
double n1,
double *e,
double *n,
double *E,
double *N,
struct Control_Points *cp, int fwd)
{
int i, j;
double dist, *pe, *pn;
if (fwd)
{
pe = cp->e1;
pn = cp->n1;
}
else
{
pe = cp->e2;
pn = cp->n2;
}
*e = E[0] + e1 * E[1] + n1 * E[2];
*n = N[0] + e1 * N[1] + n1 * N[2];
for (i = 0, j = 0; i < cp->count; i++)
{
if (cp->status[i] > 0)
{
dist = tps_base_func (e1, n1, pe[i], pn[i]);
*e += E[j + 3] * dist;
*n += N[j + 3] * dist;
j++;
}
}
return MSUCCESS;
}
GCP_PRIVATE int
gcp_I_compute_georef_equations_tps (struct Control_Points *cp,
double **E12tps, double **N12tps,
double **E21tps, double **N21tps)
{
double *tempptr;
int numactive;
int status, i;
double xmax, xmin, ymax, ymin;
double delx, dely;
double xx, yy;
double sumx, sumy, sumx2, sumy2, sumxy;
double SSxx, SSyy, SSxy;
for (i = numactive = 0; i < cp->count; i++)
{
if (cp->status[i] > 0)
numactive++;
}
if (numactive < 3)
return MNPTERR;
if (numactive > 100000)
return MNPTERR;
xmin = xmax = cp->e1[0];
ymin = ymax = cp->n1[0];
sumx = sumy = sumx2 = sumy2 = sumxy = 0.0;
for (i = 0; i < cp->count; i++)
{
if (cp->status[i] > 0)
{
xx = cp->e1[i];
yy = cp->n1[i];
xmax = MAX (xmax, xx);
xmin = MIN (xmin, xx);
ymax = MAX (ymax, yy);
ymin = MIN (ymin, yy);
sumx += xx;
sumx2 += xx * xx;
sumy += yy;
sumy2 += yy * yy;
sumxy += xx * yy;
}
}
delx = xmax - xmin;
dely = ymax - ymin;
SSxx = sumx2 - sumx * sumx / numactive;
SSyy = sumy2 - sumy * sumy / numactive;
SSxy = sumxy - sumx * sumy / numactive;
if (delx < 0.001 * dely || dely < 0.001 * delx ||
fabs (SSxy * SSxy / (SSxx * SSyy)) > 0.99)
{
return MUNSOLVABLE;
}
xmin = xmax = cp->e2[0];
ymin = ymax = cp->n2[0];
sumx = sumy = sumx2 = sumy2 = sumxy = 0.0;
for (i = 0; i < cp->count; i++)
{
if (cp->status[i] > 0)
{
xx = cp->e2[i];
yy = cp->n2[i];
xmax = MAX (xmax, xx);
xmin = MIN (xmin, xx);
ymax = MAX (ymax, yy);
ymin = MIN (ymin, yy);
sumx += xx;
sumx2 += xx * xx;
sumy += yy;
sumy2 += yy * yy;
sumxy += xx * yy;
}
}
delx = xmax - xmin;
dely = ymax - ymin;
SSxx = sumx2 - sumx * sumx / numactive;
SSyy = sumy2 - sumy * sumy / numactive;
SSxy = sumxy - sumx * sumy / numactive;
if (delx < 0.001 * dely || dely < 0.001 * delx ||
fabs (SSxy * SSxy / (SSxx * SSyy)) > 0.99)
{
return MUNSOLVABLE;
}
status = calccoef (cp, E12tps, N12tps);
if (status != MSUCCESS)
return status;
tempptr = cp->e1;
cp->e1 = cp->e2;
cp->e2 = tempptr;
tempptr = cp->n1;
cp->n1 = cp->n2;
cp->n2 = tempptr;
status = calccoef (cp, E21tps, N21tps);
tempptr = cp->e1;
cp->e1 = cp->e2;
cp->e2 = tempptr;
tempptr = cp->n1;
cp->n1 = cp->n2;
cp->n2 = tempptr;
return status;
}
static int
calccoef (struct Control_Points *cp, double **E, double **N)
{
struct MATRIX m;
double *a;
double *b;
int numactive;
int status, i;
for (i = numactive = 0; i < cp->count; i++)
{
if (cp->status[i] > 0)
numactive++;
}
m.n = numactive + 3;
m.v = calloc (m.n * m.n, sizeof (double));
if (m.v == NULL)
fprintf (stderr, "out of memory - I_compute_georef_equations_tps()\n");
a = calloc (m.n, sizeof (double));
if (a == NULL)
fprintf (stderr, "out of memory - I_compute_georef_equations_tps()\n");
b = calloc (m.n, sizeof (double));
if (b == NULL)
fprintf (stderr, "out of memory - I_compute_georef_equations_tps()\n");
*E = calloc (m.n, sizeof (double));
if (*E == NULL)
fprintf (stderr, "out of memory - I_compute_georef_equations_tps()\n");
*N = calloc (m.n, sizeof (double));
if (*N == NULL)
fprintf (stderr, "out of memory - I_compute_georef_equations_tps()\n");
status = calcls (cp, &m, a, b, *E, *N);
free (m.v);
free (a);
free (b);
return status;
}
static int
calcls (struct Control_Points *cp, struct MATRIX *m, double a[], double b[], double E[],
double N[]
)
{
int i, j, n, o, numactive = 0;
double dist = 0.0, dx, dy;
for (i = 1; i <= m->n; i++)
{
for (j = i; j <= m->n; j++)
{
M (i, j) = 0.0;
if (i != j)
M (j, i) = 0.0;
}
a[i - 1] = b[i - 1] = 0.0;
}
for (n = 0; n < cp->count; n++)
{
if (cp->status[n] > 0)
{
a[numactive + 3] = cp->e2[n];
b[numactive + 3] = cp->n2[n];
numactive++;
M (1, numactive + 3) = 1.0;
M (2, numactive + 3) = cp->e1[n];
M (3, numactive + 3) = cp->n1[n];
M (numactive + 3, 1) = 1.0;
M (numactive + 3, 2) = cp->e1[n];
M (numactive + 3, 3) = cp->n1[n];
}
}
if (numactive < m->n - 3)
return MINTERR;
i = 0;
for (n = 0; n < cp->count; n++)
{
if (cp->status[n] > 0)
{
i++;
j = 0;
for (o = 0; o <= n; o++)
{
if (cp->status[o] > 0)
{
j++;
M (i + 3, j + 3) =
tps_base_func (cp->e1[n], cp->n1[n], cp->e1[o],
cp->n1[o]);
if (i != j)
M (j + 3, i + 3) = M (i + 3, j + 3);
dx = cp->e1[n] - cp->e1[o];
dy = cp->n1[n] - cp->n1[o];
dist += sqrt (dx * dx + dy * dy);
}
}
}
}
return solvemat (m, a, b, E, N);
}
static int
solvemat (struct MATRIX *m, double a[], double b[], double E[], double N[])
{
int i, j, i2, j2, imark;
double factor, temp;
double pivot;
for (i = 1; i <= m->n; i++)
{
j = i;
pivot = M (i, j);
imark = i;
for (i2 = i + 1; i2 <= m->n; i2++)
{
temp = fabs (M (i2, j));
if (temp > fabs (pivot))
{
pivot = M (i2, j);
imark = i2;
}
}
if (pivot == 0.0)
return MUNSOLVABLE;
if (imark != i)
{
for (j2 = 1; j2 <= m->n; j2++)
{
temp = M (imark, j2);
M (imark, j2) = M (i, j2);
M (i, j2) = temp;
}
temp = a[imark - 1];
a[imark - 1] = a[i - 1];
a[i - 1] = temp;
temp = b[imark - 1];
b[imark - 1] = b[i - 1];
b[i - 1] = temp;
}
for (i2 = 1; i2 <= m->n; i2++)
{
if (i2 != i)
{
factor = M (i2, j) / pivot;
for (j2 = j; j2 <= m->n; j2++)
M (i2, j2) -= factor * M (i, j2);
a[i2 - 1] -= factor * a[i - 1];
b[i2 - 1] -= factor * b[i - 1];
}
}
}
for (i = 1; i <= m->n; i++)
{
E[i - 1] = a[i - 1] / M (i, i);
N[i - 1] = b[i - 1] / M (i, i);
}
return MSUCCESS;
}
static double
tps_base_func (const double x1, const double y1,
const double x2, const double y2)
{
double dist;
if ((x1 == x2) && (y1 == y2))
return 0.0;
dist = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
return dist * log (dist) * 0.5;
}
#endif