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