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