LCOV - code coverage report
Current view: top level - src/netbuild - NBNetBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.2 % 494 475
Test Date: 2024-11-21 15:56:26 Functions: 100.0 % 10 10

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

Generated by: LCOV version 2.0-1