/* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_COORD *coord) { int i; PJ_COORD t, org; if (0==P) return HUGE_VAL; if (n < 1) { proj_errno_set (P, EINVAL); return HUGE_VAL; } /* in the first half-step, we generate the output value */ org = *coord; *coord = proj_trans (P, direction, org); t = *coord; /* now we take n-1 full steps in inverse direction: We are */ /* out of phase due to the half step already taken */ for (i = 0; i < n - 1; i++) t = proj_trans (P, direction, proj_trans (P, -direction, t) ); /* finally, we take the last half-step */ t = proj_trans (P, -direction, t); /* checking for angular *input* since we do a roundtrip, and end where we begin */ if (proj_angular_input (P, direction)) return proj_lpz_dist (P, org, t); return proj_xyz_dist (org, t); }
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 GeoConvHelper::cartesian2geo(Position& cartesian) const { cartesian.sub(getOffsetBase()); if (myProjectionMethod == NONE) { return; } if (myProjectionMethod == SIMPLE) { const double y = cartesian.y() / 111136.; const double x = cartesian.x() / 111320. / cos(DEG2RAD(y)); cartesian.set(x, y); return; } #ifdef PROJ_API_FILE #ifdef PROJ_VERSION_MAJOR PJ_COORD c; c.xy.x = cartesian.x(); c.xy.y = cartesian.y(); c = proj_trans(myProjection, PJ_INV, c); cartesian.set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi)); #else projUV p; p.u = cartesian.x(); p.v = cartesian.y(); p = pj_inv(p, myProjection); //!!! check pj_errno p.u *= RAD_TO_DEG; p.v *= RAD_TO_DEG; cartesian.set((double) p.u, (double) p.v); #endif #endif }
bool GeoConvHelper::x2cartesian_const(Position& from) const { double x2 = from.x() * myGeoScale; double y2 = from.y() * myGeoScale; double x = x2 * myCos - y2 * mySin; double y = x2 * mySin + y2 * myCos; if (myProjectionMethod == NONE) { from.add(myOffset); } else if (myUseInverseProjection) { cartesian2geo(from); } else { if (x > 180.1 || x < -180.1) { WRITE_WARNING("Invalid longitude " + toString(x)); return false; } if (y > 90.1 || y < -90.1) { WRITE_WARNING("Invalid latitude " + toString(y)); return false; } #ifdef PROJ_API_FILE if (myProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR PJ_COORD c; c.lp.lam = proj_torad(x); c.lp.phi = proj_torad(y); c = proj_trans(myProjection, PJ_FWD, c); //!!! check pj_errno x = c.xy.x; y = c.xy.y; #else projUV p; p.u = x * DEG_TO_RAD; p.v = y * DEG_TO_RAD; p = pj_fwd(p, myProjection); //!!! check pj_errno x = p.u; y = p.v; #endif } #endif if (myProjectionMethod == SIMPLE) { x *= 111320. * cos(DEG2RAD(y)); y *= 111136.; //!!! recheck whether the axes are mirrored } } if (x > std::numeric_limits<double>::max() || y > std::numeric_limits<double>::max()) { return false; } from.set(x, y); from.add(myOffset); if (myFlatten) { from.setz(0); } return true; }
/* dimensionality as the number of dimensions given in accept */ static PJ_COORD expect_trans_n_dim (PJ_COORD ci) { if (4==T.dimensions_given_at_last_accept) return proj_trans (T.P, T.dir, ci); if (3==T.dimensions_given_at_last_accept) return pj_approx_3D_trans (T.P, T.dir, ci); return pj_approx_2D_trans (T.P, T.dir, ci); }
static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P) { int i, first_step, last_step; first_step = static_cast<struct pj_opaque*>(P->opaque)->steps; last_step = 0; for (i = first_step; i != last_step; i--) point = proj_trans (static_cast<struct pj_opaque*>(P->opaque)->pipeline[i], PJ_INV, point); return point; }
static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) { int i, first_step, last_step; first_step = 1; last_step = static_cast<struct pj_opaque*>(P->opaque)->steps + 1; for (i = first_step; i != last_step; i++) point = proj_trans (static_cast<struct pj_opaque*>(P->opaque)->pipeline[i], PJ_FWD, point); return point; }
int proj_trans_array (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord) { /****************************************************************************** Batch transform an array of PJ_COORD. Returns 0 if all coordinates are transformed without error, otherwise returns error number. ******************************************************************************/ size_t i; for (i = 0; i < n; i++) { coord[i] = proj_trans (P, direction, coord[i]); if (proj_errno(P)) return proj_errno (P); } return 0; }
bool GeoConvHelper::x2cartesian(Position& from, bool includeInBoundary) { if (includeInBoundary) { myOrigBoundary.add(from); } // init projection parameter on first use #ifdef PROJ_API_FILE if (myProjection == nullptr) { double x = from.x() * myGeoScale; switch (myProjectionMethod) { case DHDN_UTM: { int zone = (int)((x - 500000.) / 1000000.); if (zone < 1 || zone > 5) { WRITE_WARNING("Attempt to initialize DHDN_UTM-projection on invalid longitude " + toString(x)); return false; } myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3 * zone) + " +k=1 +x_0=" + toString(zone * 1000000 + 500000) + " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs"; #ifdef PROJ_VERSION_MAJOR myInverseProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str()); myGeoProjection = proj_create(PJ_DEFAULT_CTX, "+proj=latlong +datum=WGS84"); #else myInverseProjection = pj_init_plus(myProjString.c_str()); myGeoProjection = pj_init_plus("+proj=latlong +datum=WGS84"); #endif //!!! check pj_errno x = ((x - 500000.) / 1000000.) * 3; // continues with UTM } FALLTHROUGH; case UTM: { int zone = (int)(x + 180) / 6 + 1; myProjString = "+proj=utm +zone=" + toString(zone) + " +ellps=WGS84 +datum=WGS84 +units=m +no_defs"; #ifdef PROJ_VERSION_MAJOR myProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str()); #else myProjection = pj_init_plus(myProjString.c_str()); #endif //!!! check pj_errno } break; case DHDN: { int zone = (int)(x / 3); if (zone < 1 || zone > 5) { WRITE_WARNING("Attempt to initialize DHDN-projection on invalid longitude " + toString(x)); return false; } myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3 * zone) + " +k=1 +x_0=" + toString(zone * 1000000 + 500000) + " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs"; #ifdef PROJ_VERSION_MAJOR myProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str()); #else myProjection = pj_init_plus(myProjString.c_str()); #endif //!!! check pj_errno } break; default: break; } } if (myInverseProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR PJ_COORD c; c.xy.x = from.x(); c.xy.y = from.y(); c = proj_trans(myInverseProjection, PJ_INV, c); from.set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi)); #else double x = from.x(); double y = from.y(); if (pj_transform(myInverseProjection, myGeoProjection, 1, 1, &x, &y, nullptr)) { WRITE_WARNING("Could not transform (" + toString(x) + "," + toString(y) + ")"); } from.set(double(x * RAD_TO_DEG), double(y * RAD_TO_DEG)); #endif } #endif // perform conversion bool ok = x2cartesian_const(from); if (ok) { if (includeInBoundary) { myConvBoundary.add(from); } } return ok; }
bool reproject(T & geom, projection const& source, projection const& dest) { proj_transform proj_trans(source, dest); detail::geom_reproj_visitor visit(proj_trans); return visit(geom); }
T reproject_copy(T const& geom, projection const& source, projection const& dest, unsigned int & n_err) { proj_transform proj_trans(source, dest); return reproject_copy(geom, proj_trans, n_err); }
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; }
static int expect (const char *args) { /***************************************************************************** Tell GIE what to expect, when transforming the ACCEPTed input ******************************************************************************/ PJ_COORD ci, co, ce; double d; int expect_failure = 0; int expect_failure_with_errno = 0; if (0==strncmp (args, "failure", 7)) { expect_failure = 1; /* Option: Fail with an expected errno (syntax: expect failure errno -33) */ if (0==strncmp (column (args, 2), "errno", 5)) expect_failure_with_errno = errno_from_err_const (column (args, 3)); } if (T.ignore==proj_errno(T.P)) return another_skip (); if (nullptr==T.P) { /* If we expect failure, and fail, then it's a success... */ if (expect_failure) { /* Failed to fail correctly? */ if (expect_failure_with_errno && proj_errno (T.P)!=expect_failure_with_errno) return expect_failure_with_errno_message (expect_failure_with_errno, proj_errno(T.P)); return another_succeeding_failure (); } /* Otherwise, it's a true failure */ banner (T.operation); errmsg (3, "%sInvalid operation definition in line no. %d:\n %s (errno=%s/%d)\n", delim, (int) T.operation_lineno, pj_strerrno(proj_errno(T.P)), err_const_from_errno (proj_errno(T.P)), proj_errno(T.P) ); return another_failing_failure (); } /* We may still successfully fail even if the proj_create succeeded */ if (expect_failure) { proj_errno_reset (T.P); /* Try to carry out the operation - and expect failure */ ci = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; co = expect_trans_n_dim (ci); if (expect_failure_with_errno) { if (proj_errno (T.P)==expect_failure_with_errno) return another_succeeding_failure (); fprintf (T.fout, "errno=%d, expected=%d\n", proj_errno (T.P), expect_failure_with_errno); return another_failing_failure (); } /* Succeeded in failing? - that's a success */ if (co.xyz.x==HUGE_VAL) return another_succeeding_failure (); /* Failed to fail? - that's a failure */ banner (T.operation); errmsg (3, "%sFailed to fail. Operation definition in line no. %d\n", delim, (int) T.operation_lineno ); return another_failing_failure (); } if (T.verbosity > 3) { fprintf (T.fout, "%s\n", T.P->inverted? "INVERTED": "NOT INVERTED"); fprintf (T.fout, "%s\n", T.dir== 1? "forward": "reverse"); fprintf (T.fout, "%s\n", proj_angular_input (T.P, T.dir)? "angular in": "linear in"); fprintf (T.fout, "%s\n", proj_angular_output (T.P, T.dir)? "angular out": "linear out"); fprintf (T.fout, "left: %d right: %d\n", T.P->left, T.P->right); } tests++; T.e = parse_coord (args); if (HUGE_VAL==T.e.v[0]) return expect_message_cannot_parse (args); /* expected angular values, probably in degrees */ ce = proj_angular_output (T.P, T.dir)? torad_coord (T.P, T.dir, T.e): T.e; if (T.verbosity > 3) fprintf (T.fout, "EXPECTS %.12f %.12f %.12f %.12f\n", ce.v[0],ce.v[1],ce.v[2],ce.v[3]); /* input ("accepted") values, also probably in degrees */ ci = proj_angular_input (T.P, T.dir)? torad_coord (T.P, T.dir, T.a): T.a; if (T.verbosity > 3) fprintf (T.fout, "ACCEPTS %.12f %.12f %.12f %.12f\n", ci.v[0],ci.v[1],ci.v[2],ci.v[3]); /* do the transformation, but mask off dimensions not given in expect-ation */ co = expect_trans_n_dim (ci); if (T.dimensions_given < 4) co.v[3] = 0; if (T.dimensions_given < 3) co.v[2] = 0; /* angular output from proj_trans comes in radians */ T.b = proj_angular_output (T.P, T.dir)? todeg_coord (T.P, T.dir, co): co; if (T.verbosity > 3) fprintf (T.fout, "GOT %.12f %.12f %.12f %.12f\n", co.v[0],co.v[1],co.v[2],co.v[3]); #if 0 /* We need to handle unusual axis orders - that'll be an item for version 5.1 */ if (T.P->axisswap) { ce = proj_trans (T.P->axisswap, T.dir, ce); co = proj_trans (T.P->axisswap, T.dir, co); } #endif if (proj_angular_output (T.P, T.dir)) d = proj_lpz_dist (T.P, ce, co); else d = proj_xyz_dist (co, ce); if (d > T.tolerance) return expect_message (d, args); succs++; another_success (); return 0; }