PJ *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv) { /************************************************************************************** Create a new PJ object in the context ctx, using the given definition argument array argv. If ctx==0, the default context is used, if definition==0, or invalid, a null-pointer is returned. The definition arguments may use '+' as argument start indicator, as in {"+proj=utm", "+zone=32"}, or leave it out, as in {"proj=utm", "zone=32"}. **************************************************************************************/ PJ *P; const char *c; if (0==argv) return 0; if (0==ctx) ctx = pj_get_default_ctx (); /* We assume that free format is used, and build a full proj_create compatible string */ c = pj_make_args (argc, argv); if (0==c) return 0; P = proj_create (ctx, c); pj_dealloc ((char *) c); return P; }
PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *srid_from, const char *srid_to, PJ_AREA *area) { /****************************************************************************** Create a transformation pipeline between two known coordinate reference systems. srid_from and srid_to should be the value part of a +init=... parameter set, i.e. "epsg:25833" or "IGNF:AMST63". Any projection definition that can be found in a init-file in PROJ_LIB is a valid input to this function. For now the function mimics the cs2cs app: An input and an output CRS is given and coordinates are transformed via a hub datum (WGS84). This transformation strategy is referred to as "early-binding" by the EPSG. The function can be extended to support "late-binding" transformations in the future without affecting users of the function. An "area of use" can be specified in area. In the current version of this function is has no function, but is added in anticipation of a "late-binding" implementation in the future. The idea being, that if a user supplies an area of use, the more accurate transformation between two given systems can be chosen. Example call: PJ *P = proj_create_crs_to_crs(0, "epsg:25832", "epsg:25833", NULL); ******************************************************************************/ PJ *P; char buffer[512]; size_t len; /* area not in use yet, suppressing warning */ (void)area; strcpy(buffer, "+proj=pipeline +step +init="); len = strlen(buffer); strncat(buffer + len, srid_from, sizeof(buffer)-1-len); len += strlen(buffer + len); strncat(buffer + len, " +inv +step +init=", sizeof(buffer)-1-len); len += strlen(buffer + len); strncat(buffer + len, srid_to, sizeof(buffer)-1-len); P = proj_create(ctx, buffer); return P; }
GeoConvHelper::GeoConvHelper(const std::string& proj, const Position& offset, const Boundary& orig, const Boundary& conv, double scale, double rot, bool inverse, bool flatten): myProjString(proj), #ifdef PROJ_API_FILE myProjection(nullptr), myInverseProjection(nullptr), myGeoProjection(nullptr), #endif myOffset(offset), myGeoScale(scale), mySin(sin(DEG2RAD(-rot))), // rotate clockwise myCos(cos(DEG2RAD(-rot))), myProjectionMethod(NONE), myUseInverseProjection(inverse), myFlatten(flatten), myOrigBoundary(orig), myConvBoundary(conv) { if (proj == "!") { myProjectionMethod = NONE; } else if (proj == "-") { myProjectionMethod = SIMPLE; } else if (proj == "UTM") { myProjectionMethod = UTM; } else if (proj == "DHDN") { myProjectionMethod = DHDN; } else if (proj == "DHDN_UTM") { myProjectionMethod = DHDN_UTM; #ifdef PROJ_API_FILE } else { myProjectionMethod = PROJ; #ifdef PROJ_VERSION_MAJOR myProjection = proj_create(PJ_DEFAULT_CTX, proj.c_str()); #else myProjection = pj_init_plus(proj.c_str()); #endif if (myProjection == nullptr) { // !!! check pj_errno throw ProcessError("Could not build projection!"); } #endif } }
static int operation (char *args) { /***************************************************************************** Define the operation to apply to the input data (in ISO 19100 lingo, an operation is the general term describing something that can be either a conversion or a transformation) ******************************************************************************/ T.op_id++; T.operation_lineno = F->lineno; strncpy (&(T.operation[0]), F->args, MAX_OPERATION); T.operation[MAX_OPERATION] = '\0'; if (T.verbosity > 1) { finish_previous_operation (F->args); banner (args); } T.op_ok = 0; T.op_ko = 0; T.op_skip = 0; T.skip_test = 0; direction ("forward"); tolerance ("0.5 mm"); ignore ("pjd_err_dont_skip"); proj_errno_reset (T.P); if (T.P) proj_destroy (T.P); proj_errno_reset (nullptr); proj_context_use_proj4_init_rules(nullptr, T.use_proj4_init_rules); T.P = proj_create (nullptr, F->args); /* Checking that proj_create succeeds is first done at "expect" time, */ /* since we want to support "expect"ing specific error codes */ return 0; }
static int cs2cs_emulation_setup (PJ *P) { /************************************************************************************** If any cs2cs style modifiers are given (axis=..., towgs84=..., ) create the 4D API equivalent operations, so the preparation and finalization steps in the pj_inv/pj_fwd invocators can emulate the behaviour of pj_transform and the cs2cs app. Returns 1 on success, 0 on failure **************************************************************************************/ PJ *Q; paralist *p; int do_cart = 0; if (0==P) return 0; /* Don't recurse when calling proj_create (which calls us back) */ if (pj_param_exists (P->params, "break_cs2cs_recursion")) return 1; /* Swap axes? */ p = pj_param_exists (P->params, "axis"); /* Don't axisswap if data are already in "enu" order */ if (p && (0!=strcmp ("enu", p->param))) { char *def = malloc (100+strlen(P->axis)); if (0==def) return 0; sprintf (def, "break_cs2cs_recursion proj=axisswap axis=%s", P->axis); Q = proj_create (P->ctx, def); free (def); if (0==Q) return 0; P->axisswap = skip_prep_fin(Q); } /* Geoid grid(s) given? */ p = pj_param_exists (P->params, "geoidgrids"); if (p && strlen (p->param) > strlen ("geoidgrids=")) { char *gridnames = p->param + strlen ("geoidgrids="); char *def = malloc (100+strlen(gridnames)); if (0==def) return 0; sprintf (def, "break_cs2cs_recursion proj=vgridshift grids=%s", gridnames); Q = proj_create (P->ctx, def); free (def); if (0==Q) return 0; P->vgridshift = skip_prep_fin(Q); } /* Datum shift grid(s) given? */ p = pj_param_exists (P->params, "nadgrids"); if (p && strlen (p->param) > strlen ("nadgrids=")) { char *gridnames = p->param + strlen ("nadgrids="); char *def = malloc (100+strlen(gridnames)); if (0==def) return 0; sprintf (def, "break_cs2cs_recursion proj=hgridshift grids=%s", gridnames); Q = proj_create (P->ctx, def); free (def); if (0==Q) return 0; P->hgridshift = skip_prep_fin(Q); } /* We ignore helmert if we have grid shift */ p = P->hgridshift ? 0 : pj_param_exists (P->params, "towgs84"); while (p) { char *def; char *s = p->param; double *d = P->datum_params; size_t n = strlen (s); /* We ignore null helmert shifts (common in auto-translated resource files, e.g. epsg) */ if (0==d[0] && 0==d[1] && 0==d[2] && 0==d[3] && 0==d[4] && 0==d[5] && 0==d[6]) { /* If the current ellipsoid is not WGS84, then make sure the */ /* change in ellipsoid is still done. */ if (!(fabs(P->a_orig - 6378137.0) < 1e-8 && fabs(P->es_orig - 0.0066943799901413) < 1e-15)) { do_cart = 1; } break; } if (n <= 8) /* 8==strlen ("towgs84=") */ return 0; def = malloc (100+n); if (0==def) return 0; sprintf (def, "break_cs2cs_recursion proj=helmert exact %s transpose", s); Q = proj_create (P->ctx, def); pj_inherit_ellipsoid_def (P, Q); free (def); if (0==Q) return 0; P->helmert = skip_prep_fin (Q); break; } /* We also need cartesian/geographical transformations if we are working in */ /* geocentric/cartesian space or we need to do a Helmert transform. */ if (P->is_geocent || P->helmert || do_cart) { char def[150]; sprintf (def, "break_cs2cs_recursion proj=cart a=%40.20g es=%40.20g", P->a_orig, P->es_orig); Q = proj_create (P->ctx, def); if (0==Q) return 0; P->cart = skip_prep_fin (Q); sprintf (def, "break_cs2cs_recursion proj=cart ellps=WGS84"); Q = proj_create (P->ctx, def); if (0==Q) return 0; P->cart_wgs84 = skip_prep_fin (Q); } return 1; }
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; }
GeoConvHelper& GeoConvHelper::operator=(const GeoConvHelper& orig) { myProjString = orig.myProjString; myOffset = orig.myOffset; myProjectionMethod = orig.myProjectionMethod; myOrigBoundary = orig.myOrigBoundary; myConvBoundary = orig.myConvBoundary; myGeoScale = orig.myGeoScale; myCos = orig.myCos; mySin = orig.mySin; myUseInverseProjection = orig.myUseInverseProjection; myFlatten = orig.myFlatten; #ifdef PROJ_API_FILE if (myProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR proj_destroy(myProjection); #else pj_free(myProjection); #endif myProjection = nullptr; } if (myInverseProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR proj_destroy(myInverseProjection); #else pj_free(myInverseProjection); #endif myInverseProjection = nullptr; } if (myGeoProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR proj_destroy(myGeoProjection); #else pj_free(myGeoProjection); #endif myGeoProjection = nullptr; } if (orig.myProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR myProjection = proj_create(PJ_DEFAULT_CTX, orig.myProjString.c_str()); #else myProjection = pj_init_plus(orig.myProjString.c_str()); #endif } if (orig.myInverseProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR myInverseProjection = orig.myInverseProjection; #else myInverseProjection = pj_init_plus(pj_get_def(orig.myInverseProjection, 0)); #endif } if (orig.myGeoProjection != nullptr) { #ifdef PROJ_VERSION_MAJOR myGeoProjection = orig.myGeoProjection; #else myGeoProjection = pj_init_plus(pj_get_def(orig.myGeoProjection, 0)); #endif } #endif return *this; }