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