void geod_for(void) { double d,sind,u,V,X,ds,cosds,sinds,ss,de; ss = 0.; if (ellipse) { d = geod_S / (D * geod_a); if (signS) d = -d; u = 2. * (s1 - d); V = cos(u + d); X = c2 * c2 * (sind = sin(d)) * cos(d) * (2. * V * V - 1.); ds = d + X - 2. * P * V * (1. - 2. * P * cos(u)) * sind; ss = s1 + s1 - ds; } else { ds = geod_S / geod_a; if (signS) ds = - ds; } cosds = cos(ds); sinds = sin(ds); if (signS) sinds = - sinds; al21 = N * cosds - sinth1 * sinds; if (merid) { phi2 = atan( tan(HALFPI + s1 - ds) / onef); if (al21 > 0.) { al21 = PI; if (signS) de = PI; else { phi2 = - phi2; de = 0.; } } else { al21 = 0.; if (signS) { phi2 = - phi2; de = 0; } else de = PI; } } else { al21 = atan(M / al21); if (al21 > 0) al21 += PI; if (al12 < 0.) al21 -= PI; al21 = adjlon(al21); phi2 = atan(-(sinth1 * cosds + N * sinds) * sin(al21) / (ellipse ? onef * M : M)); de = atan2(sinds * sina12 , (costh1 * cosds - sinth1 * sinds * cosa12)); if (ellipse) if (signS) de += c1 * ((1. - c2) * ds + c2 * sinds * cos(ss)); else de -= c1 * ((1. - c2) * ds - c2 * sinds * cos(ss)); } lam2 = adjlon( lam1 + de ); }
void setup_tpeqd(Parameters& par, par_tpeqd& proj_parm) { double lam_1, lam_2, phi_1, phi_2, A12, pp; /* get control point locations */ phi_1 = pj_param(par.params, "rlat_1").f; lam_1 = pj_param(par.params, "rlon_1").f; phi_2 = pj_param(par.params, "rlat_2").f; lam_2 = pj_param(par.params, "rlon_2").f; if (phi_1 == phi_2 && lam_1 == lam_2) throw proj_exception(-25); par.lam0 = adjlon(0.5 * (lam_1 + lam_2)); proj_parm.dlam2 = adjlon(lam_2 - lam_1); proj_parm.cp1 = cos(phi_1); proj_parm.cp2 = cos(phi_2); proj_parm.sp1 = sin(phi_1); proj_parm.sp2 = sin(phi_2); proj_parm.cs = proj_parm.cp1 * proj_parm.sp2; proj_parm.sc = proj_parm.sp1 * proj_parm.cp2; proj_parm.ccs = proj_parm.cp1 * proj_parm.cp2 * sin(proj_parm.dlam2); proj_parm.z02 = aacos(proj_parm.sp1 * proj_parm.sp2 + proj_parm.cp1 * proj_parm.cp2 * cos(proj_parm.dlam2)); proj_parm.hz0 = .5 * proj_parm.z02; A12 = atan2(proj_parm.cp2 * sin(proj_parm.dlam2), proj_parm.cp1 * proj_parm.sp2 - proj_parm.sp1 * proj_parm.cp2 * cos(proj_parm.dlam2)); proj_parm.ca = cos(pp = aasin(proj_parm.cp1 * sin(A12))); proj_parm.sa = sin(pp); proj_parm.lp = adjlon(atan2(proj_parm.cp1 * cos(A12), proj_parm.sp1) - proj_parm.hz0); proj_parm.dlam2 *= .5; proj_parm.lamc = HALFPI - atan2(sin(A12) * proj_parm.sp1, cos(A12)) - proj_parm.dlam2; proj_parm.thz0 = tan(proj_parm.hz0); proj_parm.rhshz0 = .5 / sin(proj_parm.hz0); proj_parm.r2z0 = 0.5 / proj_parm.z02; proj_parm.z02 *= proj_parm.z02; // par.inv = s_inverse; // par.fwd = s_forward; par.es = 0.; }
XY /* forward projection entry */ pj_fwd(LP lp, PJ *P) { XY xy; double t; /* check for forward and latitude or longitude overange */ if ((t = fabs(lp.phi)-HALFPI) > EPS || fabs(lp.lam) > 10.) { xy.x = xy.y = HUGE_VAL; pj_ctx_set_errno( P->ctx, -14); } else { /* proceed with projection */ P->ctx->last_errno = 0; pj_errno = 0; errno = 0; if (fabs(t) <= EPS) lp.phi = lp.phi < 0. ? -HALFPI : HALFPI; else if (P->geoc) lp.phi = atan(P->rone_es * tan(lp.phi)); lp.lam -= P->lam0; /* compute del lp.lam */ if (!P->over) lp.lam = adjlon(lp.lam); /* adjust del longitude */ xy = (*P->fwd)(lp, P); /* project */ if ( P->ctx->last_errno ) xy.x = xy.y = HUGE_VAL; /* adjust for major axis and easting/northings */ else { xy.x = P->fr_meter * (P->a * xy.x + P->x0); xy.y = P->fr_meter * (P->a * xy.y + P->y0); } } return xy; }
PJ *PROJECTION(utm) { int zone; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) return freeup_new (P); P->opaque = Q; if (!P->es) E_ERROR(-34); P->y0 = pj_param (P->ctx, P->params, "bsouth").i ? 10000000. : 0.; P->x0 = 500000.; if (pj_param (P->ctx, P->params, "tzone").i) /* zone input ? */ if ((zone = pj_param(P->ctx, P->params, "izone").i) > 0 && zone <= 60) --zone; else E_ERROR(-35) else /* nearest central meridian input */ if ((zone = (int)(floor ((adjlon (P->lam0) + M_PI) * 30. / M_PI))) < 0) zone = 0; else if (zone >= 60) zone = 59; P->lam0 = (zone + .5) * M_PI / 30. - M_PI; P->k0 = 0.9996; P->phi0 = 0.; return setup (P); }
PJ *PROJECTION(tpeqd) { double lam_1, lam_2, phi_1, phi_2, A12, pp; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) return freeup_new (P); P->opaque = Q; /* get control point locations */ phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; if (phi_1 == phi_2 && lam_1 == lam_2) E_ERROR(-25); P->lam0 = adjlon (0.5 * (lam_1 + lam_2)); Q->dlam2 = adjlon (lam_2 - lam_1); Q->cp1 = cos (phi_1); Q->cp2 = cos (phi_2); Q->sp1 = sin (phi_1); Q->sp2 = sin (phi_2); Q->cs = Q->cp1 * Q->sp2; Q->sc = Q->sp1 * Q->cp2; Q->ccs = Q->cp1 * Q->cp2 * sin(Q->dlam2); Q->z02 = aacos(P->ctx, Q->sp1 * Q->sp2 + Q->cp1 * Q->cp2 * cos (Q->dlam2)); Q->hz0 = .5 * Q->z02; A12 = atan2(Q->cp2 * sin (Q->dlam2), Q->cp1 * Q->sp2 - Q->sp1 * Q->cp2 * cos (Q->dlam2)); Q->ca = cos(pp = aasin(P->ctx, Q->cp1 * sin(A12))); Q->sa = sin(pp); Q->lp = adjlon ( atan2 (Q->cp1 * cos(A12), Q->sp1) - Q->hz0); Q->dlam2 *= .5; Q->lamc = M_HALFPI - atan2(sin(A12) * Q->sp1, cos(A12)) - Q->dlam2; Q->thz0 = tan (Q->hz0); Q->rhshz0 = .5 / sin (Q->hz0); Q->r2z0 = 0.5 / Q->z02; Q->z02 *= Q->z02; P->inv = s_inverse; P->fwd = s_forward; P->es = 0.; return P; }
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); }
static void do_arc(void) { double az; printLL(phi2, lam2); putchar('\n'); for (az = al12; n_alpha--; ) { al12 = az = adjlon(az + del_alpha); geod_prefor(); geod_forwd(); printLL(phi2, lam2); putchar('\n'); } }
inline void setup_tpeqd(Params const& params, Parameters& par, par_tpeqd<T>& proj_parm) { T lam_1, lam_2, phi_1, phi_2, A12, pp; /* get control point locations */ phi_1 = pj_get_param_r<T, srs::spar::lat_1>(params, "lat_1", srs::dpar::lat_1); lam_1 = pj_get_param_r<T, srs::spar::lon_1>(params, "lon_1", srs::dpar::lon_1); phi_2 = pj_get_param_r<T, srs::spar::lat_2>(params, "lat_2", srs::dpar::lat_2); lam_2 = pj_get_param_r<T, srs::spar::lon_2>(params, "lon_2", srs::dpar::lon_2); if (phi_1 == phi_2 && lam_1 == lam_2) BOOST_THROW_EXCEPTION( projection_exception(error_control_point_no_dist) ); par.lam0 = adjlon(0.5 * (lam_1 + lam_2)); proj_parm.dlam2 = adjlon(lam_2 - lam_1); proj_parm.cp1 = cos(phi_1); proj_parm.cp2 = cos(phi_2); proj_parm.sp1 = sin(phi_1); proj_parm.sp2 = sin(phi_2); proj_parm.cs = proj_parm.cp1 * proj_parm.sp2; proj_parm.sc = proj_parm.sp1 * proj_parm.cp2; proj_parm.ccs = proj_parm.cp1 * proj_parm.cp2 * sin(proj_parm.dlam2); proj_parm.z02 = aacos(proj_parm.sp1 * proj_parm.sp2 + proj_parm.cp1 * proj_parm.cp2 * cos(proj_parm.dlam2)); proj_parm.hz0 = .5 * proj_parm.z02; A12 = atan2(proj_parm.cp2 * sin(proj_parm.dlam2), proj_parm.cp1 * proj_parm.sp2 - proj_parm.sp1 * proj_parm.cp2 * cos(proj_parm.dlam2)); proj_parm.ca = cos(pp = aasin(proj_parm.cp1 * sin(A12))); proj_parm.sa = sin(pp); proj_parm.lp = adjlon(atan2(proj_parm.cp1 * cos(A12), proj_parm.sp1) - proj_parm.hz0); proj_parm.dlam2 *= .5; proj_parm.lamc = geometry::math::half_pi<T>() - atan2(sin(A12) * proj_parm.sp1, cos(A12)) - proj_parm.dlam2; proj_parm.thz0 = tan(proj_parm.hz0); proj_parm.rhshz0 = .5 / sin(proj_parm.hz0); proj_parm.r2z0 = 0.5 / proj_parm.z02; proj_parm.z02 *= proj_parm.z02; par.es = 0.; }
void geod_pre(void) { /* Stuff the WGS84 projection parameters as necessary To avoid having to include <geodesic,h> */ ellipse = 1; f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */ geod_a = WGS84_semimajor_axis_meters; es = 2 * f - f * f; onef = sqrt(1. - es); geod_f = 1 - onef; f2 = geod_f/2; f4 = geod_f/4; f64 = geod_f*geod_f/64; al12 = adjlon(al12); /* reduce to +- 0-PI */ signS = fabs(al12) > HALFPI ? 1 : 0; th1 = ellipse ? atan(onef * tan(phi1)) : phi1; costh1 = cos(th1); sinth1 = sin(th1); if ((merid = fabs(sina12 = sin(al12)) < MERI_TOL)) { sina12 = 0.; cosa12 = fabs(al12) < HALFPI ? 1. : -1.; M = 0.; } else { cosa12 = cos(al12); M = costh1 * sina12; } N = costh1 * cosa12; if (ellipse) { if (merid) { c1 = 0.; c2 = f4; D = 1. - c2; D *= D; P = c2 / D; } else { c1 = geod_f * M; c2 = f4 * (1. - M * M); D = (1. - c2)*(1. - c2 - c1 * M); P = (1. + .5 * c1 * M) * c2 / D; } } if (merid) s1 = HALFPI - th1; else { s1 = (fabs(M) >= 1.) ? 0. : acos(M); s1 = sinth1 / sin(s1); s1 = (fabs(s1) >= 1.) ? 0. : acos(s1); } }
static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { switch (OUTPUT_UNITS) { /* Handle false eastings/northings and non-metric linear units */ case PJ_IO_UNITS_CARTESIAN: if (P->is_geocent) { coo = proj_trans (P->cart, PJ_FWD, coo); } coo.xyz.x *= P->fr_meter; coo.xyz.y *= P->fr_meter; coo.xyz.z *= P->fr_meter; break; /* Classic proj.4 functions return plane coordinates in units of the semimajor axis */ case PJ_IO_UNITS_CLASSIC: coo.xy.x *= P->a; coo.xy.y *= P->a; /* Falls through */ /* (<-- GCC warning silencer) */ /* to continue processing in common with PJ_IO_UNITS_PROJECTED */ case PJ_IO_UNITS_PROJECTED: coo.xyz.x = P->fr_meter * (coo.xyz.x + P->x0); coo.xyz.y = P->fr_meter * (coo.xyz.y + P->y0); coo.xyz.z = P->vfr_meter * (coo.xyz.z + P->z0); break; case PJ_IO_UNITS_WHATEVER: break; case PJ_IO_UNITS_RADIANS: coo.lpz.z = P->vfr_meter * (coo.lpz.z + P->z0); if( P->is_long_wrap_set ) { if( coo.lpz.lam != HUGE_VAL ) { coo.lpz.lam = P->long_wrap_center + adjlon(coo.lpz.lam - P->long_wrap_center); } } break; } if (P->axisswap) coo = proj_trans (P->axisswap, PJ_FWD, coo); return coo; }
void geod_pre(void) { al12 = adjlon(al12); /* reduce to +- 0-PI */ signS = fabs(al12) > HALFPI ? 1 : 0; th1 = ellipse ? atan(onef * tan(phi1)) : phi1; costh1 = cos(th1); sinth1 = sin(th1); if ((merid = fabs(sina12 = sin(al12)) < MERI_TOL)) { sina12 = 0.; cosa12 = fabs(al12) < HALFPI ? 1. : -1.; M = 0.; } else { cosa12 = cos(al12); M = costh1 * sina12; } N = costh1 * cosa12; if (ellipse) { if (merid) { c1 = 0.; c2 = f4; D = 1. - c2; D *= D; P = c2 / D; } else { c1 = geod_f * M; c2 = f4 * (1. - M * M); D = (1. - c2) * (1. - c2 - c1 * M); P = (1. + .5 * c1 * M) * c2 / D; } } if (merid) s1 = HALFPI - th1; else { s1 = (fabs(M) >= 1.) ? 0. : acos(M); s1 = sinth1 / sin(s1); s1 = (fabs(s1) >= 1.) ? 0. : acos(s1); } }
LP /* inverse projection entry */ pj_inv(XY xy, PJ *P) { LP lp; /* can't do as much preliminary checking as with forward */ if (xy.x == HUGE_VAL || xy.y == HUGE_VAL) { lp.lam = lp.phi = HUGE_VAL; pj_ctx_set_errno( P->ctx, -15); return lp; } errno = pj_errno = 0; P->ctx->last_errno = 0; xy.x = (xy.x * P->to_meter - P->x0) * P->ra; /* descale and de-offset */ xy.y = (xy.y * P->to_meter - P->y0) * P->ra; //Check for NULL pointer if (P->inv != NULL) { lp = (*P->inv)(xy, P); /* inverse project */ if (P->ctx->last_errno ) lp.lam = lp.phi = HUGE_VAL; else { lp.lam += P->lam0; /* reduce from del lp.lam */ if (!P->over) lp.lam = adjlon(lp.lam); /* adjust longitude to CM */ if (P->geoc && fabs(fabs(lp.phi)-HALFPI) > EPS) lp.phi = atan(P->one_es * tan(lp.phi)); } } else { lp.lam = lp.phi = HUGE_VAL; } return lp; }
int pj_factors(LP lp, PJ *P, double h, struct FACTORS *fac) { struct DERIVS der; double cosphi, t, n, r; /* check for forward and latitude or longitude overange */ if ((t = fabs(lp.phi)-HALFPI) > EPS || fabs(lp.lam) > 10.) { pj_errno = -14; return 1; } else { /* proceed */ errno = pj_errno = 0; if (fabs(t) <= EPS) /* adjust to pi/2 */ lp.phi = lp.phi < 0. ? -HALFPI : HALFPI; else if (P->geoc) lp.phi = atan(P->rone_es * tan(lp.phi)); lp.lam -= P->lam0; /* compute del lp.lam */ if (!P->over) lp.lam = adjlon(lp.lam); /* adjust del longitude */ if (h <= 0.) h = DEFAULT_H; if (P->spc) /* get what projection analytic values */ P->spc(lp, P, fac); if (((fac->code & (IS_ANAL_XL_YL+IS_ANAL_XP_YP)) != (IS_ANAL_XL_YL+IS_ANAL_XP_YP)) && pj_deriv(lp, h, P, &der)) return 1; if (!(fac->code & IS_ANAL_XL_YL)) { fac->der.x_l = der.x_l; fac->der.y_l = der.y_l; } if (!(fac->code & IS_ANAL_XP_YP)) { fac->der.x_p = der.x_p; fac->der.y_p = der.y_p; } cosphi = cos(lp.phi); if (!(fac->code & IS_ANAL_HK)) { fac->h = hypot(fac->der.x_p, fac->der.y_p); fac->k = hypot(fac->der.x_l, fac->der.y_l) / cosphi; if (P->es) { t = sin(lp.phi); t = 1. - P->es * t * t; n = sqrt(t); fac->h *= t * n / P->one_es; fac->k *= n; r = t * t / P->one_es; } else r = 1.; } else if (P->es) { r = sin(lp.phi); r = 1. - P->es * r * r; r = r * r / P->one_es; } else r = 1.; /* convergence */ if (!(fac->code & IS_ANAL_CONV)) { fac->conv = - atan2(fac->der.y_l, fac->der.x_l); if (fac->code & IS_ANAL_XL_YL) fac->code |= IS_ANAL_CONV; } /* areal scale factor */ fac->s = (fac->der.y_p * fac->der.x_l - fac->der.x_p * fac->der.y_l) * r / cosphi; /* meridian-parallel angle theta prime */ fac->thetap = aasin(fac->s / (fac->h * fac->k)); /* Tissot ellips axis */ t = fac->k * fac->k + fac->h * fac->h; fac->a = sqrt(t + 2. * fac->s); t = (t = t - 2. * fac->s) <= 0. ? 0. : sqrt(t); fac->b = 0.5 * (fac->a - t); fac->a = 0.5 * (fac->a + t); /* omega */ fac->omega = 2. * aasin((fac->a - fac->b)/(fac->a + fac->b)); } return 0; }
LP nad_cvt(LP in, int inverse, struct CTABLE *ct) { LP t, tb; if (in.lam == HUGE_VAL) return in; /* normalize input to ll origin */ tb = in; tb.lam -= ct->ll.lam; tb.phi -= ct->ll.phi; tb.lam = adjlon(tb.lam); t = nad_intr(tb, ct); if (inverse) { LP del, dif; int i = MAX_TRY; if (t.lam == HUGE_VAL) return t; t.lam = tb.lam + t.lam; t.phi = tb.phi - t.phi; do { del = nad_intr(t, ct); /* This case used to return failure, but I have changed it to return the first order approximation of the inverse shift. This avoids cases where the grid shift *into* this grid came from another grid. While we aren't returning optimally correct results I feel a close result in this case is better than no result. NFW To demonstrate use -112.5839956 49.4914451 against the NTv2 grid shift file from Canada. */ if (del.lam == HUGE_VAL) { if( getenv( "PROJ_DEBUG" ) != NULL ) fprintf( stderr, "Inverse grid shift iteration failed, presumably at grid edge.\n" "Using first approximation.\n" ); /* return del */; break; } t.lam -= dif.lam = t.lam - del.lam - tb.lam; t.phi -= dif.phi = t.phi + del.phi - tb.phi; } while (i-- && fabs(dif.lam) > TOL && fabs(dif.phi) > TOL); if (i < 0) { if( getenv( "PROJ_DEBUG" ) != NULL ) fprintf( stderr, "Inverse grid shift iterator failed to converge.\n" ); t.lam = t.phi = HUGE_VAL; return t; } in.lam = adjlon(t.lam + ct->ll.lam); in.phi = t.phi + ct->ll.phi; } else { if (t.lam == HUGE_VAL) in = t; else { in.lam -= t.lam; in.phi += t.phi; } } return in; }
double DistGreatCircle(double slat, double slon, double dlat, double dlon) { // double th1,costh1,sinth1,sina12,cosa12,M,N,c1,c2,D,P,s1; // int merid, signS; // Input/Output from geodesic functions double al12; // Forward azimuth double al21; // Back azimuth double geod_S; // Distance double phi1, lam1, phi2, lam2; int ellipse; double geod_f; double geod_a; double es, onef, f, f64, f2, f4; double d5; phi1 = slat * DEGREE; lam1 = slon * DEGREE; phi2 = dlat * DEGREE; lam2 = dlon * DEGREE; //void geod_inv(struct georef_state *state) { double th1, th2, thm, dthm, dlamm, dlam, sindlamm, costhm, sinthm, cosdthm, sindthm, L, E, cosd, d, X, Y, T, sind, tandlammp, u, v, D, A, B; // Stuff the WGS84 projection parameters as necessary // To avoid having to include <geodesic,h> // ellipse = 1; f = 1.0 / WGSinvf; // WGS84 ellipsoid flattening parameter // geod_a = WGS84_semimajor_axis_meters; es = 2 * f - f * f; onef = sqrt(1. - es); geod_f = 1 - onef; f2 = geod_f / 2; f4 = geod_f / 4; f64 = geod_f*geod_f / 64; if (ellipse) { th1 = atan(onef * tan(phi1)); th2 = atan(onef * tan(phi2)); } else { th1 = phi1; th2 = phi2; } thm = .5 * (th1 + th2); dthm = .5 * (th2 - th1); dlamm = .5 * (dlam = adjlon(lam2 - lam1)); if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) { al12 = al21 = geod_S = 0.; return 0.0; } sindlamm = sin(dlamm); costhm = cos(thm); sinthm = sin(thm); cosdthm = cos(dthm); sindthm = sin(dthm); L = sindthm * sindthm + (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm; d = acos(cosd = 1 - L - L); if (ellipse) { E = cosd + cosd; sind = sin(d); Y = sinthm * cosdthm; Y *= (Y + Y) / (1. - L); T = sindthm * costhm; T *= (T + T) / L; X = Y + T; Y -= T; T = d / sind; D = 4. * T * T; A = D * E; B = D + D; geod_S = geod_a * sind * (T - f4 * (T * X - Y) + f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) + D * X * Y)); tandlammp = tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X)) * (f2 * T + f64 * (32. * T - (20. * T - A) * X - (B + 4.) * Y)) * tan(dlam))); } else { geod_S = geod_a * d; tandlammp = tan(dlamm); } u = atan2(sindthm, (tandlammp * costhm)); v = atan2(cosdthm, (tandlammp * sinthm)); al12 = adjlon(TWOPI + v - u); al21 = adjlon(TWOPI - v - u); } d5 = geod_S / 1852.0; return d5; }
#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 */
void geod_inv() { double th1,th2,thm,dthm,dlamm,dlam,sindlamm,costhm,sinthm,cosdthm, sindthm,L,E,cosd,d,X,Y,T,sind,tandlammp,u,v,D,A,B; /* Stuff the WGS84 projection parameters as necessary To avoid having to include <geodesic,h> */ ellipse = 1; f = 1.0 / WGSinvf; /* WGS84 ellipsoid flattening parameter */ geod_a = WGS84_semimajor_axis_meters; es = 2 * f - f * f; onef = sqrt(1. - es); geod_f = 1 - onef; f2 = geod_f/2; f4 = geod_f/4; f64 = geod_f*geod_f/64; if (ellipse) { th1 = atan(onef * tan(phi1)); th2 = atan(onef * tan(phi2)); } else { th1 = phi1; th2 = phi2; } thm = .5 * (th1 + th2); dthm = .5 * (th2 - th1); dlamm = .5 * ( dlam = adjlon(lam2 - lam1) ); if (fabs(dlam) < DTOL && fabs(dthm) < DTOL) { al12 = al21 = geod_S = 0.; return; } sindlamm = sin(dlamm); costhm = cos(thm); sinthm = sin(thm); cosdthm = cos(dthm); sindthm = sin(dthm); L = sindthm * sindthm + (cosdthm * cosdthm - sinthm * sinthm) * sindlamm * sindlamm; d = acos(cosd = 1 - L - L); if (ellipse) { E = cosd + cosd; sind = sin( d ); Y = sinthm * cosdthm; Y *= (Y + Y) / (1. - L); T = sindthm * costhm; T *= (T + T) / L; X = Y + T; Y -= T; T = d / sind; D = 4. * T * T; A = D * E; B = D + D; geod_S = geod_a * sind * (T - f4 * (T * X - Y) + f64 * (X * (A + (T - .5 * (A - E)) * X) - Y * (B + E * Y) + D * X * Y)); tandlammp = tan(.5 * (dlam - .25 * (Y + Y - E * (4. - X)) * (f2 * T + f64 * (32. * T - (20. * T - A) * X - (B + 4.) * Y)) * tan(dlam))); } else { geod_S = geod_a * d; tandlammp = tan(dlamm); } u = atan2(sindthm , (tandlammp * costhm)); v = atan2(cosdthm , (tandlammp * sinthm)); al12 = adjlon(TWOPI + v - u); al21 = adjlon(TWOPI - v - u); }
int pj_factors(LP lp, const PJ *P, double h, struct FACTORS *fac) { double cosphi, t, n, r; int err; PJ_COORD coo = {{0, 0, 0, 0}}; coo.lp = lp; /* Failing the 3 initial checks will most likely be due to */ /* earlier errors, so we leave errno alone */ if (0==fac) return 1; if (0==P) return 1; if (HUGE_VAL==lp.lam) return 1; /* But from here, we're ready to make our own mistakes */ err = proj_errno_reset (P); /* Indicate that all factors are numerical approximations */ fac->code = 0; /* Check for latitude or longitude overange */ if ((fabs (lp.phi)-M_HALFPI) > EPS || fabs (lp.lam) > 10.) { proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); return 1; } /* Set a reasonable step size for the numerical derivatives */ h = fabs (h); if (h < EPS) h = DEFAULT_H; /* If input latitudes are geocentric, convert to geographic */ if (P->geoc) lp = proj_geocentric_latitude (P, PJ_INV, coo).lp; /* If latitude + one step overshoots the pole, move it slightly inside, */ /* so the numerical derivative still exists */ if (fabs (lp.phi) > (M_HALFPI - h)) lp.phi = lp.phi < 0. ? -(M_HALFPI-h) : (M_HALFPI-h); /* Longitudinal distance from central meridian */ lp.lam -= P->lam0; if (!P->over) lp.lam = adjlon(lp.lam); /* Derivatives */ if (pj_deriv (lp, h, P, &(fac->der))) { proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); return 1; } /* Scale factors */ cosphi = cos (lp.phi); fac->h = hypot (fac->der.x_p, fac->der.y_p); fac->k = hypot (fac->der.x_l, fac->der.y_l) / cosphi; if (P->es != 0.0) { t = sin(lp.phi); t = 1. - P->es * t * t; n = sqrt(t); fac->h *= t * n / P->one_es; fac->k *= n; r = t * t / P->one_es; } else r = 1.; /* Convergence */ fac->conv = -atan2 (fac->der.x_p, fac->der.y_p); /* Areal scale factor */ fac->s = (fac->der.y_p * fac->der.x_l - fac->der.x_p * fac->der.y_l) * r / cosphi; /* Meridian-parallel angle (theta prime) */ fac->thetap = aasin(P->ctx,fac->s / (fac->h * fac->k)); /* Tissot ellipse axis */ t = fac->k * fac->k + fac->h * fac->h; fac->a = sqrt(t + 2. * fac->s); t = t - 2. * fac->s; t = t > 0? sqrt(t): 0; fac->b = 0.5 * (fac->a - t); fac->a = 0.5 * (fac->a + t); /* Angular distortion */ fac->omega = 2. * aasin(P->ctx, (fac->a - fac->b) / (fac->a + fac->b) ); proj_errno_restore (P, err); return 0; }
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; }