LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 186 207 89.9 %
Date: 2024-05-08 15:29:52 Functions: 25 27 92.6 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    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             : /// @date    Sept 2002
      22             : ///
      23             : // A basic edge for routing applications
      24             : /****************************************************************************/
      25             : #include <config.h>
      26             : 
      27             : #include <utils/common/MsgHandler.h>
      28             : #include <utils/common/ToString.h>
      29             : #include <algorithm>
      30             : #include <cassert>
      31             : #include <iostream>
      32             : #include <utils/vehicle/SUMOVTypeParameter.h>
      33             : #include <utils/emissions/PollutantsInterface.h>
      34             : #include <utils/emissions/HelpersHarmonoise.h>
      35             : #include "ROLane.h"
      36             : #include "RONet.h"
      37             : #include "ROVehicle.h"
      38             : #include "ROEdge.h"
      39             : 
      40             : 
      41             : // ===========================================================================
      42             : // static member definitions
      43             : // ===========================================================================
      44             : bool ROEdge::myInterpolate = false;
      45             : bool ROEdge::myHaveTTWarned = false;
      46             : bool ROEdge::myHaveEWarned = false;
      47             : ROEdgeVector ROEdge::myEdges;
      48             : double ROEdge::myPriorityFactor(0);
      49             : double ROEdge::myMinEdgePriority(std::numeric_limits<double>::max());
      50             : double ROEdge::myEdgePriorityRange(0);
      51             : 
      52             : 
      53             : // ===========================================================================
      54             : // method definitions
      55             : // ===========================================================================
      56      311257 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority) :
      57             :     Named(id),
      58      311257 :     myFromJunction(from),
      59      311257 :     myToJunction(to),
      60      311257 :     myIndex(index),
      61      311257 :     myPriority(priority),
      62      311257 :     mySpeed(-1),
      63      311257 :     myLength(0),
      64      311257 :     myAmSink(false),
      65      311257 :     myAmSource(false),
      66      311257 :     myUsingTTTimeLine(false),
      67      311257 :     myUsingETimeLine(false),
      68      311257 :     myCombinedPermissions(0),
      69      311257 :     myOtherTazConnector(nullptr),
      70      311257 :     myTimePenalty(0) {
      71      622514 :     while ((int)myEdges.size() <= index) {
      72      311257 :         myEdges.push_back(0);
      73             :     }
      74      311257 :     myEdges[index] = this;
      75      311257 :     if (from == nullptr && to == nullptr) {
      76             :         // TAZ edge, no lanes
      77        2410 :         myCombinedPermissions = SVCAll;
      78             :     } else {
      79             :         // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
      80      308847 :         myBoundary.add(from->getPosition());
      81      308847 :         myBoundary.add(to->getPosition());
      82             :     }
      83      311257 : }
      84             : 
      85             : 
      86      602730 : ROEdge::~ROEdge() {
      87      657033 :     for (ROLane* const lane : myLanes) {
      88      348436 :         delete lane;
      89             :     }
      90      308597 :     delete myReversedRoutingEdge;
      91      308597 :     delete myRailwayRoutingEdge;
      92     1219924 : }
      93             : 
      94             : 
      95             : void
      96      351926 : ROEdge::addLane(ROLane* lane) {
      97      351926 :     const double speed = lane->getSpeed();
      98      351926 :     if (speed > mySpeed) {
      99      309349 :         mySpeed = speed;
     100      309349 :         myLength = lane->getLength();
     101             :     }
     102      351926 :     mySpeed = speed > mySpeed ? speed : mySpeed;
     103      351926 :     myLanes.push_back(lane);
     104             : 
     105             :     // integrate new allowed classes
     106      351926 :     myCombinedPermissions |= lane->getPermissions();
     107      351926 : }
     108             : 
     109             : 
     110             : void
     111      605308 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
     112      605308 :     if (isInternal()) {
     113             :         // for internal edges after an internal junction,
     114             :         // this is called twice and only the second call counts
     115             :         myFollowingEdges.clear();
     116             :         myFollowingViaEdges.clear();
     117             :     }
     118      605308 :     if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
     119      590225 :         myFollowingEdges.push_back(s);
     120      590225 :         myFollowingViaEdges.push_back(std::make_pair(s, via));
     121      590225 :         if (isTazConnector() && s->getFromJunction() != nullptr) {
     122        2607 :             myBoundary.add(s->getFromJunction()->getPosition());
     123             :         }
     124      590225 :         if (!isInternal()) {
     125      283743 :             s->myApproachingEdges.push_back(this);
     126      283743 :             if (s->isTazConnector() && getToJunction() != nullptr) {
     127        2608 :                 s->myBoundary.add(getToJunction()->getPosition());
     128             :             }
     129             :         }
     130      590225 :         if (via != nullptr) {
     131      138242 :             if (via->myApproachingEdges.size() == 0) {
     132      138242 :                 via->myApproachingEdges.push_back(this);
     133             :             }
     134             :         }
     135             :     }
     136      605308 : }
     137             : 
     138             : 
     139             : void
     140         189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
     141         189 :     myEfforts.add(timeBegin, timeEnd, value);
     142         189 :     myUsingETimeLine = true;
     143         189 : }
     144             : 
     145             : 
     146             : void
     147      250836 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
     148      250836 :     myTravelTimes.add(timeBegin, timeEnd, value);
     149      250836 :     myUsingTTTimeLine = true;
     150      250836 : }
     151             : 
     152             : 
     153             : double
     154           0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
     155           0 :     double ret = 0;
     156           0 :     if (!getStoredEffort(time, ret)) {
     157           0 :         return myLength / MIN2(veh->getMaxSpeed(), mySpeed) + myTimePenalty;
     158             :     }
     159           0 :     return ret;
     160             : }
     161             : 
     162             : 
     163             : double
     164       42845 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
     165             :     assert(this != other);
     166       42845 :     if (doBoundaryEstimate) {
     167        9377 :         return myBoundary.distanceTo2D(other->myBoundary);
     168             :     }
     169             :     if (isTazConnector()) {
     170          88 :         if (other->isTazConnector()) {
     171          79 :             return myBoundary.distanceTo2D(other->myBoundary);
     172             :         }
     173           9 :         return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
     174             :     }
     175       33380 :     if (other->isTazConnector()) {
     176         615 :         return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
     177             :     }
     178       32765 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
     179             :     //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
     180             : }
     181             : 
     182             : 
     183             : bool
     184       26607 : ROEdge::hasLoadedTravelTime(double time) const {
     185       26607 :     return myUsingTTTimeLine && myTravelTimes.describesTime(time);
     186             : }
     187             : 
     188             : 
     189             : double
     190    18062910 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
     191    18062910 :     if (myUsingTTTimeLine) {
     192     8147245 :         if (myTravelTimes.describesTime(time)) {
     193     8136459 :             double lineTT = myTravelTimes.getValue(time);
     194     8136459 :             if (myInterpolate) {
     195             :                 const double inTT = lineTT;
     196          68 :                 const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
     197          68 :                 if (split >= 0) {
     198          18 :                     lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
     199             :                 }
     200             :             }
     201     8136459 :             return MAX2(getMinimumTravelTime(veh), lineTT);
     202             :         } else {
     203       10786 :             if (!myHaveTTWarned) {
     204           6 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
     205           2 :                 myHaveTTWarned = true;
     206             :             }
     207             :         }
     208             :     }
     209     9926451 :     const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * mySpeed) : mySpeed;
     210     9926451 :     return myLength / speed + myTimePenalty;
     211             : }
     212             : 
     213             : 
     214             : double
     215           0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
     216           0 :     double ret = 0;
     217           0 :     if (!edge->getStoredEffort(time, ret)) {
     218           0 :         const double v = MIN2(veh->getMaxSpeed(), edge->mySpeed);
     219           0 :         ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
     220             :     }
     221           0 :     return ret;
     222             : }
     223             : 
     224             : 
     225             : bool
     226        1736 : ROEdge::getStoredEffort(double time, double& ret) const {
     227        1736 :     if (myUsingETimeLine) {
     228         190 :         if (!myEfforts.describesTime(time)) {
     229           0 :             if (!myHaveEWarned) {
     230           0 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
     231           0 :                 myHaveEWarned = true;
     232             :             }
     233           0 :             return false;
     234             :         }
     235         190 :         if (myInterpolate) {
     236           0 :             const double inTT = myTravelTimes.getValue(time);
     237           0 :             const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
     238           0 :             if (ratio >= 0.) {
     239           0 :                 ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
     240           0 :                 return true;
     241             :             }
     242             :         }
     243         190 :         ret = myEfforts.getValue(time);
     244         190 :         return true;
     245             :     }
     246             :     return false;
     247             : }
     248             : 
     249             : 
     250             : int
     251       26040 : ROEdge::getNumSuccessors() const {
     252       26040 :     if (myAmSink) {
     253             :         return 0;
     254             :     }
     255       26040 :     return (int) myFollowingEdges.size();
     256             : }
     257             : 
     258             : 
     259             : int
     260       21918 : ROEdge::getNumPredecessors() const {
     261       21918 :     if (myAmSource) {
     262             :         return 0;
     263             :     }
     264       21918 :     return (int) myApproachingEdges.size();
     265             : }
     266             : 
     267             : 
     268             : const ROEdge*
     269          16 : ROEdge::getNormalBefore() const {
     270             :     const ROEdge* result = this;
     271          40 :     while (result->isInternal()) {
     272             :         assert(myApproachingEdges.size() == 1);
     273          24 :         result = result->myApproachingEdges.front();
     274             :     }
     275          16 :     return result;
     276             : }
     277             : 
     278             : 
     279             : 
     280             : const ROEdge*
     281           8 : ROEdge::getNormalAfter() const {
     282             :     const ROEdge* result = this;
     283          16 :     while (result->isInternal()) {
     284             :         assert(myFollowingEdges.size() == 1);
     285           8 :         result = result->myFollowingEdges.front();
     286             :     }
     287           8 :     return result;
     288             : }
     289             : 
     290             : 
     291             : void
     292        9023 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
     293        9023 :     if (myUsingETimeLine) {
     294         147 :         double value = myLength / mySpeed;
     295         294 :         const SUMOEmissionClass c = PollutantsInterface::getClassByName("unknown");
     296         147 :         if (measure == "CO") {
     297          26 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     298             :         }
     299         147 :         if (measure == "CO2") {
     300          19 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     301             :         }
     302         147 :         if (measure == "HC") {
     303          26 :             value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     304             :         }
     305         147 :         if (measure == "PMx") {
     306          19 :             value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     307             :         }
     308         147 :         if (measure == "NOx") {
     309          19 :             value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     310             :         }
     311         147 :         if (measure == "fuel") {
     312          19 :             value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     313             :         }
     314         147 :         if (measure == "electricity") {
     315           0 :             value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     316             :         }
     317         147 :         myEfforts.fillGaps(value, boundariesOverride);
     318             :     }
     319        9023 :     if (myUsingTTTimeLine) {
     320        6410 :         myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
     321             :     }
     322        9023 : }
     323             : 
     324             : 
     325             : void
     326         224 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
     327         448 :     for (const std::string& key : restrictionKeys) {
     328         224 :         const std::string value = getParameter(key, "1e40");
     329         224 :         myParamRestrictions.push_back(StringUtils::toDouble(value));
     330             :     }
     331         224 : }
     332             : 
     333             : 
     334             : double
     335      114812 : ROEdge::getLengthGeometryFactor() const {
     336      114812 :     return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
     337             : }
     338             : 
     339             : 
     340             : bool
     341      644099 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
     342      644099 :     for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
     343     1288198 :         if (!(*i)->prohibits(vehicle)) {
     344             :             return false;
     345             :         }
     346             :     }
     347             :     return true;
     348             : }
     349             : 
     350             : 
     351             : const ROEdgeVector&
     352        6714 : ROEdge::getAllEdges() {
     353        6714 :     return myEdges;
     354             : }
     355             : 
     356             : 
     357             : const Position
     358        1702 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
     359        1702 :     const double middle = (stop.endPos + stop.startPos) / 2.;
     360        5106 :     const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
     361        1702 :     return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
     362             : }
     363             : 
     364             : 
     365             : const ROEdgeVector&
     366     2355163 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
     367     2355163 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     368     2325279 :         return myFollowingEdges;
     369             :     }
     370             : #ifdef HAVE_FOX
     371       29884 :     FXMutexLock locker(myLock);
     372             : #endif
     373             :     std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
     374       29884 :     if (i != myClassesSuccessorMap.end()) {
     375             :         // can use cached value
     376       26843 :         return i->second;
     377             :     }
     378             :     // this vClass is requested for the first time. rebuild all successors
     379             :     std::set<ROEdge*> followers;
     380        8848 :     for (const ROLane* const lane : myLanes) {
     381        5807 :         if ((lane->getPermissions() & vClass) != 0) {
     382       11824 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     383        7075 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     384        6556 :                     followers.insert(&next.first->getEdge());
     385             :                 }
     386             :             }
     387             :         }
     388             :     }
     389             :     // also add district edges (they are not connected at the lane level
     390       10097 :     for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
     391        7056 :         if ((*it)->isTazConnector()) {
     392             :             followers.insert(*it);
     393             :         }
     394             :     }
     395        3041 :     myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
     396             :                                          followers.begin(), followers.end());
     397        3041 :     return myClassesSuccessorMap[vClass];
     398             : }
     399             : 
     400             : 
     401             : const ROConstEdgePairVector&
     402    12980590 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
     403    12980590 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     404    12117931 :         return myFollowingViaEdges;
     405             :     }
     406             : #ifdef HAVE_FOX
     407      862659 :     FXMutexLock locker(myLock);
     408             : #endif
     409             :     std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
     410      862659 :     if (i != myClassesViaSuccessorMap.end()) {
     411             :         // can use cached value
     412      843651 :         return i->second;
     413             :     }
     414             :     // this vClass is requested for the first time. rebuild all successors
     415             :     std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
     416       52130 :     for (const ROLane* const lane : myLanes) {
     417       33122 :         if ((lane->getPermissions() & vClass) != 0) {
     418       64740 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     419       41181 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     420       36174 :                     followers.insert(std::make_pair(&next.first->getEdge(), next.second));
     421             :                 }
     422             :             }
     423             :         }
     424             :     }
     425             :     // also add district edges (they are not connected at the lane level
     426       64632 :     for (const ROEdge* e : myFollowingEdges) {
     427       45624 :         if (e->isTazConnector()) {
     428         192 :             followers.insert(std::make_pair(e, e));
     429             :         }
     430             :     }
     431       19008 :     myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
     432             :                                             followers.begin(), followers.end());
     433       19008 :     return myClassesViaSuccessorMap[vClass];
     434             : }
     435             : 
     436             : 
     437             : bool
     438      305391 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
     439      305391 :     const ROEdgeVector& followers = getSuccessors(vClass);
     440      305391 :     return std::find(followers.begin(), followers.end(), &e) != followers.end();
     441             : }
     442             : 
     443             : bool
     444           3 : ROEdge::initPriorityFactor(double priorityFactor) {
     445           3 :     myPriorityFactor = priorityFactor;
     446             :     double maxEdgePriority = -std::numeric_limits<double>::max();
     447          57 :     for (ROEdge* edge : myEdges) {
     448          54 :         maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     449          97 :         myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     450             :     }
     451           3 :     myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     452           3 :     if (myEdgePriorityRange == 0) {
     453           1 :         WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
     454           1 :         myPriorityFactor = 0;
     455           1 :         return false;
     456             :     }
     457             :     return true;
     458             : }
     459             : 
     460             : 
     461             : /****************************************************************************/

Generated by: LCOV version 1.14