LCOV - code coverage report
Current view: top level - src/netbuild - NBNetBuilder.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 466 480 97.1 %
Date: 2024-05-07 15:28:01 Functions: 10 10 100.0 %

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

Generated by: LCOV version 1.14