LCOV - code coverage report
Current view: top level - src/utils/geom - GeoConvHelper.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 214 273 78.4 %
Date: 2024-05-07 15:28:01 Functions: 25 26 96.2 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    GeoConvHelper.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    2006-08-01
      19             : ///
      20             : // static methods for processing the coordinates conversion for the current net
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <map>
      25             : #include <cmath>
      26             : #include <cassert>
      27             : #include <climits>
      28             : #include <regex>
      29             : #include <utils/common/MsgHandler.h>
      30             : #include <utils/common/ToString.h>
      31             : #include <utils/geom/GeomHelper.h>
      32             : #include <utils/options/OptionsCont.h>
      33             : #include <utils/iodevices/OutputDevice.h>
      34             : #include "GeoConvHelper.h"
      35             : 
      36             : 
      37             : // ===========================================================================
      38             : // static member variables
      39             : // ===========================================================================
      40             : 
      41             : GeoConvHelper GeoConvHelper::myProcessing("!", Position(), Boundary(), Boundary());
      42             : GeoConvHelper GeoConvHelper::myLoaded("!", Position(), Boundary(), Boundary());
      43             : GeoConvHelper GeoConvHelper::myFinal("!", Position(), Boundary(), Boundary());
      44             : int GeoConvHelper::myNumLoaded = 0;
      45             : std::map<std::string, std::pair<std::string, Position> > GeoConvHelper::myLoadedPlain;
      46             : 
      47             : // ===========================================================================
      48             : // method definitions
      49             : // ===========================================================================
      50             : 
      51      178880 : GeoConvHelper::GeoConvHelper(const std::string& proj, const Position& offset,
      52      178880 :                              const Boundary& orig, const Boundary& conv, double scale, double rot, bool inverse, bool flatten):
      53      178880 :     myProjString(proj),
      54             : #ifdef PROJ_API_FILE
      55      178880 :     myProjection(nullptr),
      56      178880 :     myInverseProjection(nullptr),
      57      178880 :     myGeoProjection(nullptr),
      58             : #endif
      59      178880 :     myOffset(offset),
      60      178880 :     myGeoScale(scale),
      61      178880 :     mySin(sin(DEG2RAD(-rot))), // rotate clockwise
      62      178880 :     myCos(cos(DEG2RAD(-rot))),
      63      178880 :     myProjectionMethod(NONE),
      64      178880 :     myUseInverseProjection(inverse),
      65      178880 :     myFlatten(flatten),
      66      178880 :     myOrigBoundary(orig),
      67      178880 :     myConvBoundary(conv) {
      68      178880 :     if (proj == "!") {
      69      173813 :         myProjectionMethod = NONE;
      70        5067 :     } else if (proj == "-") {
      71           3 :         myProjectionMethod = SIMPLE;
      72        5064 :     } else if (proj == "UTM") {
      73         265 :         myProjectionMethod = UTM;
      74        4799 :     } else if (proj == "DHDN") {
      75           0 :         myProjectionMethod = DHDN;
      76        4799 :     } else if (proj == "DHDN_UTM") {
      77           0 :         myProjectionMethod = DHDN_UTM;
      78             : #ifdef PROJ_API_FILE
      79             :     } else {
      80        4799 :         myProjectionMethod = PROJ;
      81        4799 :         initProj(proj);
      82        4799 :         if (myProjection == nullptr) {
      83             :             // avoid error about missing datum shift file
      84           0 :             myProjString = std::regex_replace(proj, std::regex("\\+geoidgrids[^ ]*"), std::string(""));
      85           0 :             myProjString = std::regex_replace(myProjString, std::regex("\\+step \\+proj=vgridshift \\+grids[^ ]*"), std::string(""));
      86           0 :             if (myProjString != proj) {
      87           0 :                 WRITE_WARNING(TL("Ignoring geoidgrids and vgridshift in projection"));
      88           0 :                 initProj(myProjString);
      89             :             }
      90             :         }
      91        4799 :         if (myProjection == nullptr) {
      92             :             // !!! check pj_errno
      93           0 :             throw ProcessError(TL("Could not build projection!"));
      94             :         }
      95             : #endif
      96             :     }
      97      178880 : }
      98             : 
      99             : 
     100             : #ifdef PROJ_API_FILE
     101             : void
     102        4799 : GeoConvHelper::initProj(const std::string& proj) {
     103             : #ifdef PROJ_VERSION_MAJOR
     104        4799 :     myProjection = proj_create(PJ_DEFAULT_CTX, proj.c_str());
     105             : #else
     106             :     myProjection = pj_init_plus(proj.c_str());
     107             : #endif
     108        4799 : }
     109             : #endif
     110             : 
     111             : 
     112      178876 : GeoConvHelper::~GeoConvHelper() {
     113             : #ifdef PROJ_API_FILE
     114      178876 :     if (myProjection != nullptr) {
     115             : #ifdef PROJ_VERSION_MAJOR
     116       14191 :         proj_destroy(myProjection);
     117             : #else
     118             :         pj_free(myProjection);
     119             : #endif
     120             :     }
     121      178876 :     if (myInverseProjection != nullptr) {
     122             : #ifdef PROJ_VERSION_MAJOR
     123           0 :         proj_destroy(myInverseProjection);
     124             : #else
     125             :         pj_free(myInverseProjection);
     126             : #endif
     127             :     }
     128      178876 :     if (myGeoProjection != nullptr) {
     129             : #ifdef PROJ_VERSION_MAJOR
     130           0 :         proj_destroy(myGeoProjection);
     131             : #else
     132             :         pj_free(myGeoProjection);
     133             : #endif
     134             :     }
     135             : #endif
     136      178876 : }
     137             : 
     138             : bool
     139        2326 : GeoConvHelper::operator==(const GeoConvHelper& o) const {
     140             :     return (
     141        2326 :                myProjString == o.myProjString &&
     142         370 :                myOffset == o.myOffset &&
     143         740 :                myProjectionMethod == o.myProjectionMethod &&
     144         370 :                myOrigBoundary == o.myOrigBoundary &&
     145           0 :                myConvBoundary == o.myConvBoundary &&
     146           0 :                myGeoScale == o.myGeoScale &&
     147           0 :                myCos == o.myCos &&
     148           0 :                mySin == o.mySin &&
     149        2326 :                myUseInverseProjection == o.myUseInverseProjection &&
     150             :                myFlatten == o.myFlatten
     151        2326 :            );
     152             : }
     153             : 
     154             : GeoConvHelper&
     155       88913 : GeoConvHelper::operator=(const GeoConvHelper& orig) {
     156       88913 :     myProjString = orig.myProjString;
     157       88913 :     myOffset = orig.myOffset;
     158       88913 :     myProjectionMethod = orig.myProjectionMethod;
     159             :     myOrigBoundary = orig.myOrigBoundary;
     160             :     myConvBoundary = orig.myConvBoundary;
     161       88913 :     myGeoScale = orig.myGeoScale;
     162       88913 :     myCos = orig.myCos;
     163       88913 :     mySin = orig.mySin;
     164       88913 :     myUseInverseProjection = orig.myUseInverseProjection;
     165       88913 :     myFlatten = orig.myFlatten;
     166             : #ifdef PROJ_API_FILE
     167       88913 :     if (myProjection != nullptr) {
     168             : #ifdef PROJ_VERSION_MAJOR
     169          18 :         proj_destroy(myProjection);
     170             : #else
     171             :         pj_free(myProjection);
     172             : #endif
     173          18 :         myProjection = nullptr;
     174             :     }
     175       88913 :     if (myInverseProjection != nullptr) {
     176             : #ifdef PROJ_VERSION_MAJOR
     177           0 :         proj_destroy(myInverseProjection);
     178             : #else
     179             :         pj_free(myInverseProjection);
     180             : #endif
     181           0 :         myInverseProjection = nullptr;
     182             :     }
     183       88913 :     if (myGeoProjection != nullptr) {
     184             : #ifdef PROJ_VERSION_MAJOR
     185           0 :         proj_destroy(myGeoProjection);
     186             : #else
     187             :         pj_free(myGeoProjection);
     188             : #endif
     189           0 :         myGeoProjection = nullptr;
     190             :     }
     191       88913 :     if (orig.myProjection != nullptr) {
     192             : #ifdef PROJ_VERSION_MAJOR
     193        9163 :         myProjection = proj_create(PJ_DEFAULT_CTX, orig.myProjString.c_str());
     194             : #else
     195             :         myProjection = pj_init_plus(orig.myProjString.c_str());
     196             : #endif
     197             :     }
     198       88913 :     if (orig.myInverseProjection != nullptr) {
     199             : #ifdef PROJ_VERSION_MAJOR
     200           0 :         myInverseProjection = orig.myInverseProjection;
     201             : #else
     202             :         myInverseProjection = pj_init_plus(pj_get_def(orig.myInverseProjection, 0));
     203             : #endif
     204             :     }
     205       88913 :     if (orig.myGeoProjection != nullptr) {
     206             : #ifdef PROJ_VERSION_MAJOR
     207           0 :         myGeoProjection = orig.myGeoProjection;
     208             : #else
     209             :         myGeoProjection = pj_init_plus(pj_get_def(orig.myGeoProjection, 0));
     210             : #endif
     211             :     }
     212             : #endif
     213       88913 :     return *this;
     214             : }
     215             : 
     216             : 
     217             : bool
     218        2266 : GeoConvHelper::init(OptionsCont& oc) {
     219        2266 :     std::string proj = "!"; // the default
     220        2266 :     double scale = oc.getFloat("proj.scale");
     221        2266 :     double rot = oc.getFloat("proj.rotate");
     222        4532 :     Position offset = Position(oc.getFloat("offset.x"), oc.getFloat("offset.y"), oc.getFloat("offset.z"));
     223        6798 :     bool inverse = oc.exists("proj.inverse") && oc.getBool("proj.inverse");
     224        6733 :     bool flatten = oc.exists("flatten") && oc.getBool("flatten");
     225             : 
     226        4532 :     if (oc.getBool("simple-projection")) {
     227             :         proj = "-";
     228             :     }
     229             : 
     230             : #ifdef PROJ_API_FILE
     231        2266 :     if (oc.getBool("proj.inverse") && oc.getString("proj") == "!") {
     232           0 :         WRITE_ERROR(TL("Inverse projection works only with explicit proj parameters."));
     233           0 :         return false;
     234             :     }
     235        2266 :     unsigned numProjections = oc.getBool("simple-projection") + oc.getBool("proj.utm") + oc.getBool("proj.dhdn") + oc.getBool("proj.dhdnutm") + (oc.getString("proj").length() > 1);
     236        2266 :     if (numProjections > 1) {
     237           0 :         WRITE_ERROR(TL("The projection method needs to be uniquely defined."));
     238           0 :         return false;
     239             :     }
     240             : 
     241        4532 :     if (oc.getBool("proj.utm")) {
     242             :         proj = "UTM";
     243        4004 :     } else if (oc.getBool("proj.dhdn")) {
     244             :         proj = "DHDN";
     245        4004 :     } else if (oc.getBool("proj.dhdnutm")) {
     246             :         proj = "DHDN_UTM";
     247        4004 :     } else if (!oc.isDefault("proj")) {
     248           0 :         proj = oc.getString("proj");
     249             :     }
     250             : #endif
     251        2266 :     myProcessing = GeoConvHelper(proj, offset, Boundary(), Boundary(), scale, rot, inverse, flatten);
     252        2266 :     myFinal = myProcessing;
     253             :     return true;
     254             : }
     255             : 
     256             : 
     257             : void
     258       40530 : GeoConvHelper::init(const std::string& proj, const Position& offset, const Boundary& orig,
     259             :                     const Boundary& conv, double scale) {
     260       40530 :     myProcessing = GeoConvHelper(proj, offset, orig, conv, scale);
     261       40530 :     myProcessing.resolveAbstractProjection();
     262       40530 :     myFinal = myProcessing;
     263       40530 : }
     264             : 
     265             : void
     266       41995 : GeoConvHelper::resolveAbstractProjection() {
     267             : #ifdef PROJ_API_FILE
     268       41995 :     if (myProjection == nullptr &&
     269       37525 :             myProjectionMethod != NONE && myProjectionMethod != SIMPLE) {
     270             :         const std::string origProj = myProjString;
     271             :         // try to initialized projection based on origBoundary
     272           1 :         Position tmp = myOrigBoundary.getCenter();
     273           1 :         x2cartesian(tmp, false);
     274           1 :         if (myProjection == nullptr) {
     275           0 :             WRITE_WARNING("Failed to intialized projection '" + origProj + "' based on origBoundary centered on '" + toString(myOrigBoundary.getCenter()) + "'");
     276           0 :             myProjectionMethod = NONE;
     277             :         }
     278             :     }
     279             : #endif
     280       41995 : }
     281             : 
     282             : void
     283        2311 : GeoConvHelper::addProjectionOptions(OptionsCont& oc) {
     284        2311 :     oc.addOptionSubTopic("Projection");
     285             : 
     286        2311 :     oc.doRegister("simple-projection", new Option_Bool(false));
     287        4622 :     oc.addSynonyme("simple-projection", "proj.simple", true);
     288        4622 :     oc.addDescription("simple-projection", "Projection", TL("Uses a simple method for projection"));
     289             : 
     290        2311 :     oc.doRegister("proj.scale", new Option_Float(1.0));
     291        4622 :     oc.addDescription("proj.scale", "Projection", TL("Scaling factor for input coordinates"));
     292             : 
     293        2311 :     oc.doRegister("proj.rotate", new Option_Float(0.0));
     294        4622 :     oc.addDescription("proj.rotate", "Projection", TL("Rotation (clockwise degrees) for input coordinates"));
     295             : 
     296             : #ifdef PROJ_API_FILE
     297        2311 :     oc.doRegister("proj.utm", new Option_Bool(false));
     298        4622 :     oc.addDescription("proj.utm", "Projection", TL("Determine the UTM zone (for a universal transversal mercator projection based on the WGS84 ellipsoid)"));
     299             : 
     300        2311 :     oc.doRegister("proj.dhdn", new Option_Bool(false));
     301        4622 :     oc.addDescription("proj.dhdn", "Projection", "Determine the DHDN zone (for a transversal mercator projection based on the bessel ellipsoid, \"Gauss-Krueger\")");
     302             : 
     303        4622 :     oc.doRegister("proj", new Option_String("!"));
     304        4622 :     oc.addDescription("proj", "Projection", TL("Uses STR as proj.4 definition for projection"));
     305             : 
     306        2311 :     oc.doRegister("proj.inverse", new Option_Bool(false));
     307        4622 :     oc.addDescription("proj.inverse", "Projection", TL("Inverses projection"));
     308             : 
     309        2311 :     oc.doRegister("proj.dhdnutm", new Option_Bool(false));
     310        4622 :     oc.addDescription("proj.dhdnutm", "Projection", TL("Convert from Gauss-Krueger to UTM"));
     311             : #endif // PROJ_API_FILE
     312        2311 : }
     313             : 
     314             : 
     315             : bool
     316      683587 : GeoConvHelper::usingGeoProjection() const {
     317      683587 :     return myProjectionMethod != NONE;
     318             : }
     319             : 
     320             : 
     321             : bool
     322         370 : GeoConvHelper::usingInverseGeoProjection() const {
     323         370 :     return myUseInverseProjection;
     324             : }
     325             : 
     326             : 
     327             : void
     328       21896 : GeoConvHelper::cartesian2geo(Position& cartesian) const {
     329       21896 :     cartesian.sub(getOffsetBase());
     330       21896 :     if (myProjectionMethod == NONE) {
     331        3010 :         return;
     332             :     }
     333       18886 :     if (myProjectionMethod == SIMPLE) {
     334           0 :         const double y = cartesian.y() / 111136.;
     335           0 :         const double x = cartesian.x() / 111320. / cos(DEG2RAD(y));
     336             :         cartesian.set(x, y);
     337           0 :         return;
     338             :     }
     339             : #ifdef PROJ_API_FILE
     340             : #ifdef PROJ_VERSION_MAJOR
     341             :     PJ_COORD c;
     342             :     c.xy.x = cartesian.x();
     343             :     c.xy.y = cartesian.y();
     344       18886 :     c = proj_trans(myProjection, PJ_INV, c);
     345       18886 :     cartesian.set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi));
     346             : #else
     347             :     projUV p;
     348             :     p.u = cartesian.x();
     349             :     p.v = cartesian.y();
     350             :     p = pj_inv(p, myProjection);
     351             :     //!!! check pj_errno
     352             :     p.u *= RAD_TO_DEG;
     353             :     p.v *= RAD_TO_DEG;
     354             :     cartesian.set((double) p.u, (double) p.v);
     355             : #endif
     356             : #endif
     357             : }
     358             : 
     359             : 
     360             : bool
     361      878930 : GeoConvHelper::x2cartesian(Position& from, bool includeInBoundary) {
     362      878930 :     if (includeInBoundary) {
     363      673906 :         myOrigBoundary.add(from);
     364             :     }
     365             :     // init projection parameter on first use
     366             : #ifdef PROJ_API_FILE
     367      878930 :     if (myProjection == nullptr) {
     368      511341 :         double x = from.x() * myGeoScale;
     369      511341 :         switch (myProjectionMethod) {
     370           0 :             case DHDN_UTM: {
     371           0 :                 int zone = (int)((x - 500000.) / 1000000.);
     372           0 :                 if (zone < 1 || zone > 5) {
     373           0 :                     WRITE_WARNING("Attempt to initialize DHDN_UTM-projection on invalid longitude " + toString(x));
     374           0 :                     return false;
     375             :                 }
     376           0 :                 myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3 * zone) +
     377           0 :                                " +k=1 +x_0=" + toString(zone * 1000000 + 500000) +
     378           0 :                                " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
     379             : #ifdef PROJ_VERSION_MAJOR
     380           0 :                 myInverseProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str());
     381           0 :                 myGeoProjection = proj_create(PJ_DEFAULT_CTX, "+proj=latlong +datum=WGS84");
     382             : #else
     383             :                 myInverseProjection = pj_init_plus(myProjString.c_str());
     384             :                 myGeoProjection = pj_init_plus("+proj=latlong +datum=WGS84");
     385             : #endif
     386             :                 //!!! check pj_errno
     387           0 :                 x = ((x - 500000.) / 1000000.) * 3; // continues with UTM
     388             :             }
     389             :             FALLTHROUGH;
     390         251 :             case UTM: {
     391         251 :                 int zone = (int)(x + 180) / 6 + 1;
     392         502 :                 myProjString = "+proj=utm +zone=" + toString(zone) +
     393         251 :                                " +ellps=WGS84 +datum=WGS84 +units=m +no_defs";
     394             : #ifdef PROJ_VERSION_MAJOR
     395         251 :                 myProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str());
     396             : #else
     397             :                 myProjection = pj_init_plus(myProjString.c_str());
     398             : #endif
     399             :                 //!!! check pj_errno
     400             :             }
     401         251 :             break;
     402           0 :             case DHDN: {
     403           0 :                 int zone = (int)(x / 3);
     404           0 :                 if (zone < 1 || zone > 5) {
     405           0 :                     WRITE_WARNING("Attempt to initialize DHDN-projection on invalid longitude " + toString(x));
     406           0 :                     return false;
     407             :                 }
     408           0 :                 myProjString = "+proj=tmerc +lat_0=0 +lon_0=" + toString(3 * zone) +
     409           0 :                                " +k=1 +x_0=" + toString(zone * 1000000 + 500000) +
     410           0 :                                " +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs";
     411             : #ifdef PROJ_VERSION_MAJOR
     412           0 :                 myProjection = proj_create(PJ_DEFAULT_CTX, myProjString.c_str());
     413             : #else
     414             :                 myProjection = pj_init_plus(myProjString.c_str());
     415             : #endif
     416             :                 //!!! check pj_errno
     417             :             }
     418           0 :             break;
     419             :             default:
     420             :                 break;
     421             :         }
     422             :     }
     423      878930 :     if (myInverseProjection != nullptr) {
     424             : #ifdef PROJ_VERSION_MAJOR
     425             :         PJ_COORD c;
     426             :         c.xy.x = from.x();
     427             :         c.xy.y = from.y();
     428           0 :         c = proj_trans(myInverseProjection, PJ_INV, c);
     429           0 :         from.set(proj_todeg(c.lp.lam), proj_todeg(c.lp.phi));
     430             : #else
     431             :         double x = from.x();
     432             :         double y = from.y();
     433             :         if (pj_transform(myInverseProjection, myGeoProjection, 1, 1, &x, &y, nullptr)) {
     434             :             WRITE_WARNINGF(TL("Could not transform (%,%)"), toString(x), toString(y));
     435             :         }
     436             :         from.set(double(x * RAD_TO_DEG), double(y * RAD_TO_DEG));
     437             : #endif
     438             :     }
     439             : #endif
     440             :     // perform conversion
     441      878930 :     bool ok = x2cartesian_const(from);
     442      878930 :     if (ok) {
     443      878929 :         if (includeInBoundary) {
     444      673905 :             myConvBoundary.add(from);
     445             :         }
     446             :     }
     447             :     return ok;
     448             : }
     449             : 
     450             : 
     451             : bool
     452      879220 : GeoConvHelper::x2cartesian_const(Position& from) const {
     453      879220 :     double x2 = from.x() * myGeoScale;
     454      879220 :     double y2 = from.y() * myGeoScale;
     455      879220 :     double x = x2 * myCos - y2 * mySin;
     456      879220 :     double y = x2 * mySin + y2 * myCos;
     457      879220 :     if (myProjectionMethod == NONE) {
     458             :         // do nothing
     459      368144 :     } else if (myUseInverseProjection) {
     460           0 :         cartesian2geo(from);
     461             :     } else {
     462      368144 :         if (x > 180.1 || x < -180.1) {
     463           0 :             WRITE_WARNING("Invalid longitude " + toString(x));
     464           0 :             return false;
     465             :         }
     466      368144 :         if (y > 90.1 || y < -90.1) {
     467           2 :             WRITE_WARNING("Invalid latitude " + toString(y));
     468           1 :             return false;
     469             :         }
     470             : #ifdef PROJ_API_FILE
     471      368143 :         if (myProjection != nullptr) {
     472             : #ifdef PROJ_VERSION_MAJOR
     473             :             PJ_COORD c;
     474      368129 :             c.lp.lam = proj_torad(x);
     475      368129 :             c.lp.phi = proj_torad(y);
     476      368129 :             c = proj_trans(myProjection, PJ_FWD, c);
     477             :             //!!! check pj_errno
     478      368129 :             x = c.xy.x;
     479      368129 :             y = c.xy.y;
     480             : #else
     481             :             projUV p;
     482             :             p.u = x * DEG_TO_RAD;
     483             :             p.v = y * DEG_TO_RAD;
     484             :             p = pj_fwd(p, myProjection);
     485             :             //!!! check pj_errno
     486             :             x = p.u;
     487             :             y = p.v;
     488             : #endif
     489             :         }
     490             : #endif
     491      368143 :         if (myProjectionMethod == SIMPLE) {
     492             :             // Sinusoidal projection (https://en.wikipedia.org/wiki/Sinusoidal_projection)
     493          14 :             x *= 111320. * cos(DEG2RAD(y));
     494          14 :             y *= 111136.;
     495             :             //!!! recheck whether the axes are mirrored
     496             :         }
     497             :     }
     498      879219 :     if (x > std::numeric_limits<double>::max() ||
     499      879219 :             y > std::numeric_limits<double>::max()) {
     500             :         return false;
     501             :     }
     502             :     from.set(x, y);
     503             :     from.add(myOffset);
     504      879219 :     if (myFlatten) {
     505             :         from.setz(0);
     506             :     }
     507             :     return true;
     508             : }
     509             : 
     510             : 
     511             : void
     512        1272 : GeoConvHelper::moveConvertedBy(double x, double y) {
     513             :     myOffset.add(x, y);
     514        1272 :     myConvBoundary.moveby(x, y);
     515        1272 : }
     516             : 
     517             : 
     518             : const Boundary&
     519        4810 : GeoConvHelper::getOrigBoundary() const {
     520        4810 :     return myOrigBoundary;
     521             : }
     522             : 
     523             : 
     524             : const Boundary&
     525       17414 : GeoConvHelper::getConvBoundary() const {
     526       17414 :     return myConvBoundary;
     527             : }
     528             : 
     529             : 
     530             : const Position
     531        2583 : GeoConvHelper::getOffset() const {
     532        2583 :     return myOffset;
     533             : }
     534             : 
     535             : 
     536             : const Position
     537       25719 : GeoConvHelper::getOffsetBase() const {
     538       25719 :     return myOffset;
     539             : }
     540             : 
     541             : 
     542             : const std::string&
     543        3710 : GeoConvHelper::getProjString() const {
     544        3710 :     return myProjString;
     545             : }
     546             : 
     547             : 
     548             : void
     549        1880 : GeoConvHelper::computeFinal(bool lefthand) {
     550        1880 :     if (myNumLoaded == 0) {
     551         857 :         myFinal = myProcessing;
     552         857 :         if (lefthand) {
     553             :             myFinal.myOffset.mul(1, -1);
     554             :         }
     555             :     } else  {
     556        1023 :         if (lefthand) {
     557             :             myProcessing.myOffset.mul(1, -1);
     558             :         }
     559        4092 :         myFinal = GeoConvHelper(
     560             :                       // prefer options over loaded location
     561        2046 :                       myProcessing.usingGeoProjection() ? myProcessing.getProjString() : myLoaded.getProjString(),
     562             :                       // let offset and boundary lead back to the original coords of the loaded data
     563        2046 :                       myProcessing.getOffset() + myLoaded.getOffset(),
     564             :                       myLoaded.getOrigBoundary(),
     565             :                       // the new boundary (updated during loading)
     566        1023 :                       myProcessing.getConvBoundary());
     567             :     }
     568        1880 :     if (lefthand) {
     569          23 :         myFinal.myConvBoundary.flipY();
     570             :     }
     571        1880 : }
     572             : 
     573             : 
     574             : void
     575        1453 : GeoConvHelper::setLoaded(const GeoConvHelper& loaded) {
     576        1453 :     myNumLoaded++;
     577        1453 :     if (myNumLoaded > 1) {
     578          24 :         WRITE_WARNINGF(TL("Ignoring loaded location attribute nr. % for tracking of original location"), toString(myNumLoaded));
     579             :     } else {
     580        1441 :         myLoaded = loaded;
     581             :     }
     582        1453 : }
     583             : 
     584             : 
     585             : void
     586         497 : GeoConvHelper::setLoadedPlain(const std::string& nodFile, const GeoConvHelper& loaded) {
     587        1491 :     myLoadedPlain[nodFile] = {loaded.getProjString(), loaded.getOffset()};
     588         497 : }
     589             : 
     590             : 
     591             : GeoConvHelper*
     592        1092 : GeoConvHelper::getLoadedPlain(const std::string& edgFile) {
     593        3276 :     std::string nodFile = StringUtils::replace(edgFile, ".edg.xml", ".nod.xml");
     594             :     auto it = myLoadedPlain.find(nodFile);
     595        1092 :     if (it != myLoadedPlain.end()) {
     596         465 :         return new GeoConvHelper(it->second.first, it->second.second, Boundary(), Boundary());
     597             :     } else {
     598             :         return nullptr;
     599             :     }
     600             : }
     601             : 
     602             : 
     603             : void
     604           0 : GeoConvHelper::resetLoaded() {
     605           0 :     myNumLoaded = 0;
     606             :     myLoadedPlain.clear();
     607           0 : }
     608             : 
     609             : 
     610             : void
     611        1950 : GeoConvHelper::writeLocation(OutputDevice& into) {
     612        1950 :     into.openTag(SUMO_TAG_LOCATION);
     613        1950 :     into.writeAttr(SUMO_ATTR_NET_OFFSET, myFinal.getOffsetBase());
     614        1950 :     into.writeAttr(SUMO_ATTR_CONV_BOUNDARY, myFinal.getConvBoundary());
     615        1950 :     if (myFinal.usingGeoProjection()) {
     616         478 :         into.setPrecision(gPrecisionGeo);
     617             :     }
     618        1950 :     into.writeAttr(SUMO_ATTR_ORIG_BOUNDARY, myFinal.getOrigBoundary());
     619        1950 :     if (myFinal.usingGeoProjection()) {
     620         478 :         into.setPrecision();
     621             :     }
     622        1950 :     into.writeAttr(SUMO_ATTR_ORIG_PROJ, myFinal.getProjString());
     623        1950 :     into.closeTag();
     624        1950 :     into.lf();
     625        1950 : }
     626             : 
     627             : 
     628             : /****************************************************************************/

Generated by: LCOV version 1.14