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 : /****************************************************************************/