LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.6 % 224 203
Test Date: 2024-12-21 15:45:41 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-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              : /// @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       478868 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority) :
      58              :     Named(id),
      59       478868 :     myFromJunction(from),
      60       478868 :     myToJunction(to),
      61       478868 :     myIndex(index),
      62       478868 :     myPriority(priority),
      63       478868 :     mySpeed(-1),
      64       478868 :     myLength(0),
      65       478868 :     myAmSink(false),
      66       478868 :     myAmSource(false),
      67       478868 :     myUsingTTTimeLine(false),
      68       478868 :     myUsingETimeLine(false),
      69       478868 :     myCombinedPermissions(0),
      70       478868 :     myOtherTazConnector(nullptr),
      71       478868 :     myTimePenalty(0) {
      72       957736 :     while ((int)myEdges.size() <= index) {
      73       478868 :         myEdges.push_back(0);
      74              :     }
      75       478868 :     myEdges[index] = this;
      76       478868 :     if (from == nullptr && to == nullptr) {
      77              :         // TAZ edge, no lanes
      78        27714 :         myCombinedPermissions = SVCAll;
      79              :     } else {
      80              :         // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
      81       451154 :         myBoundary.add(from->getPosition());
      82       451154 :         myBoundary.add(to->getPosition());
      83              :     }
      84       478868 : }
      85              : 
      86              : 
      87           13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
      88              :     Named(id),
      89           13 :     myFromJunction(const_cast<RONode*>(from)),
      90           13 :     myToJunction(const_cast<RONode*>(to)),
      91           13 :     myIndex(-1),
      92           13 :     myPriority(0),
      93           13 :     mySpeed(std::numeric_limits<double>::max()),
      94           13 :     myLength(0),
      95           13 :     myAmSink(false),
      96           13 :     myAmSource(false),
      97           13 :     myUsingTTTimeLine(false),
      98           13 :     myUsingETimeLine(false),
      99           13 :     myCombinedPermissions(p),
     100           13 :     myOtherTazConnector(nullptr),
     101           13 :     myTimePenalty(0)
     102           13 : { }
     103              : 
     104              : 
     105       941654 : ROEdge::~ROEdge() {
     106      1074094 :     for (ROLane* const lane : myLanes) {
     107       597886 :         delete lane;
     108              :     }
     109       476208 :     delete myReversedRoutingEdge;
     110       476208 :     delete myFlippedRoutingEdge;
     111       476208 :     delete myRailwayRoutingEdge;
     112      1894070 : }
     113              : 
     114              : 
     115              : void
     116       601376 : ROEdge::addLane(ROLane* lane) {
     117       601376 :     const double speed = lane->getSpeed();
     118       601376 :     if (speed > mySpeed) {
     119       451480 :         mySpeed = speed;
     120       451480 :         myLength = lane->getLength();
     121              :     }
     122       601376 :     mySpeed = speed > mySpeed ? speed : mySpeed;
     123       601376 :     myLanes.push_back(lane);
     124              : 
     125              :     // integrate new allowed classes
     126       601376 :     myCombinedPermissions |= lane->getPermissions();
     127       601376 : }
     128              : 
     129              : 
     130              : void
     131      1084485 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
     132      1084485 :     if (isInternal()) {
     133              :         // for internal edges after an internal junction,
     134              :         // this is called twice and only the second call counts
     135              :         myFollowingEdges.clear();
     136              :         myFollowingViaEdges.clear();
     137              :     }
     138      1084485 :     if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
     139      1025553 :         myFollowingEdges.push_back(s);
     140      1025553 :         myFollowingViaEdges.push_back(std::make_pair(s, via));
     141      1025553 :         if (isTazConnector() && s->getFromJunction() != nullptr) {
     142        21842 :             myBoundary.add(s->getFromJunction()->getPosition());
     143              :         }
     144      1025553 :         if (!isInternal()) {
     145       373405 :             s->myApproachingEdges.push_back(this);
     146       373405 :             if (s->isTazConnector() && getToJunction() != nullptr) {
     147        21843 :                 s->myBoundary.add(getToJunction()->getPosition());
     148              :             }
     149              :         }
     150      1025553 :         if (via != nullptr) {
     151       267680 :             if (via->myApproachingEdges.size() == 0) {
     152       267491 :                 via->myApproachingEdges.push_back(this);
     153              :             }
     154              :         }
     155              :     }
     156      1084485 : }
     157              : 
     158              : 
     159              : void
     160          189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
     161          189 :     myEfforts.add(timeBegin, timeEnd, value);
     162          189 :     myUsingETimeLine = true;
     163          189 : }
     164              : 
     165              : 
     166              : void
     167       246881 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
     168       246881 :     myTravelTimes.add(timeBegin, timeEnd, value);
     169       246881 :     myUsingTTTimeLine = true;
     170       246881 : }
     171              : 
     172              : 
     173              : double
     174            0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
     175            0 :     double ret = 0;
     176            0 :     if (!getStoredEffort(time, ret)) {
     177            0 :         return myLength / MIN2(veh->getMaxSpeed(), mySpeed) + myTimePenalty;
     178              :     }
     179            0 :     return ret;
     180              : }
     181              : 
     182              : 
     183              : double
     184        43896 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
     185              :     assert(this != other);
     186        43896 :     if (doBoundaryEstimate) {
     187        10057 :         return myBoundary.distanceTo2D(other->myBoundary);
     188              :     }
     189        33839 :     if (isTazConnector()) {
     190          116 :         if (other->isTazConnector()) {
     191          106 :             return myBoundary.distanceTo2D(other->myBoundary);
     192              :         }
     193           10 :         return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
     194              :     }
     195        33723 :     if (other->isTazConnector()) {
     196          647 :         return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
     197              :     }
     198        33076 :     return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
     199              :     //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
     200              : }
     201              : 
     202              : 
     203              : bool
     204        26659 : ROEdge::hasLoadedTravelTime(double time) const {
     205        26659 :     return myUsingTTTimeLine && myTravelTimes.describesTime(time);
     206              : }
     207              : 
     208              : 
     209              : double
     210     11119965 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
     211     11119965 :     if (myUsingTTTimeLine) {
     212      4311129 :         if (myTravelTimes.describesTime(time)) {
     213      4302071 :             double lineTT = myTravelTimes.getValue(time);
     214      4302071 :             if (myInterpolate) {
     215              :                 const double inTT = lineTT;
     216           68 :                 const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
     217           68 :                 if (split >= 0) {
     218           18 :                     lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
     219              :                 }
     220              :             }
     221      4302071 :             return MAX2(getMinimumTravelTime(veh), lineTT);
     222              :         } else {
     223         9058 :             if (!myHaveTTWarned) {
     224            3 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
     225            1 :                 myHaveTTWarned = true;
     226              :             }
     227              :         }
     228              :     }
     229      6817894 :     const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * mySpeed) : mySpeed;
     230      6817894 :     return myLength / speed + myTimePenalty;
     231              : }
     232              : 
     233              : 
     234              : double
     235            0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
     236            0 :     double ret = 0;
     237            0 :     if (!edge->getStoredEffort(time, ret)) {
     238            0 :         const double v = MIN2(veh->getMaxSpeed(), edge->mySpeed);
     239            0 :         ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
     240              :     }
     241            0 :     return ret;
     242              : }
     243              : 
     244              : 
     245              : bool
     246         1656 : ROEdge::getStoredEffort(double time, double& ret) const {
     247         1656 :     if (myUsingETimeLine) {
     248          190 :         if (!myEfforts.describesTime(time)) {
     249            0 :             if (!myHaveEWarned) {
     250            0 :                 WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
     251            0 :                 myHaveEWarned = true;
     252              :             }
     253            0 :             return false;
     254              :         }
     255          190 :         if (myInterpolate) {
     256            0 :             const double inTT = myTravelTimes.getValue(time);
     257            0 :             const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
     258            0 :             if (ratio >= 0.) {
     259            0 :                 ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
     260            0 :                 return true;
     261              :             }
     262              :         }
     263          190 :         ret = myEfforts.getValue(time);
     264          190 :         return true;
     265              :     }
     266              :     return false;
     267              : }
     268              : 
     269              : 
     270              : int
     271        16484 : ROEdge::getNumSuccessors() const {
     272        16484 :     if (myAmSink) {
     273              :         return 0;
     274              :     }
     275        16484 :     return (int) myFollowingEdges.size();
     276              : }
     277              : 
     278              : 
     279              : int
     280        12362 : ROEdge::getNumPredecessors() const {
     281        12362 :     if (myAmSource) {
     282              :         return 0;
     283              :     }
     284        12362 :     return (int) myApproachingEdges.size();
     285              : }
     286              : 
     287              : 
     288              : const ROEdge*
     289           16 : ROEdge::getNormalBefore() const {
     290              :     const ROEdge* result = this;
     291           40 :     while (result->isInternal()) {
     292              :         assert(myApproachingEdges.size() == 1);
     293           24 :         result = result->myApproachingEdges.front();
     294              :     }
     295           16 :     return result;
     296              : }
     297              : 
     298              : 
     299              : 
     300              : const ROEdge*
     301            8 : ROEdge::getNormalAfter() const {
     302              :     const ROEdge* result = this;
     303           16 :     while (result->isInternal()) {
     304              :         assert(myFollowingEdges.size() == 1);
     305            8 :         result = result->myFollowingEdges.front();
     306              :     }
     307            8 :     return result;
     308              : }
     309              : 
     310              : 
     311              : void
     312         4927 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
     313         4927 :     if (myUsingETimeLine) {
     314          147 :         double value = myLength / mySpeed;
     315          147 :         const SUMOEmissionClass c = PollutantsInterface::getClassByName("unknown");
     316          147 :         if (measure == "CO") {
     317           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     318              :         }
     319          147 :         if (measure == "CO2") {
     320           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     321              :         }
     322          147 :         if (measure == "HC") {
     323           26 :             value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     324              :         }
     325          147 :         if (measure == "PMx") {
     326           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     327              :         }
     328          147 :         if (measure == "NOx") {
     329           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     330              :         }
     331          147 :         if (measure == "fuel") {
     332           19 :             value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     333              :         }
     334          147 :         if (measure == "electricity") {
     335            0 :             value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
     336              :         }
     337          147 :         myEfforts.fillGaps(value, boundariesOverride);
     338              :     }
     339         4927 :     if (myUsingTTTimeLine) {
     340         3542 :         myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
     341              :     }
     342         4927 : }
     343              : 
     344              : 
     345              : void
     346          224 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
     347          448 :     for (const std::string& key : restrictionKeys) {
     348          224 :         const std::string value = getParameter(key, "1e40");
     349          224 :         myParamRestrictions.push_back(StringUtils::toDouble(value));
     350              :     }
     351          224 : }
     352              : 
     353              : 
     354              : double
     355       118409 : ROEdge::getLengthGeometryFactor() const {
     356       118409 :     return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
     357              : }
     358              : 
     359              : 
     360              : bool
     361       326880 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
     362       326880 :     for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
     363       653760 :         if (!(*i)->prohibits(vehicle)) {
     364              :             return false;
     365              :         }
     366              :     }
     367              :     return true;
     368              : }
     369              : 
     370              : 
     371              : const ROEdgeVector&
     372        13355 : ROEdge::getAllEdges() {
     373        13355 :     return myEdges;
     374              : }
     375              : 
     376              : 
     377              : const Position
     378         1371 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
     379         1371 :     const double middle = (stop.endPos + stop.startPos) / 2.;
     380         4113 :     const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
     381         1371 :     return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
     382              : }
     383              : 
     384              : 
     385              : const ROEdgeVector&
     386      1265154 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
     387      1265154 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     388      1242654 :         return myFollowingEdges;
     389              :     }
     390              : #ifdef HAVE_FOX
     391        22500 :     FXMutexLock locker(myLock);
     392              : #endif
     393              :     std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
     394        22500 :     if (i != myClassesSuccessorMap.end()) {
     395              :         // can use cached value
     396        19764 :         return i->second;
     397              :     }
     398              :     // this vClass is requested for the first time. rebuild all successors
     399              :     std::set<ROEdge*> followers;
     400         7516 :     for (const ROLane* const lane : myLanes) {
     401         4780 :         if ((lane->getPermissions() & vClass) != 0) {
     402        10291 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     403         6060 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     404         5703 :                     followers.insert(&next.first->getEdge());
     405              :                 }
     406              :             }
     407              :         }
     408              :     }
     409              :     // also add district edges (they are not connected at the lane level
     410         8603 :     for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
     411         5867 :         if ((*it)->isTazConnector()) {
     412              :             followers.insert(*it);
     413              :         }
     414              :     }
     415         2736 :     myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
     416              :                                          followers.begin(), followers.end());
     417         2736 :     return myClassesSuccessorMap[vClass];
     418              : }
     419              : 
     420              : 
     421              : const ROConstEdgePairVector&
     422      8520976 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
     423      8520976 :     if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
     424      8024822 :         return myFollowingViaEdges;
     425              :     }
     426              : #ifdef HAVE_FOX
     427       496154 :     FXMutexLock locker(myLock);
     428              : #endif
     429              :     std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
     430       496154 :     if (i != myClassesViaSuccessorMap.end()) {
     431              :         // can use cached value
     432       482376 :         return i->second;
     433              :     }
     434              :     // this vClass is requested for the first time. rebuild all successors
     435              :     std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
     436        36024 :     for (const ROLane* const lane : myLanes) {
     437        22246 :         if ((lane->getPermissions() & vClass) != 0) {
     438        44165 :             for (const auto& next : lane->getOutgoingViaLanes()) {
     439        26906 :                 if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
     440        24126 :                     followers.insert(std::make_pair(&next.first->getEdge(), next.second));
     441              :                 }
     442              :             }
     443              :         }
     444              :     }
     445              :     // also add district edges (they are not connected at the lane level
     446        42841 :     for (const ROEdge* e : myFollowingEdges) {
     447        29063 :         if (e->isTazConnector()) {
     448          288 :             followers.insert(std::make_pair(e, e));
     449              :         }
     450              :     }
     451        13778 :     myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
     452              :                                             followers.begin(), followers.end());
     453        13778 :     return myClassesViaSuccessorMap[vClass];
     454              : }
     455              : 
     456              : 
     457              : bool
     458       173693 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
     459       173693 :     const ROEdgeVector& followers = getSuccessors(vClass);
     460       173693 :     return std::find(followers.begin(), followers.end(), &e) != followers.end();
     461              : }
     462              : 
     463              : bool
     464            3 : ROEdge::initPriorityFactor(double priorityFactor) {
     465            3 :     myPriorityFactor = priorityFactor;
     466              :     double maxEdgePriority = -std::numeric_limits<double>::max();
     467           57 :     for (ROEdge* edge : myEdges) {
     468           54 :         maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     469           97 :         myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     470              :     }
     471            3 :     myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     472            3 :     if (myEdgePriorityRange == 0) {
     473            1 :         WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
     474            1 :         myPriorityFactor = 0;
     475            1 :         return false;
     476              :     }
     477              :     return true;
     478              : }
     479              : 
     480              : 
     481              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1