LCOV - code coverage report
Current view: top level - src/netbuild - NBNetBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.4 % 495 477
Test Date: 2024-12-21 15:45:41 Functions: 100.0 % 10 10

            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    NBNetBuilder.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Thimor Bohn
      18              : /// @author  Sascha Krieg
      19              : /// @author  Michael Behrisch
      20              : /// @author  Walter Bamberger
      21              : /// @date    20 Nov 2001
      22              : ///
      23              : // Instance responsible for building networks
      24              : /****************************************************************************/
      25              : #include <config.h>
      26              : 
      27              : #include <string>
      28              : #include <fstream>
      29              : #include <utils/options/OptionsCont.h>
      30              : #include <utils/common/MsgHandler.h>
      31              : #include <utils/common/UtilExceptions.h>
      32              : #include <utils/common/StringTokenizer.h>
      33              : #include <utils/common/SUMOVehicleClass.h>
      34              : #include <utils/common/SysUtils.h>
      35              : #include <utils/common/ToString.h>
      36              : #include <utils/geom/GeoConvHelper.h>
      37              : #include "NBAlgorithms.h"
      38              : #include "NBAlgorithms_Ramps.h"
      39              : #include "NBAlgorithms_Railway.h"
      40              : #include "NBHeightMapper.h"
      41              : #include "NBNodeCont.h"
      42              : #include "NBEdgeCont.h"
      43              : #include "NBPTStop.h"
      44              : #include "NBTrafficLightLogicCont.h"
      45              : #include "NBDistrictCont.h"
      46              : #include "NBDistrict.h"
      47              : #include "NBRequest.h"
      48              : #include "NBTypeCont.h"
      49              : #include "NBNetBuilder.h"
      50              : 
      51              : 
      52              : // ===========================================================================
      53              : // method definitions
      54              : // ===========================================================================
      55         2002 : NBNetBuilder::NBNetBuilder() :
      56         2002 :     myEdgeCont(myTypeCont),
      57         4004 :     myNetworkHaveCrossings(false) {
      58         2002 : }
      59              : 
      60              : 
      61         4004 : NBNetBuilder::~NBNetBuilder() {}
      62              : 
      63              : 
      64              : void
      65         2002 : NBNetBuilder::applyOptions(OptionsCont& oc) {
      66              :     // apply options to type control
      67         6006 :     myTypeCont.setEdgeTypeDefaults(oc.getInt("default.lanenumber"), oc.getFloat("default.lanewidth"), oc.getFloat("default.speed"), oc.getFloat("default.friction"),
      68         6006 :                                    oc.getInt("default.priority"), parseVehicleClasses(oc.getString("default.allow"), oc.getString("default.disallow")),
      69         2002 :                                    SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype")));
      70              :     // apply options to edge control
      71         2002 :     myEdgeCont.applyOptions(oc);
      72              :     // apply options to traffic light logics control
      73         1992 :     myTLLCont.applyOptions(oc);
      74         1992 :     NBEdge::setDefaultConnectionLength(oc.getFloat("default.connection-length"));
      75         1992 : }
      76              : 
      77              : 
      78              : void
      79         1704 : NBNetBuilder::compute(OptionsCont& oc, const std::set<std::string>& explicitTurnarounds, bool mayAddOrRemove) {
      80              :     // reset shapes and angles for stable netedit computation
      81         1704 :     if (myNodeCont.resetNodeShapes()) {
      82            0 :         myEdgeCont.computeAngles();
      83              :     }
      84              : 
      85              :     GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
      86              : 
      87         1704 :     const bool lefthand = oc.getBool("lefthand");
      88         1704 :     if (lefthand) {
      89           23 :         mirrorX();
      90              :     }
      91              : 
      92              :     // MODIFYING THE SETS OF NODES AND EDGES
      93              :     // Removes edges that are connecting the same node
      94         3408 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing self-loops"));
      95              :     int numRemovedEdges = 0;
      96         1704 :     numRemovedEdges += myNodeCont.removeSelfLoops(myDistrictCont, myEdgeCont, myTLLCont);
      97         1704 :     PROGRESS_TIME_MESSAGE(before);
      98         5024 :     if (mayAddOrRemove && oc.exists("remove-edges.isolated") && oc.getBool("remove-edges.isolated")) {
      99           10 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding isolated roads"));
     100            5 :         numRemovedEdges += myNodeCont.removeIsolatedRoads(myDistrictCont, myEdgeCont);
     101            5 :         PROGRESS_TIME_MESSAGE(before);
     102              :     }
     103         6617 :     if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
     104           46 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding largest components"));
     105           46 :         const bool hasStops = oc.exists("ptstop-output") && oc.isSet("ptstop-output") && !myPTStopCont.getStops().empty();
     106           23 :         numRemovedEdges += myNodeCont.removeComponents(myDistrictCont, myEdgeCont, oc.getInt("keep-edges.components"), hasStops);
     107           23 :         PROGRESS_TIME_MESSAGE(before);
     108              :     }
     109         5024 :     if (mayAddOrRemove && oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload")) {
     110              :         // pre-process lines to set permissions
     111            4 :         if (!myPTLineCont.getLines().empty()) {
     112            2 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
     113            1 :             myPTLineCont.process(myEdgeCont, myPTStopCont);
     114            1 :             PROGRESS_TIME_MESSAGE(before);
     115              :         }
     116            7 :         if (oc.isSet("keep-edges.explicit") || oc.isSet("keep-edges.input-file")) {
     117            4 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing unwished edges"));
     118            2 :             numRemovedEdges += myEdgeCont.removeUnwishedEdges(myDistrictCont);
     119            2 :             PROGRESS_TIME_MESSAGE(before);
     120              :         }
     121            4 :         const int removed = myEdgeCont.removeEdgesBySpeed(myDistrictCont);
     122            4 :         if (removed > 0) {
     123            0 :             numRemovedEdges += removed;
     124            0 :             WRITE_MESSAGEF(TL(" Removed % edges because by minimum speed."), removed);
     125              :         }
     126            4 :         const int removed2 = myEdgeCont.removeEdgesByPermissions(myDistrictCont);
     127            4 :         if (removed2 > 0) {
     128            1 :             numRemovedEdges += removed2;
     129            2 :             WRITE_MESSAGEF(TL(" Removed % edges based on vClass."), removed2);
     130              :         }
     131              :     }
     132         3408 :     if (mayAddOrRemove && oc.getFloat("keep-lanes.min-width") > 0.) {
     133         1704 :         const int removed = myEdgeCont.removeLanesByWidth(myDistrictCont, oc.getFloat("keep-lanes.min-width"));
     134         1704 :         if (removed > 0) {
     135            0 :             numRemovedEdges += removed;
     136            0 :             WRITE_MESSAGEF(TL(" Removed % edges because of lane width."), removed);
     137              :         }
     138              :     }
     139              :     // Processing pt stops and lines
     140         1704 :     if (!myPTStopCont.getStops().empty()) {
     141          298 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing public transport stops"));
     142          447 :         if (!(oc.exists("ptline-output") && oc.isSet("ptline-output"))
     143          403 :                 && !oc.getBool("ptstop-output.no-bidi")) {
     144          103 :             myPTStopCont.localizePTStops(myEdgeCont);
     145              :         }
     146          149 :         myPTStopCont.assignEdgeForFloatingStops(myEdgeCont, 20);
     147          149 :         myPTStopCont.assignLanes(myEdgeCont);
     148          149 :         PROGRESS_TIME_MESSAGE(before);
     149              :     }
     150         6617 :     if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
     151              :         // post process rail components unless they have stops
     152           23 :         numRemovedEdges += myNodeCont.removeRailComponents(myDistrictCont, myEdgeCont, myPTStopCont);
     153              :     }
     154              :     // removal is done, clean up roundabouts
     155         1704 :     if (numRemovedEdges > 0) {
     156           20 :         myEdgeCont.cleanupRoundabouts();
     157              :     }
     158              : 
     159         1704 :     if (!myPTLineCont.getLines().empty()) {
     160          194 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
     161           97 :         myPTLineCont.process(myEdgeCont, myPTStopCont);
     162           97 :         PROGRESS_TIME_MESSAGE(before);
     163              :     }
     164              : 
     165         3320 :     if (oc.exists("ptline-clean-up") && oc.getBool("ptline-clean-up")) {
     166            4 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Cleaning up public transport stops that are not served by any line"));
     167            2 :         myPTStopCont.postprocess(myPTLineCont.getServedPTStops());
     168            2 :         PROGRESS_TIME_MESSAGE(before);
     169              :     } else {
     170         1702 :         int numDeletedStops = myPTStopCont.cleanupDeleted(myEdgeCont);
     171         1702 :         if (numDeletedStops > 0) {
     172           48 :             WRITE_WARNINGF(TL("Removed % pt stops because they could not be assigned to the network"), toString(numDeletedStops));
     173              :         }
     174              :     }
     175              : 
     176         1841 :     if (!myPTStopCont.getStops().empty() && !oc.getBool("ptstop-output.no-bidi")) {
     177          266 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Align pt stop id signs with corresponding edge id signs"));
     178          133 :         myPTStopCont.alignIdSigns();
     179          133 :         PROGRESS_TIME_MESSAGE(before);
     180              :     }
     181              :     // analyze and fix railway topology
     182              :     int numAddedBidi = 0;
     183         3320 :     if (oc.exists("railway.topology.all-bidi") && oc.getBool("railway.topology.all-bidi")) {
     184            6 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     185            6 :         numAddedBidi = NBRailwayTopologyAnalyzer::makeAllBidi(myEdgeCont);
     186         3308 :     } else if (oc.exists("railway.topology.repair") && oc.getBool("railway.topology.repair")) {
     187              :         // correct railway angles for angle-based connectivity heuristic
     188           70 :         myEdgeCont.checkGeometries(0, false,
     189              :                                    oc.getFloat("geometry.min-radius"), false,
     190           35 :                                    oc.getBool("geometry.min-radius.fix.railways"), true);
     191           35 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     192           35 :         numAddedBidi = NBRailwayTopologyAnalyzer::repairTopology(myEdgeCont, myPTStopCont, myPTLineCont);
     193              :     }
     194         1704 :     NBRailwaySignalGuesser::guessRailSignals(myEdgeCont, myPTStopCont);
     195         1704 :     if (numAddedBidi > 0) {
     196              :         // update routes
     197           37 :         myPTLineCont.process(myEdgeCont, myPTStopCont, true);
     198              :     }
     199         3320 :     if (oc.exists("railway.topology.direction-priority") && oc.getBool("railway.topology.direction-priority")) {
     200            1 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     201            1 :         NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, true);
     202         3318 :     } else if (oc.exists("railway.topology.extend-priority") && oc.getBool("railway.topology.extend-priority")) {
     203            3 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     204            3 :         NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, false);
     205              :     }
     206         3320 :     if (oc.exists("railway.topology.output") && oc.isSet("railway.topology.output")) {
     207           29 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     208           29 :         NBRailwayTopologyAnalyzer::analyzeTopology(myEdgeCont);
     209              :     }
     210         3320 :     if (oc.exists("railway.geometry.straighten") && oc.getBool("railway.geometry.straighten")) {
     211            0 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     212            0 :         NBRailwayGeometryHelper::straigthenCorrdidor(myEdgeCont, oc.getFloat("geometry.max-angle"));
     213              :     }
     214              : 
     215              : 
     216         6634 :     if (mayAddOrRemove && oc.exists("edges.join-tram-dist") && oc.getFloat("edges.join-tram-dist") >= 0) {
     217              :         // should come before joining junctions
     218           12 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining tram edges"));
     219            6 :         int numJoinedTramEdges = myEdgeCont.joinTramEdges(myDistrictCont, myPTStopCont, myPTLineCont, oc.getFloat("edges.join-tram-dist"));
     220            6 :         PROGRESS_TIME_MESSAGE(before);
     221            6 :         if (numJoinedTramEdges > 0) {
     222           12 :             WRITE_MESSAGEF(TL(" Joined % tram edges into roads."), toString(numJoinedTramEdges));
     223              :         }
     224              :     }
     225         3408 :     if (oc.getBool("junctions.join")
     226         4904 :             || (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     227         3271 :             || oc.getBool("tls.guess.joining")
     228         6342 :             || (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals"))) {
     229              :         // preliminary geometry computations to determine the length of edges
     230              :         // This depends on turning directions and sorting of edge list
     231              :         // in case junctions are joined geometry computations have to be repeated
     232              :         // preliminary roundabout computations to avoid damaging roundabouts via junctions.join or ramps.guess
     233          147 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     234          147 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     235          147 :         myEdgeCont.computeLaneShapes();
     236          147 :         myNodeCont.computeNodeShapes();
     237          147 :         myEdgeCont.computeEdgeShapes();
     238          294 :         if (oc.getBool("roundabouts.guess")) {
     239          147 :             myEdgeCont.guessRoundabouts();
     240              :         }
     241          147 :         const std::set<EdgeSet>& roundabouts = myEdgeCont.getRoundabouts();
     242          147 :         for (std::set<EdgeSet>::const_iterator it_round = roundabouts.begin();
     243          161 :                 it_round != roundabouts.end(); ++it_round) {
     244              :             std::vector<std::string> nodeIDs;
     245          111 :             for (EdgeSet::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
     246           97 :                 nodeIDs.push_back((*it_edge)->getToNode()->getID());
     247              :             }
     248           14 :             myNodeCont.addJoinExclusion(nodeIDs);
     249           14 :         }
     250          147 :         NBNodeTypeComputer::validateRailCrossings(myNodeCont, myTLLCont);
     251         3162 :     } else if ((myEdgeCont.hasGuessedRoundabouts() || oc.getBool("crossings.guess")) && oc.getBool("roundabouts.guess")) {
     252           48 :         myEdgeCont.guessRoundabouts();
     253           48 :         myEdgeCont.markRoundabouts();
     254              :     }
     255              :     // join junctions (may create new "geometry"-nodes so it needs to come before removing these
     256         5024 :     if (mayAddOrRemove && oc.exists("junctions.join-exclude") && oc.isSet("junctions.join-exclude")) {
     257            2 :         myNodeCont.addJoinExclusion(oc.getStringVector("junctions.join-exclude"));
     258              :     }
     259         1704 :     int numJoined = myNodeCont.joinLoadedClusters(myDistrictCont, myEdgeCont, myTLLCont);
     260         3408 :     if (mayAddOrRemove && oc.getBool("junctions.join")) {
     261          208 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junction clusters"));
     262          104 :         numJoined += myNodeCont.joinJunctions(oc.getFloat("junctions.join-dist"), myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont);
     263          104 :         PROGRESS_TIME_MESSAGE(before);
     264              :     }
     265         1704 :     if (numJoined > 0) {
     266          180 :         WRITE_MESSAGEF(TL(" Joined % junction cluster(s)."), toString(numJoined));
     267              :     }
     268         5112 :     if (mayAddOrRemove && oc.exists("junctions.join-same") && oc.getBool("junctions.join-same")) {
     269           20 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junctions with identical coordinates"));
     270           10 :         int numJoined2 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont);
     271           10 :         PROGRESS_TIME_MESSAGE(before);
     272           10 :         if (numJoined2 > 0) {
     273            6 :             WRITE_MESSAGEF(TL(" Joined % junctions."), toString(numJoined2));
     274              :         }
     275              :     }
     276              :     //
     277         5024 :     if (mayAddOrRemove && oc.exists("join-lanes") && oc.getBool("join-lanes")) {
     278            2 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining lanes"));
     279            1 :         const int num = myEdgeCont.joinLanes(SVC_IGNORING) + myEdgeCont.joinLanes(SVC_PEDESTRIAN);
     280            1 :         PROGRESS_TIME_MESSAGE(before);
     281            2 :         WRITE_MESSAGEF(TL("   Joined lanes on % edges."), toString(num));
     282              :     }
     283              :     //
     284         1704 :     if (mayAddOrRemove) {
     285         3408 :         const bool removeGeometryNodes = oc.exists("geometry.remove") && oc.getBool("geometry.remove");
     286         6717 :         before = PROGRESS_BEGIN_TIME_MESSAGE("Removing empty nodes" + std::string(removeGeometryNodes ? " and geometry nodes" : ""));
     287              :         // removeUnwishedNodes needs turnDirections. @todo: try to call this less often
     288         1704 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     289         1704 :         const int numRemoved = myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, removeGeometryNodes);
     290         1704 :         PROGRESS_TIME_MESSAGE(before);
     291         3408 :         WRITE_MESSAGEF(TL("   % nodes removed."), toString(numRemoved));
     292              :     }
     293              : 
     294              :     // MOVE TO ORIGIN
     295              :     // compute new boundary after network modifications have taken place
     296         1704 :     Boundary boundary;
     297        52395 :     for (std::map<std::string, NBNode*>::const_iterator it = myNodeCont.begin(); it != myNodeCont.end(); ++it) {
     298        50691 :         boundary.add(it->second->getPosition());
     299              :     }
     300        92462 :     for (std::map<std::string, NBEdge*>::const_iterator it = myEdgeCont.begin(); it != myEdgeCont.end(); ++it) {
     301        90758 :         boundary.add(it->second->getGeometry().getBoxBoundary());
     302              :     }
     303              :     geoConvHelper.setConvBoundary(boundary);
     304              : 
     305         4206 :     if (!oc.getBool("offset.disable-normalization") && oc.isDefault("offset.x") && oc.isDefault("offset.y")) {
     306         1249 :         moveToOrigin(geoConvHelper, lefthand);
     307              :     }
     308         1704 :     geoConvHelper.computeFinal(lefthand); // information needed for location element fixed at this point
     309              : 
     310         4933 :     if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
     311            6 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Reducing geometries"));
     312            3 :         myEdgeCont.reduceGeometries(oc.getFloat("geometry.min-dist"));
     313            3 :         PROGRESS_TIME_MESSAGE(before);
     314              :     }
     315              :     // @note: removing geometry can create similar edges so joinSimilarEdges  must come afterwards
     316              :     // @note: likewise splitting can destroy similarities so joinSimilarEdges must come before
     317         3408 :     if (mayAddOrRemove && oc.getBool("edges.join")) {
     318           38 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining similar edges"));
     319           38 :         const bool removeDuplicates = oc.exists("junctions.join-same") && oc.getBool("junctions.join-same");
     320           19 :         myNodeCont.joinSimilarEdges(myDistrictCont, myEdgeCont, myTLLCont, removeDuplicates);
     321              :         // now we may have new chances to remove geometry if wished
     322           38 :         if (oc.exists("geometry.remove") && oc.getBool("geometry.remove")) {
     323            1 :             myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, true);
     324              :         }
     325           19 :         PROGRESS_TIME_MESSAGE(before);
     326              :     }
     327         3408 :     if (oc.getBool("opposites.guess")) {
     328           32 :         PROGRESS_BEGIN_MESSAGE(TL("guessing opposite direction edges"));
     329           16 :         myEdgeCont.guessOpposites();
     330           16 :         PROGRESS_DONE_MESSAGE();
     331              :     }
     332              :     //
     333         5112 :     if (mayAddOrRemove && oc.exists("geometry.split") && oc.getBool("geometry.split")) {
     334            6 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Splitting geometry edges"));
     335            3 :         myEdgeCont.splitGeometry(myDistrictCont, myNodeCont);
     336              :         // newly split junctions might also be joinable
     337            3 :         PROGRESS_TIME_MESSAGE(before);
     338            6 :         if (oc.getBool("junctions.join-same")) {
     339            1 :             int numJoined3 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont);
     340            1 :             if (numJoined3 > 0) {
     341            2 :                 WRITE_MESSAGEF(TL(" Joined % junctions after splitting geometry."), toString(numJoined3));
     342              :             }
     343              :         }
     344              :     }
     345              :     // turning direction
     346         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing turning directions"));
     347         1704 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont);
     348         1704 :     PROGRESS_TIME_MESSAGE(before);
     349              :     // correct edge geometries to avoid overlap
     350         3320 :     if (oc.exists("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap")) {
     351         1601 :         myNodeCont.avoidOverlap();
     352              :     }
     353              : 
     354              :     // GUESS TLS POSITIONS
     355         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Assigning nodes to traffic lights"));
     356         3408 :     if (oc.isSet("tls.set")) {
     357            8 :         std::vector<std::string> tlControlledNodes = oc.getStringVector("tls.set");
     358           16 :         TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
     359           16 :         for (std::vector<std::string>::const_iterator i = tlControlledNodes.begin(); i != tlControlledNodes.end(); ++i) {
     360            8 :             NBNode* node = myNodeCont.retrieve(*i);
     361            8 :             if (node == nullptr) {
     362            0 :                 WRITE_WARNING("Building a tl-logic for junction '" + *i + "' is not possible." + "\n The junction '" + *i + "' is not known.");
     363              :             } else {
     364           16 :                 myNodeCont.setAsTLControlled(node, myTLLCont, type);
     365              :             }
     366              :         }
     367            8 :     }
     368         1704 :     myNodeCont.guessTLs(oc, myTLLCont);
     369         1704 :     PROGRESS_TIME_MESSAGE(before);
     370              : 
     371              :     // guess ramps (after guessing tls because ramps should not be build at traffic lights)
     372         3408 :     const bool modifyRamps = mayAddOrRemove && (
     373         5024 :                                  (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     374         4922 :                                  || (oc.exists("ramps.set") && oc.isSet("ramps.set")));
     375         4906 :     if (modifyRamps || (oc.exists("ramps.guess-acceleration-lanes") && oc.getBool("ramps.guess-acceleration-lanes"))) {
     376         1616 :         before = SysUtils::getCurrentMillis();
     377         1616 :         if (modifyRamps) {
     378          177 :             PROGRESS_BEGIN_MESSAGE(TL("Guessing and setting on-/off-ramps"));
     379              :         }
     380         1616 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     381         1616 :         NBRampsComputer rc;
     382         1616 :         rc.computeRamps(*this, oc, mayAddOrRemove);
     383              : 
     384         1616 :         if (modifyRamps) {
     385           59 :             PROGRESS_TIME_MESSAGE(before);
     386              :         }
     387              :     }
     388              :     // guess bike lanes
     389         5107 :     if (mayAddOrRemove && ((oc.getBool("bikelanes.guess") || oc.getBool("bikelanes.guess.from-permissions")))) {
     390           18 :         const int bikelanes = myEdgeCont.guessSpecialLanes(SVC_BICYCLE, oc.getFloat("default.bikelane-width"),
     391              :                               oc.getFloat("bikelanes.guess.min-speed"),
     392              :                               oc.getFloat("bikelanes.guess.max-speed"),
     393           12 :                               oc.getBool("bikelanes.guess.from-permissions"),
     394              :                               "bikelanes.guess.exclude",
     395            6 :                               myTLLCont);
     396           12 :         WRITE_MESSAGEF(TL("Guessed % bike lanes."), toString(bikelanes));
     397              :     }
     398              : 
     399              :     // guess sidewalks
     400         5100 :     if (mayAddOrRemove && ((oc.getBool("sidewalks.guess") || oc.getBool("sidewalks.guess.from-permissions")))) {
     401           42 :         const int sidewalks = myEdgeCont.guessSpecialLanes(SVC_PEDESTRIAN, oc.getFloat("default.sidewalk-width"),
     402              :                               oc.getFloat("sidewalks.guess.min-speed"),
     403              :                               oc.getFloat("sidewalks.guess.max-speed"),
     404           28 :                               oc.getBool("sidewalks.guess.from-permissions"),
     405              :                               "sidewalks.guess.exclude",
     406           14 :                               myTLLCont);
     407           28 :         WRITE_MESSAGEF(TL("Guessed % sidewalks."), toString(sidewalks));
     408              :     }
     409              :     // check whether any not previously setable connections may be set now
     410         1704 :     myEdgeCont.recheckPostProcessConnections();
     411              : 
     412              :     // remap ids if wished
     413         1704 :     if (mayAddOrRemove) {
     414         1704 :         int numChangedEdges = myEdgeCont.remapIDs(oc.getBool("numerical-ids"), oc.isSet("reserved-ids"), oc.getString("prefix"), myPTStopCont);
     415         1704 :         int numChangedNodes = myNodeCont.remapIDs(oc.getBool("numerical-ids"), oc.isSet("reserved-ids"), oc.getString("prefix"), myTLLCont);
     416         1704 :         if (numChangedEdges + numChangedNodes > 0) {
     417           46 :             WRITE_MESSAGEF(TL("Remapped % edge IDs and % node IDs."), toString(numChangedEdges), toString(numChangedNodes));
     418              :         }
     419              :     }
     420              : 
     421              :     //
     422         3408 :     if (oc.exists("geometry.max-angle")) {
     423         3232 :         myEdgeCont.checkGeometries(
     424         3232 :             DEG2RAD(oc.getFloat("geometry.max-angle")),
     425         3232 :             oc.getBool("geometry.max-angle.fix"),
     426              :             oc.getFloat("geometry.min-radius"),
     427         3232 :             oc.getBool("geometry.min-radius.fix"),
     428         3232 :             oc.getBool("geometry.min-radius.fix.railways"));
     429              :     }
     430              : 
     431              :     // GEOMETRY COMPUTATION
     432              :     //
     433         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Sorting nodes' edges"));
     434         1704 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     435         1704 :     PROGRESS_TIME_MESSAGE(before);
     436         1704 :     myEdgeCont.computeLaneShapes();
     437              :     //
     438         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node shapes"));
     439         3408 :     if (oc.exists("geometry.junction-mismatch-threshold")) {
     440         3232 :         myNodeCont.computeNodeShapes(oc.getFloat("geometry.junction-mismatch-threshold"));
     441              :     } else {
     442           88 :         myNodeCont.computeNodeShapes();
     443              :     }
     444         1704 :     PROGRESS_TIME_MESSAGE(before);
     445              :     //
     446         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing edge shapes"));
     447         2960 :     myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
     448         1704 :     PROGRESS_TIME_MESSAGE(before);
     449              :     // resort edges based on the node and edge shapes
     450         1704 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont, true);
     451         1704 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     452              : 
     453              :     // APPLY SPEED MODIFICATIONS
     454         3408 :     if (oc.exists("speed.offset")) {
     455         1616 :         const double speedOffset = oc.getFloat("speed.offset");
     456         1616 :         const double speedFactor = oc.getFloat("speed.factor");
     457         1616 :         const double speedMin = oc.getFloat("speed.minimum");
     458         1616 :         if (speedOffset != 0 || speedFactor != 1 || speedMin > 0) {
     459            6 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Applying speed modifications"));
     460            7 :             for (const auto& it : myEdgeCont) {
     461            5 :                 NBEdge* const e = it.second;
     462           10 :                 for (int i = 0; i < e->getNumLanes(); i++) {
     463            6 :                     e->setSpeed(i, MAX2(e->getLaneSpeed(i) * speedFactor + speedOffset, speedMin));
     464              :                 }
     465              :             }
     466            2 :             PROGRESS_TIME_MESSAGE(before);
     467              :         }
     468              :     }
     469              : 
     470              :     // CONNECTIONS COMPUTATION
     471              :     //
     472         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node types"));
     473         1704 :     NBNodeTypeComputer::computeNodeTypes(myNodeCont, myTLLCont);
     474         1704 :     PROGRESS_TIME_MESSAGE(before);
     475              :     //
     476         1704 :     myNetworkHaveCrossings = oc.getBool("walkingareas");
     477         3408 :     if (mayAddOrRemove && oc.getBool("crossings.guess")) {
     478           58 :         myNetworkHaveCrossings = true;
     479           58 :         int crossings = 0;
     480         3447 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     481         3389 :             crossings += (*i).second->guessCrossings();
     482              :         }
     483          116 :         WRITE_MESSAGEF(TL("Guessed % pedestrian crossings."), toString(crossings));
     484              :     }
     485         1704 :     if (!myNetworkHaveCrossings) {
     486              :         bool haveValidCrossings = false;
     487              :         // recheck whether we had crossings in the input
     488        48349 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     489        46815 :             if (i->second->getCrossings().size() > 0) {
     490          103 :                 myNetworkHaveCrossings = true;
     491              :                 haveValidCrossings = true;
     492          103 :                 break;
     493        46712 :             } else if (i->second->getCrossingsIncludingInvalid().size() > 0) {
     494            0 :                 myNetworkHaveCrossings = true;
     495              :             }
     496              :         }
     497         1637 :         if (myNetworkHaveCrossings && !haveValidCrossings) {
     498              :             // initial crossings removed or invalidated, keep walkingareas
     499            0 :             oc.resetWritable();
     500            0 :             oc.set("walkingareas", "true");
     501              :         }
     502              :     }
     503              : 
     504         1704 :     if (!mayAddOrRemove && myNetworkHaveCrossings) {
     505              :         // crossings added via netedit
     506            0 :         oc.resetWritable();
     507            0 :         oc.set("no-internal-links", "false");
     508              :     }
     509              : 
     510              :     //
     511         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing priorities"));
     512         1704 :     NBEdgePriorityComputer::computeEdgePriorities(myNodeCont);
     513         1704 :     PROGRESS_TIME_MESSAGE(before);
     514              :     //
     515         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approached edges"));
     516         1704 :     myEdgeCont.computeEdge2Edges(oc.getBool("no-left-connections"));
     517         1704 :     PROGRESS_TIME_MESSAGE(before);
     518              :     //
     519         3408 :     if (oc.getBool("roundabouts.guess")) {
     520         3354 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing and setting roundabouts"));
     521         1677 :         const int numGuessed = myEdgeCont.guessRoundabouts();
     522         1677 :         if (numGuessed > 0) {
     523           28 :             WRITE_MESSAGEF(TL(" Guessed % roundabout(s)."), toString(numGuessed));
     524              :         }
     525         1677 :         PROGRESS_TIME_MESSAGE(before);
     526              :     }
     527         1704 :     myEdgeCont.markRoundabouts();
     528              :     //
     529         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approaching lanes"));
     530         1704 :     myEdgeCont.computeLanes2Edges();
     531         1704 :     PROGRESS_TIME_MESSAGE(before);
     532              :     //
     533         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Dividing of lanes on approached lanes"));
     534         1704 :     myNodeCont.computeLanes2Lanes();
     535         1704 :     myEdgeCont.sortOutgoingLanesConnections();
     536         1704 :     PROGRESS_TIME_MESSAGE(before);
     537              :     //
     538         3408 :     if (oc.getBool("fringe.guess")) {
     539            4 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing Network fringe"));
     540            2 :         const int numGuessed = myNodeCont.guessFringe();
     541            2 :         if (numGuessed > 0) {
     542            4 :             WRITE_MESSAGEF(TL(" Guessed % fringe nodes."), toString(numGuessed));
     543              :         }
     544            2 :         PROGRESS_TIME_MESSAGE(before);
     545              :     }
     546              :     //
     547         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing turnarounds"));
     548         3408 :     if (!oc.getBool("no-turnarounds")) {
     549         1020 :         myEdgeCont.appendTurnarounds(
     550         2040 :             oc.getBool("no-turnarounds.tls"),
     551         2040 :             oc.getBool("no-turnarounds.fringe"),
     552         2040 :             oc.getBool("no-turnarounds.except-deadend"),
     553         2040 :             oc.getBool("no-turnarounds.except-turnlane"),
     554         2040 :             oc.getBool("no-turnarounds.geometry"));
     555              :     } else {
     556         1368 :         myEdgeCont.appendTurnarounds(explicitTurnarounds, oc.getBool("no-turnarounds.tls"));
     557              :     }
     558         5057 :     if (oc.exists("railway.topology.repair.stop-turn") && oc.getBool("railway.topology.repair.stop-turn")
     559         1737 :             && myPTStopCont.getStops().size() > 0) {
     560              :         // allow direction reversal at all bidi-edges with stops
     561           25 :         myEdgeCont.appendRailwayTurnarounds(myPTStopCont);
     562              :     }
     563         1704 :     PROGRESS_TIME_MESSAGE(before);
     564              :     //
     565         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Rechecking of lane endings"));
     566         1704 :     myEdgeCont.recheckLanes();
     567         1704 :     PROGRESS_TIME_MESSAGE(before);
     568              : 
     569         1876 :     if (myNetworkHaveCrossings && !oc.getBool("no-internal-links")) {
     570         4314 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     571         4146 :             i->second->buildCrossingsAndWalkingAreas();
     572              :         }
     573              :     } else {
     574        48193 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     575              :             // needed by netedit if the last crossings was deleted from the network
     576              :             // and walkingareas have been invalidated since the last call to compute()
     577        46657 :             i->second->discardWalkingareas();
     578              :         }
     579         3072 :         if (oc.getBool("no-internal-links")) {
     580        23871 :             for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     581        23319 :                 i->second->discardAllCrossings(false);
     582              :             }
     583              :         }
     584              :     }
     585              :     // join traffic lights (after building connections)
     586         3408 :     if (oc.getBool("tls.join")) {
     587           72 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining traffic light nodes"));
     588           36 :         myNodeCont.joinTLS(myTLLCont, oc.getFloat("tls.join-dist"));
     589           36 :         PROGRESS_TIME_MESSAGE(before);
     590              :     }
     591              : 
     592              :     // COMPUTING RIGHT-OF-WAY AND TRAFFIC LIGHT PROGRAMS
     593              :     //
     594         3408 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light control information"));
     595         1704 :     myTLLCont.setTLControllingInformation(myEdgeCont, myNodeCont);
     596         3318 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files")) {
     597           22 :         myTLLCont.setOpenDriveSignalParameters();
     598              :     }
     599         1703 :     PROGRESS_TIME_MESSAGE(before);
     600              :     //
     601         3406 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node logics"));
     602         1703 :     myNodeCont.computeLogics(myEdgeCont);
     603         1703 :     PROGRESS_TIME_MESSAGE(before);
     604              : 
     605              :     //
     606         3406 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light logics"));
     607         1703 :     std::pair<int, int> numbers = myTLLCont.computeLogics(oc);
     608         1703 :     PROGRESS_TIME_MESSAGE(before);
     609         1703 :     std::string progCount = "";
     610         1703 :     if (numbers.first != numbers.second) {
     611           27 :         progCount = "(" + toString(numbers.second) + " programs) ";
     612              :     }
     613         5109 :     WRITE_MESSAGEF(TL(" % traffic light(s) %computed."), toString(numbers.first), progCount);
     614         3340 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files") && oc.getBool("opendrive.signal-groups")) {
     615            0 :         myTLLCont.applyOpenDriveControllers(oc);
     616              :     }
     617              : 
     618        92557 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     619        90854 :         (*i).second->sortOutgoingConnectionsByIndex();
     620              :     }
     621              :     // FINISHING INNER EDGES
     622              :     std::set<NBTrafficLightDefinition*> largeNodeTLS;
     623         3406 :     if (!oc.getBool("no-internal-links")) {
     624         3453 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Building inner edges"));
     625              :         // walking areas shall only be built if crossings are wished as well
     626        28631 :         for (const auto& item : myNodeCont) {
     627        27480 :             if (item.second->buildInnerEdges() > NBTrafficLightDefinition::MIN_YELLOW_SECONDS) {
     628         4817 :                 const std::set<NBTrafficLightDefinition*>& tlDefs = item.second->getControllingTLS();
     629         4817 :                 largeNodeTLS.insert(tlDefs.begin(), tlDefs.end());
     630              :             }
     631              :         }
     632         1151 :         PROGRESS_TIME_MESSAGE(before);
     633              :     }
     634              :     // PATCH NODE SHAPES
     635         3406 :     if (oc.getFloat("junctions.scurve-stretch") > 0) {
     636              :         // @note: nodes have collected correction hints in buildInnerEdges()
     637            4 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("stretching junctions to smooth geometries"));
     638            2 :         myEdgeCont.computeLaneShapes();
     639            2 :         myNodeCont.computeNodeShapes();
     640            3 :         myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
     641           15 :         for (const auto& item : myNodeCont) {
     642           13 :             item.second->buildInnerEdges();
     643              :         }
     644            2 :         PROGRESS_TIME_MESSAGE(before);
     645              :     }
     646         1886 :     if (myEdgeCont.getNumEdgeSplits() > 0 && !oc.getBool("no-internal-links")) {
     647              :         // edges with custom lengths were split, this has to take into account
     648              :         // internal edge lengths (after geometry computation)
     649           75 :         myEdgeCont.fixSplitCustomLength();
     650              :     }
     651              :     // recheck phases for large junctions
     652         2425 :     for (NBTrafficLightDefinition* def : largeNodeTLS) {
     653          722 :         myTLLCont.computeSingleLogic(oc, def);
     654              :     }
     655              :     // compute lane-to-lane node logics (require traffic lights and inner edges to be done)
     656         1703 :     myNodeCont.computeLogics2(myEdgeCont, oc);
     657              : 
     658              :     // remove guessed traffic lights at junctions without conflicts (requires computeLogics2)
     659         1703 :     myNodeCont.recheckGuessedTLS(myTLLCont);
     660              : 
     661              :     // compute keepClear status (requires computeLogics2)
     662         1703 :     myNodeCont.computeKeepClear();
     663              : 
     664              :     //
     665         3406 :     if (oc.isSet("street-sign-output")) {
     666            2 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Generating street signs"));
     667            1 :         myEdgeCont.generateStreetSigns();
     668            1 :         PROGRESS_TIME_MESSAGE(before);
     669              :     }
     670              : 
     671              : 
     672         3406 :     if (lefthand != oc.getBool("flip-y-axis")) {
     673           23 :         mirrorX();
     674              :     }
     675              : 
     676         4933 :     if (oc.exists("geometry.check-overlap")  && oc.getFloat("geometry.check-overlap") > 0) {
     677            0 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking overlapping edges"));
     678            0 :         myEdgeCont.checkOverlap(oc.getFloat("geometry.check-overlap"), oc.getFloat("geometry.check-overlap.vertical-threshold"));
     679            0 :         PROGRESS_TIME_MESSAGE(before);
     680              :     }
     681         1724 :     if (geoConvHelper.getConvBoundary().getZRange() > 0 && oc.getFloat("geometry.max-grade") > 0) {
     682           42 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking edge grade"));
     683              :         // user input is in %
     684           21 :         myEdgeCont.checkGrade(oc.getFloat("geometry.max-grade") / 100);
     685           21 :         PROGRESS_TIME_MESSAGE(before);
     686              :     }
     687              : 
     688              :     // find accesses for pt rail stops and add bidi-stops
     689         1703 :     if (!myPTStopCont.getStops().empty()) {
     690              :         // re-adapt stop lanes after adding special lanes and cutting edge shapes at junction
     691          135 :         myPTStopCont.assignLanes(myEdgeCont);
     692          135 :         before = SysUtils::getCurrentMillis();
     693              :         int numBidiStops = 0;
     694          270 :         if (!oc.getBool("ptstop-output.no-bidi")) {
     695          133 :             numBidiStops = myPTStopCont.generateBidiStops(myEdgeCont);
     696              :         }
     697          270 :         PROGRESS_BEGIN_MESSAGE(TL("Find accesses for pt rail stops"));
     698          135 :         double maxRadius = oc.getFloat("railway.access-distance");
     699          135 :         double accessFactor = oc.getFloat("railway.access-factor");
     700          135 :         int maxCount = oc.getInt("railway.max-accesses");
     701          135 :         myPTStopCont.findAccessEdgesForRailStops(myEdgeCont, maxRadius, maxCount, accessFactor);
     702          135 :         PROGRESS_TIME_MESSAGE(before);
     703          135 :         if (numBidiStops > 0) {
     704           63 :             myPTLineCont.fixBidiStops(myEdgeCont);
     705              :         }
     706              :     }
     707         1703 :     myPTLineCont.removeInvalidEdges(myEdgeCont);
     708              :     // ensure that all turning lanes have sufficient permissions
     709         1703 :     myPTLineCont.fixPermissions();
     710              : 
     711         4930 :     if (oc.exists("ignore-change-restrictions") && !oc.isDefault("ignore-change-restrictions")) {
     712            3 :         SVCPermissions ignoring = parseVehicleClasses(oc.getStringVector("ignore-change-restrictions"));
     713            3 :         myEdgeCont.updateAllChangeRestrictions(ignoring);
     714              :     }
     715              : 
     716         1703 :     NBRequest::reportWarnings();
     717              :     // report on very large networks
     718         5107 :     if (MAX2(geoConvHelper.getConvBoundary().xmax(), geoConvHelper.getConvBoundary().ymax()) > 1000000 ||
     719         1701 :             MIN2(geoConvHelper.getConvBoundary().xmin(), geoConvHelper.getConvBoundary().ymin()) < -1000000) {
     720            4 :         WRITE_WARNING(TL("Network contains very large coordinates and will probably flicker in the GUI. Check for outlying nodes and make sure the network is shifted to the coordinate origin"));
     721              :     }
     722              : 
     723              :     // clean up OSM processing params
     724         3318 :     if (oc.exists("osm-files") && oc.isSet("osm-files")) {
     725        34341 :         for (auto item : myEdgeCont) {
     726        34174 :             item.second->unsetParameter(NBTrafficLightDefinition::OSM_DIRECTION);
     727              :         }
     728              :     }
     729         1704 : }
     730              : 
     731              : 
     732              : void
     733         1249 : NBNetBuilder::moveToOrigin(GeoConvHelper& geoConvHelper, bool lefthand) {
     734         2498 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Moving network to origin"));
     735         1249 :     Boundary boundary = geoConvHelper.getConvBoundary();
     736         1249 :     const double x = -boundary.xmin();
     737         1249 :     const double y = -(lefthand ? boundary.ymax() : boundary.ymin());
     738              :     //if (lefthand) {
     739              :     //    y = boundary.ymax();
     740              :     //}
     741        38529 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     742        37280 :         (*i).second->reshiftPosition(x, y);
     743              :     }
     744        69072 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     745        67823 :         (*i).second->reshiftPosition(x, y);
     746              :     }
     747         1299 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     748           50 :         (*i).second->reshiftPosition(x, y);
     749              :     }
     750         2899 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     751         1650 :         stopIt.second->reshiftPosition(x, y);
     752              :     }
     753         1249 :     geoConvHelper.moveConvertedBy(x, y);
     754         1249 :     PROGRESS_TIME_MESSAGE(before);
     755         1249 : }
     756              : 
     757              : 
     758              : void
     759           46 : NBNetBuilder::mirrorX() {
     760              :     // mirror the network along the X-axis
     761          888 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     762          842 :         (*i).second->mirrorX();
     763              :     }
     764         1190 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     765         1144 :         (*i).second->mirrorX();
     766              :     }
     767           46 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     768            0 :         (*i).second->mirrorX();
     769              :     }
     770          105 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     771           59 :         stopIt.second->mirrorX();
     772              :     }
     773           46 : }
     774              : 
     775              : 
     776              : bool
     777       428909 : NBNetBuilder::transformCoordinate(Position& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     778       428909 :     Position orig(from);
     779              :     bool ok = true;
     780              :     if (GeoConvHelper::getNumLoaded() > 1
     781         2500 :             && GeoConvHelper::getLoaded().usingGeoProjection()
     782         2326 :             && from_srs != nullptr
     783         2326 :             && from_srs->usingGeoProjection()
     784       431235 :             && *from_srs != GeoConvHelper::getLoaded()) {
     785         2326 :         from_srs->cartesian2geo(from);
     786         2326 :         ok &= GeoConvHelper::getLoaded().x2cartesian(from, false);
     787              :     }
     788       428909 :     if (from_srs == nullptr || !GeoConvHelper::getProcessing().usingGeoProjection()) {
     789              :         // if getProcessing is not a geo-projection, assume it a cartesian transformation (i.e. shift)
     790       428794 :         ok &= GeoConvHelper::getProcessing().x2cartesian(from, includeInBoundary);
     791              : 
     792       189060 :         if (from_srs == nullptr && GeoConvHelper::getProcessing().usingGeoProjection()
     793       160016 :                 && GeoConvHelper::getNumLoaded() > 0
     794       428830 :                 && GeoConvHelper::getLoaded().usingGeoProjection()) {
     795              :             // apply geo patch to loaded geo-network (offset must match)
     796           36 :             from = from + GeoConvHelper::getLoaded().getOffset();
     797              :         }
     798              :     }
     799       428909 :     if (ok) {
     800       428909 :         const NBHeightMapper& hm = NBHeightMapper::get();
     801       428909 :         if (hm.ready()) {
     802          604 :             if (from_srs != nullptr && from_srs->usingGeoProjection()) {
     803          600 :                 from_srs->cartesian2geo(orig);
     804              :             }
     805          604 :             from.setz(hm.getZ(orig));
     806              :         }
     807              :     }
     808              :     const double eps = 1e-6;
     809       428909 :     from.set(std::round(from.x() / eps) * eps, std::round(from.y() / eps) * eps, std::round(from.z() / eps) * eps);
     810       428909 :     return ok;
     811              : }
     812              : 
     813              : 
     814              : bool
     815       144218 : NBNetBuilder::transformCoordinates(PositionVector& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     816       144218 :     const double maxLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
     817       144218 :     if (maxLength > 0 && from.size() > 1) {
     818              :         // transformation to cartesian coordinates must happen before we can check segment length
     819              :         PositionVector copy = from;
     820          118 :         for (int i = 0; i < (int) from.size(); i++) {
     821           85 :             transformCoordinate(copy[i], false);
     822              :         }
     823           33 :         addGeometrySegments(from, copy, maxLength);
     824           33 :     }
     825              :     bool ok = true;
     826       504993 :     for (int i = 0; i < (int) from.size(); i++) {
     827       360775 :         ok = ok && transformCoordinate(from[i], includeInBoundary, from_srs);
     828              :     }
     829       144218 :     return ok;
     830              : }
     831              : 
     832              : 
     833              : int
     834           71 : NBNetBuilder::addGeometrySegments(PositionVector& from, const PositionVector& cartesian, const double maxLength) {
     835              :     // check lengths and insert new points where needed (in the original
     836              :     // coordinate system)
     837              :     int inserted = 0;
     838          161 :     for (int i = 0; i < (int)cartesian.size() - 1; i++) {
     839           90 :         Position start = from[i + inserted];
     840           90 :         Position end = from[i + inserted + 1];
     841           90 :         double length = cartesian[i].distanceTo(cartesian[i + 1]);
     842           90 :         const Position step = (end - start) * (maxLength / length);
     843              :         int steps = 0;
     844          312 :         while (length > maxLength) {
     845          222 :             length -= maxLength;
     846          222 :             steps++;
     847          222 :             from.insert(from.begin() + i + inserted + 1, start + (step * steps));
     848          222 :             inserted++;
     849              :         }
     850              :     }
     851           71 :     return inserted;
     852              : }
     853              : 
     854              : 
     855              : bool
     856          622 : NBNetBuilder::runningNetedit() {
     857              :     // see GNELoadThread::fillOptions
     858         1244 :     return OptionsCont::getOptions().exists("new");
     859              : }
     860              : 
     861              : 
     862              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1