satdump/src-core/projection/standard/stereo.cpp

215 lines
5.9 KiB
C++
Raw Permalink Normal View History

2024-02-23 01:22:22 +01:00
#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;
}
2025-01-12 20:25:45 +01:00
bool projection_stereo_fwd(const projection_t *proj, double lam, double phi, double *x, double *y)
2024-02-23 01:22:22 +01:00
{
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;
}
2025-01-12 20:25:45 +01:00
bool projection_stereo_inv(const projection_t *proj, double x, double y, double *lam, double *phi)
2024-02-23 01:22:22 +01:00
{
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;
}
}