LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSTLLogicControl.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 65.8 % 407 268
Test Date: 2026-03-02 16:00:03 Functions: 81.7 % 60 49

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

Generated by: LCOV version 2.0-1