Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 MSTLLogicControl.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Friedemann Wesner
18 : /// @author Laura Bieker
19 : /// @author Julia Ringel
20 : /// @author Michael Behrisch
21 : /// @author Sascha Krieg
22 : /// @date Sept 2002
23 : ///
24 : // A class that stores and controls tls and switching of their programs
25 : /****************************************************************************/
26 : #include <config.h>
27 :
28 : #include <vector>
29 : #include <algorithm>
30 : #include <cassert>
31 : #include <iterator>
32 : #include "MSTrafficLightLogic.h"
33 : #include "MSSimpleTrafficLightLogic.h"
34 : #include "MSTLLogicControl.h"
35 : #include "MSOffTrafficLightLogic.h"
36 : #include "MSRailSignalConstraint.h"
37 : #include "MSDriveWay.h"
38 : #include <microsim/MSEventControl.h>
39 : #include <microsim/MSNet.h>
40 : #include <utils/common/StringUtils.h>
41 : #include <utils/common/ToString.h>
42 : #include <utils/common/MsgHandler.h>
43 :
44 : #define TRACI_PROGRAM "online"
45 :
46 : // ===========================================================================
47 : // method definitions
48 : // ===========================================================================
49 : /* -------------------------------------------------------------------------
50 : * MSTLLogicControl::TLSLogicVariants - methods
51 : * ----------------------------------------------------------------------- */
52 111735 : MSTLLogicControl::TLSLogicVariants::TLSLogicVariants() :
53 111735 : myCurrentProgram(nullptr),
54 111735 : myDefaultProgram(nullptr) {
55 111735 : }
56 :
57 :
58 111539 : MSTLLogicControl::TLSLogicVariants::~TLSLogicVariants() {
59 : std::map<std::string, MSTrafficLightLogic*>::const_iterator j;
60 232949 : for (const auto& var : myVariants) {
61 121410 : delete var.second;
62 : }
63 115726 : for (OnSwitchAction* osa : mySwitchActions) {
64 4187 : delete osa;
65 : }
66 111539 : }
67 :
68 :
69 : bool
70 110976 : MSTLLogicControl::TLSLogicVariants::checkOriginalTLS() const {
71 : bool hadErrors = false;
72 222063 : for (std::map<std::string, MSTrafficLightLogic*>::const_iterator j = myVariants.begin(); j != myVariants.end(); ++j) {
73 111087 : const MSTrafficLightLogic::Phases& phases = (*j).second->getPhases();
74 111087 : int linkNo = (int)(*j).second->getLinks().size();
75 : bool hadProgramErrors = false;
76 628984 : for (MSTrafficLightLogic::Phases::const_iterator i = phases.begin(); i != phases.end(); ++i) {
77 517897 : if ((int)(*i)->getState().length() < linkNo) {
78 : hadProgramErrors = true;
79 : }
80 : }
81 111087 : if (hadProgramErrors) {
82 0 : WRITE_ERRORF(TL("Mismatching phase size in tls '%', program '%'."), (*j).second->getID(), (*j).first);
83 : hadErrors = true;
84 : }
85 : }
86 110976 : return !hadErrors;
87 : }
88 :
89 :
90 : void
91 110976 : MSTLLogicControl::TLSLogicVariants::saveInitialStates() {
92 110976 : myOriginalLinkStates = myCurrentProgram->collectLinkStates();
93 110976 : }
94 :
95 :
96 : void
97 1647 : MSTLLogicControl::TLSLogicVariants::saveState(OutputDevice& out) {
98 3311 : for (const auto& item : myVariants) {
99 1664 : item.second->saveState(out);
100 : }
101 1647 : }
102 :
103 :
104 : bool
105 121627 : MSTLLogicControl::TLSLogicVariants::addLogic(const std::string& programID,
106 : MSTrafficLightLogic* logic, bool netWasLoaded, bool isNewDefault) {
107 121627 : if (myVariants.find(programID) != myVariants.end()) {
108 0 : delete logic;
109 0 : return false;
110 : }
111 : // assert the links are set
112 121627 : if (netWasLoaded) {
113 : // this one has not yet its links set
114 9781 : if (myCurrentProgram == nullptr) {
115 : const std::string id = logic->getID();
116 0 : delete logic;
117 0 : throw ProcessError(TLF("No initial signal plan loaded for tls '%'.", id));
118 : }
119 9781 : logic->adaptLinkInformationFrom(*myCurrentProgram);
120 9781 : if (logic->getLinks().size() > logic->getPhase(0).getState().size()) {
121 : const std::string id = logic->getID();
122 6 : delete logic;
123 18 : throw ProcessError(TLF("Mismatching phase size in tls '%', program '%'.", id, programID));
124 : }
125 : }
126 : // add to the list of active
127 121621 : if (myVariants.size() == 0 || isNewDefault) {
128 121621 : if (myCurrentProgram != nullptr) {
129 9886 : myCurrentProgram->deactivateProgram();
130 : }
131 121621 : myCurrentProgram = logic;
132 121621 : myCurrentProgram->activateProgram();
133 121621 : if (myVariants.size() == 0) {
134 111735 : myDefaultProgram = logic;
135 : }
136 : }
137 : // add to the list of logic
138 121621 : myVariants[programID] = logic;
139 121621 : if (myVariants.size() == 1 || isNewDefault) {
140 121621 : logic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
141 121621 : executeOnSwitchActions();
142 : }
143 : return true;
144 : }
145 :
146 :
147 : MSTrafficLightLogic*
148 22252 : MSTLLogicControl::TLSLogicVariants::getLogic(const std::string& programID) const {
149 22252 : if (myVariants.find(programID) == myVariants.end()) {
150 : return nullptr;
151 : }
152 2847 : return myVariants.find(programID)->second;
153 : }
154 :
155 :
156 : MSTrafficLightLogic*
157 792 : MSTLLogicControl::TLSLogicVariants::getLogicInstantiatingOff(MSTLLogicControl& tlc, const std::string& programID) {
158 792 : if (myVariants.find(programID) == myVariants.end()) {
159 44 : if (programID == "off") {
160 : // build an off-tll if this switch indicates it
161 41 : MSTrafficLightLogic* tlLogic = new MSOffTrafficLightLogic(tlc, myCurrentProgram->getID());
162 82 : if (!addLogic("off", tlLogic, true, true)) {
163 : // inform the user if this fails
164 0 : throw ProcessError(TLF("Could not build an off-state for tls '%'.", myCurrentProgram->getID()));
165 : }
166 : } else {
167 : // inform the user about a missing logic
168 12 : throw ProcessError(TLF("Can not switch tls '%' to program '%';\n The program is not known.", myCurrentProgram->getID(), programID));
169 : }
170 : }
171 789 : return getLogic(programID);
172 : }
173 :
174 :
175 : void
176 43 : MSTLLogicControl::TLSLogicVariants::setStateInstantiatingOnline(MSTLLogicControl& tlc,
177 : const std::string& state) {
178 : // build only once...
179 43 : MSTrafficLightLogic* logic = getLogic(TRACI_PROGRAM);
180 43 : if (logic == nullptr) {
181 33 : MSPhaseDefinition* phase = new MSPhaseDefinition(SUMOTime_DAY, state);
182 33 : phase->earliestEnd = SUMOTime_DAY; // prevent immediate switch
183 : std::vector<MSPhaseDefinition*> phases;
184 33 : phases.push_back(phase);
185 33 : logic = new MSSimpleTrafficLightLogic(tlc, myCurrentProgram->getID(), TRACI_PROGRAM, 0, TrafficLightType::STATIC, phases, 0,
186 33 : MSNet::getInstance()->getCurrentTimeStep() + DELTA_T,
187 99 : Parameterised::Map());
188 66 : if (addLogic(TRACI_PROGRAM, logic, true, true)) {
189 33 : MSNet::getInstance()->createTLWrapper(logic);
190 : }
191 33 : } else {
192 10 : MSPhaseDefinition nphase(SUMOTime_DAY, state);
193 10 : *(dynamic_cast<MSSimpleTrafficLightLogic*>(logic)->getPhases()[0]) = nphase;
194 10 : switchTo(tlc, TRACI_PROGRAM);
195 10 : }
196 43 : }
197 :
198 :
199 : void
200 4187 : MSTLLogicControl::TLSLogicVariants::addSwitchCommand(OnSwitchAction* c) {
201 4187 : mySwitchActions.push_back(c);
202 4187 : }
203 :
204 :
205 : std::vector<MSTrafficLightLogic*>
206 40806 : MSTLLogicControl::TLSLogicVariants::getAllLogics() const {
207 : std::vector<MSTrafficLightLogic*> ret;
208 : std::map<std::string, MSTrafficLightLogic*>::const_iterator i;
209 87478 : for (i = myVariants.begin(); i != myVariants.end(); ++i) {
210 46672 : ret.push_back((*i).second);
211 : }
212 40806 : return ret;
213 0 : }
214 :
215 :
216 : bool
217 0 : MSTLLogicControl::TLSLogicVariants::isActive(const MSTrafficLightLogic* tl) const {
218 0 : return tl == myCurrentProgram;
219 : }
220 :
221 :
222 : MSTrafficLightLogic*
223 15299251 : MSTLLogicControl::TLSLogicVariants::getActive() const {
224 15299251 : return myCurrentProgram;
225 : }
226 :
227 : MSTrafficLightLogic*
228 21354 : MSTLLogicControl::TLSLogicVariants::getDefault() const {
229 21354 : return myDefaultProgram;
230 : }
231 :
232 :
233 : void
234 504 : MSTLLogicControl::TLSLogicVariants::switchTo(MSTLLogicControl& tlc, const std::string& programID) {
235 : // set the found wished sub-program as this tls' current one
236 504 : const std::string state = myCurrentProgram->getCurrentPhaseDef().getState();
237 504 : myCurrentProgram->deactivateProgram();
238 504 : myCurrentProgram = getLogicInstantiatingOff(tlc, programID);
239 503 : myCurrentProgram->activateProgram();
240 503 : myCurrentProgram->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
241 503 : if (state != myCurrentProgram->getCurrentPhaseDef().getState()) {
242 301 : myCurrentProgram->resetLastSwitch(SIMSTEP);
243 : };
244 503 : executeOnSwitchActions();
245 503 : }
246 :
247 :
248 : void
249 2990903 : MSTLLogicControl::TLSLogicVariants::executeOnSwitchActions() const {
250 3129727 : for (std::vector<OnSwitchAction*>::const_iterator i = mySwitchActions.begin(); i != mySwitchActions.end(); ++i) {
251 138824 : (*i)->execute();
252 : }
253 2990903 : }
254 :
255 :
256 : void
257 865573 : MSTLLogicControl::TLSLogicVariants::addLink(MSLink* link, MSLane* lane, int pos) {
258 1733406 : for (std::map<std::string, MSTrafficLightLogic*>::iterator i = myVariants.begin(); i != myVariants.end(); ++i) {
259 867833 : (*i).second->addLink(link, lane, pos);
260 : }
261 865573 : }
262 :
263 : void
264 944 : MSTLLogicControl::TLSLogicVariants::ignoreLinkIndex(int pos) {
265 1896 : for (std::map<std::string, MSTrafficLightLogic*>::iterator i = myVariants.begin(); i != myVariants.end(); ++i) {
266 952 : (*i).second->ignoreLinkIndex(pos);
267 : }
268 944 : }
269 :
270 :
271 : /* -------------------------------------------------------------------------
272 : * method definitions for the Switching Procedures
273 : * ----------------------------------------------------------------------- */
274 : /* -------------------------------------------------------------------------
275 : * method definitions for WAUTSwitchProcedure
276 : * ----------------------------------------------------------------------- */
277 : bool
278 648 : MSTLLogicControl::WAUTSwitchProcedure::trySwitch(SUMOTime step) {
279 : // switch to the next programm if the GSP is reached
280 648 : if (isPosAtGSP(step, *myFrom)) {
281 : // adapt program's state
282 8 : if (mySwitchSynchron) {
283 0 : adaptLogic(step);
284 : } else {
285 8 : switchToPos(step, *myTo, getGSPTime(*myTo));
286 : }
287 : // switch to destination program
288 8 : return true;
289 : }
290 : // do not switch, yet
291 : return false;
292 : }
293 :
294 :
295 : SUMOTime
296 656 : MSTLLogicControl::WAUTSwitchProcedure::getGSPTime(const MSTrafficLightLogic& logic) const {
297 1312 : return string2time(logic.getParameter("GSP", "0"));
298 : }
299 :
300 :
301 : bool
302 648 : MSTLLogicControl::WAUTSwitchProcedure::isPosAtGSP(SUMOTime currentTime, const MSTrafficLightLogic& logic) {
303 648 : const SUMOTime gspTime = getGSPTime(logic) % logic.getDefaultCycleTime();
304 648 : const SUMOTime programTime = logic.getOffsetFromIndex(logic.getCurrentPhaseIndex()) + logic.getSpentDuration(currentTime);
305 648 : return gspTime == programTime;
306 : }
307 :
308 :
309 : SUMOTime
310 8 : MSTLLogicControl::WAUTSwitchProcedure::getDiffToStartOfPhase(MSTrafficLightLogic& logic, SUMOTime toTime) {
311 8 : int stepOfMyPos = logic.getIndexFromOffset(toTime);
312 8 : SUMOTime startOfPhase = logic.getOffsetFromIndex(stepOfMyPos);
313 : assert(toTime >= startOfPhase);
314 8 : return toTime - startOfPhase;
315 : }
316 :
317 :
318 : void
319 8 : MSTLLogicControl::WAUTSwitchProcedure::switchToPos(SUMOTime simStep, MSTrafficLightLogic& logic, SUMOTime toTime) {
320 8 : int stepTo = logic.getIndexFromOffset(toTime);
321 8 : SUMOTime diff = getDiffToStartOfPhase(logic, toTime);
322 8 : const MSPhaseDefinition& phase = logic.getPhase(stepTo);
323 8 : SUMOTime leftDuration = phase.duration - diff;
324 8 : logic.changeStepAndDuration(myControl, simStep, stepTo, leftDuration);
325 8 : }
326 :
327 :
328 :
329 : /* -------------------------------------------------------------------------
330 : * method definitions for WAUTSwitchProcedure_JustSwitch
331 : * ----------------------------------------------------------------------- */
332 278 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::WAUTSwitchProcedure_JustSwitch(
333 : MSTLLogicControl& control, WAUT& waut,
334 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
335 278 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {}
336 :
337 :
338 556 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::~WAUTSwitchProcedure_JustSwitch() {}
339 :
340 :
341 : bool
342 278 : MSTLLogicControl::WAUTSwitchProcedure_JustSwitch::trySwitch(SUMOTime) {
343 278 : return true;
344 : }
345 :
346 :
347 :
348 : /* -------------------------------------------------------------------------
349 : * method definitions for WAUTSwitchProcedure_GSP
350 : * ----------------------------------------------------------------------- */
351 8 : MSTLLogicControl::WAUTSwitchProcedure_GSP::WAUTSwitchProcedure_GSP(
352 : MSTLLogicControl& control, WAUT& waut,
353 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
354 8 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {}
355 :
356 :
357 16 : MSTLLogicControl::WAUTSwitchProcedure_GSP::~WAUTSwitchProcedure_GSP() {}
358 :
359 :
360 : void
361 0 : MSTLLogicControl::WAUTSwitchProcedure_GSP::adaptLogic(SUMOTime step) {
362 0 : const SUMOTime gspTo = getGSPTime(*myTo) % myTo->getDefaultCycleTime();
363 0 : const SUMOTime currentPosTo = myTo->getOffsetFromIndex(myTo->getCurrentPhaseIndex()) + myTo->getSpentDuration(step);
364 0 : SUMOTime deltaToStretch = gspTo - currentPosTo;
365 0 : if (deltaToStretch < 0) {
366 0 : deltaToStretch += myTo->getDefaultCycleTime();
367 : }
368 0 : const int stepTo = myTo->getIndexFromOffset(gspTo);
369 0 : const SUMOTime newdur = myTo->getPhase(stepTo).duration - getDiffToStartOfPhase(*myTo, gspTo) + deltaToStretch;
370 0 : myTo->changeStepAndDuration(myControl, step, stepTo, newdur);
371 0 : }
372 :
373 :
374 :
375 : /* -------------------------------------------------------------------------
376 : * method definitions for WAUTSwitchProcedure_Stretch
377 : * ----------------------------------------------------------------------- */
378 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::WAUTSwitchProcedure_Stretch(
379 : MSTLLogicControl& control, WAUT& waut,
380 0 : MSTrafficLightLogic* from, MSTrafficLightLogic* to, bool synchron)
381 0 : : MSTLLogicControl::WAUTSwitchProcedure(control, waut, from, to, synchron) {
382 0 : int idx = 1;
383 0 : while (myTo->hasParameter("B" + toString(idx) + ".begin")) {
384 : StretchRange def;
385 0 : def.begin = string2time(myTo->getParameter("B" + toString(idx) + ".begin"));
386 0 : def.end = string2time(myTo->getParameter("B" + toString(idx) + ".end"));
387 0 : def.fac = StringUtils::toDouble(myTo->getParameter("B" + toString(idx) + ".factor"));
388 0 : myStretchRanges.emplace_back(def);
389 : }
390 :
391 0 : }
392 :
393 :
394 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::~WAUTSwitchProcedure_Stretch() {}
395 :
396 :
397 : void
398 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::adaptLogic(SUMOTime step) {
399 0 : SUMOTime gspTo = getGSPTime(*myTo);
400 0 : SUMOTime cycleTime = myTo->getDefaultCycleTime();
401 : // the position, where the logic has to be after synchronisation
402 0 : SUMOTime posAfterSyn = myTo->getPhaseIndexAtTime(step);
403 : // calculate the difference, that has to be equalized
404 : SUMOTime deltaToCut = 0;
405 0 : if (posAfterSyn < gspTo) {
406 0 : deltaToCut = posAfterSyn + cycleTime - gspTo;
407 : } else {
408 0 : deltaToCut = posAfterSyn - gspTo;
409 : }
410 : // test, wheter cutting of the Signalplan is possible
411 : SUMOTime deltaPossible = 0;
412 0 : for (const StretchRange& def : myStretchRanges) {
413 : assert(def.end >= def.begin);
414 0 : deltaPossible += def.end - def.begin;
415 : }
416 0 : int stretchUmlaufAnz = (int) StringUtils::toDouble(myTo->getParameter("StretchUmlaufAnz", ""));
417 0 : deltaPossible = stretchUmlaufAnz * deltaPossible;
418 0 : if ((deltaPossible > deltaToCut) && (deltaToCut < (cycleTime / 2))) {
419 0 : cutLogic(step, gspTo, deltaToCut);
420 : } else {
421 0 : SUMOTime deltaToStretch = (cycleTime - deltaToCut) % cycleTime;
422 0 : stretchLogic(step, gspTo, deltaToStretch);
423 : }
424 0 : }
425 :
426 :
427 : void
428 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::cutLogic(SUMOTime step, SUMOTime startPos, SUMOTime allCutTime) {
429 0 : int actStep = myTo->getIndexFromOffset(startPos);
430 : // switches to startPos and cuts this phase, if there is a "Bereich"
431 : SUMOTime toCut = 0;
432 0 : for (const StretchRange& def : myStretchRanges) {
433 0 : int stepOfBegin = myTo->getIndexFromOffset(def.begin);
434 0 : if (stepOfBegin == actStep) {
435 0 : if (def.begin < startPos) {
436 0 : toCut = def.end - startPos;
437 : } else {
438 0 : toCut = def.end - def.begin;
439 : }
440 : toCut = MIN2(allCutTime, toCut);
441 0 : allCutTime = allCutTime - toCut;
442 : }
443 : }
444 0 : SUMOTime remainingDur = myTo->getPhase(actStep).duration - getDiffToStartOfPhase(*myTo, startPos);
445 0 : SUMOTime newDur = remainingDur - toCut;
446 0 : myTo->changeStepAndDuration(myControl, step, actStep, newDur);
447 :
448 : // changes the duration of all other phases
449 0 : int currStep = (actStep + 1) % (int)myTo->getPhases().size();
450 0 : while (allCutTime > 0) {
451 0 : for (int i = currStep; i < (int) myTo->getPhases().size(); i++) {
452 0 : SUMOTime beginOfPhase = myTo->getOffsetFromIndex(i);
453 0 : SUMOTime durOfPhase = myTo->getPhase(i).duration;
454 0 : SUMOTime endOfPhase = beginOfPhase + durOfPhase;
455 0 : for (const StretchRange& def : myStretchRanges) {
456 0 : if ((beginOfPhase <= def.begin) && (endOfPhase >= def.end)) {
457 0 : SUMOTime maxCutOfPhase = MIN2(def.end - def.begin, allCutTime);
458 0 : allCutTime = allCutTime - maxCutOfPhase;
459 0 : durOfPhase = durOfPhase - maxCutOfPhase;
460 : }
461 : }
462 0 : myTo->addOverridingDuration(durOfPhase);
463 : }
464 : currStep = 0;
465 : }
466 0 : }
467 :
468 : void
469 0 : MSTLLogicControl::WAUTSwitchProcedure_Stretch::stretchLogic(SUMOTime step, SUMOTime startPos, SUMOTime allStretchTime) {
470 0 : int currStep = myTo->getIndexFromOffset(startPos);
471 0 : SUMOTime durOfPhase = myTo->getPhase(currStep).duration;
472 : SUMOTime remainingStretchTime = allStretchTime;
473 : SUMOTime StretchTimeOfPhase = 0;
474 0 : int stretchUmlaufAnz = (int) StringUtils::toDouble(myTo->getParameter("StretchUmlaufAnz", ""));
475 : double facSum = 0;
476 0 : for (const StretchRange& def : myStretchRanges) {
477 0 : facSum += def.fac;
478 : }
479 0 : facSum *= stretchUmlaufAnz;
480 :
481 : //switch to startPos and stretch this phase, if there is a end of "bereich" between startpos and end of phase
482 0 : SUMOTime diffToStart = getDiffToStartOfPhase(*myTo, startPos);
483 0 : for (const StretchRange& def : myStretchRanges) {
484 0 : SUMOTime endOfPhase = (startPos + durOfPhase - diffToStart);
485 0 : if (def.end <= endOfPhase && def.end >= startPos) {
486 0 : double actualfac = def.fac / facSum;
487 0 : facSum = facSum - def.fac;
488 0 : StretchTimeOfPhase = TIME2STEPS(int(STEPS2TIME(remainingStretchTime) * actualfac + 0.5));
489 0 : remainingStretchTime = allStretchTime - StretchTimeOfPhase;
490 : }
491 : }
492 0 : if (facSum == 0) {
493 0 : WRITE_WARNINGF(TL("The computed factor sum in WAUT '%' at time '%' equals zero;\n assuming an error in WAUT definition."), myWAUT.id, toString(STEPS2TIME(step)));
494 0 : return;
495 : }
496 0 : durOfPhase = durOfPhase - diffToStart + StretchTimeOfPhase;
497 0 : myTo->changeStepAndDuration(myControl, step, currStep, durOfPhase);
498 :
499 0 : currStep = (currStep + 1) % (int)myTo->getPhases().size();
500 : // stretch all other phases, if there is a "bereich"
501 0 : while (remainingStretchTime > 0) {
502 0 : for (int i = currStep; i < (int)myTo->getPhases().size() && remainingStretchTime > 0; i++) {
503 0 : durOfPhase = myTo->getPhase(i).duration;
504 0 : SUMOTime beginOfPhase = myTo->getOffsetFromIndex(i);
505 0 : SUMOTime endOfPhase = beginOfPhase + durOfPhase;
506 0 : for (const StretchRange& def : myStretchRanges) {
507 0 : if ((beginOfPhase <= def.end) && (endOfPhase >= def.end)) {
508 0 : double actualfac = def.fac / facSum;
509 0 : StretchTimeOfPhase = TIME2STEPS(int(STEPS2TIME(remainingStretchTime) * actualfac + 0.5));
510 0 : facSum -= def.fac;
511 0 : durOfPhase += StretchTimeOfPhase;
512 0 : remainingStretchTime -= StretchTimeOfPhase;
513 : }
514 : }
515 0 : myTo->addOverridingDuration(durOfPhase);
516 : }
517 : currStep = 0;
518 : }
519 : }
520 :
521 :
522 : /* -------------------------------------------------------------------------
523 : * method definitions for MSTLLogicControl
524 : * ----------------------------------------------------------------------- */
525 41234 : MSTLLogicControl::MSTLLogicControl()
526 41234 : : myNetWasLoaded(false) {}
527 :
528 :
529 40790 : MSTLLogicControl::~MSTLLogicControl() {
530 : // delete tls
531 152329 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
532 111539 : delete (*i).second;
533 : }
534 : // delete WAUTs
535 40962 : for (std::map<std::string, WAUT*>::const_iterator i = myWAUTs.begin(); i != myWAUTs.end(); ++i) {
536 172 : delete (*i).second;
537 : }
538 40790 : }
539 :
540 :
541 : void
542 0 : MSTLLogicControl::setTrafficLightSignals(SUMOTime t) const {
543 0 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
544 0 : (*i).second->getActive()->setTrafficLightSignals(t);
545 : }
546 0 : }
547 :
548 :
549 : std::vector<MSTrafficLightLogic*>
550 17771 : MSTLLogicControl::getAllLogics() const {
551 : std::vector<MSTrafficLightLogic*> ret;
552 : std::map<std::string, TLSLogicVariants*>::const_iterator i;
553 58474 : for (i = myLogics.begin(); i != myLogics.end(); ++i) {
554 40703 : std::vector<MSTrafficLightLogic*> s = (*i).second->getAllLogics();
555 : copy(s.begin(), s.end(), back_inserter(ret));
556 40703 : }
557 17771 : return ret;
558 0 : }
559 :
560 : MSTLLogicControl::TLSLogicVariants&
561 4755701 : MSTLLogicControl::get(const std::string& id) const {
562 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
563 4755701 : if (i == myLogics.end()) {
564 12 : throw InvalidArgument("The tls '" + id + "' is not known.");
565 : }
566 4755697 : return *(*i).second;
567 : }
568 :
569 :
570 : MSTrafficLightLogic*
571 239970 : MSTLLogicControl::get(const std::string& id, const std::string& programID) const {
572 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
573 239970 : if (i == myLogics.end()) {
574 : return nullptr;
575 : }
576 21334 : return (*i).second->getLogic(programID);
577 : }
578 :
579 :
580 : std::vector<std::string>
581 2554 : MSTLLogicControl::getAllTLIds() const {
582 : std::vector<std::string> ret;
583 9425 : for (std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.begin(); i != myLogics.end(); ++i) {
584 6871 : ret.push_back((*i).first);
585 : }
586 2554 : return ret;
587 0 : }
588 :
589 :
590 : bool
591 121414 : MSTLLogicControl::add(const std::string& id, const std::string& programID,
592 : MSTrafficLightLogic* logic, bool newDefault) {
593 : std::map<std::string, TLSLogicVariants*>::iterator it = myLogics.find(id);
594 : TLSLogicVariants* tlmap;
595 121414 : if (it == myLogics.end()) {
596 111735 : tlmap = myLogics[id] = new TLSLogicVariants();
597 : } else {
598 9679 : tlmap = it->second;
599 : }
600 121414 : return tlmap->addLogic(programID, logic, myNetWasLoaded, newDefault);
601 : }
602 :
603 :
604 : bool
605 149463 : MSTLLogicControl::knows(const std::string& id) const {
606 149463 : return myLogics.count(id) != 0;
607 : }
608 :
609 :
610 : bool
611 40768 : MSTLLogicControl::closeNetworkReading() {
612 : bool hadErrors = false;
613 151744 : for (const auto& it : myLogics) {
614 110976 : hadErrors |= !it.second->checkOriginalTLS();
615 110976 : it.second->saveInitialStates();
616 : }
617 40768 : myNetWasLoaded = true;
618 40768 : return !hadErrors;
619 : }
620 :
621 :
622 : bool
623 0 : MSTLLogicControl::isActive(const MSTrafficLightLogic* tl) const {
624 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(tl->getID());
625 0 : if (i == myLogics.end()) {
626 : return false;
627 : }
628 0 : return (*i).second->isActive(tl);
629 : }
630 :
631 :
632 : MSTrafficLightLogic*
633 85846 : MSTLLogicControl::getActive(const std::string& id) const {
634 : std::map<std::string, TLSLogicVariants*>::const_iterator i = myLogics.find(id);
635 85846 : if (i == myLogics.end()) {
636 : return nullptr;
637 : }
638 85846 : return (*i).second->getActive();
639 : }
640 :
641 :
642 : void
643 450 : MSTLLogicControl::switchTo(const std::string& id, const std::string& programID) {
644 : // try to get the tls program definitions
645 : std::map<std::string, TLSLogicVariants*>::iterator i = myLogics.find(id);
646 : // handle problems
647 450 : if (i == myLogics.end()) {
648 0 : throw ProcessError(TLF("Could not switch tls '%' to program '%': No such tls exists.", id, programID));
649 : }
650 450 : (*i).second->switchTo(*this, programID);
651 450 : }
652 :
653 :
654 : void
655 172 : MSTLLogicControl::addWAUT(SUMOTime refTime, const std::string& id,
656 : const std::string& startProg, SUMOTime period) {
657 : // check whether the waut was already defined
658 172 : if (myWAUTs.find(id) != myWAUTs.end()) {
659 : // report an error if so
660 0 : throw InvalidArgument(TLF("Waut '%' was already defined.", id));
661 : }
662 172 : WAUT* w = new WAUT;
663 172 : w->id = id;
664 172 : w->refTime = refTime;
665 172 : w->startProg = startProg;
666 172 : w->period = period;
667 172 : myWAUTs[id] = w;
668 172 : }
669 :
670 :
671 : void
672 346 : MSTLLogicControl::addWAUTSwitch(const std::string& wautid,
673 : SUMOTime when, const std::string& to) {
674 : // try to get the waut
675 346 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
676 : // report an error if the waut is not known
677 0 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
678 : }
679 : // build and save the waut switch definition
680 346 : WAUT* waut = myWAUTs[wautid];
681 : WAUTSwitch s;
682 : s.to = to;
683 346 : s.when = (waut->refTime + when);
684 346 : if (waut->period > 0) {
685 82 : s.when = s.when % waut->period;
686 : }
687 346 : myWAUTs[wautid]->switches.push_back(s);
688 346 : }
689 :
690 :
691 : void
692 170 : MSTLLogicControl::addWAUTJunction(const std::string& wautid,
693 : const std::string& tls,
694 : const std::string& proc,
695 : bool synchron) {
696 : // try to get the waut
697 170 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
698 : // report an error if the waut is not known
699 12 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
700 : }
701 : // try to get the tls to switch
702 166 : if (myLogics.find(tls) == myLogics.end()) {
703 : // report an error if the tls is not known
704 6 : throw InvalidArgument(TLF("TLS '%' to switch in WAUT '%' was not yet defined.", tls, wautid));
705 : }
706 : WAUTJunction j;
707 : j.junction = tls;
708 : j.procedure = proc;
709 164 : j.synchron = synchron;
710 164 : myWAUTs[wautid]->junctions.push_back(j);
711 :
712 164 : std::string initProg = myWAUTs[wautid]->startProg;
713 164 : std::vector<WAUTSwitch>::const_iterator first = myWAUTs[wautid]->switches.end();
714 : SUMOTime minExecTime = -1;
715 506 : for (std::vector<WAUTSwitch>::const_iterator i = myWAUTs[wautid]->switches.begin(); i != myWAUTs[wautid]->switches.end(); ++i) {
716 342 : if ((*i).when > MSNet::getInstance()->getCurrentTimeStep() && (minExecTime == -1 || (*i).when < minExecTime)) {
717 128 : minExecTime = (*i).when;
718 : first = i;
719 : }
720 342 : if (first != myWAUTs[wautid]->switches.begin()) {
721 220 : initProg = (*(first - 1)).to;
722 : }
723 : }
724 : // activate the first one
725 164 : switchTo(tls, initProg);
726 164 : }
727 :
728 :
729 : void
730 168 : MSTLLogicControl::closeWAUT(const std::string& wautid) {
731 : // try to get the waut
732 168 : if (myWAUTs.find(wautid) == myWAUTs.end()) {
733 : // report an error if the waut is not known
734 0 : throw InvalidArgument(TLF("Waut '%' was not yet defined.", wautid));
735 : }
736 168 : WAUT* w = myWAUTs.find(wautid)->second;
737 168 : std::string initProg = myWAUTs[wautid]->startProg;
738 : // get the switch to be performed as first
739 : SUMOTime minExecTime = SUMOTime_MAX;
740 : int firstIndex = -1;
741 : int i = 0;
742 514 : for (const WAUTSwitch& s : w->switches) {
743 346 : if (s.when >= SIMSTEP && s.when < minExecTime) {
744 : minExecTime = s.when;
745 : firstIndex = i;
746 : }
747 346 : i++;
748 : }
749 : // activate the first one
750 168 : if (firstIndex >= 0) {
751 312 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
752 156 : new SwitchInitCommand(*this, wautid, firstIndex), MAX2(SIMSTEP, minExecTime));
753 : }
754 : /*
755 : // set the current program to all junctions
756 : for(std::vector<WAUTJunction>::const_iterator i=w->junctions.begin(); i!=w->junctions.end(); ++i) {
757 : switchTo((*i).junction, initProg);
758 : }
759 : */
760 168 : }
761 :
762 :
763 : SUMOTime
764 288 : MSTLLogicControl::initWautSwitch(MSTLLogicControl::SwitchInitCommand& cmd) {
765 : const std::string& wautid = cmd.getWAUTID();
766 : int& index = cmd.getIndex();
767 288 : WAUT* waut = myWAUTs[wautid];
768 288 : WAUTSwitch s = waut->switches[index];
769 574 : for (std::vector<WAUTJunction>::iterator i = myWAUTs[wautid]->junctions.begin(); i != myWAUTs[wautid]->junctions.end(); ++i) {
770 : // get the current program and the one to instantiate
771 288 : TLSLogicVariants* vars = myLogics.find((*i).junction)->second;
772 288 : MSTrafficLightLogic* from = vars->getActive();
773 288 : MSTrafficLightLogic* to = vars->getLogicInstantiatingOff(*this, s.to);
774 : WAUTSwitchProcedure* proc = nullptr;
775 286 : if ((*i).procedure == "GSP") {
776 8 : proc = new WAUTSwitchProcedure_GSP(*this, *myWAUTs[wautid], from, to, (*i).synchron);
777 278 : } else if ((*i).procedure == "Stretch") {
778 0 : proc = new WAUTSwitchProcedure_Stretch(*this, *myWAUTs[wautid], from, to, (*i).synchron);
779 : } else {
780 278 : proc = new WAUTSwitchProcedure_JustSwitch(*this, *myWAUTs[wautid], from, to, (*i).synchron);
781 : }
782 :
783 : WAUTSwitchProcess p;
784 : p.junction = (*i).junction;
785 286 : p.proc = proc;
786 286 : p.from = from;
787 286 : p.to = to;
788 :
789 286 : myCurrentlySwitched.push_back(p);
790 : }
791 286 : index++;
792 286 : if (index == (int)waut->switches.size()) {
793 154 : if (waut->period <= 0) {
794 : return 0;
795 : } else {
796 52 : index = 0; // start over
797 148 : for (WAUTSwitch& ws : waut->switches) {
798 96 : ws.when += waut->period;
799 : }
800 : }
801 : }
802 184 : return myWAUTs[wautid]->switches[index].when - MSNet::getInstance()->getCurrentTimeStep();
803 : }
804 :
805 :
806 : void
807 57083808 : MSTLLogicControl::check2Switch(SUMOTime step) {
808 57084734 : for (std::vector<WAUTSwitchProcess>::iterator i = myCurrentlySwitched.begin(); i != myCurrentlySwitched.end();) {
809 : const WAUTSwitchProcess& proc = *i;
810 926 : if (proc.proc->trySwitch(step)) {
811 286 : delete proc.proc;
812 : // do not switch away from TraCI control
813 286 : if (getActive(proc.to->getID())->getProgramID() != TRACI_PROGRAM) {
814 286 : switchTo(proc.to->getID(), proc.to->getProgramID());
815 : }
816 286 : i = myCurrentlySwitched.erase(i);
817 : } else {
818 : ++i;
819 : }
820 : }
821 57083808 : }
822 :
823 :
824 : std::pair<SUMOTime, MSPhaseDefinition>
825 0 : MSTLLogicControl::getPhaseDef(const std::string& tlid) const {
826 0 : MSTrafficLightLogic* tl = getActive(tlid);
827 0 : return std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), tl->getCurrentPhaseDef());
828 : }
829 :
830 :
831 : void
832 114 : MSTLLogicControl::switchOffAll() {
833 223 : for (const auto& logic : myLogics) {
834 109 : if (logic.second->getActive()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
835 : // there is no sensible fall-back behavior when switching of rail
836 : // signals so they should ignore tls.all-off
837 10 : continue;
838 : }
839 198 : logic.second->addLogic("off", new MSOffTrafficLightLogic(*this, logic.first), true, true);
840 : }
841 114 : }
842 :
843 :
844 : void
845 479 : MSTLLogicControl::saveState(OutputDevice& out) {
846 479 : MSRailSignalConstraint::saveState(out); // always saves vehicle tracker states
847 2126 : for (const auto& logic : myLogics) {
848 1647 : logic.second->saveState(out);
849 : }
850 479 : MSDriveWay::saveState(out);
851 479 : }
852 :
853 :
854 : void
855 186 : MSTLLogicControl::clearState(SUMOTime time, bool quickReload) {
856 186 : MSRailSignalConstraint::clearState();
857 186 : if (quickReload) {
858 0 : for (const auto& variants : myLogics) {
859 0 : for (auto& logic : variants.second->getAllLogics()) {
860 0 : if (logic->getLogicType() == TrafficLightType::OFF
861 0 : || logic->getLogicType() == TrafficLightType::RAIL_SIGNAL
862 0 : || logic->getLogicType() == TrafficLightType::RAIL_CROSSING) {
863 0 : continue;
864 : }
865 : int step = 0;
866 : const SUMOTime cycleTime = logic->getDefaultCycleTime();
867 0 : auto& phases = logic->getPhases();
868 0 : SUMOTime offset = logic->getOffset();
869 0 : if (offset >= 0) {
870 0 : offset = (time + cycleTime - (offset % cycleTime)) % cycleTime;
871 : } else {
872 0 : offset = (time + ((-offset) % cycleTime)) % cycleTime;
873 : }
874 :
875 0 : while (offset >= phases[step]->duration) {
876 0 : offset -= phases[step]->duration;
877 0 : step++;
878 : }
879 0 : logic->loadState(*this, time, step, offset, logic->isActive());
880 0 : }
881 : }
882 : }
883 186 : }
884 :
885 :
886 : /****************************************************************************/
|