LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSLaneSpeedTrigger.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 84 116 72.4 %
Date: 2024-05-07 15:28:01 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-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    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         386 : MSLaneSpeedTrigger::MSLaneSpeedTrigger(const std::string& id,
      53             :                                        const std::vector<MSLane*>& destLanes,
      54         386 :                                        const std::string& file) :
      55             :     Named(id),
      56             :     SUMOSAXHandler(file),
      57         386 :     myDestLanes(destLanes),
      58         386 :     myDefaultSpeed(destLanes[0]->getSpeedLimit()),
      59         386 :     myDefaultFriction(destLanes[0]->getFrictionCoefficient()),
      60         386 :     myAmOverriding(false),
      61         386 :     mySpeedOverrideValue(destLanes[0]->getSpeedLimit()),
      62         772 :     myDidInit(false) {
      63         386 :     myInstances[id] = this;
      64         386 :     if (file != "") {
      65         168 :         if (!XMLSubSys::runParser(*this, file)) {
      66           0 :             throw ProcessError();
      67             :         }
      68         168 :         if (!myDidInit) {
      69         168 :             init();
      70             :         }
      71             :     }
      72         386 : }
      73             : 
      74             : 
      75             : void
      76         386 : MSLaneSpeedTrigger::init() {
      77             :     // set the process to the begin
      78         386 :     myCurrentSpeedEntry = myLoadedSpeeds.begin();
      79         386 :     myCurrentFrictionEntry = myLoadedFrictions.begin();
      80             :     // pass previous time steps
      81         386 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
      82         386 :     while (myCurrentSpeedEntry != myLoadedSpeeds.end() && myCurrentSpeedEntry->first < now) {
      83           0 :         processCommand(true, now);
      84             :     }
      85         386 :     while (myCurrentFrictionEntry != myLoadedFrictions.end() && myCurrentFrictionEntry->first < now) {
      86           0 :         executeFrictionChange(now);
      87             :     }
      88             : 
      89             :     // add the processing to the event handler
      90         386 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
      91         309 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
      92         309 :             new WrappingCommand<MSLaneSpeedTrigger>(this, &MSLaneSpeedTrigger::executeSpeedChange),
      93             :             myCurrentSpeedEntry->first);
      94             :     }
      95         386 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
      96          54 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
      97          54 :             new WrappingCommand<MSLaneSpeedTrigger>(this, &MSLaneSpeedTrigger::executeFrictionChange),
      98             :             myCurrentFrictionEntry->first);
      99             :     }
     100         386 :     myDidInit = true;
     101         386 : }
     102             : 
     103             : 
     104         675 : MSLaneSpeedTrigger::~MSLaneSpeedTrigger() {
     105             :     myInstances.erase(getID());
     106         675 : }
     107             : 
     108             : 
     109             : SUMOTime
     110         411 : MSLaneSpeedTrigger::executeSpeedChange(SUMOTime currentTime) {
     111         411 :     return processCommand(true, currentTime);
     112             : }
     113             : 
     114             : 
     115             : SUMOTime
     116         411 : MSLaneSpeedTrigger::processCommand(bool move2next, SUMOTime currentTime) {
     117         411 :     const double speed = getCurrentSpeed();
     118         411 :     const bool altered = speed != myDefaultSpeed;
     119         902 :     for (MSLane* const lane : myDestLanes) {
     120         491 :         lane->setMaxSpeed(speed, altered);
     121             :     }
     122         411 :     if (!move2next) {
     123             :         // changed from the gui
     124             :         return 0;
     125             :     }
     126         411 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
     127             :         ++myCurrentSpeedEntry;
     128             :     }
     129         411 :     if (myCurrentSpeedEntry != myLoadedSpeeds.end()) {
     130         108 :         return myCurrentSpeedEntry->first - currentTime;
     131             :     }
     132             :     return 0;
     133             : }
     134             : 
     135             : 
     136             : SUMOTime
     137          48 : MSLaneSpeedTrigger::executeFrictionChange(SUMOTime currentTime) {
     138          48 :     const double friction = getCurrentFriction();
     139         133 :     for (MSLane* const lane : myDestLanes) {
     140          85 :         lane->setFrictionCoefficient(friction);
     141             :     }
     142          48 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
     143             :         ++myCurrentFrictionEntry;
     144             :     }
     145          48 :     if (myCurrentFrictionEntry != myLoadedFrictions.end()) {
     146           0 :         return myCurrentFrictionEntry->first - currentTime;
     147             :     }
     148             :     return 0;
     149             : }
     150             : 
     151             : 
     152             : void
     153         602 : MSLaneSpeedTrigger::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     154             :     // check whether the correct tag is read
     155         602 :     if (element != SUMO_TAG_STEP) {
     156         173 :         return;
     157             :     }
     158             :     // extract the values
     159         429 :     bool ok = true;
     160         429 :     const SUMOTime next = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME, getID().c_str(), ok);
     161         429 :     double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, getID().c_str(), ok, -1);
     162         429 :     double friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, getID().c_str(), ok, -1);
     163             :     // check the values
     164         429 :     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         429 :     if (speed < 0 && friction < 0) {
     170          54 :         speed = myDefaultSpeed;
     171          54 :         friction = myDefaultFriction;
     172             :     }
     173         429 :     if (speed < 0 && attrs.hasAttribute(SUMO_ATTR_SPEED)) {
     174           0 :         speed = myDefaultSpeed;
     175             :     }
     176         429 :     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         429 :     if (speed >= 0) {
     181         429 :         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         423 :             myLoadedSpeeds.push_back(std::make_pair(next, speed));
     186             :         }
     187             :     }
     188         429 :     if (friction >= 0) {
     189          54 :         myLoadedFrictions.push_back(std::make_pair(next, friction));
     190             :     }
     191             : }
     192             : 
     193             : 
     194             : void
     195         820 : MSLaneSpeedTrigger::myEndElement(int element) {
     196         820 :     if (element == SUMO_TAG_VSS && !myDidInit) {
     197         218 :         init();
     198             :     }
     199         820 : }
     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         411 : MSLaneSpeedTrigger::getCurrentSpeed() const {
     237         411 :     if (myAmOverriding) {
     238           0 :         return mySpeedOverrideValue;
     239             :     } else {
     240         411 :         if (myLoadedSpeeds.empty()) {
     241           0 :             return myDefaultSpeed;
     242             :         }
     243         411 :         const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     244             :         // ok, maybe the first shall not yet be the valid one
     245         411 :         if (myCurrentSpeedEntry == myLoadedSpeeds.begin() && myCurrentSpeedEntry->first > now) {
     246           0 :             return myDefaultSpeed;
     247             :         }
     248             :         // try the loaded
     249         411 :         if (myCurrentSpeedEntry != myLoadedSpeeds.end() && myCurrentSpeedEntry->first <= now) {
     250         411 :             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          48 : MSLaneSpeedTrigger::getCurrentFriction() const {
     262          48 :     if (myLoadedFrictions.empty()) {
     263           0 :         return myDefaultFriction;
     264             :     }
     265          48 :     const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
     266             :     // ok, maybe the first shall not yet be the valid one
     267          48 :     if (myCurrentFrictionEntry == myLoadedFrictions.begin() && myCurrentFrictionEntry->first > now) {
     268           0 :         return myDefaultFriction;
     269             :     }
     270             :     // try the loaded
     271          48 :     if (myCurrentFrictionEntry != myLoadedFrictions.end() && myCurrentFrictionEntry->first <= now) {
     272          48 :         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 1.14