LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSLaneSpeedTrigger.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 72.4 % 116 84
Test Date: 2025-12-06 15:35:27 Functions: 73.3 % 15 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    MSLaneSpeedTrigger.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Sascha Krieg
      18              : /// @author  Michael Behrisch
      19              : /// @author  Laura Bieker
      20              : /// @date    Sept 2002
      21              : ///
      22              : // Changes the speed allowed on a set of lanes
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <string>
      27              : #include <utils/common/MsgHandler.h>
      28              : #include <utils/common/WrappingCommand.h>
      29              : #include <utils/xml/SUMOXMLDefinitions.h>
      30              : #include <utils/common/UtilExceptions.h>
      31              : #include <utils/xml/XMLSubSys.h>
      32              : #include <utils/common/StringUtils.h>
      33              : #include <microsim/MSEventControl.h>
      34              : #include <microsim/MSLane.h>
      35              : #include <microsim/MSNet.h>
      36              : #include <microsim/MSEdge.h>
      37              : #include "MSLaneSpeedTrigger.h"
      38              : 
      39              : #include <microsim/MSGlobals.h>
      40              : #include <mesosim/MELoop.h>
      41              : #include <mesosim/MESegment.h>
      42              : 
      43              : 
      44              : // ===========================================================================
      45              : // static members
      46              : // ===========================================================================
      47              : std::map<std::string, MSLaneSpeedTrigger*> MSLaneSpeedTrigger::myInstances;
      48              : 
      49              : // ===========================================================================
      50              : // method definitions
      51              : // ===========================================================================
      52          568 : MSLaneSpeedTrigger::MSLaneSpeedTrigger(const std::string& id,
      53              :                                        const std::vector<MSLane*>& destLanes,
      54          568 :                                        const std::string& file) :
      55              :     Named(id),
      56              :     SUMOSAXHandler(file),
      57          568 :     myDestLanes(destLanes),
      58          568 :     myDefaultSpeed(destLanes[0]->getSpeedLimit()),
      59          568 :     myDefaultFriction(destLanes[0]->getFrictionCoefficient()),
      60          568 :     myAmOverriding(false),
      61          568 :     mySpeedOverrideValue(destLanes[0]->getSpeedLimit()),
      62         1136 :     myDidInit(false) {
      63          568 :     myInstances[id] = this;
      64          568 :     if (file != "") {
      65          168 :         if (!XMLSubSys::runParser(*this, file)) {
      66            0 :             throw ProcessError();
      67              :         }
      68          168 :         if (!myDidInit) {
      69          168 :             init();
      70              :         }
      71              :     }
      72          568 : }
      73              : 
      74              : 
      75              : void
      76          568 : MSLaneSpeedTrigger::init() {
      77              :     // set the process to the begin
      78          568 :     myCurrentSpeedEntry = myLoadedSpeeds.begin();
      79          568 :     myCurrentFrictionEntry = myLoadedFrictions.begin();
      80              :     // pass previous time steps
      81          568 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
      82          568 :     while (myCurrentSpeedEntry != myLoadedSpeeds.end() && myCurrentSpeedEntry->first < now) {
      83            0 :         processCommand(true, now);
      84              :     }
      85          568 :     while (myCurrentFrictionEntry != myLoadedFrictions.end() && myCurrentFrictionEntry->first < now) {
      86            0 :         executeFrictionChange(now);
      87              :     }
      88              : 
      89              :     // add the processing to the event handler
      90          568 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
      91          307 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
      92          307 :             new WrappingCommand<MSLaneSpeedTrigger>(this, &MSLaneSpeedTrigger::executeSpeedChange),
      93              :             myCurrentSpeedEntry->first);
      94              :     }
      95          568 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
      96           52 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
      97           52 :             new WrappingCommand<MSLaneSpeedTrigger>(this, &MSLaneSpeedTrigger::executeFrictionChange),
      98              :             myCurrentFrictionEntry->first);
      99              :     }
     100          568 :     myDidInit = true;
     101          568 : }
     102              : 
     103              : 
     104         1036 : MSLaneSpeedTrigger::~MSLaneSpeedTrigger() {
     105              :     myInstances.erase(getID());
     106         1036 : }
     107              : 
     108              : 
     109              : SUMOTime
     110          408 : MSLaneSpeedTrigger::executeSpeedChange(SUMOTime currentTime) {
     111          408 :     return processCommand(true, currentTime);
     112              : }
     113              : 
     114              : 
     115              : SUMOTime
     116          408 : MSLaneSpeedTrigger::processCommand(bool move2next, SUMOTime currentTime) {
     117          408 :     const double speed = getCurrentSpeed();
     118          408 :     const bool altered = speed != myDefaultSpeed;
     119          893 :     for (MSLane* const lane : myDestLanes) {
     120          485 :         lane->setMaxSpeed(speed, altered);
     121              :     }
     122          408 :     if (!move2next) {
     123              :         // changed from the gui
     124              :         return 0;
     125              :     }
     126          408 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
     127              :         ++myCurrentSpeedEntry;
     128              :     }
     129          408 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
     130          106 :         return myCurrentSpeedEntry->first - currentTime;
     131              :     }
     132              :     return 0;
     133              : }
     134              : 
     135              : 
     136              : SUMOTime
     137           47 : MSLaneSpeedTrigger::executeFrictionChange(SUMOTime currentTime) {
     138           47 :     const double friction = getCurrentFriction();
     139          130 :     for (MSLane* const lane : myDestLanes) {
     140           83 :         lane->setFrictionCoefficient(friction);
     141              :     }
     142           47 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
     143              :         ++myCurrentFrictionEntry;
     144              :     }
     145           47 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
     146            0 :         return myCurrentFrictionEntry->first - currentTime;
     147              :     }
     148              :     return 0;
     149              : }
     150              : 
     151              : 
     152              : void
     153          597 : MSLaneSpeedTrigger::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     154              :     // check whether the correct tag is read
     155          597 :     if (element != SUMO_TAG_STEP) {
     156          173 :         return;
     157              :     }
     158              :     // extract the values
     159          424 :     bool ok = true;
     160          424 :     const SUMOTime next = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME, getID().c_str(), ok);
     161          424 :     double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, getID().c_str(), ok, -1);
     162          424 :     double friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, getID().c_str(), ok, -1);
     163              :     // check the values
     164          424 :     if (next < 0 || (speed > 0 && !myLoadedSpeeds.empty() && myLoadedSpeeds.back().first > next) ||
     165            0 :             (friction > 0 && !myLoadedFrictions.empty() && myLoadedFrictions.back().first > next)) {
     166            0 :         WRITE_ERRORF(TL("Invalid or unsorted time entry in vss '%'."), getID());
     167            0 :         return;
     168              :     }
     169          424 :     if (speed < 0 && friction < 0) {
     170           52 :         speed = myDefaultSpeed;
     171           52 :         friction = myDefaultFriction;
     172              :     }
     173           52 :     if (speed < 0 && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     174            0 :         speed = myDefaultSpeed;
     175              :     }
     176          424 :     if (friction < 0 && attrs.hasAttribute(SUMO_ATTR_FRICTION)) {
     177            0 :         friction = myDefaultFriction;
     178              :     }
     179              :     // set the values for the next step if they are valid
     180          424 :     if (speed >= 0) {
     181          424 :         if (myLoadedSpeeds.size() != 0 && myLoadedSpeeds.back().first == next) {
     182           18 :             WRITE_WARNINGF(TL("Time % was set twice for vss '%'; replacing first entry."), time2string(next), getID());
     183            6 :             myLoadedSpeeds.back().second = speed;
     184              :         } else {
     185          418 :             myLoadedSpeeds.push_back(std::make_pair(next, speed));
     186              :         }
     187              :     }
     188          424 :     if (friction >= 0) {
     189           52 :         myLoadedFrictions.push_back(std::make_pair(next, friction));
     190              :     }
     191              : }
     192              : 
     193              : 
     194              : void
     195          997 : MSLaneSpeedTrigger::myEndElement(int element) {
     196          997 :     if (element == SUMO_TAG_VSS && !myDidInit) {
     197          400 :         init();
     198              :     }
     199          997 : }
     200              : 
     201              : 
     202              : double
     203            0 : MSLaneSpeedTrigger::getDefaultSpeed() const {
     204            0 :     return myDefaultSpeed;
     205              : }
     206              : 
     207              : 
     208              : void
     209            0 : MSLaneSpeedTrigger::setOverriding(bool val) {
     210            0 :     myAmOverriding = val;
     211            0 :     processCommand(false, MSNet::getInstance()->getCurrentTimeStep());
     212            0 : }
     213              : 
     214              : 
     215              : void
     216            0 : MSLaneSpeedTrigger::setOverridingValue(double val) {
     217            0 :     mySpeedOverrideValue = val;
     218            0 :     processCommand(false, MSNet::getInstance()->getCurrentTimeStep());
     219            0 : }
     220              : 
     221              : 
     222              : double
     223            0 : MSLaneSpeedTrigger::getLoadedSpeed() {
     224            0 :     if (myLoadedSpeeds.empty()) {
     225            0 :         return myDefaultSpeed;
     226              :     }
     227            0 :     if (myCurrentSpeedEntry != myLoadedSpeeds.begin()) {
     228            0 :         return (*(myCurrentSpeedEntry - 1)).second;
     229              :     } else {
     230            0 :         return myCurrentSpeedEntry->second;
     231              :     }
     232              : }
     233              : 
     234              : 
     235              : double
     236          408 : MSLaneSpeedTrigger::getCurrentSpeed() const {
     237          408 :     if (myAmOverriding) {
     238            0 :         return mySpeedOverrideValue;
     239              :     } else {
     240          408 :         if (myLoadedSpeeds.empty()) {
     241            0 :             return myDefaultSpeed;
     242              :         }
     243          408 :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     244              :         // ok, maybe the first shall not yet be the valid one
     245          408 :         if (myCurrentSpeedEntry == myLoadedSpeeds.begin() && myCurrentSpeedEntry->first > now) {
     246            0 :             return myDefaultSpeed;
     247              :         }
     248              :         // try the loaded
     249          408 :         if (myCurrentSpeedEntry != myLoadedSpeeds.end() && myCurrentSpeedEntry->first <= now) {
     250          408 :             return myCurrentSpeedEntry->second;
     251              :         } else {
     252              :             // we have run past the end of the loaded steps or the current step is not yet active:
     253              :             // -> use the value of the previous step
     254            0 :             return (*(myCurrentSpeedEntry - 1)).second;
     255              :         }
     256              :     }
     257              : }
     258              : 
     259              : 
     260              : double
     261           47 : MSLaneSpeedTrigger::getCurrentFriction() const {
     262           47 :     if (myLoadedFrictions.empty()) {
     263            0 :         return myDefaultFriction;
     264              :     }
     265           47 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     266              :     // ok, maybe the first shall not yet be the valid one
     267           47 :     if (myCurrentFrictionEntry == myLoadedFrictions.begin() && myCurrentFrictionEntry->first > now) {
     268            0 :         return myDefaultFriction;
     269              :     }
     270              :     // try the loaded
     271           47 :     if (myCurrentFrictionEntry != myLoadedFrictions.end() && myCurrentFrictionEntry->first <= now) {
     272           47 :         return myCurrentFrictionEntry->second;
     273              :     } else {
     274              :         // we have run past the end of the loaded steps or the current step is not yet active:
     275              :         // -> use the value of the previous step
     276            0 :         return (*(myCurrentFrictionEntry - 1)).second;
     277              :     }
     278              : }
     279              : 
     280              : 
     281              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1