LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.3 % 227 205
Test Date: 2026-01-01 15:49:29 Functions: 92.9 % 28 26

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2002-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    ROEdge.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Christian Roessel
      18              : /// @author  Michael Behrisch
      19              : /// @author  Melanie Knocke
      20              : /// @author  Yun-Pang Floetteroed
      21              : /// @author  Ruediger Ebendt
      22              : /// @date    Sept 2002
      23              : ///
      24              : // A basic edge for routing applications
      25              : /****************************************************************************/
      26              : #include <config.h>
      27              : 
      28              : #include <utils/common/MsgHandler.h>
      29              : #include <utils/common/ToString.h>
      30              : #include <algorithm>
      31              : #include <cassert>
      32              : #include <iostream>
      33              : #include <utils/vehicle/SUMOVTypeParameter.h>
      34              : #include <utils/emissions/PollutantsInterface.h>
      35              : #include <utils/emissions/HelpersHarmonoise.h>
      36              : #include "ROLane.h"
      37              : #include "RONet.h"
      38              : #include "ROVehicle.h"
      39              : #include "ROEdge.h"
      40              : 
      41              : 
      42              : // ===========================================================================
      43              : // static member definitions
      44              : // ===========================================================================
      45              : bool ROEdge::myInterpolate = false;
      46              : bool ROEdge::myHaveTTWarned = false;
      47              : bool ROEdge::myHaveEWarned = false;
      48              : ROEdgeVector ROEdge::myEdges;
      49              : double ROEdge::myPriorityFactor(0);
      50              : double ROEdge::myMinEdgePriority(std::numeric_limits<double>::max());
      51              : double ROEdge::myEdgePriorityRange(0);
      52              : 
      53              : 
      54              : // ===========================================================================
      55              : // method definitions
      56              : // ===========================================================================
      57       286937 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority, const std::string& type, const std::string& routingType) :
      58              :     Named(id),
      59       286937 :     myFromJunction(from),
      60       286937 :     myToJunction(to),
      61       286937 :     myIndex(index),
      62       286937 :     myPriority(priority),
      63       286937 :     myType(type),
      64       286937 :     myRoutingType(routingType),
      65       286937 :     mySpeed(-1),
      66       286937 :     myLength(0),
      67       286937 :     myAmSink(false),
      68       286937 :     myAmSource(false),
      69       286937 :     myUsingTTTimeLine(false),
      70       286937 :     myUsingETimeLine(false),
      71       286937 :     mySpeedRestrictions(nullptr),
      72       286937 :     myCombinedPermissions(0),
      73       286937 :     myOtherTazConnector(nullptr),
      74       573874 :     myTimePenalty(0) {
      75       573874 :     while ((int)myEdges.size() <= index) {
      76       286937 :         myEdges.push_back(0);
      77              :     }
      78       286937 :     myEdges[index] = this;
      79       286937 :     if (from == nullptr && to == nullptr) {
      80              :         // TAZ edge, no lanes
      81         3632 :         myCombinedPermissions = SVCAll;
      82              :     } else {
      83              :         // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
      84       283305 :         myBoundary.add(from->getPosition());
      85       283305 :         myBoundary.add(to->getPosition());
      86              :     }
      87       286937 : }
      88              : 
      89              : 
      90           13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
      91              :     Named(id),
      92           13 :     myFromJunction(const_cast<RONode*>(from)),
      93           13 :     myToJunction(const_cast<RONode*>(to)),
      94           13 :     myIndex(-1),
      95           13 :     myPriority(0),
      96           13 :     myType(""),
      97           13 :     mySpeed(std::numeric_limits<double>::max()),
      98           13 :     myLength(0),
      99           13 :     myAmSink(false),
     100           13 :     myAmSource(false),
     101           13 :     myUsingTTTimeLine(false),
     102           13 :     myUsingETimeLine(false),
     103           13 :     myCombinedPermissions(p),
     104           13 :     myOtherTazConnector(nullptr),
     105           13 :     myTimePenalty(0)
     106           13 : { }
     107              : 
     108              : 
     109       841697 : ROEdge::~ROEdge() {
     110       600806 :     for (ROLane* const lane : myLanes) {
     111       316516 :         delete lane;
     112              :     }
     113       284290 :     delete myReversedRoutingEdge;
     114       284290 :     delete myFlippedRoutingEdge;
     115       284290 :     delete myRailwayRoutingEdge;
     116      1125987 : }
     117              : 
     118              : 
     119              : void
     120       320006 : ROEdge::addLane(ROLane* lane) {
     121       320006 :     const double speed = lane->getSpeed();
     122       320006 :     if (speed > mySpeed) {
     123       283859 :         mySpeed = speed;
     124       283859 :         myLength = lane->getLength();
     125              :     }
     126       320006 :     mySpeed = speed > mySpeed ? speed : mySpeed;
     127       320006 :     myLanes.push_back(lane);
     128              : 
     129              :     // integrate new allowed classes
     130       320006 :     myCombinedPermissions |= lane->getPermissions();
     131       320006 : }
     132              : 
     133              : 
     134              : void
     135       566650 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
     136       566650 :     if (isInternal()) {
     137              :         // for internal edges after an internal junction,
     138              :         // this is called twice and only the second call counts
     139              :         myFollowingEdges.clear();
     140              :         myFollowingViaEdges.clear();
     141              :     }
     142       566650 :     if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
     143       553378 :         myFollowingEdges.push_back(s);
     144       553378 :         myFollowingViaEdges.push_back(std::make_pair(s, via));
     145       553378 :         if (isTazConnector() && s->getFromJunction() != nullptr) {
     146         3834 :             myBoundary.add(s->getFromJunction()->getPosition());
     147              :         }
     148       553378 :         if (!isInternal()) {
     149       260509 :             s->myApproachingEdges.push_back(this);
     150       260509 :             if (s->isTazConnector() && getToJunction() != nullptr) {
     151         3835 :                 s->myBoundary.add(getToJunction()->getPosition());
     152              :             }
     153              :         }
     154       553378 :         if (via != nullptr) {
     155       134419 :             if (via->myApproachingEdges.size() == 0) {
     156       134144 :                 via->myApproachingEdges.push_back(this);
     157              :             }
     158              :         }
     159              :     }
     160       566650 : }
     161              : 
     162              : 
     163              : void
     164          189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
     165          189 :     myEfforts.add(timeBegin, timeEnd, value);
     166          189 :     myUsingETimeLine = true;
     167          189 : }
     168              : 
     169              : 
     170              : void
     171       247817 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
     172       247817 :     myTravelTimes.add(timeBegin, timeEnd, value);
     173       247817 :     myUsingTTTimeLine = true;
     174       247817 : }
     175              : 
     176              : 
     177              : double
     178            0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
     179            0 :     double ret = 0;
     180            0 :     if (!getStoredEffort(time, ret)) {
     181            0 :         return myLength / getMaxSpeed(veh);
     182              :     }
     183            0 :     return ret;
     184              : }
     185              : 
     186              : 
     187              : double
     188        45925 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
     189              :     assert(this != other);
     190        45925 :     if (doBoundaryEstimate) {
     191        11472 :         return myBoundary.distanceTo2D(other->myBoundary);
     192              :     }
     193        34453 :     if (isTazConnector()) {
     194          197 :         if (other->isTazConnector()) {
     195          186 :             return myBoundary.distanceTo2D(other->myBoundary);
     196              :         }
     197           11 :         return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
     198              :     }
     199        34256 :     if (other->isTazConnector()) {
     200          817 :         return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
     201              :     }
     202        33439 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
     203              :     //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
     204              : }
     205              : 
     206              : 
     207              : bool
     208        26723 : ROEdge::hasLoadedTravelTime(double time) const {
     209        26723 :     return myUsingTTTimeLine && myTravelTimes.describesTime(time);
     210              : }
     211              : 
     212              : 
     213              : double
     214     13344641 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
     215     13344641 :     if (myUsingTTTimeLine) {
     216      4330552 :         if (myTravelTimes.describesTime(time)) {
     217      4321794 :             double lineTT = myTravelTimes.getValue(time);
     218      4321794 :             if (myInterpolate) {
     219              :                 const double inTT = lineTT;
     220           68 :                 const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
     221           68 :                 if (split >= 0) {
     222           18 :                     lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
     223              :                 }
     224              :             }
     225      4321794 :             return MAX2(getMinimumTravelTime(veh), lineTT);
     226              :         } else {
     227         8758 :             if (!myHaveTTWarned) {
     228            0 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
     229            0 :                 myHaveTTWarned = true;
     230              :             }
     231              :         }
     232              :     }
     233      9022847 :     const double speed = veh != nullptr ? getMaxSpeed(veh) : mySpeed;
     234      9022847 :     return myLength / speed + myTimePenalty;
     235              : }
     236              : 
     237              : 
     238              : double
     239            0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
     240            0 :     double ret = 0;
     241            0 :     if (!edge->getStoredEffort(time, ret)) {
     242            0 :         ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, edge->getMaxSpeed(veh), 0);
     243              :     }
     244            0 :     return ret;
     245              : }
     246              : 
     247              : 
     248              : bool
     249         1666 : ROEdge::getStoredEffort(double time, double& ret) const {
     250         1666 :     if (myUsingETimeLine) {
     251          190 :         if (!myEfforts.describesTime(time)) {
     252            0 :             if (!myHaveEWarned) {
     253            0 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
     254            0 :                 myHaveEWarned = true;
     255              :             }
     256            0 :             return false;
     257              :         }
     258          190 :         if (myInterpolate) {
     259            0 :             const double inTT = myTravelTimes.getValue(time);
     260            0 :             const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
     261            0 :             if (ratio >= 0.) {
     262            0 :                 ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
     263            0 :                 return true;
     264              :             }
     265              :         }
     266          190 :         ret = myEfforts.getValue(time);
     267          190 :         return true;
     268              :     }
     269              :     return false;
     270              : }
     271              : 
     272              : 
     273              : int
     274        19236 : ROEdge::getNumSuccessors() const {
     275        19236 :     if (myAmSink) {
     276              :         return 0;
     277              :     }
     278        19236 :     return (int) myFollowingEdges.size();
     279              : }
     280              : 
     281              : 
     282              : int
     283        15110 : ROEdge::getNumPredecessors() const {
     284        15110 :     if (myAmSource) {
     285              :         return 0;
     286              :     }
     287        15110 :     return (int) myApproachingEdges.size();
     288              : }
     289              : 
     290              : 
     291              : const ROEdge*
     292           16 : ROEdge::getNormalBefore() const {
     293              :     const ROEdge* result = this;
     294           40 :     while (result->isInternal()) {
     295              :         assert(myApproachingEdges.size() == 1);
     296           24 :         result = result->myApproachingEdges.front();
     297              :     }
     298           16 :     return result;
     299              : }
     300              : 
     301              : 
     302              : 
     303              : const ROEdge*
     304            8 : ROEdge::getNormalAfter() const {
     305              :     const ROEdge* result = this;
     306           16 :     while (result->isInternal()) {
     307              :         assert(myFollowingEdges.size() == 1);
     308            8 :         result = result->myFollowingEdges.front();
     309              :     }
     310            8 :     return result;
     311              : }
     312              : 
     313              : 
     314              : void
     315         6228 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
     316         6228 :     if (myUsingETimeLine) {
     317          147 :         double value = myLength / mySpeed;
     318          147 :         const SUMOEmissionClass c = PollutantsInterface::getClassByName("HBEFA4/default");
     319          147 :         if (measure == "CO") {
     320           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     321              :         }
     322          147 :         if (measure == "CO2") {
     323           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     324              :         }
     325          147 :         if (measure == "HC") {
     326           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     327              :         }
     328          147 :         if (measure == "PMx") {
     329           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     330              :         }
     331          147 :         if (measure == "NOx") {
     332           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     333              :         }
     334          147 :         if (measure == "fuel") {
     335           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     336              :         }
     337          147 :         if (measure == "electricity") {
     338            0 :             value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     339              :         }
     340          147 :         myEfforts.fillGaps(value, boundariesOverride);
     341              :     }
     342         6228 :     if (myUsingTTTimeLine) {
     343         3924 :         myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
     344              :     }
     345         6228 : }
     346              : 
     347              : 
     348              : void
     349          408 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
     350          816 :     for (const std::string& key : restrictionKeys) {
     351          408 :         const std::string value = getParameter(key, "1e40");
     352          408 :         myParamRestrictions.push_back(StringUtils::toDouble(value));
     353              :     }
     354          408 : }
     355              : 
     356              : 
     357              : double
     358       139696 : ROEdge::getLengthGeometryFactor() const {
     359       139696 :     return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
     360              : }
     361              : 
     362              : 
     363              : bool
     364       327631 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
     365       327631 :     for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
     366       327631 :         if (!(*i)->prohibits(vehicle)) {
     367              :             return false;
     368              :         }
     369              :     }
     370              :     return true;
     371              : }
     372              : 
     373              : 
     374              : const ROEdgeVector&
     375         7905 : ROEdge::getAllEdges() {
     376         7905 :     return myEdges;
     377              : }
     378              : 
     379              : 
     380              : const Position
     381         1415 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
     382         1415 :     const double middle = (stop.endPos + stop.startPos) / 2.;
     383         4245 :     const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
     384         1415 :     return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
     385              : }
     386              : 
     387              : 
     388              : const ROEdgeVector&
     389      1374240 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
     390      1374240 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     391      1323492 :         return myFollowingEdges;
     392              :     }
     393              : #ifdef HAVE_FOX
     394        50748 :     FXMutexLock locker(myLock);
     395              : #endif
     396              :     std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
     397        50748 :     if (i != myClassesSuccessorMap.end()) {
     398              :         // can use cached value
     399        46956 :         return i->second;
     400              :     }
     401              :     // this vClass is requested for the first time. rebuild all successors
     402              :     std::set<ROEdge*> followers;
     403        10324 :     for (const ROLane* const lane : myLanes) {
     404         6532 :         if ((lane->getPermissions() & vClass) != 0) {
     405        13943 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     406         8313 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     407         7722 :                     followers.insert(&next.first->getEdge());
     408              :                 }
     409              :             }
     410              :         }
     411              :     }
     412              :     // also add district edges (they are not connected at the lane level
     413        11943 :     for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
     414         8151 :         if ((*it)->isTazConnector()) {
     415              :             followers.insert(*it);
     416              :         }
     417              :     }
     418         3792 :     myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
     419              :                                          followers.begin(), followers.end());
     420         3792 :     return myClassesSuccessorMap[vClass];
     421              : }
     422              : 
     423              : 
     424              : const ROConstEdgePairVector&
     425     10615494 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
     426     10615494 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     427      9661698 :         return myFollowingViaEdges;
     428              :     }
     429              : #ifdef HAVE_FOX
     430       953796 :     FXMutexLock locker(myLock);
     431              : #endif
     432              :     std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
     433       953796 :     if (i != myClassesViaSuccessorMap.end()) {
     434              :         // can use cached value
     435       932733 :         return i->second;
     436              :     }
     437              :     // this vClass is requested for the first time. rebuild all successors
     438              :     std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
     439        56476 :     for (const ROLane* const lane : myLanes) {
     440        35413 :         if ((lane->getPermissions() & vClass) != 0) {
     441        70523 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     442        44569 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     443        39467 :                     followers.insert(std::make_pair(&next.first->getEdge(), next.second));
     444              :                 }
     445              :             }
     446              :         }
     447              :     }
     448              :     // also add district edges (they are not connected at the lane level
     449        70102 :     for (const ROEdge* e : myFollowingEdges) {
     450        49039 :         if (e->isTazConnector()) {
     451          372 :             followers.insert(std::make_pair(e, e));
     452              :         }
     453              :     }
     454        21063 :     myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
     455              :                                             followers.begin(), followers.end());
     456        21063 :     return myClassesViaSuccessorMap[vClass];
     457              : }
     458              : 
     459              : 
     460              : bool
     461       328927 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
     462              :     // @todo needs to be used with #12501
     463              :     UNUSED_PARAMETER(ignoreTransientPermissions);
     464       328927 :     const ROEdgeVector& followers = getSuccessors(vClass);
     465       328927 :     return std::find(followers.begin(), followers.end(), &e) != followers.end();
     466              : }
     467              : 
     468              : bool
     469            3 : ROEdge::initPriorityFactor(double priorityFactor) {
     470            3 :     myPriorityFactor = priorityFactor;
     471              :     double maxEdgePriority = -std::numeric_limits<double>::max();
     472           57 :     for (ROEdge* edge : myEdges) {
     473           54 :         maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     474           97 :         myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     475              :     }
     476            3 :     myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     477            3 :     if (myEdgePriorityRange == 0) {
     478            1 :         WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
     479            1 :         myPriorityFactor = 0;
     480            1 :         return false;
     481              :     }
     482              :     return true;
     483              : }
     484              : 
     485              : 
     486              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1