LCOV - code coverage report
Current view: top level - src/netload - NLEdgeControlBuilder.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 87.7 % 114 100
Test Date: 2025-11-13 15:38:19 Functions: 87.5 % 16 14

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    NLEdgeControlBuilder.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Leonhard Luecken
      19              : /// @date    Mon, 9 Jul 2001
      20              : ///
      21              : // Interface for building edges
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <vector>
      26              : #include <string>
      27              : #include <map>
      28              : #include <algorithm>
      29              : #include <iterator>
      30              : #include <mesosim/MELoop.h>
      31              : #include <microsim/MSGlobals.h>
      32              : #include <microsim/MSLane.h>
      33              : #include <microsim/MSEdge.h>
      34              : #include <microsim/MSEdgeControl.h>
      35              : #include <utils/common/StringTokenizer.h>
      36              : #include <utils/common/UtilExceptions.h>
      37              : #include <utils/options/OptionsCont.h>
      38              : #include "NLBuilder.h"
      39              : #include "NLEdgeControlBuilder.h"
      40              : #include <utils/iodevices/OutputDevice.h>
      41              : 
      42              : 
      43              : // ===========================================================================
      44              : // method definitions
      45              : // ===========================================================================
      46        39017 : NLEdgeControlBuilder::NLEdgeControlBuilder()
      47        39017 :     : myCurrentNumericalLaneID(0), myCurrentNumericalEdgeID(0), myEdges(0), myCurrentLaneIndex(-1) {
      48        39017 :     myActiveEdge = (MSEdge*) nullptr;
      49        39017 :     myLaneStorage = new std::vector<MSLane*>();
      50        39017 : }
      51              : 
      52              : 
      53        39017 : NLEdgeControlBuilder::~NLEdgeControlBuilder() {
      54        39017 :     delete myLaneStorage;
      55        78034 : }
      56              : 
      57              : 
      58              : void
      59      1616906 : NLEdgeControlBuilder::beginEdgeParsing(
      60              :     const std::string& id, const SumoXMLEdgeFunc function,
      61              :     const std::string& streetName,
      62              :     const std::string& edgeType,
      63              :     const std::string& routingType,
      64              :     int priority,
      65              :     const std::string& bidi,
      66              :     double distance) {
      67              :     // closeEdge might not have been called because the last edge had an error, so we clear the lane storage
      68      1616906 :     myLaneStorage->clear();
      69      1616906 :     myActiveEdge = buildEdge(id, function, streetName, edgeType, routingType, priority, distance);
      70      1616906 :     if (MSEdge::dictionary(id) != nullptr) {
      71           12 :         throw InvalidArgument("Another edge with the id '" + id + "' exists.");
      72              :     }
      73      1616902 :     myEdges.push_back(myActiveEdge);
      74      1616902 :     if (bidi != "") {
      75        27964 :         myBidiEdges[myActiveEdge] = bidi;
      76              :     }
      77      1616902 : }
      78              : 
      79              : 
      80              : MSLane*
      81      1549451 : NLEdgeControlBuilder::addLane(const std::string& id,
      82              :                               double maxSpeed, double friction, double length,
      83              :                               const PositionVector& shape, double width,
      84              :                               SVCPermissions permissions,
      85              :                               SVCPermissions changeLeft, SVCPermissions changeRight,
      86              :                               int index, bool isRampAccel,
      87              :                               const std::string& type,
      88              :                               const PositionVector& outlineShape) {
      89      1549451 :     MSLane* lane = new MSLane(id, maxSpeed, friction, length, myActiveEdge, myCurrentNumericalLaneID++, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape);
      90      1549451 :     myLaneStorage->push_back(lane);
      91      1549451 :     myCurrentLaneIndex = index;
      92      1549451 :     return lane;
      93              : }
      94              : 
      95              : 
      96              : void
      97         2178 : NLEdgeControlBuilder::addStopOffsets(const StopOffset& stopOffset) {
      98         2178 :     if (myCurrentLaneIndex == -1) {
      99         1158 :         setDefaultStopOffset(stopOffset);
     100              :     } else {
     101         1020 :         updateCurrentLaneStopOffset(stopOffset);
     102              :     }
     103         2178 : }
     104              : 
     105              : 
     106              : std::string
     107            0 : NLEdgeControlBuilder::reportCurrentEdgeOrLane() const {
     108            0 :     std::stringstream ss;
     109            0 :     if (myCurrentLaneIndex != -1) {
     110            0 :         ss << "lane " << myCurrentLaneIndex << " of ";
     111              :     }
     112            0 :     ss << "edge '" << myActiveEdge->getID() << "'";
     113            0 :     return ss.str();
     114            0 : }
     115              : 
     116              : 
     117              : void
     118         1020 : NLEdgeControlBuilder::updateCurrentLaneStopOffset(const StopOffset& stopOffset) {
     119         1020 :     if (myLaneStorage->size() == 0) {
     120            0 :         throw ProcessError("myLaneStorage cannot be empty");
     121              :     }
     122         1020 :     if (stopOffset.isDefined()) {
     123         1020 :         if (myLaneStorage->back()->getLaneStopOffsets().isDefined()) {
     124            0 :             WRITE_WARNING("Duplicate stopOffset definition for lane " + toString(myLaneStorage->back()->getIndex()) +
     125              :                           " on edge " + myActiveEdge->getID() + "!")
     126              :         } else {
     127         1020 :             myLaneStorage->back()->setLaneStopOffset(stopOffset);
     128              :         }
     129              :     }
     130         1020 : }
     131              : 
     132              : 
     133              : void
     134         1158 : NLEdgeControlBuilder::setDefaultStopOffset(const StopOffset& stopOffsets) {
     135         1158 :     if (myCurrentDefaultStopOffset.isDefined()) {
     136            0 :         WRITE_WARNING("Duplicate stopOffset definition for edge " + myActiveEdge->getID() + ". Ignoring duplicate specification.")
     137              :     } else {
     138         1158 :         myCurrentDefaultStopOffset = stopOffsets;
     139              :     }
     140         1158 : }
     141              : 
     142              : 
     143              : void
     144      1616774 : NLEdgeControlBuilder::applyDefaultStopOffsetsToLanes() {
     145      1616774 :     if (myActiveEdge == nullptr) {
     146            0 :         throw ProcessError("myActiveEdge cannot be nullptr");
     147              :     }
     148      1616774 :     if (myCurrentDefaultStopOffset.isDefined()) {
     149         3118 :         for (const auto& l : *myLaneStorage) {
     150         1960 :             if (!l->getLaneStopOffsets().isDefined()) {
     151         1132 :                 l->setLaneStopOffset(myCurrentDefaultStopOffset);
     152              :             }
     153              :         }
     154              :     }
     155      1616774 : }
     156              : 
     157              : 
     158              : void
     159         8030 : NLEdgeControlBuilder::addNeigh(const std::string id) {
     160         8030 :     myOppositeLanes.push_back({myLaneStorage->back(), id});
     161         8030 : }
     162              : 
     163              : 
     164              : MSEdge*
     165      1616774 : NLEdgeControlBuilder::closeEdge() {
     166      1616774 :     applyDefaultStopOffsetsToLanes();
     167      1616774 :     std::vector<MSLane*>* lanes = new std::vector<MSLane*>();
     168      1616774 :     lanes->reserve(myLaneStorage->size());
     169      1616774 :     copy(myLaneStorage->begin(), myLaneStorage->end(), back_inserter(*lanes));
     170      1616774 :     myLaneStorage->clear();
     171      1616774 :     myActiveEdge->initialize(lanes);
     172      1616774 :     myCurrentDefaultStopOffset.reset();
     173      1616774 :     return myActiveEdge;
     174              : }
     175              : 
     176              : 
     177              : void
     178      1951050 : NLEdgeControlBuilder::closeLane() {
     179      1951050 :     myCurrentLaneIndex = -1;
     180      1951050 : }
     181              : 
     182              : 
     183              : MSEdgeControl*
     184        38596 : NLEdgeControlBuilder::build(const MMVersion& networkVersion) {
     185        44433 :     if (MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
     186        11594 :         MSEdge::setMesoIgnoredVClasses(parseVehicleClasses(OptionsCont::getOptions().getStringVector("meso-ignore-lanes-by-vclass")));
     187              :     }
     188              :     // connecting opposite lanes must happen before MSEdge::closeBuilding
     189        46626 :     for (auto item : myOppositeLanes) {
     190         8030 :         MSLane* oppo = MSLane::dictionary(item.second);
     191         8030 :         if (oppo == nullptr) {
     192            0 :             WRITE_ERRORF("Unknown neigh lane '%' for lane '%'", item.second, item.first->getID());
     193              :         } else {
     194         8030 :             item.first->setOpposite(oppo);
     195              :         }
     196              :     }
     197              :     // consistency check
     198              :     std::set<const MSLane*> checked;
     199        46611 :     for (auto item : myOppositeLanes) {
     200         8025 :         if (item.first->getOpposite() != nullptr) {
     201         8025 :             if (item.first->getOpposite()->getOpposite() != item.first) {
     202           16 :                 if (checked.count(item.first->getOpposite()) == 0) {
     203           18 :                     WRITE_WARNINGF(TL("Asymmetrical neigh lane '%' for lane '%'"), item.second, item.first->getID());
     204            6 :                     item.first->getOpposite()->setOpposite(item.first);
     205              :                 } else {
     206           50 :                     throw ProcessError(TLF("Mutually inconsistent neigh lane definitions for lanes '%', '%' and '%'",
     207           30 :                                            item.first->getID(), item.first->getOpposite()->getID(), Named::getIDSecure(item.first->getOpposite()->getOpposite())));
     208              :                 }
     209              :             }
     210              :             checked.insert(item.first);
     211         8025 :             checked.insert(item.first->getOpposite());
     212              :         }
     213              :     }
     214      1652844 :     for (MSEdge* const edge : myEdges) {
     215      1614258 :         edge->closeBuilding();
     216              :     }
     217      1652844 :     for (MSEdge* const edge : myEdges) {
     218      1614258 :         edge->rebuildAllowedTargets(false);
     219              :         // segment building depends on the finished list of successors (for multi-queue)
     220      1614258 :         if (MSGlobals::gUseMesoSim && !edge->getLanes().empty()) {
     221       285288 :             MSGlobals::gMesoNet->buildSegmentsFor(*edge, OptionsCont::getOptions());
     222              :         }
     223              :     }
     224              :     // mark internal edges belonging to a roundabout (after all edges are build)
     225        38586 :     if (MSGlobals::gUsingInternalLanes) {
     226      1360129 :         for (MSEdge* const edge : myEdges) {
     227      1327434 :             if (edge->isInternal()) {
     228       699126 :                 if (edge->getNumSuccessors() != 1 || edge->getNumPredecessors() != 1) {
     229            0 :                     throw ProcessError(TLF("Internal edge '%' is not properly connected (probably a manually modified net.xml).", edge->getID()));
     230              :                 }
     231       699126 :                 if (edge->getSuccessors()[0]->isRoundabout() || edge->getPredecessors()[0]->isRoundabout()) {
     232              :                     edge->markAsRoundabout();
     233              :                 }
     234              :             }
     235              :         }
     236              :     }
     237        38586 :     if (!deprecatedVehicleClassesSeen.empty()) {
     238            0 :         WRITE_WARNINGF(TL("Deprecated vehicle classes '%' in input network."), toString(deprecatedVehicleClassesSeen));
     239              :         deprecatedVehicleClassesSeen.clear();
     240              :     }
     241              :     // check for bi-directional edges (this are edges in opposing direction and superposable/congruent shapes)
     242        38586 :     if (myBidiEdges.size() > 0 || networkVersion > MMVersion(1, 0)) {
     243        45561 :         for (auto& item : myBidiEdges) {
     244        27964 :             item.first->checkAndRegisterBiDirEdge(item.second);
     245              :         }
     246              :         //WRITE_MESSAGEF(TL("Loaded % bidirectional edges"), toString(myBidiEdges.size()));
     247              :     } else {
     248              :         // legacy network
     249       867685 :         for (MSEdge* e : myEdges) {
     250      1693402 :             e->checkAndRegisterBiDirEdge();
     251              :         }
     252              :     }
     253              :     // take into account bidi lanes when deciding on whether an edge allows changing
     254      1652844 :     for (MSEdge* const edge : myEdges) {
     255      1614258 :         edge->buildLaneChanger();
     256              :     }
     257        77172 :     return new MSEdgeControl(myEdges);
     258              : }
     259              : 
     260              : 
     261              : MSEdge*
     262      1464904 : NLEdgeControlBuilder::buildEdge(const std::string& id, const SumoXMLEdgeFunc function,
     263              :                                 const std::string& streetName, const std::string& edgeType, const std::string& routingType,
     264              :                                 const int priority, const double distance) {
     265      1464904 :     return new MSEdge(id, myCurrentNumericalEdgeID++, function, streetName, edgeType, routingType, priority, distance);
     266              : }
     267              : 
     268        16502 : void NLEdgeControlBuilder::addCrossingEdges(const std::vector<std::string>& crossingEdges) {
     269        16502 :     myActiveEdge->setCrossingEdges(crossingEdges);
     270        16502 : }
     271              : 
     272              : 
     273              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1