LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSTLLogicControl.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 66.3 % 412 273
Test Date: 2026-03-26 16:31:35 Functions: 82.0 % 61 50

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

Generated by: LCOV version 2.0-1