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