LCOV - code coverage report
Current view: top level - src/router - ROEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.9 % 208 185
Test Date: 2024-11-20 15:55:46 Functions: 92.6 % 27 25

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

Generated by: LCOV version 2.0-1