LCOV - code coverage report
Current view: top level - src/netbuild - NBNetBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.7 % 518 501
Test Date: 2026-03-26 16:31:35 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-2026 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         2483 : NBNetBuilder::NBNetBuilder() :
      56         2483 :     myEdgeCont(myTypeCont),
      57         4966 :     myNetworkHaveCrossings(false) {
      58         2483 : }
      59              : 
      60              : 
      61         4966 : NBNetBuilder::~NBNetBuilder() {}
      62              : 
      63              : 
      64              : void
      65         2483 : NBNetBuilder::applyOptions(OptionsCont& oc) {
      66              :     // apply options to type control
      67         7449 :     myTypeCont.setEdgeTypeDefaults(oc.getInt("default.lanenumber"), oc.getFloat("default.lanewidth"), oc.getFloat("default.speed"), oc.getFloat("default.friction"),
      68         7449 :                                    oc.getInt("default.priority"), parseVehicleClasses(oc.getString("default.allow"), oc.getString("default.disallow")),
      69         2483 :                                    SUMOXMLDefinitions::LaneSpreadFunctions.get(oc.getString("default.spreadtype")));
      70              :     // apply options to edge control
      71         2483 :     myEdgeCont.applyOptions(oc);
      72              :     // apply options to traffic light logics control
      73         2473 :     myTLLCont.applyOptions(oc);
      74         2473 :     NBEdge::setDefaultConnectionLength(oc.getFloat("default.connection-length"));
      75         2473 : }
      76              : 
      77              : 
      78              : void
      79         2183 : NBNetBuilder::compute(OptionsCont& oc, const std::set<std::string>& explicitTurnarounds, bool mayAddOrRemove) {
      80              :     GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
      81              : 
      82         2183 :     const bool lefthand = oc.getBool("lefthand");
      83         2183 :     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         4366 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Removing self-loops"));
      90              :     int numRemovedEdges = 0;
      91         2183 :     numRemovedEdges += myNodeCont.removeSelfLoops(myDistrictCont, myEdgeCont, myTLLCont);
      92         2183 :     PROGRESS_TIME_MESSAGE(before);
      93         6461 :     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         8533 :     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         6461 :     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         4366 :     if (mayAddOrRemove && oc.getFloat("keep-lanes.min-width") > 0.) {
     128         2183 :         const int removed = myEdgeCont.removeLanesByWidth(myDistrictCont, oc.getFloat("keep-lanes.min-width"));
     129         2183 :         if (removed > 0) {
     130            0 :             numRemovedEdges += removed;
     131            0 :             WRITE_MESSAGEF(TL(" Removed % edges because of lane width."), removed);
     132              :         }
     133              :     }
     134         8555 :     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         2183 :     if (!myPTStopCont.getStops().empty()) {
     142          352 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing public transport stops"));
     143          528 :         if (!(oc.exists("ptline-output") && oc.isSet("ptline-output"))
     144          478 :                 && !oc.getBool("ptstop-output.no-bidi")) {
     145          124 :             myPTStopCont.localizePTStops(myEdgeCont);
     146              :         }
     147          176 :         myPTStopCont.assignEdgeForFloatingStops(myEdgeCont, 20);
     148          176 :         myPTStopCont.assignLanes(myEdgeCont);
     149          176 :         PROGRESS_TIME_MESSAGE(before);
     150              :     }
     151         8533 :     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         2183 :     if (numRemovedEdges > 0) {
     157           18 :         myEdgeCont.cleanupRoundabouts();
     158              :     }
     159              : 
     160         2183 :     if (!myPTLineCont.getLines().empty()) {
     161          208 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Revising public transport stops based on pt lines"));
     162          104 :         myPTLineCont.process(myEdgeCont, myPTStopCont);
     163          104 :         PROGRESS_TIME_MESSAGE(before);
     164              :     }
     165              : 
     166         2354 :     if (!myPTStopCont.getStops().empty() && !oc.getBool("ptstop-output.no-bidi")) {
     167          326 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Align pt stop id signs with corresponding edge id signs"));
     168          163 :         myPTStopCont.alignIdSigns();
     169          163 :         PROGRESS_TIME_MESSAGE(before);
     170              :     }
     171              :     // analyze and fix railway topology
     172              :     int numAddedBidi = 0;
     173         4278 :     if (oc.exists("railway.topology.all-bidi") && oc.getBool("railway.topology.all-bidi")) {
     174            9 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     175            9 :         numAddedBidi = NBRailwayTopologyAnalyzer::makeAllBidi(myEdgeCont);
     176         4260 :     } else if (oc.exists("railway.topology.repair") && oc.getBool("railway.topology.repair")) {
     177              :         // correct railway angles for angle-based connectivity heuristic
     178           80 :         myEdgeCont.checkGeometries(0, false,
     179              :                                    oc.getFloat("geometry.min-radius"), false,
     180           40 :                                    oc.getBool("geometry.min-radius.fix.railways"), true);
     181           40 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     182           40 :         numAddedBidi = NBRailwayTopologyAnalyzer::repairTopology(myEdgeCont, myPTStopCont, myPTLineCont);
     183              :     }
     184         2183 :     NBRailwaySignalGuesser::guessRailSignals(myNodeCont, myEdgeCont, myPTStopCont);
     185         2183 :     if (numAddedBidi > 0) {
     186              :         // update routes
     187           44 :         myPTLineCont.process(myEdgeCont, myPTStopCont, true);
     188              :     }
     189         4278 :     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         4364 :     } else if (oc.exists("railway.topology.extend-priority")
     193         6368 :             && (oc.getBool("railway.topology.extend-priority") || oc.getStringVector("railway.topology.ptline-priority").size() > 0)) {
     194            4 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     195            8 :         if (oc.getStringVector("railway.topology.ptline-priority").size() > 0) {
     196            1 :             SVCPermissions vClasses = parseVehicleClasses(oc.getStringVector("railway.topology.ptline-priority"));
     197            1 :             NBRailwayTopologyAnalyzer::setPTLinePriority(myEdgeCont, myPTLineCont, vClasses);
     198              :         }
     199            4 :         NBRailwayTopologyAnalyzer::extendDirectionPriority(myEdgeCont, false);
     200              :     }
     201         4278 :     if (oc.exists("railway.topology.output") && oc.isSet("railway.topology.output")) {
     202           29 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     203           29 :         NBRailwayTopologyAnalyzer::analyzeTopology(myEdgeCont);
     204              :     }
     205         4278 :     if (oc.exists("railway.geometry.straighten") && oc.getBool("railway.geometry.straighten")) {
     206            0 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false); // recompute after new edges were added
     207            0 :         NBRailwayGeometryHelper::straigthenCorrdidor(myEdgeCont, oc.getFloat("geometry.max-angle"));
     208              :     }
     209              : 
     210              : 
     211         8549 :     if (mayAddOrRemove && oc.exists("edges.join-tram-dist") && oc.getFloat("edges.join-tram-dist") >= 0) {
     212              :         // should come before joining junctions
     213           14 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining tram edges"));
     214            7 :         int numJoinedTramEdges = myEdgeCont.joinTramEdges(myDistrictCont, myPTStopCont, myPTLineCont, oc.getFloat("edges.join-tram-dist"));
     215            7 :         PROGRESS_TIME_MESSAGE(before);
     216            7 :         if (numJoinedTramEdges > 0) {
     217           14 :             WRITE_MESSAGEF(TL(" Joined % tram edges into roads."), toString(numJoinedTramEdges));
     218              :         }
     219              :     }
     220         4366 :     if (oc.getBool("junctions.join")
     221         6323 :             || (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     222         4220 :             || oc.getBool("tls.guess.joining")
     223         8231 :             || (oc.exists("tls.guess-signals") && oc.getBool("tls.guess-signals"))) {
     224              :         // preliminary geometry computations to determine the length of edges
     225              :         // This depends on turning directions and sorting of edge list
     226              :         // in case junctions are joined geometry computations have to be repeated
     227              :         // preliminary roundabout computations to avoid damaging roundabouts via junctions.join or ramps.guess
     228          156 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     229          156 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     230          156 :         myEdgeCont.computeLaneShapes();
     231          156 :         myNodeCont.computeNodeShapes();
     232          156 :         myEdgeCont.computeEdgeShapes();
     233          312 :         if (oc.getBool("roundabouts.guess")) {
     234          156 :             myEdgeCont.guessRoundabouts();
     235              :         }
     236          156 :         const std::set<EdgeSet>& roundabouts = myEdgeCont.getRoundabouts();
     237          156 :         for (std::set<EdgeSet>::const_iterator it_round = roundabouts.begin();
     238          170 :                 it_round != roundabouts.end(); ++it_round) {
     239              :             std::vector<std::string> nodeIDs;
     240          111 :             for (EdgeSet::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
     241           97 :                 nodeIDs.push_back((*it_edge)->getToNode()->getID());
     242              :             }
     243           14 :             myNodeCont.addJoinExclusion(nodeIDs);
     244           14 :         }
     245          156 :         NBNodeTypeComputer::validateRailCrossings(myNodeCont, myTLLCont);
     246         4102 :     } else if ((myEdgeCont.hasGuessedRoundabouts() || oc.getBool("crossings.guess")) && oc.getBool("roundabouts.guess")) {
     247           48 :         myEdgeCont.guessRoundabouts();
     248           48 :         myEdgeCont.markRoundabouts();
     249              :     }
     250              :     // join junctions (may create new "geometry"-nodes so it needs to come before removing these
     251         6461 :     if (mayAddOrRemove && oc.exists("junctions.join-exclude") && oc.isSet("junctions.join-exclude")) {
     252            2 :         myNodeCont.addJoinExclusion(oc.getStringVector("junctions.join-exclude"));
     253              :     }
     254         2183 :     int numJoined = myNodeCont.joinLoadedClusters(myDistrictCont, myEdgeCont, myTLLCont);
     255         4366 :     if (mayAddOrRemove && oc.getBool("junctions.join")) {
     256          226 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junction clusters"));
     257          113 :         numJoined += myNodeCont.joinJunctions(oc.getFloat("junctions.join-dist"), myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont);
     258          113 :         PROGRESS_TIME_MESSAGE(before);
     259              :     }
     260         2183 :     if (numJoined > 0) {
     261          200 :         WRITE_MESSAGEF(TL(" Joined % junction cluster(s)."), toString(numJoined));
     262              :     }
     263         6538 :     if (mayAddOrRemove && oc.getFloat("junctions.join-same") >= 0) {
     264           22 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining junctions with similar coordinates"));
     265           11 :         int numJoined2 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont, oc.getFloat("junctions.join-same"));
     266           11 :         PROGRESS_TIME_MESSAGE(before);
     267           11 :         if (numJoined2 > 0) {
     268            6 :             WRITE_MESSAGEF(TL(" Joined % junctions."), toString(numJoined2));
     269              :         }
     270              :     }
     271              :     //
     272         6461 :     if (mayAddOrRemove && oc.exists("join-lanes") && oc.getBool("join-lanes")) {
     273            2 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining lanes"));
     274            1 :         const int num = myEdgeCont.joinLanes(SVC_IGNORING) + myEdgeCont.joinLanes(SVC_PEDESTRIAN);
     275            1 :         PROGRESS_TIME_MESSAGE(before);
     276            2 :         WRITE_MESSAGEF(TL("   Joined lanes on % edges."), toString(num));
     277              :     }
     278              :     //
     279         2183 :     if (mayAddOrRemove) {
     280         4366 :         const bool removeGeometryNodes = oc.exists("geometry.remove") && oc.getBool("geometry.remove");
     281         8621 :         before = PROGRESS_BEGIN_TIME_MESSAGE("Removing empty nodes" + std::string(removeGeometryNodes ? " and geometry nodes" : ""));
     282              :         // removeUnwishedNodes needs turnDirections. @todo: try to call this less often
     283         2183 :         NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     284         2183 :         const int numRemoved = myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, removeGeometryNodes);
     285         2183 :         PROGRESS_TIME_MESSAGE(before);
     286         4366 :         WRITE_MESSAGEF(TL("   % nodes removed."), toString(numRemoved));
     287              :     }
     288              : 
     289              :     // MOVE TO ORIGIN
     290              :     // compute new boundary after network modifications have taken place
     291         2183 :     Boundary boundary;
     292        61729 :     for (std::map<std::string, NBNode*>::const_iterator it = myNodeCont.begin(); it != myNodeCont.end(); ++it) {
     293        59546 :         boundary.add(it->second->getPosition());
     294              :     }
     295       108568 :     for (std::map<std::string, NBEdge*>::const_iterator it = myEdgeCont.begin(); it != myEdgeCont.end(); ++it) {
     296       106385 :         boundary.add(it->second->getGeometry().getBoxBoundary());
     297              :     }
     298              :     geoConvHelper.setConvBoundary(boundary);
     299              : 
     300         5483 :     if (!oc.getBool("offset.disable-normalization") && oc.isDefault("offset.x") && oc.isDefault("offset.y")) {
     301         1648 :         moveToOrigin(geoConvHelper, lefthand);
     302              :     }
     303         2183 :     roundInputs();
     304         2183 :     geoConvHelper.computeFinal(lefthand); // information needed for location element fixed at this point
     305              : 
     306              :     // reset shapes and angles for stable re-computation
     307         2183 :     if (myNodeCont.resetNodeShapes()) {
     308          156 :         myEdgeCont.computeAngles();
     309              :     }
     310              : 
     311         6370 :     if (oc.exists("geometry.min-dist") && !oc.isDefault("geometry.min-dist")) {
     312            6 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Reducing geometries"));
     313            3 :         myEdgeCont.reduceGeometries(oc.getFloat("geometry.min-dist"));
     314            3 :         PROGRESS_TIME_MESSAGE(before);
     315              :     }
     316              :     // @note: removing geometry can create similar edges so joinSimilarEdges  must come afterwards
     317              :     // @note: likewise splitting can destroy similarities so joinSimilarEdges must come before
     318         4366 :     if (mayAddOrRemove && oc.getBool("edges.join")) {
     319           38 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining similar edges"));
     320           19 :         const bool removeDuplicates = oc.getFloat("junctions.join-same") >= 0;
     321           19 :         myNodeCont.joinSimilarEdges(myDistrictCont, myEdgeCont, myTLLCont, removeDuplicates);
     322              :         // now we may have new chances to remove geometry if wished
     323           38 :         if (oc.exists("geometry.remove") && oc.getBool("geometry.remove")) {
     324            1 :             myNodeCont.removeUnwishedNodes(myDistrictCont, myEdgeCont, myTLLCont, myPTStopCont, myPTLineCont, myParkingCont, true);
     325              :         }
     326           19 :         PROGRESS_TIME_MESSAGE(before);
     327              :     }
     328         4366 :     if (oc.getBool("opposites.guess")) {
     329           32 :         PROGRESS_BEGIN_MESSAGE(TL("guessing opposite direction edges"));
     330           16 :         myEdgeCont.guessOpposites();
     331           16 :         PROGRESS_DONE_MESSAGE();
     332              :     }
     333              :     //
     334         6549 :     if (mayAddOrRemove && oc.exists("geometry.split") && oc.getBool("geometry.split")) {
     335            8 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Splitting geometry edges"));
     336            4 :         myEdgeCont.splitGeometry(myDistrictCont, myNodeCont);
     337              :         // newly split junctions might also be joinable
     338            4 :         PROGRESS_TIME_MESSAGE(before);
     339            8 :         if (oc.getFloat("junctions.join-same") >= 0) {
     340            2 :             int numJoined3 = myNodeCont.joinSameJunctions(myDistrictCont, myEdgeCont, myTLLCont, oc.getFloat("junctions.join-same"));
     341            2 :             if (numJoined3 > 0) {
     342            4 :                 WRITE_MESSAGEF(TL(" Joined % junctions after splitting geometry."), toString(numJoined3));
     343              :             }
     344              :         }
     345              :     }
     346              :     // turning direction
     347         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing turning directions"));
     348         2183 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont);
     349         2183 :     PROGRESS_TIME_MESSAGE(before);
     350              :     // correct edge geometries to avoid overlap
     351         4278 :     if (oc.exists("geometry.avoid-overlap") && oc.getBool("geometry.avoid-overlap")) {
     352         1590 :         myNodeCont.avoidOverlap();
     353              :     }
     354              : 
     355              :     // GUESS TLS POSITIONS
     356         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Assigning nodes to traffic lights"));
     357         4366 :     if (oc.isSet("tls.set")) {
     358            8 :         std::vector<std::string> tlControlledNodes = oc.getStringVector("tls.set");
     359           16 :         TrafficLightType type = SUMOXMLDefinitions::TrafficLightTypes.get(oc.getString("tls.default-type"));
     360           16 :         for (std::vector<std::string>::const_iterator i = tlControlledNodes.begin(); i != tlControlledNodes.end(); ++i) {
     361            8 :             NBNode* node = myNodeCont.retrieve(*i);
     362            8 :             if (node == nullptr) {
     363            0 :                 WRITE_WARNING("Building a tl-logic for junction '" + *i + "' is not possible." + "\n The junction '" + *i + "' is not known.");
     364              :             } else {
     365           16 :                 myNodeCont.setAsTLControlled(node, myTLLCont, type);
     366              :             }
     367              :         }
     368            8 :     }
     369         2183 :     myNodeCont.guessTLs(oc, myTLLCont);
     370         2183 :     PROGRESS_TIME_MESSAGE(before);
     371              : 
     372              :     // guess ramps (after guessing tls because ramps should not be build at traffic lights)
     373         4366 :     const bool modifyRamps = mayAddOrRemove && (
     374         6461 :                                  (oc.exists("ramps.guess") && oc.getBool("ramps.guess"))
     375         6359 :                                  || (oc.exists("ramps.set") && oc.isSet("ramps.set")));
     376         6343 :     if (modifyRamps || (oc.exists("ramps.guess-acceleration-lanes") && oc.getBool("ramps.guess-acceleration-lanes"))) {
     377         2095 :         before = SysUtils::getCurrentMillis();
     378         2095 :         if (modifyRamps) {
     379          177 :             PROGRESS_BEGIN_MESSAGE(TL("Guessing and setting on-/off-ramps"));
     380              :         }
     381         2095 :         NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     382         2095 :         NBRampsComputer rc;
     383         2095 :         rc.computeRamps(*this, oc, mayAddOrRemove);
     384              : 
     385         2095 :         if (modifyRamps) {
     386           59 :             PROGRESS_TIME_MESSAGE(before);
     387              :         }
     388              :     }
     389              :     // guess bike lanes
     390         6543 :     if (mayAddOrRemove && ((oc.getBool("bikelanes.guess") || oc.getBool("bikelanes.guess.from-permissions")))) {
     391           21 :         const int bikelanes = myEdgeCont.guessSpecialLanes(SVC_BICYCLE, oc.getFloat("default.bikelane-width"),
     392              :                               oc.getFloat("bikelanes.guess.min-speed"),
     393              :                               oc.getFloat("bikelanes.guess.max-speed"),
     394           14 :                               oc.getBool("bikelanes.guess.from-permissions"),
     395              :                               "bikelanes.guess.exclude",
     396            7 :                               myTLLCont);
     397           14 :         WRITE_MESSAGEF(TL("Guessed % bike lanes."), toString(bikelanes));
     398              :     }
     399              : 
     400              :     // guess sidewalks
     401         6377 :     if (mayAddOrRemove && ((oc.getBool("sidewalks.guess") || oc.getBool("sidewalks.guess.from-permissions")))) {
     402          522 :         const int sidewalks = myEdgeCont.guessSpecialLanes(SVC_PEDESTRIAN, oc.getFloat("default.sidewalk-width"),
     403              :                               oc.getFloat("sidewalks.guess.min-speed"),
     404              :                               oc.getFloat("sidewalks.guess.max-speed"),
     405          348 :                               oc.getBool("sidewalks.guess.from-permissions"),
     406              :                               "sidewalks.guess.exclude",
     407          174 :                               myTLLCont);
     408          348 :         WRITE_MESSAGEF(TL("Guessed % sidewalks."), toString(sidewalks));
     409              :     }
     410              :     // check whether any not previously setable connections may be set now
     411         2183 :     myEdgeCont.recheckPostProcessConnections();
     412              : 
     413              :     // remap ids if wished
     414         2183 :     if (mayAddOrRemove) {
     415         2183 :         const bool numericalIDs = oc.getBool("numerical-ids");
     416         2183 :         const bool reservedIDs = oc.isSet("reserved-ids");
     417         2183 :         const bool keptIDs = oc.isSet("kept-ids");
     418         2183 :         int numChangedEdges = myEdgeCont.remapIDs(numericalIDs, reservedIDs, keptIDs, oc.getString("prefix.edge"), myPTStopCont);
     419         2183 :         int numChangedNodes = myNodeCont.remapIDs(numericalIDs, reservedIDs, keptIDs, oc.getString("prefix.junction"), myTLLCont);
     420         2183 :         if (numChangedEdges + numChangedNodes > 0) {
     421           88 :             WRITE_MESSAGEF(TL("Remapped % edge IDs and % node IDs."), toString(numChangedEdges), toString(numChangedNodes));
     422              :         }
     423              :     }
     424              : 
     425              :     //
     426         4366 :     if (oc.exists("geometry.max-angle")) {
     427         4190 :         myEdgeCont.checkGeometries(
     428         4190 :             DEG2RAD(oc.getFloat("geometry.max-angle")),
     429         4190 :             oc.getBool("geometry.max-angle.fix"),
     430              :             oc.getFloat("geometry.min-radius"),
     431         4190 :             oc.getBool("geometry.min-radius.fix"),
     432         4190 :             oc.getBool("geometry.min-radius.fix.railways"));
     433              :     }
     434              : 
     435              :     // GEOMETRY COMPUTATION
     436              :     //
     437         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Sorting nodes' edges"));
     438         2183 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont);
     439         2183 :     PROGRESS_TIME_MESSAGE(before);
     440         2183 :     myEdgeCont.computeLaneShapes();
     441              :     //
     442         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node shapes"));
     443         4366 :     if (oc.exists("geometry.junction-mismatch-threshold")) {
     444         4190 :         myNodeCont.computeNodeShapes(oc.getFloat("geometry.junction-mismatch-threshold"));
     445              :     } else {
     446           88 :         myNodeCont.computeNodeShapes();
     447              :     }
     448         2183 :     PROGRESS_TIME_MESSAGE(before);
     449              :     //
     450         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing edge shapes"));
     451         3839 :     myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
     452         2183 :     PROGRESS_TIME_MESSAGE(before);
     453              :     // resort edges based on the node and edge shapes
     454         2183 :     NBNodesEdgesSorter::sortNodesEdges(myNodeCont, true);
     455         2183 :     NBTurningDirectionsComputer::computeTurnDirections(myNodeCont, false);
     456              : 
     457              :     // APPLY SPEED MODIFICATIONS
     458         4366 :     if (oc.exists("speed.offset")) {
     459         2095 :         const double speedOffset = oc.getFloat("speed.offset");
     460         2095 :         const double speedFactor = oc.getFloat("speed.factor");
     461         2095 :         const double speedMin = oc.getFloat("speed.minimum");
     462         2095 :         if (speedOffset != 0 || speedFactor != 1 || speedMin > 0) {
     463            6 :             before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Applying speed modifications"));
     464            7 :             for (const auto& it : myEdgeCont) {
     465            5 :                 NBEdge* const e = it.second;
     466           10 :                 for (int i = 0; i < e->getNumLanes(); i++) {
     467            6 :                     e->setSpeed(i, MAX2(e->getLaneSpeed(i) * speedFactor + speedOffset, speedMin));
     468              :                 }
     469              :             }
     470            2 :             PROGRESS_TIME_MESSAGE(before);
     471              :         }
     472              :     }
     473              : 
     474              :     // CONNECTIONS COMPUTATION
     475              :     //
     476         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node types"));
     477         2183 :     NBNode::initRailSignalClasses(myNodeCont);
     478         2183 :     NBNodeTypeComputer::computeNodeTypes(myNodeCont, myTLLCont);
     479         2183 :     PROGRESS_TIME_MESSAGE(before);
     480              :     //
     481         2183 :     myNetworkHaveCrossings = oc.getBool("walkingareas");
     482         4366 :     if (mayAddOrRemove && oc.getBool("crossings.guess")) {
     483           58 :         myNetworkHaveCrossings = true;
     484           58 :         int crossings = 0;
     485         3446 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     486         3388 :             crossings += (*i).second->guessCrossings();
     487              :         }
     488          116 :         WRITE_MESSAGEF(TL("Guessed % pedestrian crossings."), toString(crossings));
     489              :     }
     490         2183 :     if (!myNetworkHaveCrossings) {
     491              :         bool haveValidCrossings = false;
     492              :         // recheck whether we had crossings in the input
     493        57710 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     494        55705 :             if (i->second->getCrossings().size() > 0) {
     495          108 :                 myNetworkHaveCrossings = true;
     496              :                 haveValidCrossings = true;
     497          108 :                 break;
     498        55597 :             } else if (i->second->getCrossingsIncludingInvalid().size() > 0) {
     499            0 :                 myNetworkHaveCrossings = true;
     500              :             }
     501              :         }
     502         2113 :         if (myNetworkHaveCrossings && !haveValidCrossings) {
     503              :             // initial crossings removed or invalidated, keep walkingareas
     504            0 :             oc.resetWritable();
     505            0 :             oc.set("walkingareas", "true");
     506              :         }
     507              :     }
     508              : 
     509         2183 :     if (!mayAddOrRemove && myNetworkHaveCrossings) {
     510              :         // crossings added via netedit
     511            0 :         oc.resetWritable();
     512            0 :         oc.set("no-internal-links", "false");
     513              :     }
     514              : 
     515              :     //
     516         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing priorities"));
     517         2183 :     NBEdgePriorityComputer::computeEdgePriorities(myNodeCont);
     518         2183 :     PROGRESS_TIME_MESSAGE(before);
     519              :     //
     520         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approached edges"));
     521         2183 :     myEdgeCont.computeEdge2Edges(oc.getBool("no-left-connections"));
     522         2183 :     PROGRESS_TIME_MESSAGE(before);
     523              :     //
     524         4366 :     if (oc.getBool("roundabouts.guess")) {
     525         4304 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing and setting roundabouts"));
     526         2152 :         const int numGuessed = myEdgeCont.guessRoundabouts();
     527         2152 :         if (numGuessed > 0) {
     528           30 :             WRITE_MESSAGEF(TL(" Guessed % roundabout(s)."), toString(numGuessed));
     529              :         }
     530         2152 :         PROGRESS_TIME_MESSAGE(before);
     531              :     }
     532         2183 :     myEdgeCont.markRoundabouts();
     533              :     //
     534         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing approaching lanes"));
     535         2183 :     myEdgeCont.computeLanes2Edges();
     536         2183 :     PROGRESS_TIME_MESSAGE(before);
     537              :     //
     538         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Dividing of lanes on approached lanes"));
     539         2183 :     myNodeCont.computeLanes2Lanes();
     540         2183 :     myEdgeCont.sortOutgoingLanesConnections();
     541         2183 :     PROGRESS_TIME_MESSAGE(before);
     542              :     //
     543         4366 :     if (oc.getBool("fringe.guess")) {
     544            4 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Guessing Network fringe"));
     545            2 :         const int numGuessed = myNodeCont.guessFringe();
     546            2 :         if (numGuessed > 0) {
     547            4 :             WRITE_MESSAGEF(TL(" Guessed % fringe nodes."), toString(numGuessed));
     548              :         }
     549            2 :         PROGRESS_TIME_MESSAGE(before);
     550              :     }
     551              :     //
     552         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Processing turnarounds"));
     553         4366 :     if (!oc.getBool("no-turnarounds")) {
     554         1410 :         myEdgeCont.appendTurnarounds(
     555         2820 :             oc.getBool("no-turnarounds.tls"),
     556         2820 :             oc.getBool("no-turnarounds.fringe"),
     557         2820 :             oc.getBool("no-turnarounds.except-deadend"),
     558         2820 :             oc.getBool("no-turnarounds.except-turnlane"),
     559         2820 :             oc.getBool("no-turnarounds.geometry"));
     560              :     } else {
     561         1546 :         myEdgeCont.appendTurnarounds(explicitTurnarounds, oc.getBool("no-turnarounds.tls"));
     562              :     }
     563         6498 :     if (oc.exists("railway.topology.repair.stop-turn") && oc.getBool("railway.topology.repair.stop-turn")
     564         2220 :             && myPTStopCont.getStops().size() > 0) {
     565              :         // allow direction reversal at all bidi-edges with stops
     566           29 :         myEdgeCont.appendRailwayTurnarounds(myPTStopCont);
     567              :     }
     568         2183 :     PROGRESS_TIME_MESSAGE(before);
     569              :     //
     570         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Rechecking of lane endings"));
     571         2183 :     myEdgeCont.recheckLanes();
     572         2183 :     PROGRESS_TIME_MESSAGE(before);
     573              : 
     574         2363 :     if (myNetworkHaveCrossings && !oc.getBool("no-internal-links")) {
     575         4387 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     576         4211 :             i->second->buildCrossingsAndWalkingAreas();
     577              :         }
     578              :     } else {
     579        57544 :         for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     580              :             // needed by netedit if the last crossings was deleted from the network
     581              :             // and walkingareas have been invalidated since the last call to compute()
     582        55537 :             i->second->discardWalkingareas();
     583              :         }
     584         4014 :         if (oc.getBool("no-internal-links")) {
     585        31903 :             for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     586        31262 :                 i->second->discardAllCrossings(false);
     587              :             }
     588              :         }
     589              :     }
     590              :     // join traffic lights (after building connections)
     591         4366 :     if (oc.getBool("tls.join")) {
     592           72 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Joining traffic light nodes"));
     593           36 :         myNodeCont.joinTLS(myTLLCont, oc.getFloat("tls.join-dist"));
     594           36 :         PROGRESS_TIME_MESSAGE(before);
     595              :     }
     596              : 
     597              :     // COMPUTING RIGHT-OF-WAY AND TRAFFIC LIGHT PROGRAMS
     598              :     //
     599         4366 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light control information"));
     600         2183 :     myTLLCont.setTLControllingInformation(myEdgeCont, myNodeCont);
     601         4276 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files")) {
     602           23 :         myTLLCont.setOpenDriveSignalParameters();
     603              :     }
     604         2182 :     PROGRESS_TIME_MESSAGE(before);
     605              :     //
     606         4364 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing node logics"));
     607         2182 :     myNodeCont.computeLogics(myEdgeCont);
     608         2182 :     PROGRESS_TIME_MESSAGE(before);
     609              : 
     610              :     //
     611         4364 :     before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Computing traffic light logics"));
     612         2182 :     std::pair<int, int> numbers = myTLLCont.computeLogics(oc);
     613         2182 :     PROGRESS_TIME_MESSAGE(before);
     614         2182 :     std::string progCount = "";
     615         2182 :     if (numbers.first != numbers.second) {
     616           27 :         progCount = "(" + toString(numbers.second) + " programs) ";
     617              :     }
     618         6546 :     WRITE_MESSAGEF(TL(" % traffic light(s) %computed."), toString(numbers.first), progCount);
     619         4299 :     if (oc.exists("opendrive-files") && oc.isSet("opendrive-files") && oc.getBool("opendrive.signal-groups")) {
     620            0 :         myTLLCont.applyOpenDriveControllers(oc);
     621              :     }
     622              : 
     623       108806 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     624       106624 :         (*i).second->sortOutgoingConnectionsByIndex();
     625              :     }
     626              :     // FINISHING INNER EDGES
     627              :     std::set<NBTrafficLightDefinition*> largeNodeTLS;
     628         4364 :     if (!oc.getBool("no-internal-links")) {
     629         4623 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Building inner edges"));
     630              :         // walking areas shall only be built if crossings are wished as well
     631        30023 :         for (const auto& item : myNodeCont) {
     632        28482 :             if (item.second->buildInnerEdges() > NBTrafficLightDefinition::MIN_YELLOW_SECONDS) {
     633         4808 :                 const std::set<NBTrafficLightDefinition*>& tlDefs = item.second->getControllingTLS();
     634         4808 :                 largeNodeTLS.insert(tlDefs.begin(), tlDefs.end());
     635              :             }
     636              :         }
     637         1541 :         PROGRESS_TIME_MESSAGE(before);
     638              :     }
     639              :     // PATCH NODE SHAPES
     640         4364 :     if (oc.getFloat("junctions.scurve-stretch") > 0) {
     641              :         // @note: nodes have collected correction hints in buildInnerEdges()
     642            4 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("stretching junctions to smooth geometries"));
     643            2 :         myEdgeCont.computeLaneShapes();
     644            2 :         myNodeCont.computeNodeShapes();
     645            3 :         myEdgeCont.computeEdgeShapes(oc.getBool("geometry.max-grade.fix") ? oc.getFloat("geometry.max-grade") / 100 : -1);
     646           15 :         for (const auto& item : myNodeCont) {
     647           13 :             item.second->buildInnerEdges();
     648              :         }
     649            2 :         PROGRESS_TIME_MESSAGE(before);
     650              :     }
     651         2384 :     if (myEdgeCont.getNumEdgeSplits() > 0 && !oc.getBool("no-internal-links")) {
     652              :         // edges with custom lengths were split, this has to take into account
     653              :         // internal edge lengths (after geometry computation)
     654           86 :         myEdgeCont.fixSplitCustomLength();
     655              :     }
     656              :     // recheck phases for large junctions
     657         2914 :     for (NBTrafficLightDefinition* def : largeNodeTLS) {
     658          732 :         myTLLCont.computeSingleLogic(oc, def);
     659              :     }
     660              :     // compute lane-to-lane node logics (require traffic lights and inner edges to be done)
     661         2182 :     myNodeCont.computeLogics2(myEdgeCont, oc);
     662              : 
     663              :     // remove guessed traffic lights at junctions without conflicts (requires computeLogics2)
     664         2182 :     myNodeCont.recheckGuessedTLS(myTLLCont);
     665              : 
     666              :     // compute keepClear status (requires computeLogics2)
     667         2182 :     myNodeCont.computeKeepClear();
     668              : 
     669              :     //
     670         4364 :     if (oc.isSet("street-sign-output")) {
     671            2 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Generating street signs"));
     672            1 :         myEdgeCont.generateStreetSigns();
     673            1 :         PROGRESS_TIME_MESSAGE(before);
     674              :     }
     675              : 
     676              : 
     677         4364 :     if (lefthand != oc.getBool("flip-y-axis")) {
     678           23 :         mirrorX();
     679              :     }
     680              : 
     681         6370 :     if (oc.exists("geometry.check-overlap")  && oc.getFloat("geometry.check-overlap") > 0) {
     682            0 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking overlapping edges"));
     683            0 :         myEdgeCont.checkOverlap(oc.getFloat("geometry.check-overlap"), oc.getFloat("geometry.check-overlap.vertical-threshold"));
     684            0 :         PROGRESS_TIME_MESSAGE(before);
     685              :     }
     686         2207 :     if (geoConvHelper.getConvBoundary().getZRange() > 0 && oc.getFloat("geometry.max-grade") > 0) {
     687           50 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Checking edge grade"));
     688              :         // user input is in %
     689           25 :         myEdgeCont.checkGrade(oc.getFloat("geometry.max-grade") / 100);
     690           25 :         PROGRESS_TIME_MESSAGE(before);
     691              :     }
     692              : 
     693              :     // find accesses for pt rail stops and add bidi-stops
     694         2182 :     if (!myPTStopCont.getStops().empty()) {
     695              :         // re-adapt stop lanes after adding special lanes and cutting edge shapes at junction
     696          167 :         myPTStopCont.assignLanes(myEdgeCont);
     697          167 :         before = SysUtils::getCurrentMillis();
     698              :         int numBidiStops = 0;
     699          334 :         if (!oc.getBool("ptstop-output.no-bidi")) {
     700          163 :             numBidiStops = myPTStopCont.generateBidiStops(myEdgeCont);
     701              :         } else {
     702            4 :             numBidiStops = myPTStopCont.countBidiStops(myEdgeCont);
     703              :         }
     704          334 :         PROGRESS_BEGIN_MESSAGE(TL("Find accesses for pt rail stops"));
     705          167 :         double maxRadius = oc.getFloat("railway.access-distance");
     706          167 :         double accessFactor = oc.getFloat("railway.access-factor");
     707          167 :         int maxCount = oc.getInt("railway.max-accesses");
     708          167 :         myPTStopCont.findAccessEdgesForRailStops(myEdgeCont, maxRadius, maxCount, accessFactor);
     709          167 :         PROGRESS_TIME_MESSAGE(before);
     710          167 :         if (numBidiStops > 0) {
     711           77 :             myPTLineCont.fixBidiStops(myEdgeCont);
     712              :         }
     713              :     }
     714         2182 :     myPTLineCont.removeInvalidEdges(myEdgeCont);
     715              :     // ensure that all turning lanes have sufficient permissions
     716         2182 :     myPTLineCont.fixPermissions();
     717         4276 :     if (oc.exists("ptline-clean-up") && oc.getBool("ptline-clean-up")) {
     718            8 :         before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Cleaning up public transport stops that are not served by any line"));
     719            4 :         std::set<std::string> usedStops = myPTLineCont.getServedPTStops();
     720            4 :         myPTStopCont.postprocess(usedStops);
     721            4 :         PROGRESS_TIME_MESSAGE(before);
     722              :     } else {
     723         2178 :         int numDeletedStops = myPTStopCont.cleanupDeleted(myEdgeCont);
     724         2178 :         if (numDeletedStops > 0) {
     725           48 :             WRITE_WARNINGF(TL("Removed % pt stops because they could not be assigned to the network"), toString(numDeletedStops));
     726              :         }
     727              :     }
     728              : 
     729         6367 :     if (oc.exists("ignore-change-restrictions") && !oc.isDefault("ignore-change-restrictions")) {
     730            3 :         SVCPermissions ignoring = parseVehicleClasses(oc.getStringVector("ignore-change-restrictions"));
     731            3 :         myEdgeCont.updateAllChangeRestrictions(ignoring);
     732              :     }
     733              : 
     734         2182 :     NBRequest::reportWarnings();
     735              :     // report on very large networks
     736         6543 :     if (MAX2(geoConvHelper.getConvBoundary().xmax(), geoConvHelper.getConvBoundary().ymax()) > 1000000 ||
     737         2179 :             MIN2(geoConvHelper.getConvBoundary().xmin(), geoConvHelper.getConvBoundary().ymin()) < -1000000) {
     738            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"));
     739              :     }
     740              : 
     741              :     // clean up OSM processing params
     742         4276 :     if (oc.exists("osm-files") && oc.isSet("osm-files")) {
     743        35534 :         for (auto item : myEdgeCont) {
     744        35024 :             item.second->unsetParameter(NBTrafficLightDefinition::OSM_DIRECTION);
     745              :         }
     746              :     }
     747         2182 : }
     748              : 
     749              : 
     750              : void
     751         1648 : NBNetBuilder::moveToOrigin(GeoConvHelper& geoConvHelper, bool lefthand) {
     752         3296 :     long before = PROGRESS_BEGIN_TIME_MESSAGE(TL("Moving network to origin"));
     753         1648 :     Boundary boundary = geoConvHelper.getConvBoundary();
     754         1648 :     const double x = -boundary.xmin();
     755         1648 :     const double y = -(lefthand ? boundary.ymax() : boundary.ymin());
     756              :     //if (lefthand) {
     757              :     //    y = boundary.ymax();
     758              :     //}
     759        40091 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     760        38443 :         (*i).second->reshiftPosition(x, y);
     761              :     }
     762        70676 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     763        69028 :         (*i).second->reshiftPosition(x, y);
     764              :     }
     765         1719 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     766           71 :         (*i).second->reshiftPosition(x, y);
     767              :     }
     768         3511 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     769         1863 :         stopIt.second->reshiftPosition(x, y);
     770              :     }
     771         1648 :     geoConvHelper.moveConvertedBy(x, y);
     772         1648 :     PROGRESS_TIME_MESSAGE(before);
     773         1648 : }
     774              : 
     775              : 
     776              : void
     777         2183 : NBNetBuilder::roundInputs() {
     778              :     // ensure that computed speeds (using during right-of-way computation) are the same as the written speeds
     779       108568 :     for (auto item : myEdgeCont) {
     780       106385 :         item.second->roundSpeed();
     781              :     }
     782              :     // ensure that derived junction and lane geometry computation is done with the same input
     783              :     // edge coordinates as those that will be written to the output.
     784        61729 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     785        59546 :         (*i).second->roundGeometry();
     786              :     }
     787       108568 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     788       106385 :         (*i).second->roundGeometry();
     789              :     }
     790         2183 : }
     791              : 
     792              : 
     793              : void
     794           46 : NBNetBuilder::mirrorX() {
     795              :     // mirror the network along the X-axis
     796          875 :     for (std::map<std::string, NBNode*>::const_iterator i = myNodeCont.begin(); i != myNodeCont.end(); ++i) {
     797          829 :         (*i).second->mirrorX();
     798              :     }
     799         1180 :     for (std::map<std::string, NBEdge*>::const_iterator i = myEdgeCont.begin(); i != myEdgeCont.end(); ++i) {
     800         1134 :         (*i).second->mirrorX();
     801              :     }
     802           46 :     for (std::map<std::string, NBDistrict*>::const_iterator i = myDistrictCont.begin(); i != myDistrictCont.end(); ++i) {
     803            0 :         (*i).second->mirrorX();
     804              :     }
     805          105 :     for (const auto& stopIt : myPTStopCont.getStops()) {
     806           59 :         stopIt.second->mirrorX();
     807              :     }
     808           46 : }
     809              : 
     810              : 
     811              : bool
     812       593681 : NBNetBuilder::transformCoordinate(Position& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     813       593681 :     Position orig(from);
     814              :     bool ok = true;
     815              :     if (GeoConvHelper::getNumLoaded() > 1
     816         2786 :             && GeoConvHelper::getLoaded().usingGeoProjection()
     817         2612 :             && from_srs != nullptr
     818         2612 :             && from_srs->usingGeoProjection()
     819       596293 :             && *from_srs != GeoConvHelper::getLoaded()) {
     820         2612 :         from_srs->cartesian2geo(from);
     821         2612 :         ok &= GeoConvHelper::getLoaded().x2cartesian(from, false);
     822              :     }
     823       593681 :     if (from_srs == nullptr || !GeoConvHelper::getProcessing().usingGeoProjection()) {
     824              :         // if getProcessing is not a geo-projection, assume it a cartesian transformation (i.e. shift)
     825       593566 :         ok &= GeoConvHelper::getProcessing().x2cartesian(from, includeInBoundary);
     826              : 
     827       198619 :         if (from_srs == nullptr && GeoConvHelper::getProcessing().usingGeoProjection()
     828       165822 :                 && GeoConvHelper::getNumLoaded() > 0
     829       593602 :                 && GeoConvHelper::getLoaded().usingGeoProjection()) {
     830              :             // apply geo patch to loaded geo-network (offset must match)
     831           36 :             from = from + GeoConvHelper::getLoaded().getOffset();
     832              :         }
     833              :     }
     834       593681 :     if (ok) {
     835       593681 :         const NBHeightMapper& hm = NBHeightMapper::get();
     836       593681 :         if (hm.ready()) {
     837         1532 :             if (from_srs != nullptr && from_srs->usingGeoProjection()) {
     838         1528 :                 from_srs->cartesian2geo(orig);
     839              :             }
     840         1532 :             from.setz(hm.getZ(orig) + GeoConvHelper::getProcessing().getOffset().z());
     841              :         }
     842              :     }
     843              :     const double eps = 1e-6;
     844       593681 :     from.set(std::round(from.x() / eps) * eps, std::round(from.y() / eps) * eps, std::round(from.z() / eps) * eps);
     845       593681 :     return ok;
     846              : }
     847              : 
     848              : 
     849              : bool
     850       204569 : NBNetBuilder::transformCoordinates(PositionVector& from, bool includeInBoundary, GeoConvHelper* from_srs) {
     851       204569 :     const double maxLength = OptionsCont::getOptions().getFloat("geometry.max-segment-length");
     852       204569 :     if (maxLength > 0 && from.size() > 1) {
     853              :         // transformation to cartesian coordinates must happen before we can check segment length
     854              :         PositionVector copy = from;
     855          118 :         for (int i = 0; i < (int) from.size(); i++) {
     856           85 :             transformCoordinate(copy[i], false);
     857              :         }
     858           33 :         addGeometrySegments(from, copy, maxLength);
     859           33 :     }
     860              :     bool ok = true;
     861       720432 :     for (int i = 0; i < (int) from.size(); i++) {
     862       515863 :         ok = ok && transformCoordinate(from[i], includeInBoundary, from_srs);
     863              :     }
     864       204569 :     return ok;
     865              : }
     866              : 
     867              : 
     868              : int
     869           71 : NBNetBuilder::addGeometrySegments(PositionVector& from, const PositionVector& cartesian, const double maxLength) {
     870              :     // check lengths and insert new points where needed (in the original
     871              :     // coordinate system)
     872              :     int inserted = 0;
     873          161 :     for (int i = 0; i < (int)cartesian.size() - 1; i++) {
     874           90 :         Position start = from[i + inserted];
     875           90 :         Position end = from[i + inserted + 1];
     876           90 :         double length = cartesian[i].distanceTo(cartesian[i + 1]);
     877           90 :         const Position step = (end - start) * (maxLength / length);
     878              :         int steps = 0;
     879          312 :         while (length > maxLength) {
     880          222 :             length -= maxLength;
     881          222 :             steps++;
     882          222 :             from.insert(from.begin() + i + inserted + 1, start + (step * steps));
     883          222 :             inserted++;
     884              :         }
     885              :     }
     886           71 :     return inserted;
     887              : }
     888              : 
     889              : 
     890              : bool
     891          894 : NBNetBuilder::runningNetedit() {
     892              :     // see GNELoadThread::fillOptions
     893         1788 :     return OptionsCont::getOptions().exists("new");
     894              : }
     895              : 
     896              : 
     897              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1