LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.7 % 227 206
Test Date: 2025-05-18 15:30:03 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       546916 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority, const std::string& type) :
      58              :     Named(id),
      59       546916 :     myFromJunction(from),
      60       546916 :     myToJunction(to),
      61       546916 :     myIndex(index),
      62       546916 :     myPriority(priority),
      63       546916 :     myType(type),
      64       546916 :     mySpeed(-1),
      65       546916 :     myLength(0),
      66       546916 :     myAmSink(false),
      67       546916 :     myAmSource(false),
      68       546916 :     myUsingTTTimeLine(false),
      69       546916 :     myUsingETimeLine(false),
      70       546916 :     myRestrictions(nullptr),
      71       546916 :     myCombinedPermissions(0),
      72       546916 :     myOtherTazConnector(nullptr),
      73      1093832 :     myTimePenalty(0) {
      74      1093832 :     while ((int)myEdges.size() <= index) {
      75       546916 :         myEdges.push_back(0);
      76              :     }
      77       546916 :     myEdges[index] = this;
      78       546916 :     if (from == nullptr && to == nullptr) {
      79              :         // TAZ edge, no lanes
      80        28004 :         myCombinedPermissions = SVCAll;
      81              :     } else {
      82              :         // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
      83       518912 :         myBoundary.add(from->getPosition());
      84       518912 :         myBoundary.add(to->getPosition());
      85              :     }
      86       546916 : }
      87              : 
      88              : 
      89           13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
      90              :     Named(id),
      91           13 :     myFromJunction(const_cast<RONode*>(from)),
      92           13 :     myToJunction(const_cast<RONode*>(to)),
      93           13 :     myIndex(-1),
      94           13 :     myPriority(0),
      95           26 :     myType(""),
      96           13 :     mySpeed(std::numeric_limits<double>::max()),
      97           13 :     myLength(0),
      98           13 :     myAmSink(false),
      99           13 :     myAmSource(false),
     100           13 :     myUsingTTTimeLine(false),
     101           13 :     myUsingETimeLine(false),
     102           13 :     myCombinedPermissions(p),
     103           13 :     myOtherTazConnector(nullptr),
     104           13 :     myTimePenalty(0)
     105           13 : { }
     106              : 
     107              : 
     108      1621631 : ROEdge::~ROEdge() {
     109      1218030 :     for (ROLane* const lane : myLanes) {
     110       673774 :         delete lane;
     111              :     }
     112       544256 :     delete myReversedRoutingEdge;
     113       544256 :     delete myFlippedRoutingEdge;
     114       544256 :     delete myRailwayRoutingEdge;
     115      2165887 : }
     116              : 
     117              : 
     118              : void
     119       677264 : ROEdge::addLane(ROLane* lane) {
     120       677264 :     const double speed = lane->getSpeed();
     121       677264 :     if (speed > mySpeed) {
     122       519466 :         mySpeed = speed;
     123       519466 :         myLength = lane->getLength();
     124              :     }
     125       677264 :     mySpeed = speed > mySpeed ? speed : mySpeed;
     126       677264 :     myLanes.push_back(lane);
     127              : 
     128              :     // integrate new allowed classes
     129       677264 :     myCombinedPermissions |= lane->getPermissions();
     130       677264 : }
     131              : 
     132              : 
     133              : void
     134      1222042 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
     135      1222042 :     if (isInternal()) {
     136              :         // for internal edges after an internal junction,
     137              :         // this is called twice and only the second call counts
     138              :         myFollowingEdges.clear();
     139              :         myFollowingViaEdges.clear();
     140              :     }
     141      1222042 :     if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
     142      1160487 :         myFollowingEdges.push_back(s);
     143      1160487 :         myFollowingViaEdges.push_back(std::make_pair(s, via));
     144      1160487 :         if (isTazConnector() && s->getFromJunction() != nullptr) {
     145        22014 :             myBoundary.add(s->getFromJunction()->getPosition());
     146              :         }
     147      1160487 :         if (!isInternal()) {
     148       435156 :             s->myApproachingEdges.push_back(this);
     149       435156 :             if (s->isTazConnector() && getToJunction() != nullptr) {
     150        22015 :                 s->myBoundary.add(getToJunction()->getPosition());
     151              :             }
     152              :         }
     153      1160487 :         if (via != nullptr) {
     154       301622 :             if (via->myApproachingEdges.size() == 0) {
     155       301325 :                 via->myApproachingEdges.push_back(this);
     156              :             }
     157              :         }
     158              :     }
     159      1222042 : }
     160              : 
     161              : 
     162              : void
     163          189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
     164          189 :     myEfforts.add(timeBegin, timeEnd, value);
     165          189 :     myUsingETimeLine = true;
     166          189 : }
     167              : 
     168              : 
     169              : void
     170       247462 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
     171       247462 :     myTravelTimes.add(timeBegin, timeEnd, value);
     172       247462 :     myUsingTTTimeLine = true;
     173       247462 : }
     174              : 
     175              : 
     176              : double
     177            0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
     178            0 :     double ret = 0;
     179            0 :     if (!getStoredEffort(time, ret)) {
     180            0 :         return myLength / MIN2(veh->getMaxSpeed(), getVClassMaxSpeed(veh->getVClass())) + myTimePenalty;
     181              :     }
     182            0 :     return ret;
     183              : }
     184              : 
     185              : 
     186              : double
     187        44459 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
     188              :     assert(this != other);
     189        44459 :     if (doBoundaryEstimate) {
     190        10099 :         return myBoundary.distanceTo2D(other->myBoundary);
     191              :     }
     192        34360 :     if (isTazConnector()) {
     193          207 :         if (other->isTazConnector()) {
     194          196 :             return myBoundary.distanceTo2D(other->myBoundary);
     195              :         }
     196           11 :         return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
     197              :     }
     198        34153 :     if (other->isTazConnector()) {
     199          817 :         return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
     200              :     }
     201        33336 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
     202              :     //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
     203              : }
     204              : 
     205              : 
     206              : bool
     207        26723 : ROEdge::hasLoadedTravelTime(double time) const {
     208        26723 :     return myUsingTTTimeLine && myTravelTimes.describesTime(time);
     209              : }
     210              : 
     211              : 
     212              : double
     213     12167555 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
     214     12167555 :     if (myUsingTTTimeLine) {
     215      4315441 :         if (myTravelTimes.describesTime(time)) {
     216      4306383 :             double lineTT = myTravelTimes.getValue(time);
     217      4306383 :             if (myInterpolate) {
     218              :                 const double inTT = lineTT;
     219           68 :                 const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
     220           68 :                 if (split >= 0) {
     221           18 :                     lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
     222              :                 }
     223              :             }
     224      4306383 :             return MAX2(getMinimumTravelTime(veh), lineTT);
     225              :         } else {
     226         9058 :             if (!myHaveTTWarned) {
     227            3 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
     228            1 :                 myHaveTTWarned = true;
     229              :             }
     230              :         }
     231              :     }
     232     15722232 :     const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * getVClassMaxSpeed(veh->getVClass())) : mySpeed;
     233      7861172 :     return myLength / speed + myTimePenalty;
     234              : }
     235              : 
     236              : 
     237              : double
     238            0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
     239            0 :     double ret = 0;
     240            0 :     if (!edge->getStoredEffort(time, ret)) {
     241            0 :         const double v = MIN2(veh->getMaxSpeed(), edge->getVClassMaxSpeed(veh->getVClass()));
     242            0 :         ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 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        16656 : ROEdge::getNumSuccessors() const {
     275        16656 :     if (myAmSink) {
     276              :         return 0;
     277              :     }
     278        16656 :     return (int) myFollowingEdges.size();
     279              : }
     280              : 
     281              : 
     282              : int
     283        12534 : ROEdge::getNumPredecessors() const {
     284        12534 :     if (myAmSource) {
     285              :         return 0;
     286              :     }
     287        12534 :     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         5115 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
     316         5115 :     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         5115 :     if (myUsingTTTimeLine) {
     343         3571 :         myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
     344              :     }
     345         5115 : }
     346              : 
     347              : 
     348              : void
     349          296 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
     350          592 :     for (const std::string& key : restrictionKeys) {
     351          296 :         const std::string value = getParameter(key, "1e40");
     352          296 :         myParamRestrictions.push_back(StringUtils::toDouble(value));
     353              :     }
     354          296 : }
     355              : 
     356              : 
     357              : double
     358       122809 : ROEdge::getLengthGeometryFactor() const {
     359       122809 :     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       655262 :         if (!(*i)->prohibits(vehicle)) {
     367              :             return false;
     368              :         }
     369              :     }
     370              :     return true;
     371              : }
     372              : 
     373              : 
     374              : const ROEdgeVector&
     375        13532 : ROEdge::getAllEdges() {
     376        13532 :     return myEdges;
     377              : }
     378              : 
     379              : 
     380              : const Position
     381         1403 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
     382         1403 :     const double middle = (stop.endPos + stop.startPos) / 2.;
     383         4209 :     const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
     384         1403 :     return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
     385              : }
     386              : 
     387              : 
     388              : const ROEdgeVector&
     389      1266968 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
     390      1266968 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     391      1243622 :         return myFollowingEdges;
     392              :     }
     393              : #ifdef HAVE_FOX
     394        23346 :     FXMutexLock locker(myLock);
     395              : #endif
     396              :     std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
     397        23346 :     if (i != myClassesSuccessorMap.end()) {
     398              :         // can use cached value
     399        20145 :         return i->second;
     400              :     }
     401              :     // this vClass is requested for the first time. rebuild all successors
     402              :     std::set<ROEdge*> followers;
     403         8947 :     for (const ROLane* const lane : myLanes) {
     404         5746 :         if ((lane->getPermissions() & vClass) != 0) {
     405        12070 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     406         7192 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     407         6689 :                     followers.insert(&next.first->getEdge());
     408              :                 }
     409              :             }
     410              :         }
     411              :     }
     412              :     // also add district edges (they are not connected at the lane level
     413        10309 :     for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
     414         7108 :         if ((*it)->isTazConnector()) {
     415              :             followers.insert(*it);
     416              :         }
     417              :     }
     418         3201 :     myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
     419              :                                          followers.begin(), followers.end());
     420         3201 :     return myClassesSuccessorMap[vClass];
     421              : }
     422              : 
     423              : 
     424              : const ROConstEdgePairVector&
     425      9578208 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
     426      9578208 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     427      8786632 :         return myFollowingViaEdges;
     428              :     }
     429              : #ifdef HAVE_FOX
     430       791576 :     FXMutexLock locker(myLock);
     431              : #endif
     432              :     std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
     433       791576 :     if (i != myClassesViaSuccessorMap.end()) {
     434              :         // can use cached value
     435       771897 :         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        53333 :     for (const ROLane* const lane : myLanes) {
     440        33654 :         if ((lane->getPermissions() & vClass) != 0) {
     441        66471 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     442        42153 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     443        37161 :                     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        66342 :     for (const ROEdge* e : myFollowingEdges) {
     450        46663 :         if (e->isTazConnector()) {
     451          372 :             followers.insert(std::make_pair(e, e));
     452              :         }
     453              :     }
     454        19679 :     myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
     455              :                                             followers.begin(), followers.end());
     456        19679 :     return myClassesViaSuccessorMap[vClass];
     457              : }
     458              : 
     459              : 
     460              : bool
     461       174737 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
     462       174737 :     const ROEdgeVector& followers = getSuccessors(vClass);
     463       174737 :     return std::find(followers.begin(), followers.end(), &e) != followers.end();
     464              : }
     465              : 
     466              : bool
     467            3 : ROEdge::initPriorityFactor(double priorityFactor) {
     468            3 :     myPriorityFactor = priorityFactor;
     469              :     double maxEdgePriority = -std::numeric_limits<double>::max();
     470           57 :     for (ROEdge* edge : myEdges) {
     471           54 :         maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     472           97 :         myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     473              :     }
     474            3 :     myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     475            3 :     if (myEdgePriorityRange == 0) {
     476            1 :         WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
     477            1 :         myPriorityFactor = 0;
     478            1 :         return false;
     479              :     }
     480              :     return true;
     481              : }
     482              : 
     483              : 
     484              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1