mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
215 lines
No EOL
5.9 KiB
C++
215 lines
No EOL
5.9 KiB
C++
#include "stereo.h"
|
|
|
|
namespace proj
|
|
{
|
|
namespace
|
|
{
|
|
enum Mode
|
|
{
|
|
S_POLE = 0,
|
|
N_POLE = 1,
|
|
OBLIQ = 2,
|
|
EQUIT = 3
|
|
};
|
|
|
|
struct projection_stereo_t
|
|
{
|
|
double phits;
|
|
double sinX1;
|
|
double cosX1;
|
|
double akm1;
|
|
enum Mode mode;
|
|
};
|
|
|
|
double pj_tsfn(double phi, double sinphi, double e)
|
|
{
|
|
double cosphi = cos(phi);
|
|
return exp(e * atanh(e * sinphi)) * (sinphi > 0 ? cosphi / (1 + sinphi) : (1 - sinphi) / cosphi);
|
|
}
|
|
|
|
double ssfn_(double phit, double sinphi, double eccen)
|
|
{
|
|
sinphi *= eccen;
|
|
return (tan(.5 * (M_PI_2 + phit)) * pow((1. - sinphi) / (1. + sinphi), .5 * eccen));
|
|
}
|
|
}
|
|
|
|
#define EPS10 1.e-10
|
|
#define NITER 8
|
|
#define CONV 1.e-10
|
|
|
|
bool projection_stereo_setup(projection_t *proj)
|
|
{
|
|
projection_stereo_t *ptr = (projection_stereo_t *)malloc(sizeof(projection_stereo_t));
|
|
proj->proj_dat = ptr;
|
|
|
|
ptr->phits = M_HALFPI;
|
|
|
|
// printf("k0 %f, x0 %f, y0 %f, e %f, es %f\n", proj->k0, proj->x0, proj->y0, proj->e,
|
|
// proj->es);
|
|
|
|
double t;
|
|
if (fabs((t = fabs(proj->phi0)) - M_HALFPI) < EPS10)
|
|
ptr->mode = proj->phi0 < 0. ? S_POLE : N_POLE;
|
|
else
|
|
ptr->mode = t > EPS10 ? OBLIQ : EQUIT;
|
|
ptr->phits = fabs(ptr->phits);
|
|
|
|
if (proj->es != 0.0)
|
|
{
|
|
double X;
|
|
|
|
switch (ptr->mode)
|
|
{
|
|
case N_POLE:
|
|
case S_POLE:
|
|
if (fabs(ptr->phits - M_HALFPI) < EPS10)
|
|
ptr->akm1 =
|
|
2. * proj->k0 /
|
|
sqrt(pow(1 + proj->e, 1 + proj->e) * pow(1 - proj->e, 1 - proj->e));
|
|
else
|
|
{
|
|
t = sin(ptr->phits);
|
|
ptr->akm1 = cos(ptr->phits) / pj_tsfn(ptr->phits, t, proj->e);
|
|
t *= proj->e;
|
|
ptr->akm1 /= sqrt(1. - t * t);
|
|
}
|
|
break;
|
|
case EQUIT:
|
|
case OBLIQ:
|
|
t = sin(proj->phi0);
|
|
X = 2. * atan(ssfn_(proj->phi0, t, proj->e)) - M_HALFPI;
|
|
t *= proj->e;
|
|
ptr->akm1 = 2. * proj->k0 * cos(proj->phi0) / sqrt(1. - t * t);
|
|
ptr->sinX1 = sin(X);
|
|
ptr->cosX1 = cos(X);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Spherical NOT implemented!
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool projection_stereo_fwd(const projection_t *proj, double lam, double phi, double *x, double *y)
|
|
{
|
|
projection_stereo_t *ptr = (projection_stereo_t *)proj->proj_dat;
|
|
|
|
double coslam, sinlam, sinX = 0.0, cosX = 0.0, A = 0.0, sinphi;
|
|
|
|
coslam = cos(lam);
|
|
sinlam = sin(lam);
|
|
sinphi = sin(phi);
|
|
if (ptr->mode == OBLIQ || ptr->mode == EQUIT)
|
|
{
|
|
const double X = 2. * atan(ssfn_(phi, sinphi, proj->e)) - M_HALFPI;
|
|
sinX = sin(X);
|
|
cosX = cos(X);
|
|
}
|
|
|
|
switch (ptr->mode)
|
|
{
|
|
case OBLIQ:
|
|
{
|
|
const double denom =
|
|
ptr->cosX1 * (1. + ptr->sinX1 * sinX + ptr->cosX1 * cosX * coslam);
|
|
if (denom == 0)
|
|
{
|
|
return true;
|
|
}
|
|
A = ptr->akm1 / denom;
|
|
*y = A * (ptr->cosX1 * sinX - ptr->sinX1 * cosX * coslam);
|
|
*x = A * cosX;
|
|
break;
|
|
}
|
|
|
|
case EQUIT:
|
|
/* avoid zero division */
|
|
if (1. + cosX * coslam == 0.0)
|
|
{
|
|
*y = HUGE_VAL;
|
|
}
|
|
else
|
|
{
|
|
A = ptr->akm1 / (1. + cosX * coslam);
|
|
*y = A * sinX;
|
|
}
|
|
*x = A * cosX;
|
|
break;
|
|
|
|
case S_POLE:
|
|
phi = -phi;
|
|
coslam = -coslam;
|
|
sinphi = -sinphi;
|
|
[[fallthrough]];
|
|
case N_POLE:
|
|
if (fabs(phi - M_HALFPI) < 1e-15)
|
|
*x = 0;
|
|
else
|
|
*x = ptr->akm1 * pj_tsfn(phi, sinphi, proj->e);
|
|
*y = -*x * coslam;
|
|
break;
|
|
}
|
|
|
|
*x = *x * sinlam;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool projection_stereo_inv(const projection_t *proj, double x, double y, double *lam, double *phi)
|
|
{
|
|
projection_stereo_t *ptr = (projection_stereo_t *)proj->proj_dat;
|
|
|
|
double cosphi, sinphi, tp = 0.0, phi_l = 0.0, rho, halfe = 0.0, halfpi = 0.0;
|
|
rho = hypot(x, y);
|
|
|
|
switch (ptr->mode)
|
|
{
|
|
case OBLIQ:
|
|
case EQUIT:
|
|
tp = 2. * atan2(rho * ptr->cosX1, ptr->akm1);
|
|
cosphi = cos(tp);
|
|
sinphi = sin(tp);
|
|
if (rho == 0.0)
|
|
phi_l = asin(cosphi * ptr->sinX1);
|
|
else
|
|
phi_l = asin(cosphi * ptr->sinX1 + (y * sinphi * ptr->cosX1 / rho));
|
|
|
|
tp = tan(.5 * (M_HALFPI + phi_l));
|
|
x *= sinphi;
|
|
y = rho * ptr->cosX1 * cosphi - y * ptr->sinX1 * sinphi;
|
|
halfpi = M_HALFPI;
|
|
halfe = .5 * proj->e;
|
|
break;
|
|
case N_POLE:
|
|
y = -y;
|
|
[[fallthrough]];
|
|
case S_POLE:
|
|
tp = -rho / ptr->akm1;
|
|
phi_l = M_HALFPI - 2. * atan(tp);
|
|
halfpi = -M_HALFPI;
|
|
halfe = -.5 * proj->e;
|
|
break;
|
|
}
|
|
|
|
for (int i = NITER; i > 0; --i)
|
|
{
|
|
sinphi = proj->e * sin(phi_l);
|
|
*phi = 2. * atan(tp * pow((1. + sinphi) / (1. - sinphi), halfe)) - halfpi;
|
|
if (fabs(phi_l - *phi) < CONV)
|
|
{
|
|
if (ptr->mode == S_POLE)
|
|
*phi = -*phi;
|
|
*lam = (x == 0. && y == 0.) ? 0. : atan2(x, y);
|
|
return false;
|
|
}
|
|
phi_l = *phi;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} |