// INVERSE(s_inverse) sphere // Project coordinates from cartesian (x, y) to geographic (lon, lat) inline void inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const { T N, M, xp, yp, z, Az, cz, sz, cAz; N = this->m_proj_parm.hn * aasin(xy_y * this->m_proj_parm.rn); M = this->m_proj_parm.hm * aasin(xy_x * this->m_proj_parm.rm * cos(N * this->m_proj_parm.two_r_n) / cos(N)); xp = 2. * sin(M); yp = 2. * sin(N) * cos(M * this->m_proj_parm.two_r_m) / cos(M); cAz = cos(Az = aatan2(xp, yp) - this->m_proj_parm.theta); z = 2. * aasin(0.5 * boost::math::hypot(xp, yp)); sz = sin(z); cz = cos(z); lp_lat = aasin(this->m_proj_parm.sp0 * cz + this->m_proj_parm.cp0 * sz * cAz); lp_lon = aatan2(sz * sin(Az), this->m_proj_parm.cp0 * cz - this->m_proj_parm.sp0 * sz * cAz); }
static PJ_XY t_forward(PJ_LP lp, PJ *P) { /* spheroid */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosphi, coslam; cosphi = cos(lp.phi); coslam = cos(lp.lam); lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + Q->lamp); lp.phi = aasin(P->ctx, - cosphi * coslam); return Q->link->fwd(lp, Q->link); }
// FORWARD(s_forward) sphere // Project coordinates from geographic (lon, lat) to cartesian (x, y) inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const { T Az, M, N, cp, sp, cl, shz; cp = cos(lp_lat); sp = sin(lp_lat); cl = cos(lp_lon); Az = aatan2(cp * sin(lp_lon), this->m_proj_parm.cp0 * sp - this->m_proj_parm.sp0 * cp * cl) + this->m_proj_parm.theta; shz = sin(0.5 * aacos(this->m_proj_parm.sp0 * sp + this->m_proj_parm.cp0 * cp * cl)); M = aasin(shz * sin(Az)); N = aasin(shz * cos(Az) * cos(M) / cos(M * this->m_proj_parm.two_r_m)); xy_y = this->m_proj_parm.n * sin(N * this->m_proj_parm.two_r_n); xy_x = this->m_proj_parm.m * sin(M * this->m_proj_parm.two_r_m) * cos(N) / cos(N * this->m_proj_parm.two_r_n); }
inline void fwd(geographic_type& lp_lon, geographic_type& lp_lat, cartesian_type& xy_x, cartesian_type& xy_y) const { double Az, M, N, cp, sp, cl, shz; cp = cos(lp_lat); sp = sin(lp_lat); cl = cos(lp_lon); Az = aatan2(cp * sin(lp_lon), this->m_proj_parm.cp0 * sp - this->m_proj_parm.sp0 * cp * cl) + this->m_proj_parm.theta; shz = sin(0.5 * aacos(this->m_proj_parm.sp0 * sp + this->m_proj_parm.cp0 * cp * cl)); M = aasin(shz * sin(Az)); N = aasin(shz * cos(Az) * cos(M) / cos(M * this->m_proj_parm.two_r_m)); xy_y = this->m_proj_parm.n * sin(N * this->m_proj_parm.two_r_n); xy_x = this->m_proj_parm.m * sin(M * this->m_proj_parm.two_r_m) * cos(N) / cos(N * this->m_proj_parm.two_r_n); }
static PJ_LP t_inverse(PJ_XY xy, PJ *P) { /* spheroid */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosphi, t; PJ_LP lp = Q->link->inv(xy, Q->link); if (lp.lam != HUGE_VAL) { cosphi = cos(lp.phi); t = lp.lam - Q->lamp; lp.lam = aatan2(cosphi * sin(t), - sin(lp.phi)); lp.phi = aasin(P->ctx,cosphi * cos(t)); } return lp; }
static PJ_LP o_inverse(PJ_XY xy, PJ *P) { /* spheroid */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double coslam, sinphi, cosphi; PJ_LP lp = Q->link->inv(xy, Q->link); if (lp.lam != HUGE_VAL) { coslam = cos(lp.lam -= Q->lamp); sinphi = sin(lp.phi); cosphi = cos(lp.phi); lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam); lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam - Q->cphip * sinphi); } return lp; }
#endif #define PROJ_PARMS__ \ double theta; \ double m, n; \ double two_r_m, two_r_n, rm, rn, hm, hn; \ double cp0, sp0; #define PJ_LIB__ #include "projects.h" PROJ_HEAD(oea, "Oblated Equal Area") "\n\tMisc Sph\n\tn= m= theta="; FORWARD(s_forward); /* sphere */ double Az, hz, M, N, cp, sp, cl, shz; cp = cos(lp.phi); sp = sin(lp.phi); cl = cos(lp.lam); Az = aatan2(cp * sin(lp.lam), P->cp0 * sp - P->sp0 * cp * cl) + P->theta; shz = sin(0.5 * aacos(P->sp0 * sp + P->cp0 * cp * cl)); M = aasin(shz * sin(Az)); N = aasin(shz * cos(Az) * cos(M) / cos(M * P->two_r_m)); xy.y = P->n * sin(N * P->two_r_n); xy.x = P->m * sin(M * P->two_r_m) * cos(N) / cos(N * P->two_r_n); return (xy); } INVERSE(s_inverse); /* sphere */ double N, M, xp, yp, z, Az, cz, sz, cAz; N = P->hn * aasin(xy.y * P->rn); M = P->hm * aasin(xy.x * P->rm * cos(N * P->two_r_n) / cos(N)); xp = 2. * sin(M); yp = 2. * sin(N) * cos(M * P->two_r_m) / cos(M); cAz = cos(Az = aatan2(xp, yp) - P->theta);
#include <string.h> PROJ_HEAD(ob_tran, "General Oblique Transformation") "\n\tMisc Sph" "\n\to_proj= plus parameters for projection" "\n\to_lat_p= o_lon_p= (new pole) or" "\n\to_alpha= o_lon_c= o_lat_c= or" "\n\to_lon_1= o_lat_1= o_lon_2= o_lat_2="; #define TOL 1e-10 FORWARD(o_forward); /* spheroid */ double coslam, sinphi, cosphi; (void) xy; coslam = cos(lp.lam); sinphi = sin(lp.phi); cosphi = cos(lp.phi); lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), P->sphip * cosphi * coslam + P->cphip * sinphi) + P->lamp); lp.phi = aasin(P->sphip * sinphi - P->cphip * cosphi * coslam); return (P->link->fwd(lp, P->link)); } FORWARD(t_forward); /* spheroid */ double cosphi, coslam; (void) xy; cosphi = cos(lp.phi); coslam = cos(lp.lam); lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + P->lamp); lp.phi = aasin(- cosphi * coslam); return (P->link->fwd(lp, P->link)); } INVERSE(o_inverse); /* spheroid */
PJ *PROJECTION(ob_tran) { double phip; char *name; ARGS args; PJ *R; /* projection to rotate */ struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return destructor(P, ENOMEM); P->opaque = Q; P->destructor = destructor; /* get name of projection to be translated */ if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) return destructor(P, PJD_ERR_NO_ROTATION_PROJ); /* avoid endless recursion */ if( strcmp(name, "ob_tran") == 0 ) return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); /* Create the target projection object to rotate */ args = ob_tran_target_params (P->params); R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); pj_dealloc (args.argv); if (nullptr==R) return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); Q->link = R; if (pj_param(P->ctx, P->params, "to_alpha").i) { double lamc, phic, alpha; lamc = pj_param(P->ctx, P->params, "ro_lon_c").f; phic = pj_param(P->ctx, P->params, "ro_lat_c").f; alpha = pj_param(P->ctx, P->params, "ro_alpha").f; if (fabs(fabs(phic) - M_HALFPI) <= TOL) return destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic)); phip = aasin(P->ctx,cos(phic) * sin(alpha)); } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */ Q->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f; phip = pj_param(P->ctx, P->params, "ro_lat_p").f; } else { /* specified new "equator" points */ double lam1, lam2, phi1, phi2, con; lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f; phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f; lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f; phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f; if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) return destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) - sin(phi1) * cos(phi2) * cos(lam2), sin(phi1) * cos(phi2) * sin(lam2) - cos(phi1) * sin(phi2) * sin(lam1)); phip = atan(-cos(Q->lamp - lam1) / tan(phi1)); } if (fabs(phip) > TOL) { /* oblique */ Q->cphip = cos(phip); Q->sphip = sin(phip); P->fwd = Q->link->fwd ? o_forward : nullptr; P->inv = Q->link->inv ? o_inverse : nullptr; } else { /* transverse */ P->fwd = Q->link->fwd ? t_forward : nullptr; P->inv = Q->link->inv ? t_inverse : nullptr; } /* Support some rather speculative test cases, where the rotated projection */ /* is actually latlong. We do not want scaling in that case... */ if (Q->link->right==PJ_IO_UNITS_RADIANS) P->right = PJ_IO_UNITS_PROJECTED; return P; }