52 const Boundary& orig,
const Boundary& conv,
double scale,
double rot,
bool inverse,
bool flatten):
55 myProjection(nullptr),
56 myInverseProjection(nullptr),
57 myGeoProjection(nullptr),
64 myProjectionMethod(
NONE),
65 myUseInverseProjection(inverse),
68 myConvBoundary(conv) {
75 }
else if (proj ==
"-") {
77 }
else if (proj ==
"UTM") {
79 }
else if (proj ==
"DHDN") {
81 }
else if (proj ==
"DHDN_UTM") {
87 if (myProjection ==
nullptr) {
89 myProjString = std::regex_replace(proj, std::regex(
"\\+geoidgrids[^ ]*"), std::string(
""));
90 myProjString = std::regex_replace(
myProjString, std::regex(
"\\+step \\+proj=vgridshift \\+grids[^ ]*"), std::string(
""));
96 if (myProjection ==
nullptr) {
106GeoConvHelper::initProj(
const std::string& proj) {
107#ifdef PROJ_VERSION_MAJOR
108 myProjection = proj_create(PJ_DEFAULT_CTX, proj.c_str());
109 checkError(myProjection);
110#if PROJ_VERSION_MAJOR > 5
111 if (myProjection !=
nullptr) {
112 const PJ_TYPE type = proj_get_type(myProjection);
113 if (type != PJ_TYPE_TRANSFORMATION
114 && type != PJ_TYPE_CONCATENATED_OPERATION
115 && type != PJ_TYPE_OTHER_COORDINATE_OPERATION) {
117 proj_destroy(myProjection);
118 PJ_CONTEXT* ctx = proj_context_create();
119 proj_context_use_proj4_init_rules(ctx, 1);
120 myProjection = proj_create_crs_to_crs(ctx,
121 "+proj=longlat +datum=WGS84 +type=crs +no_defs",
124 checkError(myProjection);
137 myProjection = pj_init_plus(proj.c_str());
145 if (myProjection !=
nullptr) {
146#ifdef PROJ_VERSION_MAJOR
147 proj_destroy(myProjection);
149 pj_free(myProjection);
152 if (myInverseProjection !=
nullptr) {
153#ifdef PROJ_VERSION_MAJOR
154 proj_destroy(myInverseProjection);
156 pj_free(myInverseProjection);
159 if (myGeoProjection !=
nullptr) {
160#ifdef PROJ_VERSION_MAJOR
161 proj_destroy(myGeoProjection);
163 pj_free(myGeoProjection);
198 if (myProjection !=
nullptr) {
199#ifdef PROJ_VERSION_MAJOR
200 proj_destroy(myProjection);
202 pj_free(myProjection);
204 myProjection =
nullptr;
206 if (myInverseProjection !=
nullptr) {
207#ifdef PROJ_VERSION_MAJOR
208 proj_destroy(myInverseProjection);
210 pj_free(myInverseProjection);
212 myInverseProjection =
nullptr;
214 if (myGeoProjection !=
nullptr) {
215#ifdef PROJ_VERSION_MAJOR
216 proj_destroy(myGeoProjection);
218 pj_free(myGeoProjection);
220 myGeoProjection =
nullptr;
222 if (orig.myProjection !=
nullptr) {
225 if (orig.myInverseProjection !=
nullptr) {
226#ifdef PROJ_VERSION_MAJOR
227 myInverseProjection = orig.myInverseProjection;
229 myInverseProjection = pj_init_plus(pj_get_def(orig.myInverseProjection, 0));
232 if (orig.myGeoProjection !=
nullptr) {
233#ifdef PROJ_VERSION_MAJOR
234 myGeoProjection = orig.myGeoProjection;
236 myGeoProjection = pj_init_plus(pj_get_def(orig.myGeoProjection, 0));
246 std::string proj =
"!";
247 double scale = oc.
getFloat(
"proj.scale");
248 double rot = oc.
getFloat(
"proj.rotate");
250 bool inverse = oc.
exists(
"proj.inverse") && oc.
getBool(
"proj.inverse");
251 bool flatten = oc.
exists(
"flatten") && oc.
getBool(
"flatten");
253 if (oc.
getBool(
"simple-projection")) {
258#ifdef PROJ_VERSION_MAJOR
260 if (getenv(
"SUMO_HOME") !=
nullptr) {
261 const char* paths[] = { (std::string(getenv(
"SUMO_HOME")) +
"/data/proj").c_str() };
262 proj_context_set_search_paths(PJ_DEFAULT_CTX, 1, paths);
267 WRITE_ERROR(
TL(
"Inverse projection works only with explicit proj parameters."));
271 if (numProjections > 1) {
272 WRITE_ERROR(
TL(
"The projection method needs to be uniquely defined."));
278 }
else if (oc.
getBool(
"proj.dhdn")) {
280 }
else if (oc.
getBool(
"proj.dhdnutm")) {
294 const Boundary& conv,
double scale) {
303 if (myProjection ==
nullptr &&
309 if (myProjection ==
nullptr) {
322 oc.
addSynonyme(
"simple-projection",
"proj.simple",
true);
323 oc.
addDescription(
"simple-projection",
"Projection",
TL(
"Uses a simple method for projection"));
326 oc.
addDescription(
"proj.scale",
"Projection",
TL(
"Scaling factor for input coordinates"));
329 oc.
addDescription(
"proj.rotate",
"Projection",
TL(
"Rotation (clockwise degrees) for input coordinates"));
333 oc.
addDescription(
"proj.utm",
"Projection",
TL(
"Determine the UTM zone (for a universal transversal mercator projection based on the WGS84 ellipsoid)"));
336 oc.
addDescription(
"proj.dhdn",
"Projection",
"Determine the DHDN zone (for a transversal mercator projection based on the bessel ellipsoid, \"Gauss-Krueger\")");
339 oc.
addDescription(
"proj",
"Projection",
TL(
"Uses STR as proj.4 definition for projection"));
345 oc.
addDescription(
"proj.dhdnutm",
"Projection",
TL(
"Convert from Gauss-Krueger to UTM"));
369 const double y = cartesian.
y() / 111136.;
370 const double x = cartesian.
x() / 111320. / cos(
DEG2RAD(y));
375#ifdef PROJ_VERSION_MAJOR
376 PJ_COORD c = proj_coord(cartesian.
x(), cartesian.
y(), cartesian.
z(), 0);
377 c = proj_trans(myProjection, PJ_INV, c);
378 checkError(myProjection);
380 cartesian.
set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi));
382 cartesian.
set(c.lp.lam, c.lp.phi);
388 p = pj_inv(p, myProjection);
392 cartesian.
set((
double) p.u, (
double) p.v);
399#ifdef PROJ_VERSION_MAJOR
401GeoConvHelper::checkError(projPJ projection)
const {
402 const int err_no = proj_context_errno(PJ_DEFAULT_CTX);
403 const char* err_string =
"";
405#if PROJ_VERSION_MAJOR > 7
406 err_string = proj_context_errno_string(PJ_DEFAULT_CTX, err_no);
408 err_string = proj_errno_string(err_no);
411 if (projection ==
nullptr) {
431 if (includeInBoundary) {
436 if (myProjection ==
nullptr) {
440 int zone = (int)((x - 500000.) / 1000000.);
441 if (zone < 1 || zone > 5) {
446 " +k=1 +x_0=" +
toString(zone * 1000000 + 500000) +
447 " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
448#ifdef PROJ_VERSION_MAJOR
449 myInverseProjection = proj_create(PJ_DEFAULT_CTX,
myProjString.c_str());
450 checkError(myInverseProjection);
451 myGeoProjection = proj_create(PJ_DEFAULT_CTX,
"+proj=latlong +datum=WGS84");
452 checkError(myGeoProjection);
454 myInverseProjection = pj_init_plus(
myProjString.c_str());
455 myGeoProjection = pj_init_plus(
"+proj=latlong +datum=WGS84");
457 x = ((x - 500000.) / 1000000.) * 3;
461 int zone = (int)(x + 180) / 6 + 1;
463 " +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
464#ifdef PROJ_VERSION_MAJOR
465 myProjection = proj_create(PJ_DEFAULT_CTX,
myProjString.c_str());
466 checkError(myProjection);
473 int zone = (int)(x / 3);
474 if (zone < 1 || zone > 5) {
479 " +k=1 +x_0=" +
toString(zone * 1000000 + 500000) +
480 " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
481#ifdef PROJ_VERSION_MAJOR
482 myProjection = proj_create(PJ_DEFAULT_CTX,
myProjString.c_str());
483 checkError(myProjection);
493 if (myInverseProjection !=
nullptr) {
494#ifdef PROJ_VERSION_MAJOR
495 PJ_COORD c = proj_coord(from.
x(), from.
y(), from.
z(), 0);
496 c = proj_trans(myInverseProjection, PJ_INV, c);
497 checkError(myInverseProjection);
498 from.
set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi));
502 if (pj_transform(myInverseProjection, myGeoProjection, 1, 1, &x, &y,
nullptr)) {
505 from.
set(
double(x * RAD_TO_DEG),
double(y * RAD_TO_DEG));
512 if (includeInBoundary) {
531 if (x > 180.1 || x < -180.1) {
535 if (y > 90.1 || y < -90.1) {
540 if (myProjection !=
nullptr) {
541#ifdef PROJ_VERSION_MAJOR
542 PJ_COORD c = proj_coord(myRadians ? proj_torad(x) : x, myRadians ? proj_torad(y) : y, from.
z(), 0);
543 c = proj_trans(myProjection, PJ_FWD, c);
544 checkError(myProjection);
549 p.u = x * DEG_TO_RAD;
550 p.v = y * DEG_TO_RAD;
551 p = pj_fwd(p, myProjection);
560 x *= 111320. * cos(
DEG2RAD(y));
565 if (x > std::numeric_limits<double>::max() ||
566 y > std::numeric_limits<double>::max()) {
#define WRITE_WARNINGF(...)
#define WRITE_WARNING(msg)
@ SUMO_ATTR_CONV_BOUNDARY
@ SUMO_ATTR_ORIG_BOUNDARY
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A class that stores a 2D geometrical boundary.
Position getCenter() const
Returns the center of the boundary.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
void moveby(double x, double y, double z=0)
Moves the boundary by the given amount.
void flipY()
flips ymin and ymax
static methods for processing the coordinates conversion for the current net
static void resetLoaded()
resets loaded location elements
static void setLoadedPlain(const std::string &nodFile, const GeoConvHelper &loaded)
registers the coordinate transformation as having been loaded from the given file
const Position getOffset() const
Returns the network offset.
static void writeLocation(OutputDevice &into)
writes the location element
Boundary myOrigBoundary
The boundary before conversion (x2cartesian)
static void addProjectionOptions(OptionsCont &oc)
Adds projection options to the given container.
bool x2cartesian(Position &from, bool includeInBoundary=true)
Converts the given coordinate into a cartesian and optionally update myConvBoundary.
GeoConvHelper & operator=(const GeoConvHelper &)
make assignment operator private
static GeoConvHelper * getLoadedPlain(const std::string &plainFile, const std::string &suffix=".edg.xml")
ProjectionMethod myProjectionMethod
Information whether no projection shall be done.
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
GeoConvHelper(OptionsCont &oc)
Constructor based on the stored options.
Position myOffset
The offset to apply.
void moveConvertedBy(double x, double y)
Shifts the converted boundary by the given amounts.
bool usingInverseGeoProjection() const
Returns the information whether an inverse transformation will happen.
bool operator==(const GeoConvHelper &o) const
void resolveAbstractProjection()
init projString such as 'UTM' in loaded projection
const std::string & getProjString() const
Returns the original projection definition.
const Boundary & getOrigBoundary() const
Returns the original boundary.
double mySin
The rotation to apply to geo-coordinates.
static GeoConvHelper myLoaded
coordinate transformation loaded from a location element
static GeoConvHelper myFinal
coordinate transformation to use for writing the location element and for tracking the original coord...
static void setLoaded(const GeoConvHelper &loaded)
sets the coordinate transformation loaded from a location element
double myGeoScale
The scaling to apply to geo-coordinates.
const Position getOffsetBase() const
Returns the network base.
static bool init(OptionsCont &oc)
Initialises the processing and the final instance using the given options.
bool myFlatten
whether to discard z-data
bool myUseInverseProjection
Information whether inverse projection shall be used.
Boundary myConvBoundary
The boundary after conversion (x2cartesian)
static void computeFinal(bool lefthand=false)
compute the location attributes which will be used for output based on the loaded location data,...
bool usingGeoProjection() const
Returns whether a transformation from geo to metric coordinates will be performed.
const Boundary & getConvBoundary() const
Returns the converted boundary.
bool x2cartesian_const(Position &from) const
Converts the given coordinate into a cartesian using the previous initialisation.
~GeoConvHelper()
Destructor.
std::string myProjString
A proj options string describing the proj.4-projection to use.
static int myNumLoaded
the numer of coordinate transformations loaded from location elements
static std::map< std::string, std::pair< std::string, Position > > myLoadedPlain
the projections loaded from .nod.xml (to be re-used when loading edg.xml)
static GeoConvHelper myProcessing
coordinate transformation to use for input conversion and processing
A storage for options typed value containers)
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Static storage of an output device and its base (abstract) implementation.
void lf()
writes a line feed if applicable
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
void setPrecision(int precision=gPrecision)
Sets the precision or resets it to default.
A point in 2D or 3D with translation and scaling methods.
void set(double x, double y)
set positions x and y
void sub(double dx, double dy)
Subtracts the given position from this one.
double x() const
Returns the x-position.
void add(const Position &pos)
Adds the given position to this one.
void setz(double z)
set position z
void mul(double val)
Multiplies position with the given value.
double z() const
Returns the z-position.
double y() const
Returns the y-position.
static std::string replace(std::string str, const std::string &what, const std::string &by)
Replaces all occurrences of the second string by the third string within the first string.
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.