LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.9 % 228 205
Test Date: 2025-12-06 15:35:27 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       327236 : 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       327236 :     myFromJunction(from),
      60       327236 :     myToJunction(to),
      61       327236 :     myIndex(index),
      62       327236 :     myPriority(priority),
      63       327236 :     myType(type),
      64       327236 :     myRoutingType(routingType),
      65       327236 :     mySpeed(-1),
      66       327236 :     myLength(0),
      67       327236 :     myAmSink(false),
      68       327236 :     myAmSource(false),
      69       327236 :     myUsingTTTimeLine(false),
      70       327236 :     myUsingETimeLine(false),
      71       327236 :     mySpeedRestrictions(nullptr),
      72       327236 :     myCombinedPermissions(0),
      73       327236 :     myOtherTazConnector(nullptr),
      74       654472 :     myTimePenalty(0) {
      75       654472 :     while ((int)myEdges.size() <= index) {
      76       327236 :         myEdges.push_back(0);
      77              :     }
      78       327236 :     myEdges[index] = this;
      79       327236 :     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       323604 :         myBoundary.add(from->getPosition());
      85       323604 :         myBoundary.add(to->getPosition());
      86              :     }
      87       327236 : }
      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       962594 : ROEdge::~ROEdge() {
     110       687293 :     for (ROLane* const lane : myLanes) {
     111       362704 :         delete lane;
     112              :     }
     113       324589 :     delete myReversedRoutingEdge;
     114       324589 :     delete myFlippedRoutingEdge;
     115       324589 :     delete myRailwayRoutingEdge;
     116      1287183 : }
     117              : 
     118              : 
     119              : void
     120       366194 : ROEdge::addLane(ROLane* lane) {
     121       366194 :     const double speed = lane->getSpeed();
     122       366194 :     if (speed > mySpeed) {
     123       324329 :         mySpeed = speed;
     124       324329 :         myLength = lane->getLength();
     125              :     }
     126       366194 :     mySpeed = speed > mySpeed ? speed : mySpeed;
     127       366194 :     myLanes.push_back(lane);
     128              : 
     129              :     // integrate new allowed classes
     130       366194 :     myCombinedPermissions |= lane->getPermissions();
     131       366194 : }
     132              : 
     133              : 
     134              : void
     135       646477 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
     136       646477 :     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       646477 :     if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
     143       631303 :         myFollowingEdges.push_back(s);
     144       631303 :         myFollowingViaEdges.push_back(std::make_pair(s, via));
     145       631303 :         if (isTazConnector() && s->getFromJunction() != nullptr) {
     146         3834 :             myBoundary.add(s->getFromJunction()->getPosition());
     147              :         }
     148       631303 :         if (!isInternal()) {
     149       299614 :             s->myApproachingEdges.push_back(this);
     150       299614 :             if (s->isTazConnector() && getToJunction() != nullptr) {
     151         3835 :                 s->myBoundary.add(getToJunction()->getPosition());
     152              :             }
     153              :         }
     154       631303 :         if (via != nullptr) {
     155       151915 :             if (via->myApproachingEdges.size() == 0) {
     156       151565 :                 via->myApproachingEdges.push_back(this);
     157              :             }
     158              :         }
     159              :     }
     160       646477 : }
     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 / MIN2(veh->getMaxSpeed(), getVClassMaxSpeed(veh->getVClass())) + myTimePenalty;
     182              :     }
     183            0 :     return ret;
     184              : }
     185              : 
     186              : 
     187              : double
     188        45878 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
     189              :     assert(this != other);
     190        45878 :     if (doBoundaryEstimate) {
     191        11455 :         return myBoundary.distanceTo2D(other->myBoundary);
     192              :     }
     193        34423 :     if (isTazConnector()) {
     194          207 :         if (other->isTazConnector()) {
     195          196 :             return myBoundary.distanceTo2D(other->myBoundary);
     196              :         }
     197           11 :         return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
     198              :     }
     199        34216 :     if (other->isTazConnector()) {
     200          817 :         return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
     201              :     }
     202        33399 :     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     13344214 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
     215     13344214 :     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      9022420 :     const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter(0) * getVClassMaxSpeed(veh->getVClass())) : mySpeed;
     234      9022420 :     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 :         const double v = MIN2(veh->getMaxSpeed(), edge->getVClassMaxSpeed(veh->getVClass()));
     243            0 :         ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
     244              :     }
     245            0 :     return ret;
     246              : }
     247              : 
     248              : 
     249              : bool
     250         1666 : ROEdge::getStoredEffort(double time, double& ret) const {
     251         1666 :     if (myUsingETimeLine) {
     252          190 :         if (!myEfforts.describesTime(time)) {
     253            0 :             if (!myHaveEWarned) {
     254            0 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
     255            0 :                 myHaveEWarned = true;
     256              :             }
     257            0 :             return false;
     258              :         }
     259          190 :         if (myInterpolate) {
     260            0 :             const double inTT = myTravelTimes.getValue(time);
     261            0 :             const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
     262            0 :             if (ratio >= 0.) {
     263            0 :                 ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
     264            0 :                 return true;
     265              :             }
     266              :         }
     267          190 :         ret = myEfforts.getValue(time);
     268          190 :         return true;
     269              :     }
     270              :     return false;
     271              : }
     272              : 
     273              : 
     274              : int
     275        19236 : ROEdge::getNumSuccessors() const {
     276        19236 :     if (myAmSink) {
     277              :         return 0;
     278              :     }
     279        19236 :     return (int) myFollowingEdges.size();
     280              : }
     281              : 
     282              : 
     283              : int
     284        15110 : ROEdge::getNumPredecessors() const {
     285        15110 :     if (myAmSource) {
     286              :         return 0;
     287              :     }
     288        15110 :     return (int) myApproachingEdges.size();
     289              : }
     290              : 
     291              : 
     292              : const ROEdge*
     293           16 : ROEdge::getNormalBefore() const {
     294              :     const ROEdge* result = this;
     295           40 :     while (result->isInternal()) {
     296              :         assert(myApproachingEdges.size() == 1);
     297           24 :         result = result->myApproachingEdges.front();
     298              :     }
     299           16 :     return result;
     300              : }
     301              : 
     302              : 
     303              : 
     304              : const ROEdge*
     305            8 : ROEdge::getNormalAfter() const {
     306              :     const ROEdge* result = this;
     307           16 :     while (result->isInternal()) {
     308              :         assert(myFollowingEdges.size() == 1);
     309            8 :         result = result->myFollowingEdges.front();
     310              :     }
     311            8 :     return result;
     312              : }
     313              : 
     314              : 
     315              : void
     316         6228 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
     317         6228 :     if (myUsingETimeLine) {
     318          147 :         double value = myLength / mySpeed;
     319          147 :         const SUMOEmissionClass c = PollutantsInterface::getClassByName("HBEFA4/default");
     320          147 :         if (measure == "CO") {
     321           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     322              :         }
     323          147 :         if (measure == "CO2") {
     324           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     325              :         }
     326          147 :         if (measure == "HC") {
     327           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     328              :         }
     329          147 :         if (measure == "PMx") {
     330           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     331              :         }
     332          147 :         if (measure == "NOx") {
     333           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     334              :         }
     335          147 :         if (measure == "fuel") {
     336           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     337              :         }
     338          147 :         if (measure == "electricity") {
     339            0 :             value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     340              :         }
     341          147 :         myEfforts.fillGaps(value, boundariesOverride);
     342              :     }
     343         6228 :     if (myUsingTTTimeLine) {
     344         3924 :         myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
     345              :     }
     346         6228 : }
     347              : 
     348              : 
     349              : void
     350          408 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
     351          816 :     for (const std::string& key : restrictionKeys) {
     352          408 :         const std::string value = getParameter(key, "1e40");
     353          408 :         myParamRestrictions.push_back(StringUtils::toDouble(value));
     354              :     }
     355          408 : }
     356              : 
     357              : 
     358              : double
     359       139617 : ROEdge::getLengthGeometryFactor() const {
     360       139617 :     return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
     361              : }
     362              : 
     363              : 
     364              : bool
     365       327631 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
     366       327631 :     for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
     367       327631 :         if (!(*i)->prohibits(vehicle)) {
     368              :             return false;
     369              :         }
     370              :     }
     371              :     return true;
     372              : }
     373              : 
     374              : 
     375              : const ROEdgeVector&
     376         7863 : ROEdge::getAllEdges() {
     377         7863 :     return myEdges;
     378              : }
     379              : 
     380              : 
     381              : const Position
     382         2351 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
     383         2351 :     const double middle = (stop.endPos + stop.startPos) / 2.;
     384         7053 :     const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
     385         2351 :     return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
     386              : }
     387              : 
     388              : 
     389              : const ROEdgeVector&
     390      1379413 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
     391      1379413 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     392      1328712 :         return myFollowingEdges;
     393              :     }
     394              : #ifdef HAVE_FOX
     395        50701 :     FXMutexLock locker(myLock);
     396              : #endif
     397              :     std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
     398        50701 :     if (i != myClassesSuccessorMap.end()) {
     399              :         // can use cached value
     400        46932 :         return i->second;
     401              :     }
     402              :     // this vClass is requested for the first time. rebuild all successors
     403              :     std::set<ROEdge*> followers;
     404        10261 :     for (const ROLane* const lane : myLanes) {
     405         6492 :         if ((lane->getPermissions() & vClass) != 0) {
     406        13863 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     407         8273 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     408         7691 :                     followers.insert(&next.first->getEdge());
     409              :                 }
     410              :             }
     411              :         }
     412              :     }
     413              :     // also add district edges (they are not connected at the lane level
     414        11880 :     for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
     415         8111 :         if ((*it)->isTazConnector()) {
     416              :             followers.insert(*it);
     417              :         }
     418              :     }
     419         3769 :     myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
     420              :                                          followers.begin(), followers.end());
     421         3769 :     return myClassesSuccessorMap[vClass];
     422              : }
     423              : 
     424              : 
     425              : const ROConstEdgePairVector&
     426     10645767 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
     427     10645767 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     428      9692134 :         return myFollowingViaEdges;
     429              :     }
     430              : #ifdef HAVE_FOX
     431       953633 :     FXMutexLock locker(myLock);
     432              : #endif
     433              :     std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
     434       953633 :     if (i != myClassesViaSuccessorMap.end()) {
     435              :         // can use cached value
     436       932672 :         return i->second;
     437              :     }
     438              :     // this vClass is requested for the first time. rebuild all successors
     439              :     std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
     440        56240 :     for (const ROLane* const lane : myLanes) {
     441        35279 :         if ((lane->getPermissions() & vClass) != 0) {
     442        70271 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     443        44451 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     444        39365 :                     followers.insert(std::make_pair(&next.first->getEdge(), next.second));
     445              :                 }
     446              :             }
     447              :         }
     448              :     }
     449              :     // also add district edges (they are not connected at the lane level
     450        69894 :     for (const ROEdge* e : myFollowingEdges) {
     451        48933 :         if (e->isTazConnector()) {
     452          372 :             followers.insert(std::make_pair(e, e));
     453              :         }
     454              :     }
     455        20961 :     myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
     456              :                                             followers.begin(), followers.end());
     457        20961 :     return myClassesViaSuccessorMap[vClass];
     458              : }
     459              : 
     460              : 
     461              : bool
     462       328871 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
     463              :     // @todo needs to be used with #12501
     464              :     UNUSED_PARAMETER(ignoreTransientPermissions);
     465       328871 :     const ROEdgeVector& followers = getSuccessors(vClass);
     466       328871 :     return std::find(followers.begin(), followers.end(), &e) != followers.end();
     467              : }
     468              : 
     469              : bool
     470            3 : ROEdge::initPriorityFactor(double priorityFactor) {
     471            3 :     myPriorityFactor = priorityFactor;
     472              :     double maxEdgePriority = -std::numeric_limits<double>::max();
     473           57 :     for (ROEdge* edge : myEdges) {
     474           54 :         maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     475           97 :         myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     476              :     }
     477            3 :     myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     478            3 :     if (myEdgePriorityRange == 0) {
     479            1 :         WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
     480            1 :         myPriorityFactor = 0;
     481            1 :         return false;
     482              :     }
     483              :     return true;
     484              : }
     485              : 
     486              : 
     487              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1