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