static PJ_LP e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); PJ_XY t; double yc = 0.0; int i = 0; const int N_MAX_ITER = 1000; /* Arbitrarily chosen number... */ lp.phi = Q->phi_2; lp.lam = xy.x / cos(lp.phi); do { t = loc_for(lp, P, &yc); const double denom = t.y - yc; if( denom != 0 || fabs(t.y - xy.y) > TOL ) { if( denom == 0 ) { proj_errno_set(P, PJD_ERR_NON_CONVERGENT); return proj_coord_error().lp; } lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / denom) + Q->phi_1; } if( t.x != 0 || fabs(t.x - xy.x) > TOL ) lp.lam = lp.lam * xy.x / t.x; i ++; } while (i < N_MAX_ITER && (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL)); if( i == N_MAX_ITER ) { proj_errno_set(P, PJD_ERR_NON_CONVERGENT); return proj_coord_error().lp; } return lp; }
PJ_COORD pj_fwd4d (PJ_COORD coo, PJ *P) { int last_errno = proj_errno_reset(P); if (!P->skip_fwd_prepare) coo = fwd_prepare (P, coo); if (HUGE_VAL==coo.v[0]) return proj_coord_error (); /* Call the highest dimensional converter available */ if (P->fwd4d) coo = P->fwd4d (coo, P); else if (P->fwd3d) coo.xyz = P->fwd3d (coo.lpz, P); else if (P->fwd) coo.xy = P->fwd (coo.lp, P); else { proj_errno_set (P, EINVAL); return proj_coord_error (); } if (HUGE_VAL==coo.v[0]) return proj_coord_error (); if (!P->skip_fwd_finalize) coo = fwd_finalize (P, coo); return error_or_coord(P, coo, last_errno); }
PJ_XYZ pj_fwd3d(PJ_LPZ lpz, PJ *P) { int last_errno; PJ_COORD coo = {{0,0,0,0}}; coo.lpz = lpz; last_errno = proj_errno_reset(P); if (!P->skip_fwd_prepare) coo = fwd_prepare (P, coo); if (HUGE_VAL==coo.v[0]) return proj_coord_error ().xyz; /* Do the transformation, using the lowest dimensional transformer feasible */ if (P->fwd3d) coo.xyz = P->fwd3d(coo.lpz, P); else if (P->fwd4d) coo = P->fwd4d (coo, P); else if (P->fwd) coo.xy = P->fwd (coo.lp, P); else { proj_errno_set (P, EINVAL); return proj_coord_error ().xyz; } if (HUGE_VAL==coo.v[0]) return proj_coord_error ().xyz; if (!P->skip_fwd_finalize) coo = fwd_finalize (P, coo); return error_or_coord(P, coo, last_errno).xyz; }
PJ_COORD proj_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coord) { /*************************************************************************************** Apply the transformation P to the coordinate coord, preferring the 4D interfaces if available. See also pj_approx_2D_trans and pj_approx_3D_trans in pj_internal.c, which work similarly, but prefers the 2D resp. 3D interfaces if available. ***************************************************************************************/ if (0==P) return coord; if (P->inverted) direction = -direction; switch (direction) { case PJ_FWD: return pj_fwd4d (coord, P); case PJ_INV: return pj_inv4d (coord, P); case PJ_IDENT: return coord; default: break; } proj_errno_set (P, EINVAL); return proj_coord_error (); }
static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { if (proj_errno(P)) return proj_coord_error(); proj_errno_restore(P, last_errno); return coord; }
static PJ_COORD reverse_4d(PJ_COORD coo, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; unsigned int i; PJ_COORD out; out = proj_coord_error(); for (i=0; i<4; i++) out.v[Q->axis[i]] = coo.v[i] * Q->sign[i]; return out; }
static LP reverse_2d(XY xy, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; unsigned int i; PJ_COORD out, in; in.xy = xy; out = proj_coord_error(); for (i=0; i<2; i++) out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; return out.lp; }
static XY forward_2d(LP lp, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; unsigned int i; PJ_COORD out, in; in.lp = lp; out = proj_coord_error(); for (i=0; i<2; i++) out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; return out.xy; }
static LPZ reverse_3d(XYZ xyz, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; unsigned int i; PJ_COORD in, out; out = proj_coord_error(); in.xyz = xyz; for (i=0; i<3; i++) out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; return out.lpz; }
static XYZ forward_3d(LPZ lpz, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; unsigned int i; PJ_COORD out, in; in.lpz = lpz; out = proj_coord_error(); for (i=0; i<3; i++) out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; return out.xyz; }
static PJ_LPZ reverse_3d(PJ_XYZ in, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; PJ_COORD out; double dt = 0.0; out.xyz = in; if (Q->t_obs != HUGE_VAL) { dt = Q->t_epoch - Q->t_obs; } else { out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ proj_log_debug(P, "deformation: +t_obs must be specified"); return out.lpz; } out.xyz = reverse_shift(P, in, dt); return out.lpz; }
static PJ_LP vandg_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse */ PJ_LP lp = {0.0,0.0}; double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2; x2 = xy.x * xy.x; if ((ay = fabs(xy.y)) < TOL) { lp.phi = 0.; t = x2 * x2 + TPISQ * (x2 + HPISQ); lp.lam = fabs(xy.x) <= TOL ? 0. : .5 * (x2 - PISQ + sqrt(t)) / xy.x; return (lp); } y2 = xy.y * xy.y; r = x2 + y2; r2 = r * r; c1 = - M_PI * ay * (r + PISQ); c3 = r2 + M_TWOPI * (ay * r + M_PI * (y2 + M_PI * (ay + M_HALFPI))); c2 = c1 + PISQ * (r - 3. * y2); c0 = M_PI * ay; c2 /= c3; al = c1 / c3 - THIRD * c2 * c2; m = 2. * sqrt(-THIRD * al); d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3; const double al_mul_m = al * m; if( al_mul_m == 0 ) { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return proj_coord_error().lp; } d = 3. * d /al_mul_m; t = fabs(d); if ((t - TOL) <= 1.) { d = t > 1. ? (d > 0. ? 0. : M_PI) : acos(d); lp.phi = M_PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2); if (xy.y < 0.) lp.phi = -lp.phi; t = r2 + TPISQ * (x2 - y2 + HPISQ); lp.lam = fabs(xy.x) <= TOL ? 0. : .5 * (r - PISQ + (t <= 0. ? 0. : sqrt(t))) / xy.x; } else { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return lp; } return lp; }
static PJ_XY sterea_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); double cosc, sinc, cosl, k; lp = pj_gauss(P->ctx, lp, Q->en); sinc = sin(lp.phi); cosc = cos(lp.phi); cosl = cos(lp.lam); const double denom = 1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl; if( denom == 0.0 ) { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return proj_coord_error().xy; } k = P->k0 * Q->R2 / denom; xy.x = k * cosc * sin(lp.lam); xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl); return xy; }
static PJ_COORD parse_coord (const char *args) { /***************************************************************************** Attempt to interpret args as a PJ_COORD. ******************************************************************************/ int i; const char *endp; const char *dmsendp; const char *prev = args; PJ_COORD a = proj_coord (0,0,0,0); T.dimensions_given = 0; for (i = 0; i < 4; i++) { /* proj_strtod doesn't read values like 123d45'678W so we need a bit */ /* of help from proj_dmstor. proj_strtod effectively ignores what */ /* comes after "d", so we use that fact that when dms is larger than */ /* d the value was stated in "dms" form. */ /* This could be avoided if proj_dmstor used the same proj_strtod() */ /* as gie, but that is not the case (yet). When we remove projects.h */ /* from the public API we can change that. */ double d = proj_strtod(prev, (char **) &endp); double dms = PJ_TODEG(proj_dmstor (prev, (char **) &dmsendp)); /* TODO: When projects.h is removed, call proj_dmstor() in all cases */ if (d != dms && fabs(d) < fabs(dms) && fabs(dms) < fabs(d) + 1) { d = dms; endp = dmsendp; } /* A number like -81d00'00.000 will be parsed correctly by both */ /* proj_strtod and proj_dmstor but only the latter will return */ /* the correct end-pointer. */ if (d == dms && endp != dmsendp) endp = dmsendp; /* Break out if there were no more numerals */ if (prev==endp) return i > 1? a: proj_coord_error (); a.v[i] = d; prev = endp; T.dimensions_given++; } return a; }
static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) { struct pj_opaque *Q = (struct pj_opaque *) P->opaque; PJ_COORD out, in; PJ_XYZ shift; double dt = 0.0; in.lpz = lpz; out = in; if (Q->t_obs != HUGE_VAL) { dt = Q->t_epoch - Q->t_obs; } else { out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ proj_log_debug(P, "deformation: +t_obs must be specified"); return out.xyz; } shift = get_grid_shift(P, in.xyz); out.xyz.x += dt * shift.x; out.xyz.y += dt * shift.y; out.xyz.z += dt * shift.z; return out.xyz; }
static PJ_COORD fwd_prepare (PJ *P, PJ_COORD coo) { if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1] || HUGE_VAL==coo.v[2]) return proj_coord_error (); /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; /* Check validity of angular input coordinates */ if (INPUT_UNITS==PJ_IO_UNITS_RADIANS) { double t; /* check for latitude or longitude over-range */ t = (coo.lp.phi < 0 ? -coo.lp.phi : coo.lp.phi) - M_HALFPI; if (t > PJ_EPS_LAT || coo.lp.lam > 10 || coo.lp.lam < -10) { proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); return proj_coord_error (); } /* Clamp latitude to -90..90 degree range */ if (coo.lp.phi > M_HALFPI) coo.lp.phi = M_HALFPI; if (coo.lp.phi < -M_HALFPI) coo.lp.phi = -M_HALFPI; /* If input latitude is geocentrical, convert to geographical */ if (P->geoc) coo = pj_geocentric_latitude (P, PJ_INV, coo); /* Ensure longitude is in the -pi:pi range */ if (0==P->over) coo.lp.lam = adjlon(coo.lp.lam); if (P->hgridshift) coo = proj_trans (P->hgridshift, PJ_INV, coo); else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { coo = proj_trans (P->cart_wgs84, PJ_FWD, coo); /* Go cartesian in WGS84 frame */ if( P->helmert ) coo = proj_trans (P->helmert, PJ_INV, coo); /* Step into local frame */ coo = proj_trans (P->cart, PJ_INV, coo); /* Go back to angular using local ellps */ } if (coo.lp.lam==HUGE_VAL) return coo; if (P->vgridshift) coo = proj_trans (P->vgridshift, PJ_FWD, coo); /* Go orthometric from geometric */ /* Distance from central meridian, taking system zero meridian into account */ coo.lp.lam = (coo.lp.lam - P->from_greenwich) - P->lam0; /* Ensure longitude is in the -pi:pi range */ if (0==P->over) coo.lp.lam = adjlon(coo.lp.lam); return coo; } /* We do not support gridshifts on cartesian input */ if (INPUT_UNITS==PJ_IO_UNITS_CARTESIAN && P->helmert) return proj_trans (P->helmert, PJ_INV, coo); return coo; }