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 }
static PJ_XYZ get_grid_shift(PJ* P, PJ_XYZ cartesian) { /******************************************************************************** Read correction values from grid. The cartesian input coordinates are converted to geodetic coordinates in order look up the correction values in the grid. Once the grid corrections are read we need to convert them from ENU-space to cartesian PJ_XYZ-space. ENU -> PJ_XYZ formula described in: Nørbech, T., et al, 2003(?), "Transformation from a Common Nordic Reference Frame to ETRS89 in Denmark, Finland, Norway, and Sweden – status report" ********************************************************************************/ PJ_COORD geodetic, shift, temp; double sp, cp, sl, cl; int previous_errno = proj_errno_reset(P); /* cartesian to geodetic */ geodetic.lpz = pj_inv3d(cartesian, static_cast<struct pj_opaque*>(P->opaque)->cart); /* look up correction values in grids */ shift.lp = proj_hgrid_value(P, geodetic.lp); shift.enu.u = proj_vgrid_value(P, geodetic.lp); if (proj_errno(P) == PJD_ERR_GRID_AREA) proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model", proj_todeg(geodetic.lp.lam), proj_todeg(geodetic.lp.phi)); /* grid values are stored as mm/yr, we need m/yr */ shift.xyz.x /= 1000; shift.xyz.y /= 1000; shift.xyz.z /= 1000; /* pre-calc cosines and sines */ sp = sin(geodetic.lp.phi); cp = cos(geodetic.lp.phi); sl = sin(geodetic.lp.lam); cl = cos(geodetic.lp.lam); /* ENU -> PJ_XYZ */ temp.xyz.x = -sp*cl*shift.enu.n - sl*shift.enu.e + cp*cl*shift.enu.u; temp.xyz.y = -sp*sl*shift.enu.n + cl*shift.enu.e + cp*sl*shift.enu.u; temp.xyz.z = cp*shift.enu.n + sp*shift.enu.u; shift.xyz = temp.xyz; proj_errno_restore(P, previous_errno); return shift.xyz; }
static PJ_COORD todeg_coord (PJ *P, PJ_DIRECTION dir, PJ_COORD a) { size_t i, n; const char *axis = "enut"; paralist *l = pj_param_exists (P->params, "axis"); if (l && dir==PJ_FWD) axis = l->param + strlen ("axis="); n = strlen (axis); for (i = 0; i < n; i++) if (strchr ("news", axis[i])) a.v[i] = proj_todeg (a.v[i]); return a; }
static double strtod_scaled (const char *args, double default_scale) { /***************************************************************************** Interpret <args> as a numeric followed by a linear decadal prefix. Return the properly scaled numeric ******************************************************************************/ double s; const double GRS80_DEG = 111319.4908; /* deg-to-m at equator of GRS80 */ const char *endp = args; s = proj_strtod (args, (char **) &endp); if (args==endp) return HUGE_VAL; endp = column (args, 2); if (0==strcmp(endp, "km")) s *= 1000; else if (0==strcmp(endp, "m")) s *= 1; else if (0==strcmp(endp, "dm")) s /= 10; else if (0==strcmp(endp, "cm")) s /= 100; else if (0==strcmp(endp, "mm")) s /= 1000; else if (0==strcmp(endp, "um")) s /= 1e6; else if (0==strcmp(endp, "nm")) s /= 1e9; else if (0==strcmp(endp, "rad")) s = GRS80_DEG * proj_todeg (s); else if (0==strcmp(endp, "deg")) s = GRS80_DEG * s; else s *= default_scale; return s; }
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; }