LCOV - code coverage report
Current view: top level - src/netbuild - NBNetBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.7 % 514 497
Test Date: 2025-12-06 15:35:27 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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         2113 : NBNetBuilder::NBNetBuilder() :
      56         2113 :     myEdgeCont(myTypeCont),
      57         4226 :     myNetworkHaveCrossings(false) {
      58         2113 : }
      59              : 
      60              : 
      61         4226 : NBNetBuilder::~NBNetBuilder() {}
      62              : 
      63              : 
      64              : void
      65         2113 : NBNetBuilder::applyOptions(OptionsCont& oc) {
      66              :     // apply options to type control
      67         6339 :     myTypeCont.setEdgeTypeDefaults(oc.getInt("default.lanenumber"), oc.getFloat("default.lanewidth"), oc.getFloat("default.speed"), oc.getFloat("default.friction"),
      68         6339 :                                    oc.getInt("default.priority"), parseVehicleClasses(oc.getString("default.allow"), oc.getString("default.disallow")),
      69         2113 :                                    SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype")));
      70              :     // apply options to edge control
      71         2113 :     myEdgeCont.applyOptions(oc);
      72              :     // apply options to traffic light logics control
      73         2103 :     myTLLCont.applyOptions(oc);
      74         2103 :     NBEdge::setDefaultConnectionLength(oc.getFloat("default.connection-length"));
      75         2103 : }
      76              : 
      77              : 
      78              : void
      79         1813 : NBNetBuilder::compute(OptionsCont& oc, const std::set<std::string>& explicitTurnarounds, bool mayAddOrRemove) {
      80              :     GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
      81              : 
      82         1813 :     const bool lefthand = oc.getBool("lefthand");
      83         1813 :     if (lefthand) {
      84           23 :         mirrorX();
      85              :     }
      86              : 
      87              :     // MODIFYING THE SETS OF NODES AND EDGES
      88              :     // Removes edges that are connecting the same node
      89         3626 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing self-loops"));
      90              :     int numRemovedEdges = 0;
      91         1813 :     numRemovedEdges += myNodeCont.removeSelfLoops(myDistrictCont, myEdgeCont, myTLLCont);
      92         1813 :     PROGRESS_TIME_MESSAGE(before);
      93         5351 :     if (mayAddOrRemove && oc.exists("remove-edges.isolated") && oc.getBool("remove-edges.isolated")) {
      94           10 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding isolated roads"));
      95            5 :         numRemovedEdges += myNodeCont.removeIsolatedRoads(myDistrictCont, myEdgeCont);
      96            5 :         PROGRESS_TIME_MESSAGE(before);
      97              :     }
      98         7053 :     if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
      99           46 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Finding largest components"));
     100           46 :         const bool hasStops = oc.exists("ptstop-output") && oc.isSet("ptstop-output") && !myPTStopCont.getStops().empty();
     101           23 :         numRemovedEdges += myNodeCont.removeComponents(myDistrictCont, myEdgeCont, oc.getInt("keep-edges.components"), hasStops);
     102           23 :         PROGRESS_TIME_MESSAGE(before);
     103              :     }
     104         5351 :     if (mayAddOrRemove && oc.exists("keep-edges.postload") && oc.getBool("keep-edges.postload")) {
     105              :         // pre-process lines to set permissions
     106            4 :         if (!myPTLineCont.getLines().empty()) {
     107            2 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
     108            1 :             myPTLineCont.process(myEdgeCont, myPTStopCont);
     109            1 :             PROGRESS_TIME_MESSAGE(before);
     110              :         }
     111            7 :         if (oc.isSet("keep-edges.explicit") || oc.isSet("keep-edges.input-file")) {
     112            4 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing unwished edges"));
     113            2 :             numRemovedEdges += myEdgeCont.removeUnwishedEdges(myDistrictCont);
     114            2 :             PROGRESS_TIME_MESSAGE(before);
     115              :         }
     116            4 :         const int removed = myEdgeCont.removeEdgesBySpeed(myDistrictCont);
     117            4 :         if (removed > 0) {
     118            0 :             numRemovedEdges += removed;
     119            0 :             WRITE_MESSAGEF(TL(" Removed % edges because by minimum speed."), removed);
     120              :         }
     121            4 :         const int removed2 = myEdgeCont.removeEdgesByPermissions(myDistrictCont);
     122            4 :         if (removed2 > 0) {
     123            1 :             numRemovedEdges += removed2;
     124            2 :             WRITE_MESSAGEF(TL(" Removed % edges based on vClass."), removed2);
     125              :         }
     126              :     }
     127         3626 :     if (mayAddOrRemove && oc.getFloat("keep-lanes.min-width") > 0.) {
     128         1813 :         const int removed = myEdgeCont.removeLanesByWidth(myDistrictCont, oc.getFloat("keep-lanes.min-width"));
     129         1813 :         if (removed > 0) {
     130            0 :             numRemovedEdges += removed;
     131            0 :             WRITE_MESSAGEF(TL(" Removed % edges because of lane width."), removed);
     132              :         }
     133              :     }
     134         7075 :     if (mayAddOrRemove && oc.exists("junctions.attach-removed") && oc.getFloat("junctions.attach-removed") >= 0) {
     135            1 :         const int numSplit = myEdgeCont.attachRemoved(myNodeCont, myDistrictCont, oc.getFloat("junctions.attach-removed"));
     136            1 :         if (numSplit > 0) {
     137            2 :             WRITE_MESSAGEF(TL(" Split % edges to attach removed nodes"), numSplit);
     138              :         }
     139              :     }
     140              :     // Processing pt stops and lines
     141         1813 :     if (!myPTStopCont.getStops().empty()) {
     142          334 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing public transport stops"));
     143          501 :         if (!(oc.exists("ptline-output") && oc.isSet("ptline-output"))
     144          456 :                 && !oc.getBool("ptstop-output.no-bidi")) {
     145          120 :             myPTStopCont.localizePTStops(myEdgeCont);
     146              :         }
     147          167 :         myPTStopCont.assignEdgeForFloatingStops(myEdgeCont, 20);
     148          167 :         myPTStopCont.assignLanes(myEdgeCont);
     149          167 :         PROGRESS_TIME_MESSAGE(before);
     150              :     }
     151         7053 :     if (mayAddOrRemove && oc.exists("keep-edges.components") && oc.getInt("keep-edges.components") > 0) {
     152              :         // post process rail components unless they have stops
     153           23 :         numRemovedEdges += myNodeCont.removeRailComponents(myDistrictCont, myEdgeCont, myPTStopCont);
     154              :     }
     155              :     // removal is done, clean up roundabouts
     156         1813 :     if (numRemovedEdges > 0) {
     157           18 :         myEdgeCont.cleanupRoundabouts();
     158              :     }
     159              : 
     160         1813 :     if (!myPTLineCont.getLines().empty()) {
     161          196 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
     162           98 :         myPTLineCont.process(myEdgeCont, myPTStopCont);
     163           98 :         PROGRESS_TIME_MESSAGE(before);
     164              :     }
     165              : 
     166         1973 :     if (!myPTStopCont.getStops().empty() && !oc.getBool("ptstop-output.no-bidi")) {
     167          312 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Align pt stop id signs with corresponding edge id signs"));
     168          156 :         myPTStopCont.alignIdSigns();
     169          156 :         PROGRESS_TIME_MESSAGE(before);
     170              :     }
     171              :     // analyze and fix railway topology
     172              :     int numAddedBidi = 0;
     173         3538 :     if (oc.exists("railway.topology.all-bidi") && oc.getBool("railway.topology.all-bidi")) {
     174            6 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     175            6 :         numAddedBidi = NBRailwayTopologyAnalyzer::makeAllBidi(myEdgeCont);
     176         3526 :     } else if (oc.exists("railway.topology.repair") && oc.getBool("railway.topology.repair")) {
     177              :         // correct railway angles for angle-based connectivity heuristic
     178           70 :         myEdgeCont.checkGeometries(0, false,
     179              :                                    oc.getFloat("geometry.min-radius"), false,
     180           35 :                                    oc.getBool("geometry.min-radius.fix.railways"), true);
     181           35 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     182           35 :         numAddedBidi = NBRailwayTopologyAnalyzer::repairTopology(myEdgeCont, myPTStopCont, myPTLineCont);
     183              :     }
     184         1813 :     NBRailwaySignalGuesser::guessRailSignals(myEdgeCont, myPTStopCont);
     185         1813 :     if (numAddedBidi > 0) {
     186              :         // update routes
     187           37 :         myPTLineCont.process(myEdgeCont, myPTStopCont, true);
     188              :     }
     189         3538 :     if (oc.exists("railway.topology.direction-priority") && oc.getBool("railway.topology.direction-priority")) {
     190            1 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     191            1 :         NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, true);
     192         3536 :     } else if (oc.exists("railway.topology.extend-priority") && oc.getBool("railway.topology.extend-priority")) {
     193            3 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     194            3 :         NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, false);
     195              :     }
     196         3538 :     if (oc.exists("railway.topology.output") && oc.isSet("railway.topology.output")) {
     197           29 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     198           29 :         NBRailwayTopologyAnalyzer::analyzeTopology(myEdgeCont);
     199              :     }
     200         3538 :     if (oc.exists("railway.geometry.straighten") && oc.getBool("railway.geometry.straighten")) {
     201            0 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     202            0 :         NBRailwayGeometryHelper::straigthenCorrdidor(myEdgeCont, oc.getFloat("geometry.max-angle"));
     203              :     }
     204              : 
     205              : 
     206         7069 :     if (mayAddOrRemove && oc.exists("edges.join-tram-dist") && oc.getFloat("edges.join-tram-dist") >= 0) {
     207              :         // should come before joining junctions
     208           14 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining tram edges"));
     209            7 :         int numJoinedTramEdges = myEdgeCont.joinTramEdges(myDistrictCont, myPTStopCont, myPTLineCont, oc.getFloat("edges.join-tram-dist"));
     210            7 :         PROGRESS_TIME_MESSAGE(before);
     211            7 :         if (numJoinedTramEdges > 0) {
     212           14 :             WRITE_MESSAGEF(TL(" Joined % tram edges into roads."), toString(numJoinedTramEdges));
     213              :         }
     214              :     }
     215         3626 :     if (oc.getBool("junctions.join")
     216         5213 :             || (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     217         3480 :             || oc.getBool("tls.guess.joining")
     218         6751 :             || (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals"))) {
     219              :         // preliminary geometry computations to determine the length of edges
     220              :         // This depends on turning directions and sorting of edge list
     221              :         // in case junctions are joined geometry computations have to be repeated
     222              :         // preliminary roundabout computations to avoid damaging roundabouts via junctions.join or ramps.guess
     223          156 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     224          156 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     225          156 :         myEdgeCont.computeLaneShapes();
     226          156 :         myNodeCont.computeNodeShapes();
     227          156 :         myEdgeCont.computeEdgeShapes();
     228          312 :         if (oc.getBool("roundabouts.guess")) {
     229          156 :             myEdgeCont.guessRoundabouts();
     230              :         }
     231          156 :         const std::set<EdgeSet>& roundabouts = myEdgeCont.getRoundabouts();
     232          156 :         for (std::set<EdgeSet>::const_iterator it_round = roundabouts.begin();
     233          170 :                 it_round != roundabouts.end(); ++it_round) {
     234              :             std::vector<std::string> nodeIDs;
     235          111 :             for (EdgeSet::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
     236           97 :                 nodeIDs.push_back((*it_edge)->getToNode()->getID());
     237              :             }
     238           14 :             myNodeCont.addJoinExclusion(nodeIDs);
     239           14 :         }
     240          156 :         NBNodeTypeComputer::validateRailCrossings(myNodeCont, myTLLCont);
     241         3362 :     } else if ((myEdgeCont.hasGuessedRoundabouts() || oc.getBool("crossings.guess")) && oc.getBool("roundabouts.guess")) {
     242           48 :         myEdgeCont.guessRoundabouts();
     243           48 :         myEdgeCont.markRoundabouts();
     244              :     }
     245              :     // join junctions (may create new "geometry"-nodes so it needs to come before removing these
     246         5351 :     if (mayAddOrRemove && oc.exists("junctions.join-exclude") && oc.isSet("junctions.join-exclude")) {
     247            2 :         myNodeCont.addJoinExclusion(oc.getStringVector("junctions.join-exclude"));
     248              :     }
     249         1813 :     int numJoined = myNodeCont.joinLoadedClusters(myDistrictCont, myEdgeCont, myTLLCont);
     250         3626 :     if (mayAddOrRemove && oc.getBool("junctions.join")) {
     251          226 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junction clusters"));
     252          113 :         numJoined += myNodeCont.joinJunctions(oc.getFloat("junctions.join-dist"), myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont);
     253          113 :         PROGRESS_TIME_MESSAGE(before);
     254              :     }
     255         1813 :     if (numJoined > 0) {
     256          196 :         WRITE_MESSAGEF(TL(" Joined % junction cluster(s)."), toString(numJoined));
     257              :     }
     258         5428 :     if (mayAddOrRemove && oc.getFloat("junctions.join-same") >= 0) {
     259           22 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junctions with similar coordinates"));
     260           11 :         int numJoined2 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont, oc.getFloat("junctions.join-same"));
     261           11 :         PROGRESS_TIME_MESSAGE(before);
     262           11 :         if (numJoined2 > 0) {
     263            6 :             WRITE_MESSAGEF(TL(" Joined % junctions."), toString(numJoined2));
     264              :         }
     265              :     }
     266              :     //
     267         5351 :     if (mayAddOrRemove && oc.exists("join-lanes") && oc.getBool("join-lanes")) {
     268            2 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining lanes"));
     269            1 :         const int num = myEdgeCont.joinLanes(SVC_IGNORING) + myEdgeCont.joinLanes(SVC_PEDESTRIAN);
     270            1 :         PROGRESS_TIME_MESSAGE(before);
     271            2 :         WRITE_MESSAGEF(TL("   Joined lanes on % edges."), toString(num));
     272              :     }
     273              :     //
     274         1813 :     if (mayAddOrRemove) {
     275         3626 :         const bool removeGeometryNodes = oc.exists("geometry.remove") && oc.getBool("geometry.remove");
     276         7146 :         before = PROGRESS_BEGIN_TIME_MESSAGE("Removing empty nodes" + std::string(removeGeometryNodes ? " and geometry nodes" : ""));
     277              :         // removeUnwishedNodes needs turnDirections. @todo: try to call this less often
     278         1813 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     279         1813 :         const int numRemoved = myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, removeGeometryNodes);
     280         1813 :         PROGRESS_TIME_MESSAGE(before);
     281         3626 :         WRITE_MESSAGEF(TL("   % nodes removed."), toString(numRemoved));
     282              :     }
     283              : 
     284              :     // MOVE TO ORIGIN
     285              :     // compute new boundary after network modifications have taken place
     286         1813 :     Boundary boundary;
     287        58705 :     for (std::map<std::string, NBNode*>::const_iterator it = myNodeCont.begin(); it != myNodeCont.end(); ++it) {
     288        56892 :         boundary.add(it->second->getPosition());
     289              :     }
     290       104072 :     for (std::map<std::string, NBEdge*>::const_iterator it = myEdgeCont.begin(); it != myEdgeCont.end(); ++it) {
     291       102259 :         boundary.add(it->second->getGeometry().getBoxBoundary());
     292              :     }
     293              :     geoConvHelper.setConvBoundary(boundary);
     294              : 
     295         4435 :     if (!oc.getBool("offset.disable-normalization") && oc.isDefault("offset.x") && oc.isDefault("offset.y")) {
     296         1309 :         moveToOrigin(geoConvHelper, lefthand);
     297              :     }
     298         1813 :     roundInputs();
     299         1813 :     geoConvHelper.computeFinal(lefthand); // information needed for location element fixed at this point
     300              : 
     301              :     // reset shapes and angles for stable re-computation
     302         1813 :     if (myNodeCont.resetNodeShapes()) {
     303          156 :         myEdgeCont.computeAngles();
     304              :     }
     305              : 
     306         5260 :     if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
     307            6 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Reducing geometries"));
     308            3 :         myEdgeCont.reduceGeometries(oc.getFloat("geometry.min-dist"));
     309            3 :         PROGRESS_TIME_MESSAGE(before);
     310              :     }
     311              :     // @note: removing geometry can create similar edges so joinSimilarEdges  must come afterwards
     312              :     // @note: likewise splitting can destroy similarities so joinSimilarEdges must come before
     313         3626 :     if (mayAddOrRemove && oc.getBool("edges.join")) {
     314           38 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining similar edges"));
     315           19 :         const bool removeDuplicates = oc.getFloat("junctions.join-same") >= 0;
     316           19 :         myNodeCont.joinSimilarEdges(myDistrictCont, myEdgeCont, myTLLCont, removeDuplicates);
     317              :         // now we may have new chances to remove geometry if wished
     318           38 :         if (oc.exists("geometry.remove") && oc.getBool("geometry.remove")) {
     319            1 :             myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, true);
     320              :         }
     321           19 :         PROGRESS_TIME_MESSAGE(before);
     322              :     }
     323         3626 :     if (oc.getBool("opposites.guess")) {
     324           32 :         PROGRESS_BEGIN_MESSAGE(TL("guessing opposite direction edges"));
     325           16 :         myEdgeCont.guessOpposites();
     326           16 :         PROGRESS_DONE_MESSAGE();
     327              :     }
     328              :     //
     329         5439 :     if (mayAddOrRemove && oc.exists("geometry.split") && oc.getBool("geometry.split")) {
     330            8 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Splitting geometry edges"));
     331            4 :         myEdgeCont.splitGeometry(myDistrictCont, myNodeCont);
     332              :         // newly split junctions might also be joinable
     333            4 :         PROGRESS_TIME_MESSAGE(before);
     334            8 :         if (oc.getFloat("junctions.join-same") >= 0) {
     335            2 :             int numJoined3 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont, oc.getFloat("junctions.join-same"));
     336            2 :             if (numJoined3 > 0) {
     337            4 :                 WRITE_MESSAGEF(TL(" Joined % junctions after splitting geometry."), toString(numJoined3));
     338              :             }
     339              :         }
     340              :     }
     341              :     // turning direction
     342         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing turning directions"));
     343         1813 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont);
     344         1813 :     PROGRESS_TIME_MESSAGE(before);
     345              :     // correct edge geometries to avoid overlap
     346         3538 :     if (oc.exists("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap")) {
     347         1250 :         myNodeCont.avoidOverlap();
     348              :     }
     349              : 
     350              :     // GUESS TLS POSITIONS
     351         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Assigning nodes to traffic lights"));
     352         3626 :     if (oc.isSet("tls.set")) {
     353            8 :         std::vector<std::string> tlControlledNodes = oc.getStringVector("tls.set");
     354           16 :         TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
     355           16 :         for (std::vector<std::string>::const_iterator i = tlControlledNodes.begin(); i != tlControlledNodes.end(); ++i) {
     356            8 :             NBNode* node = myNodeCont.retrieve(*i);
     357            8 :             if (node == nullptr) {
     358            0 :                 WRITE_WARNING("Building a tl-logic for junction '" + *i + "' is not possible." + "\n The junction '" + *i + "' is not known.");
     359              :             } else {
     360           16 :                 myNodeCont.setAsTLControlled(node, myTLLCont, type);
     361              :             }
     362              :         }
     363            8 :     }
     364         1813 :     myNodeCont.guessTLs(oc, myTLLCont);
     365         1813 :     PROGRESS_TIME_MESSAGE(before);
     366              : 
     367              :     // guess ramps (after guessing tls because ramps should not be build at traffic lights)
     368         3626 :     const bool modifyRamps = mayAddOrRemove && (
     369         5351 :                                  (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     370         5249 :                                  || (oc.exists("ramps.set") && oc.isSet("ramps.set")));
     371         5233 :     if (modifyRamps || (oc.exists("ramps.guess-acceleration-lanes") && oc.getBool("ramps.guess-acceleration-lanes"))) {
     372         1725 :         before = SysUtils::getCurrentMillis();
     373         1725 :         if (modifyRamps) {
     374          177 :             PROGRESS_BEGIN_MESSAGE(TL("Guessing and setting on-/off-ramps"));
     375              :         }
     376         1725 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     377         1725 :         NBRampsComputer rc;
     378         1725 :         rc.computeRamps(*this, oc, mayAddOrRemove);
     379              : 
     380         1725 :         if (modifyRamps) {
     381           59 :             PROGRESS_TIME_MESSAGE(before);
     382              :         }
     383              :     }
     384              :     // guess bike lanes
     385         5433 :     if (mayAddOrRemove && ((oc.getBool("bikelanes.guess") || oc.getBool("bikelanes.guess.from-permissions")))) {
     386           21 :         const int bikelanes = myEdgeCont.guessSpecialLanes(SVC_BICYCLE, oc.getFloat("default.bikelane-width"),
     387              :                               oc.getFloat("bikelanes.guess.min-speed"),
     388              :                               oc.getFloat("bikelanes.guess.max-speed"),
     389           14 :                               oc.getBool("bikelanes.guess.from-permissions"),
     390              :                               "bikelanes.guess.exclude",
     391            7 :                               myTLLCont);
     392           14 :         WRITE_MESSAGEF(TL("Guessed % bike lanes."), toString(bikelanes));
     393              :     }
     394              : 
     395              :     // guess sidewalks
     396         5427 :     if (mayAddOrRemove && ((oc.getBool("sidewalks.guess") || oc.getBool("sidewalks.guess.from-permissions")))) {
     397           42 :         const int sidewalks = myEdgeCont.guessSpecialLanes(SVC_PEDESTRIAN, oc.getFloat("default.sidewalk-width"),
     398              :                               oc.getFloat("sidewalks.guess.min-speed"),
     399              :                               oc.getFloat("sidewalks.guess.max-speed"),
     400           28 :                               oc.getBool("sidewalks.guess.from-permissions"),
     401              :                               "sidewalks.guess.exclude",
     402           14 :                               myTLLCont);
     403           28 :         WRITE_MESSAGEF(TL("Guessed % sidewalks."), toString(sidewalks));
     404              :     }
     405              :     // check whether any not previously setable connections may be set now
     406         1813 :     myEdgeCont.recheckPostProcessConnections();
     407              : 
     408              :     // remap ids if wished
     409         1813 :     if (mayAddOrRemove) {
     410         1813 :         const bool numericalIDs = oc.getBool("numerical-ids");
     411         1813 :         const bool reservedIDs = oc.isSet("reserved-ids");
     412         1813 :         const bool keptIDs = oc.isSet("kept-ids");
     413         1813 :         int numChangedEdges = myEdgeCont.remapIDs(numericalIDs, reservedIDs, keptIDs, oc.getString("prefix.edge"), myPTStopCont);
     414         1813 :         int numChangedNodes = myNodeCont.remapIDs(numericalIDs, reservedIDs, keptIDs, oc.getString("prefix.junction"), myTLLCont);
     415         1813 :         if (numChangedEdges + numChangedNodes > 0) {
     416           82 :             WRITE_MESSAGEF(TL("Remapped % edge IDs and % node IDs."), toString(numChangedEdges), toString(numChangedNodes));
     417              :         }
     418              :     }
     419              : 
     420              :     //
     421         3626 :     if (oc.exists("geometry.max-angle")) {
     422         3450 :         myEdgeCont.checkGeometries(
     423         3450 :             DEG2RAD(oc.getFloat("geometry.max-angle")),
     424         3450 :             oc.getBool("geometry.max-angle.fix"),
     425              :             oc.getFloat("geometry.min-radius"),
     426         3450 :             oc.getBool("geometry.min-radius.fix"),
     427         3450 :             oc.getBool("geometry.min-radius.fix.railways"));
     428              :     }
     429              : 
     430              :     // GEOMETRY COMPUTATION
     431              :     //
     432         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Sorting nodes' edges"));
     433         1813 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     434         1813 :     PROGRESS_TIME_MESSAGE(before);
     435         1813 :     myEdgeCont.computeLaneShapes();
     436              :     //
     437         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node shapes"));
     438         3626 :     if (oc.exists("geometry.junction-mismatch-threshold")) {
     439         3450 :         myNodeCont.computeNodeShapes(oc.getFloat("geometry.junction-mismatch-threshold"));
     440              :     } else {
     441           88 :         myNodeCont.computeNodeShapes();
     442              :     }
     443         1813 :     PROGRESS_TIME_MESSAGE(before);
     444              :     //
     445         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing edge shapes"));
     446         3129 :     myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
     447         1813 :     PROGRESS_TIME_MESSAGE(before);
     448              :     // resort edges based on the node and edge shapes
     449         1813 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont, true);
     450         1813 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     451              : 
     452              :     // APPLY SPEED MODIFICATIONS
     453         3626 :     if (oc.exists("speed.offset")) {
     454         1725 :         const double speedOffset = oc.getFloat("speed.offset");
     455         1725 :         const double speedFactor = oc.getFloat("speed.factor");
     456         1725 :         const double speedMin = oc.getFloat("speed.minimum");
     457         1725 :         if (speedOffset != 0 || speedFactor != 1 || speedMin > 0) {
     458            6 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Applying speed modifications"));
     459            7 :             for (const auto& it : myEdgeCont) {
     460            5 :                 NBEdge* const e = it.second;
     461           10 :                 for (int i = 0; i < e->getNumLanes(); i++) {
     462            6 :                     e->setSpeed(i, MAX2(e->getLaneSpeed(i) * speedFactor + speedOffset, speedMin));
     463              :                 }
     464              :             }
     465            2 :             PROGRESS_TIME_MESSAGE(before);
     466              :         }
     467              :     }
     468              : 
     469              :     // CONNECTIONS COMPUTATION
     470              :     //
     471         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node types"));
     472         1813 :     NBNode::initRailSignalClasses(myNodeCont);
     473         1813 :     NBNodeTypeComputer::computeNodeTypes(myNodeCont, myTLLCont);
     474         1813 :     PROGRESS_TIME_MESSAGE(before);
     475              :     //
     476         1813 :     myNetworkHaveCrossings = oc.getBool("walkingareas");
     477         3626 :     if (mayAddOrRemove && oc.getBool("crossings.guess")) {
     478           58 :         myNetworkHaveCrossings = true;
     479           58 :         int crossings = 0;
     480         3446 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     481         3388 :             crossings += (*i).second->guessCrossings();
     482              :         }
     483          116 :         WRITE_MESSAGEF(TL("Guessed % pedestrian crossings."), toString(crossings));
     484              :     }
     485         1813 :     if (!myNetworkHaveCrossings) {
     486              :         bool haveValidCrossings = false;
     487              :         // recheck whether we had crossings in the input
     488        54693 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     489        53057 :             if (i->second->getCrossings().size() > 0) {
     490          108 :                 myNetworkHaveCrossings = true;
     491              :                 haveValidCrossings = true;
     492          108 :                 break;
     493        52949 :             } else if (i->second->getCrossingsIncludingInvalid().size() > 0) {
     494            0 :                 myNetworkHaveCrossings = true;
     495              :             }
     496              :         }
     497         1744 :         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         1813 :     if (!mayAddOrRemove && myNetworkHaveCrossings) {
     505              :         // crossings added via netedit
     506            0 :         oc.resetWritable();
     507            0 :         oc.set("no-internal-links", "false");
     508              :     }
     509              : 
     510              :     //
     511         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing priorities"));
     512         1813 :     NBEdgePriorityComputer::computeEdgePriorities(myNodeCont);
     513         1813 :     PROGRESS_TIME_MESSAGE(before);
     514              :     //
     515         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approached edges"));
     516         1813 :     myEdgeCont.computeEdge2Edges(oc.getBool("no-left-connections"));
     517         1813 :     PROGRESS_TIME_MESSAGE(before);
     518              :     //
     519         3626 :     if (oc.getBool("roundabouts.guess")) {
     520         3568 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing and setting roundabouts"));
     521         1784 :         const int numGuessed = myEdgeCont.guessRoundabouts();
     522         1784 :         if (numGuessed > 0) {
     523           30 :             WRITE_MESSAGEF(TL(" Guessed % roundabout(s)."), toString(numGuessed));
     524              :         }
     525         1784 :         PROGRESS_TIME_MESSAGE(before);
     526              :     }
     527         1813 :     myEdgeCont.markRoundabouts();
     528              :     //
     529         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approaching lanes"));
     530         1813 :     myEdgeCont.computeLanes2Edges();
     531         1813 :     PROGRESS_TIME_MESSAGE(before);
     532              :     //
     533         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Dividing of lanes on approached lanes"));
     534         1813 :     myNodeCont.computeLanes2Lanes();
     535         1813 :     myEdgeCont.sortOutgoingLanesConnections();
     536         1813 :     PROGRESS_TIME_MESSAGE(before);
     537              :     //
     538         3626 :     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         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing turnarounds"));
     548         3626 :     if (!oc.getBool("no-turnarounds")) {
     549         1070 :         myEdgeCont.appendTurnarounds(
     550         2140 :             oc.getBool("no-turnarounds.tls"),
     551         2140 :             oc.getBool("no-turnarounds.fringe"),
     552         2140 :             oc.getBool("no-turnarounds.except-deadend"),
     553         2140 :             oc.getBool("no-turnarounds.except-turnlane"),
     554         2140 :             oc.getBool("no-turnarounds.geometry"));
     555              :     } else {
     556         1486 :         myEdgeCont.appendTurnarounds(explicitTurnarounds, oc.getBool("no-turnarounds.tls"));
     557              :     }
     558         5384 :     if (oc.exists("railway.topology.repair.stop-turn") && oc.getBool("railway.topology.repair.stop-turn")
     559         1846 :             && myPTStopCont.getStops().size() > 0) {
     560              :         // allow direction reversal at all bidi-edges with stops
     561           25 :         myEdgeCont.appendRailwayTurnarounds(myPTStopCont);
     562              :     }
     563         1813 :     PROGRESS_TIME_MESSAGE(before);
     564              :     //
     565         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Rechecking of lane endings"));
     566         1813 :     myEdgeCont.recheckLanes();
     567         1813 :     PROGRESS_TIME_MESSAGE(before);
     568              : 
     569         1992 :     if (myNetworkHaveCrossings && !oc.getBool("no-internal-links")) {
     570         4380 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     571         4205 :             i->second->buildCrossingsAndWalkingAreas();
     572              :         }
     573              :     } else {
     574        54527 :         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        52889 :             i->second->discardWalkingareas();
     578              :         }
     579         3276 :         if (oc.getBool("no-internal-links")) {
     580        30015 :             for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     581        29399 :                 i->second->discardAllCrossings(false);
     582              :             }
     583              :         }
     584              :     }
     585              :     // join traffic lights (after building connections)
     586         3626 :     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         3626 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light control information"));
     595         1813 :     myTLLCont.setTLControllingInformation(myEdgeCont, myNodeCont);
     596         3536 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files")) {
     597           23 :         myTLLCont.setOpenDriveSignalParameters();
     598              :     }
     599         1812 :     PROGRESS_TIME_MESSAGE(before);
     600              :     //
     601         3624 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node logics"));
     602         1812 :     myNodeCont.computeLogics(myEdgeCont);
     603         1812 :     PROGRESS_TIME_MESSAGE(before);
     604              : 
     605              :     //
     606         3624 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light logics"));
     607         1812 :     std::pair<int, int> numbers = myTLLCont.computeLogics(oc);
     608         1812 :     PROGRESS_TIME_MESSAGE(before);
     609         1812 :     std::string progCount = "";
     610         1812 :     if (numbers.first != numbers.second) {
     611           27 :         progCount = "(" + toString(numbers.second) + " programs) ";
     612              :     }
     613         5436 :     WRITE_MESSAGEF(TL(" % traffic light(s) %computed."), toString(numbers.first), progCount);
     614         3559 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files") && oc.getBool("opendrive.signal-groups")) {
     615            0 :         myTLLCont.applyOpenDriveControllers(oc);
     616              :     }
     617              : 
     618       104310 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     619       102498 :         (*i).second->sortOutgoingConnectionsByIndex();
     620              :     }
     621              :     // FINISHING INNER EDGES
     622              :     std::set<NBTrafficLightDefinition*> largeNodeTLS;
     623         3624 :     if (!oc.getBool("no-internal-links")) {
     624         3588 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Building inner edges"));
     625              :         // walking areas shall only be built if crossings are wished as well
     626        28887 :         for (const auto& item : myNodeCont) {
     627        27691 :             if (item.second->buildInnerEdges() > NBTrafficLightDefinition::MIN_YELLOW_SECONDS) {
     628         4812 :                 const std::set<NBTrafficLightDefinition*>& tlDefs = item.second->getControllingTLS();
     629         4812 :                 largeNodeTLS.insert(tlDefs.begin(), tlDefs.end());
     630              :             }
     631              :         }
     632         1196 :         PROGRESS_TIME_MESSAGE(before);
     633              :     }
     634              :     // PATCH NODE SHAPES
     635         3624 :     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         2009 :     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           83 :         myEdgeCont.fixSplitCustomLength();
     650              :     }
     651              :     // recheck phases for large junctions
     652         2541 :     for (NBTrafficLightDefinition* def : largeNodeTLS) {
     653          729 :         myTLLCont.computeSingleLogic(oc, def);
     654              :     }
     655              :     // compute lane-to-lane node logics (require traffic lights and inner edges to be done)
     656         1812 :     myNodeCont.computeLogics2(myEdgeCont, oc);
     657              : 
     658              :     // remove guessed traffic lights at junctions without conflicts (requires computeLogics2)
     659         1812 :     myNodeCont.recheckGuessedTLS(myTLLCont);
     660              : 
     661              :     // compute keepClear status (requires computeLogics2)
     662         1812 :     myNodeCont.computeKeepClear();
     663              : 
     664              :     //
     665         3624 :     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         3624 :     if (lefthand != oc.getBool("flip-y-axis")) {
     673           23 :         mirrorX();
     674              :     }
     675              : 
     676         5260 :     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         1837 :     if (geoConvHelper.getConvBoundary().getZRange() > 0 && oc.getFloat("geometry.max-grade") > 0) {
     682           50 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking edge grade"));
     683              :         // user input is in %
     684           25 :         myEdgeCont.checkGrade(oc.getFloat("geometry.max-grade") / 100);
     685           25 :         PROGRESS_TIME_MESSAGE(before);
     686              :     }
     687              : 
     688              :     // find accesses for pt rail stops and add bidi-stops
     689         1812 :     if (!myPTStopCont.getStops().empty()) {
     690              :         // re-adapt stop lanes after adding special lanes and cutting edge shapes at junction
     691          158 :         myPTStopCont.assignLanes(myEdgeCont);
     692          158 :         before = SysUtils::getCurrentMillis();
     693              :         int numBidiStops = 0;
     694          316 :         if (!oc.getBool("ptstop-output.no-bidi")) {
     695          156 :             numBidiStops = myPTStopCont.generateBidiStops(myEdgeCont);
     696              :         } else {
     697            2 :             numBidiStops = myPTStopCont.countBidiStops(myEdgeCont);
     698              :         }
     699          316 :         PROGRESS_BEGIN_MESSAGE(TL("Find accesses for pt rail stops"));
     700          158 :         double maxRadius = oc.getFloat("railway.access-distance");
     701          158 :         double accessFactor = oc.getFloat("railway.access-factor");
     702          158 :         int maxCount = oc.getInt("railway.max-accesses");
     703          158 :         myPTStopCont.findAccessEdgesForRailStops(myEdgeCont, maxRadius, maxCount, accessFactor);
     704          158 :         PROGRESS_TIME_MESSAGE(before);
     705          158 :         if (numBidiStops > 0) {
     706           65 :             myPTLineCont.fixBidiStops(myEdgeCont);
     707              :         }
     708              :     }
     709         1812 :     myPTLineCont.removeInvalidEdges(myEdgeCont);
     710              :     // ensure that all turning lanes have sufficient permissions
     711         1812 :     myPTLineCont.fixPermissions();
     712         3536 :     if (oc.exists("ptline-clean-up") && oc.getBool("ptline-clean-up")) {
     713            8 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Cleaning up public transport stops that are not served by any line"));
     714            4 :         std::set<std::string> usedStops = myPTLineCont.getServedPTStops();
     715            4 :         myPTStopCont.postprocess(usedStops);
     716            4 :         PROGRESS_TIME_MESSAGE(before);
     717              :     } else {
     718         1808 :         int numDeletedStops = myPTStopCont.cleanupDeleted(myEdgeCont);
     719         1808 :         if (numDeletedStops > 0) {
     720           48 :             WRITE_WARNINGF(TL("Removed % pt stops because they could not be assigned to the network"), toString(numDeletedStops));
     721              :         }
     722              :     }
     723              : 
     724         5257 :     if (oc.exists("ignore-change-restrictions") && !oc.isDefault("ignore-change-restrictions")) {
     725            3 :         SVCPermissions ignoring = parseVehicleClasses(oc.getStringVector("ignore-change-restrictions"));
     726            3 :         myEdgeCont.updateAllChangeRestrictions(ignoring);
     727              :     }
     728              : 
     729         1812 :     NBRequest::reportWarnings();
     730              :     // report on very large networks
     731         5433 :     if (MAX2(geoConvHelper.getConvBoundary().xmax(), geoConvHelper.getConvBoundary().ymax()) > 1000000 ||
     732         1809 :             MIN2(geoConvHelper.getConvBoundary().xmin(), geoConvHelper.getConvBoundary().ymin()) < -1000000) {
     733            6 :         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"));
     734              :     }
     735              : 
     736              :     // clean up OSM processing params
     737         3536 :     if (oc.exists("osm-files") && oc.isSet("osm-files")) {
     738        34521 :         for (auto item : myEdgeCont) {
     739        34340 :             item.second->unsetParameter(NBTrafficLightDefinition::OSM_DIRECTION);
     740              :         }
     741              :     }
     742         1812 : }
     743              : 
     744              : 
     745              : void
     746         1309 : NBNetBuilder::moveToOrigin(GeoConvHelper& geoConvHelper, bool lefthand) {
     747         2618 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Moving network to origin"));
     748         1309 :     Boundary boundary = geoConvHelper.getConvBoundary();
     749         1309 :     const double x = -boundary.xmin();
     750         1309 :     const double y = -(lefthand ? boundary.ymax() : boundary.ymin());
     751              :     //if (lefthand) {
     752              :     //    y = boundary.ymax();
     753              :     //}
     754        38957 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     755        37648 :         (*i).second->reshiftPosition(x, y);
     756              :     }
     757        69589 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     758        68280 :         (*i).second->reshiftPosition(x, y);
     759              :     }
     760         1359 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     761           50 :         (*i).second->reshiftPosition(x, y);
     762              :     }
     763         3102 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     764         1793 :         stopIt.second->reshiftPosition(x, y);
     765              :     }
     766         1309 :     geoConvHelper.moveConvertedBy(x, y);
     767         1309 :     PROGRESS_TIME_MESSAGE(before);
     768         1309 : }
     769              : 
     770              : 
     771              : void
     772         1813 : NBNetBuilder::roundInputs() {
     773              :     // ensure that computed speeds (using during right-of-way computation) are the same as the written speeds
     774       104072 :     for (auto item : myEdgeCont) {
     775       102259 :         item.second->roundSpeed();
     776              :     }
     777              :     // ensure that derived junction and lane geometry computation is done with the same input
     778              :     // edge coordinates as those that will be written to the output.
     779        58705 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     780        56892 :         (*i).second->roundGeometry();
     781              :     }
     782       104072 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     783       102259 :         (*i).second->roundGeometry();
     784              :     }
     785         1813 : }
     786              : 
     787              : 
     788              : void
     789           46 : NBNetBuilder::mirrorX() {
     790              :     // mirror the network along the X-axis
     791          875 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     792          829 :         (*i).second->mirrorX();
     793              :     }
     794         1180 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     795         1134 :         (*i).second->mirrorX();
     796              :     }
     797           46 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     798            0 :         (*i).second->mirrorX();
     799              :     }
     800          105 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     801           59 :         stopIt.second->mirrorX();
     802              :     }
     803           46 : }
     804              : 
     805              : 
     806              : bool
     807       546372 : NBNetBuilder::transformCoordinate(Position& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     808       546372 :     Position orig(from);
     809              :     bool ok = true;
     810              :     if (GeoConvHelper::getNumLoaded() > 1
     811         2786 :             && GeoConvHelper::getLoaded().usingGeoProjection()
     812         2612 :             && from_srs != nullptr
     813         2612 :             && from_srs->usingGeoProjection()
     814       548984 :             && *from_srs != GeoConvHelper::getLoaded()) {
     815         2612 :         from_srs->cartesian2geo(from);
     816         2612 :         ok &= GeoConvHelper::getLoaded().x2cartesian(from, false);
     817              :     }
     818       546372 :     if (from_srs == nullptr || !GeoConvHelper::getProcessing().usingGeoProjection()) {
     819              :         // if getProcessing is not a geo-projection, assume it a cartesian transformation (i.e. shift)
     820       546257 :         ok &= GeoConvHelper::getProcessing().x2cartesian(from, includeInBoundary);
     821              : 
     822       195908 :         if (from_srs == nullptr && GeoConvHelper::getProcessing().usingGeoProjection()
     823       163222 :                 && GeoConvHelper::getNumLoaded() > 0
     824       546293 :                 && GeoConvHelper::getLoaded().usingGeoProjection()) {
     825              :             // apply geo patch to loaded geo-network (offset must match)
     826           36 :             from = from + GeoConvHelper::getLoaded().getOffset();
     827              :         }
     828              :     }
     829       546372 :     if (ok) {
     830       546372 :         const NBHeightMapper& hm = NBHeightMapper::get();
     831       546372 :         if (hm.ready()) {
     832         1532 :             if (from_srs != nullptr && from_srs->usingGeoProjection()) {
     833         1528 :                 from_srs->cartesian2geo(orig);
     834              :             }
     835         1532 :             from.setz(hm.getZ(orig));
     836              :         }
     837              :     }
     838              :     const double eps = 1e-6;
     839       546372 :     from.set(std::round(from.x() / eps) * eps, std::round(from.y() / eps) * eps, std::round(from.z() / eps) * eps);
     840       546372 :     return ok;
     841              : }
     842              : 
     843              : 
     844              : bool
     845       190779 : NBNetBuilder::transformCoordinates(PositionVector& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     846       190779 :     const double maxLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
     847       190779 :     if (maxLength > 0 && from.size() > 1) {
     848              :         // transformation to cartesian coordinates must happen before we can check segment length
     849              :         PositionVector copy = from;
     850          118 :         for (int i = 0; i < (int) from.size(); i++) {
     851           85 :             transformCoordinate(copy[i], false);
     852              :         }
     853           33 :         addGeometrySegments(from, copy, maxLength);
     854           33 :     }
     855              :     bool ok = true;
     856       662177 :     for (int i = 0; i < (int) from.size(); i++) {
     857       471398 :         ok = ok && transformCoordinate(from[i], includeInBoundary, from_srs);
     858              :     }
     859       190779 :     return ok;
     860              : }
     861              : 
     862              : 
     863              : int
     864           71 : NBNetBuilder::addGeometrySegments(PositionVector& from, const PositionVector& cartesian, const double maxLength) {
     865              :     // check lengths and insert new points where needed (in the original
     866              :     // coordinate system)
     867              :     int inserted = 0;
     868          161 :     for (int i = 0; i < (int)cartesian.size() - 1; i++) {
     869           90 :         Position start = from[i + inserted];
     870           90 :         Position end = from[i + inserted + 1];
     871           90 :         double length = cartesian[i].distanceTo(cartesian[i + 1]);
     872           90 :         const Position step = (end - start) * (maxLength / length);
     873              :         int steps = 0;
     874          312 :         while (length > maxLength) {
     875          222 :             length -= maxLength;
     876          222 :             steps++;
     877          222 :             from.insert(from.begin() + i + inserted + 1, start + (step * steps));
     878          222 :             inserted++;
     879              :         }
     880              :     }
     881           71 :     return inserted;
     882              : }
     883              : 
     884              : 
     885              : bool
     886          840 : NBNetBuilder::runningNetedit() {
     887              :     // see GNELoadThread::fillOptions
     888         1680 :     return OptionsCont::getOptions().exists("new");
     889              : }
     890              : 
     891              : 
     892              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1