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

190 lines
4.8 KiB
C++
Raw Permalink Normal View History

#include "tpers.h"
namespace proj
{
namespace
{
enum Mode
{
N_POLE = 0,
S_POLE = 1,
EQUIT = 2,
OBLIQ = 3
};
struct projection_tpers_t
{
double height;
double sinph0;
double cosph0;
double p;
double rp;
double pn1;
double pfact;
double h;
double cg;
double sg;
double sw;
double cw;
enum Mode mode;
int tilt;
};
}
#define EPS10 1.e-10
bool projection_tpers_setup(projection_t *proj, double height, double tilt, double azi)
{
projection_tpers_t *ptr = (projection_tpers_t *)malloc(sizeof(projection_tpers_t));
proj->proj_dat = ptr;
double omega = tilt;
double gamma = azi;
ptr->tilt = 1;
ptr->cg = cos(gamma);
ptr->sg = sin(gamma);
ptr->cw = cos(omega);
ptr->sw = sin(omega);
ptr->height = height;
if (fabs(fabs(proj->phi0) - M_HALFPI) < EPS10)
ptr->mode = proj->phi0 < 0. ? S_POLE : N_POLE;
else if (fabs(proj->phi0) < EPS10)
ptr->mode = EQUIT;
else
{
ptr->mode = OBLIQ;
ptr->sinph0 = sin(proj->phi0);
ptr->cosph0 = cos(proj->phi0);
}
ptr->pn1 = ptr->height / proj->a; /* normalize by radius */
if (ptr->pn1 <= 0 || ptr->pn1 > 1e10)
{
return true;
}
ptr->p = 1. + ptr->pn1;
ptr->rp = 1. / ptr->p;
ptr->h = 1. / ptr->pn1;
ptr->pfact = (ptr->p + 1.) * ptr->h;
proj->es = 0.;
return false;
}
2025-01-12 20:25:45 +01:00
bool projection_tpers_fwd(const projection_t *proj, double lam, double phi, double *x, double *y)
{
projection_tpers_t *ptr = (projection_tpers_t *)proj->proj_dat;
double coslam, cosphi, sinphi;
sinphi = sin(phi);
cosphi = cos(phi);
coslam = cos(lam);
switch (ptr->mode)
{
case OBLIQ:
*y = ptr->sinph0 * sinphi + ptr->cosph0 * cosphi * coslam;
break;
case EQUIT:
*y = cosphi * coslam;
break;
case S_POLE:
*y = -sinphi;
break;
case N_POLE:
*y = sinphi;
break;
}
if (*y < ptr->rp)
{
return true;
}
*y = ptr->pn1 / (ptr->p - *y);
*x = *y * cosphi * sin(lam);
switch (ptr->mode)
{
case OBLIQ:
*y *= (ptr->cosph0 * sinphi - ptr->sinph0 * cosphi * coslam);
break;
case EQUIT:
*y *= sinphi;
break;
case N_POLE:
coslam = -coslam;
[[fallthrough]];
case S_POLE:
*y *= cosphi * coslam;
break;
}
if (ptr->tilt)
{
double yt, ba;
yt = *y * ptr->cg + *x * ptr->sg;
ba = 1. / (yt * ptr->sw * ptr->h + ptr->cw);
*x = (*x * ptr->cg - *y * ptr->sg) * ptr->cw * ba;
*y = yt * ba;
}
return false;
}
2025-01-12 20:25:45 +01:00
bool projection_tpers_inv(const projection_t *proj, double x, double y, double *lam, double *phi)
{
projection_tpers_t *ptr = (projection_tpers_t *)proj->proj_dat;
double rh;
if (ptr->tilt)
{
double bm, bq, yt;
yt = 1. / (ptr->pn1 - y * ptr->sw);
bm = ptr->pn1 * x * yt;
bq = ptr->pn1 * y * ptr->cw * yt;
x = bm * ptr->cg + bq * ptr->sg;
y = bq * ptr->cg - bm * ptr->sg;
}
rh = hypot(x, y);
if (fabs(rh) <= EPS10)
{
*lam = 0.;
*phi = proj->phi0;
}
else
{
double cosz, sinz;
sinz = 1. - rh * rh * ptr->pfact;
if (sinz < 0.)
{
return true;
}
sinz = (ptr->p - sqrt(sinz)) / (ptr->pn1 / rh + rh / ptr->pn1);
cosz = sqrt(1. - sinz * sinz);
switch (ptr->mode)
{
case OBLIQ:
*phi = asin(cosz * ptr->sinph0 + y * sinz * ptr->cosph0 / rh);
y = (cosz - ptr->sinph0 * sin(*phi)) * rh;
x *= sinz * ptr->cosph0;
break;
case EQUIT:
*phi = asin(y * sinz / rh);
y = cosz * rh;
x *= sinz;
break;
case N_POLE:
*phi = asin(cosz);
y = -y;
break;
case S_POLE:
*phi = -asin(cosz);
break;
}
*lam = atan2(x, y);
}
return false;
}
}