LCOV - code coverage report
Current view: top level - src/libsumo - TrafficLight.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 538 487
Test Date: 2025-11-13 15:38:19 Functions: 91.1 % 56 51

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2017-2025 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    TrafficLight.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Mario Krumnow
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @date    30.05.2012
      20              : ///
      21              : // C++ TraCI client API implementation
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <utils/common/StringUtils.h>
      26              : #include <microsim/MSLane.h>
      27              : #include <microsim/MSEdge.h>
      28              : #include <microsim/MSNet.h>
      29              : #include <microsim/MSVehicleControl.h>
      30              : #include <microsim/MSStop.h>
      31              : #include <microsim/transportables/MSTransportable.h>
      32              : #include <microsim/transportables/MSPerson.h>
      33              : #include <microsim/traffic_lights/MSTLLogicControl.h>
      34              : #include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
      35              : #include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>
      36              : #include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
      37              : #include "microsim/traffic_lights/NEMAController.h"
      38              : #include <microsim/traffic_lights/MSRailSignal.h>
      39              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      40              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      41              : #include <netload/NLDetectorBuilder.h>
      42              : #include <libsumo/TraCIConstants.h>
      43              : #include <libsumo/StorageHelper.h>
      44              : #include "Helper.h"
      45              : #include "TrafficLight.h"
      46              : 
      47              : //#define DEBUG_CONSTRAINT_DEADLOCK
      48              : 
      49              : namespace libsumo {
      50              : // ===========================================================================
      51              : // static member initializations
      52              : // ===========================================================================
      53              : SubscriptionResults TrafficLight::mySubscriptionResults;
      54              : ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
      55              : 
      56              : // ===========================================================================
      57              : // static member definitions
      58              : // ===========================================================================
      59              : std::vector<std::string>
      60          957 : TrafficLight::getIDList() {
      61          957 :     return MSNet::getInstance()->getTLSControl().getAllTLIds();
      62              : }
      63              : 
      64              : 
      65              : int
      66           28 : TrafficLight::getIDCount() {
      67           28 :     return (int)getIDList().size();
      68              : }
      69              : 
      70              : 
      71              : std::string
      72          118 : TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
      73          118 :     return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getState();
      74              : }
      75              : 
      76              : 
      77              : std::vector<TraCILogic>
      78          103 : TrafficLight::getAllProgramLogics(const std::string& tlsID) {
      79              :     std::vector<TraCILogic> result;
      80          103 :     const std::vector<MSTrafficLightLogic*> logics = Helper::getTLS(tlsID).getAllLogics();
      81          273 :     for (MSTrafficLightLogic* logic : logics) {
      82          170 :         TraCILogic l(logic->getProgramID(), (int)logic->getLogicType(), logic->getCurrentPhaseIndex());
      83          170 :         l.subParameter = logic->getParametersMap();
      84         1313 :         for (const MSPhaseDefinition* const phase : logic->getPhases()) {
      85         1143 :             l.phases.emplace_back(new TraCIPhase(STEPS2TIME(phase->duration), phase->getState(),
      86         1143 :                                                  STEPS2TIME(phase->minDuration), STEPS2TIME(phase->maxDuration),
      87         2286 :                                                  phase->getNextPhases(), phase->getName()));
      88              :         }
      89          170 :         result.emplace_back(l);
      90          170 :     }
      91          103 :     return result;
      92          103 : }
      93              : 
      94              : 
      95              : std::vector<std::string>
      96            4 : TrafficLight::getControlledJunctions(const std::string& tlsID) {
      97              :     std::set<std::string> junctionIDs;
      98            4 :     const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
      99           44 :     for (const MSTrafficLightLogic::LinkVector& llinks : links) {
     100           80 :         for (const MSLink* l : llinks) {
     101              :             junctionIDs.insert(l->getJunction()->getID());
     102              :         }
     103              :     }
     104            4 :     return std::vector<std::string>(junctionIDs.begin(), junctionIDs.end());
     105              : }
     106              : 
     107              : 
     108              : std::vector<std::string>
     109           52 : TrafficLight::getControlledLanes(const std::string& tlsID) {
     110              :     std::vector<std::string> laneIDs;
     111           52 :     const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
     112          907 :     for (const MSTrafficLightLogic::LaneVector& llanes : lanes) {
     113         1710 :         for (const MSLane* l : llanes) {
     114          855 :             laneIDs.push_back(l->getID());
     115              :         }
     116              :     }
     117           52 :     return laneIDs;
     118            0 : }
     119              : 
     120              : 
     121              : std::vector<std::vector<TraCILink> >
     122           52 : TrafficLight::getControlledLinks(const std::string& tlsID) {
     123              :     std::vector<std::vector<TraCILink> > result;
     124           52 :     const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
     125           52 :     const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
     126          907 :     for (int i = 0; i < (int)lanes.size(); ++i) {
     127              :         std::vector<TraCILink> subList;
     128          855 :         const MSTrafficLightLogic::LaneVector& llanes = lanes[i];
     129              :         const MSTrafficLightLogic::LinkVector& llinks = links[i];
     130              :         // number of links controlled by this signal (signal i)
     131         1710 :         for (int j = 0; j < (int)llanes.size(); ++j) {
     132          855 :             MSLink* link = llinks[j];
     133              :             // approached non-internal lane (if any)
     134         1710 :             const std::string to = link->getLane() != nullptr ? link->getLane()->getID() : "";
     135              :             // approached "via", internal lane (if any)
     136         1086 :             const std::string via = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
     137          855 :             subList.emplace_back(TraCILink(llanes[j]->getID(), via, to));
     138              :         }
     139          855 :         result.emplace_back(subList);
     140          855 :     }
     141           52 :     return result;
     142            0 : }
     143              : 
     144              : 
     145              : std::string
     146          984 : TrafficLight::getProgram(const std::string& tlsID) {
     147          984 :     return Helper::getTLS(tlsID).getActive()->getProgramID();
     148              : }
     149              : 
     150              : 
     151              : int
     152        63296 : TrafficLight::getPhase(const std::string& tlsID) {
     153        63296 :     return Helper::getTLS(tlsID).getActive()->getCurrentPhaseIndex();
     154              : }
     155              : 
     156              : 
     157              : std::string
     158        45220 : TrafficLight::getPhaseName(const std::string& tlsID) {
     159        45220 :     return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getName();
     160              : }
     161              : 
     162              : 
     163              : double
     164           60 : TrafficLight::getPhaseDuration(const std::string& tlsID) {
     165           60 :     return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
     166              : }
     167              : 
     168              : 
     169              : double
     170         1152 : TrafficLight::getNextSwitch(const std::string& tlsID) {
     171         1152 :     return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
     172              : }
     173              : 
     174              : 
     175              : double
     176          933 : TrafficLight::getSpentDuration(const std::string& tlsID) {
     177          933 :     return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getSpentDuration());
     178              : }
     179              : 
     180              : int
     181         3283 : TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
     182         3283 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
     183         3283 :     if (index < 0 || active->getPhaseNumber() <= index) {
     184            0 :         throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
     185            0 :                              + toString(active->getPhaseNumber() - 1) + "].");
     186              :     }
     187              :     // find all crossings which have a green light in that phas
     188              :     int result = 0;
     189              : 
     190         3283 :     const std::string& state = active->getPhases()[index]->getState();
     191        93453 :     for (int i = 0; i < (int)state.size(); i++) {
     192        90170 :         if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
     193        20748 :             for (MSLink* link : active->getLinksAt(i)) {
     194        10374 :                 if (link->getLane()->getEdge().isCrossing()) {
     195              :                     // walking forwards across
     196         2632 :                     for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
     197         1278 :                         if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
     198         1000 :                             result += 1;
     199              :                         }
     200              :                     }
     201              :                     // walking backwards across
     202         1354 :                     MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
     203         2625 :                     for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
     204         1271 :                         if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
     205           38 :                             result += 1;
     206              :                         }
     207              :                     }
     208         9020 :                 } else if (link->getLaneBefore()->getEdge().isCrossing()) {
     209              :                     // walking backwards across (in case both sides are separately controlled)
     210            8 :                     for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
     211            0 :                         if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
     212            0 :                             result += 1;
     213              :                         }
     214              :                     }
     215              :                 }
     216              :             }
     217              :         }
     218              :     }
     219         3283 :     return result;
     220              : }
     221              : 
     222              : std::vector<std::string>
     223         6132 : TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
     224              :     std::vector<std::string> result;
     225              :     // for railsignals we cannot use the "online" program
     226         6132 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     227         6132 :     if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
     228            0 :         throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
     229            0 :                              + toString(active->getNumLinks() - 1) + "].");
     230              :     }
     231         7732 :     for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
     232         1600 :         result.push_back(veh->getID());
     233         6132 :     }
     234         6132 :     return result;
     235            0 : }
     236              : 
     237              : std::vector<std::string>
     238         6122 : TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
     239              :     std::vector<std::string> result;
     240         6122 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     241         6122 :     if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
     242            0 :         throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
     243            0 :                              + toString(active->getNumLinks() - 1) + "].");
     244              :     }
     245         6302 :     for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
     246          180 :         result.push_back(veh->getID());
     247         6122 :     }
     248         6122 :     return result;
     249            0 : }
     250              : 
     251              : std::vector<std::string>
     252         6122 : TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
     253              :     std::vector<std::string> result;
     254         6122 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     255         6122 :     if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
     256            0 :         throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
     257            0 :                              + toString(active->getNumLinks() - 1) + "].");
     258              :     }
     259         6227 :     for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
     260          105 :         result.push_back(veh->getID());
     261         6122 :     }
     262         6122 :     return result;
     263            0 : }
     264              : 
     265              : std::vector<TraCISignalConstraint>
     266         1231 : TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
     267              :     std::vector<TraCISignalConstraint> result;
     268         1231 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     269         1231 :     MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
     270         1231 :     if (s == nullptr) {
     271            0 :         throw TraCIException("'" + tlsID + "' is not a rail signal");
     272              :     }
     273         2203 :     for (auto item : s->getConstraints()) {
     274          972 :         if (tripId != "" && tripId != item.first) {
     275              :             continue;
     276              :         }
     277         1946 :         for (MSRailSignalConstraint* c : item.second) {
     278         1958 :             result.push_back(buildConstraint(tlsID, item.first, c));
     279              :         }
     280              :     }
     281         1231 :     return result;
     282            0 : }
     283              : 
     284              : std::vector<TraCISignalConstraint>
     285           18 : TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
     286              :     // retrieve all constraints that have the given foeSignal (optionally filtered by foeId)
     287              :     // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
     288              :     std::vector<TraCISignalConstraint> result;
     289           78 :     for (const std::string& tlsID : getIDList()) {
     290           60 :         MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     291           60 :         MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
     292           60 :         if (s != nullptr) {
     293           67 :             for (auto item : s->getConstraints()) {
     294           50 :                 for (MSRailSignalConstraint* cand : item.second) {
     295           35 :                     MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
     296           35 :                     if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
     297           70 :                             && (foeId == "" || pc->myTripId == foeId)) {
     298           70 :                         result.push_back(buildConstraint(s->getID(), item.first, pc));
     299              :                     }
     300              :                 }
     301              :             }
     302              :         }
     303           18 :     }
     304           18 :     return result;
     305            0 : }
     306              : 
     307              : 
     308              : void
     309            5 : TrafficLight::addConstraint(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId, const int type, const int limit) {
     310            5 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     311            5 :     MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
     312            5 :     MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
     313            5 :     MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
     314            5 :     if (s == nullptr) {
     315            0 :         throw TraCIException("'" + tlsID + "' is not a rail signal");
     316              :     }
     317            5 :     if (s2 == nullptr) {
     318            0 :         throw TraCIException("'" + foeSignal + "' is not a rail signal");
     319              :     }
     320            5 :     MSRailSignalConstraint* c = new MSRailSignalConstraint_Predecessor((MSRailSignalConstraint::ConstraintType)type, s2, foeId, limit, true);
     321            5 :     s->addConstraint(tripId, c);
     322            5 : }
     323              : 
     324              : 
     325              : std::vector<TraCISignalConstraint>
     326          210 : TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
     327              : #ifdef DEBUG_CONSTRAINT_DEADLOCK
     328              :     std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
     329              : #endif
     330          210 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
     331          210 :     MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
     332          210 :     MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
     333          210 :     MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
     334          210 :     if (s == nullptr) {
     335            0 :         throw TraCIException("'" + tlsID + "' is not a rail signal");
     336              :     }
     337          210 :     if (s2 == nullptr) {
     338            0 :         throw TraCIException("'" + foeSignal + "' is not a rail signal");
     339              :     }
     340              :     MSRailSignalConstraint_Predecessor* c = nullptr;
     341          230 :     for (auto item : s->getConstraints()) {
     342          230 :         if (tripId == item.first) {
     343          225 :             for (MSRailSignalConstraint* cand : item.second) {
     344          225 :                 MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
     345          225 :                 if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
     346              :                     c = pc;
     347              :                     break;
     348              :                 }
     349              :             }
     350              :             break;
     351              :         }
     352              :     }
     353          210 :     if (c != nullptr) {
     354          210 :         const int limit = c->myLimit;
     355              :         // the two constraints are complementary so we actually remove rather than deactivate to avoid redundant conflict information
     356              :         MSRailSignalConstraint::ConstraintType type = c->getSwappedType();
     357          210 :         MSRailSignalConstraint* swapped = new MSRailSignalConstraint_Predecessor(type, s, tripId, limit, true);
     358          210 :         swapped->updateParameters(c->getParametersMap());
     359          210 :         swapParameters(swapped);
     360          210 :         s->removeConstraint(tripId, c);
     361          210 :         s2->addConstraint(foeId, swapped);
     362          210 :         return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
     363              :     } else {
     364            0 :         throw TraCIException("Rail signal '" + tlsID + "' does not have a constraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
     365              :     }
     366              : }
     367              : 
     368              : 
     369              : std::vector<std::pair<std::string, std::string> >
     370          310 : TrafficLight::getSwapParams(int constraintType) {
     371              :     std::vector<std::pair<std::string, std::string> > result({
     372              :         {"vehID", "foeID"},
     373              :         {"line", "foeLine"},
     374         1550 :         {"arrival", "foeArrival"}});
     375              : 
     376          310 :     if (constraintType == MSRailSignalConstraint::ConstraintType::BIDI_PREDECESSOR) {
     377              :         std::vector<std::pair<std::string, std::string> > special({
     378              :             {"busStop", "busStop2"},
     379              :             {"priorStop", "priorStop2"},
     380           75 :             {"stopArrival", "foeStopArrival"}});
     381           15 :         result.insert(result.end(), special.begin(), special.end());
     382           15 :     }
     383          310 :     return result;
     384          325 : }
     385              : 
     386              : 
     387              : void
     388          210 : TrafficLight::swapParameters(MSRailSignalConstraint* c) {
     389              :     // swap parameters that were assigned by generateRailSignalConstraints.py
     390          870 :     for (auto keys : getSwapParams(c->getType())) {
     391          660 :         swapParameters(c, keys.first, keys.second);
     392          210 :     }
     393          210 : }
     394              : 
     395              : void
     396          660 : TrafficLight::swapParameters(MSRailSignalConstraint* c, const std::string& key1, const std::string& key2) {
     397          660 :     const std::string value1 = c->getParameter(key1);
     398         1320 :     const std::string value2 = c->getParameter(key2);
     399          660 :     if (value1 != "") {
     400           70 :         c->setParameter(key2, value1);
     401              :     } else {
     402          590 :         c->unsetParameter(key2);
     403              :     }
     404          660 :     if (value2 != "") {
     405           70 :         c->setParameter(key1, value2);
     406              :     } else {
     407          590 :         c->unsetParameter(key1);
     408              :     }
     409          660 : }
     410              : 
     411              : void
     412          100 : TrafficLight::swapParameters(TraCISignalConstraint& c) {
     413              :     // swap parameters that were assigned by generateRailSignalConstraints.py
     414          415 :     for (auto keys : getSwapParams(c.type)) {
     415          315 :         swapParameters(c, keys.first, keys.second);
     416          100 :     }
     417          100 : }
     418              : 
     419              : void
     420          315 : TrafficLight::swapParameters(TraCISignalConstraint& c, const std::string& key1, const std::string& key2) {
     421              :     auto it1 = c.param.find(key1);
     422              :     auto it2 = c.param.find(key2);
     423          315 :     const std::string value1 = it1 != c.param.end() ? it1->second : "";
     424          350 :     const std::string value2 = it2 != c.param.end() ? it2->second : "";
     425          315 :     if (value1 != "") {
     426           35 :         c.param[key2] = value1;
     427              :     } else {
     428              :         c.param.erase(key2);
     429              :     }
     430          315 :     if (value2 != "") {
     431           35 :         c.param[key1] = value2;
     432              :     } else {
     433              :         c.param.erase(key1);
     434              :     }
     435          315 : }
     436              : 
     437              : 
     438              : void
     439           25 : TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
     440              :     // remove all constraints that have the given foeId
     441              :     // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
     442          125 :     for (const std::string& tlsCand : getIDList()) {
     443          100 :         if (tlsID == "" || tlsCand == tlsID) {
     444           85 :             MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
     445           85 :             MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
     446           85 :             if (s != nullptr) {
     447          150 :                 for (auto item : s->getConstraints()) {
     448           65 :                     if (tripId == "" || item.first == tripId) {
     449          120 :                         for (MSRailSignalConstraint* cand : item.second) {
     450           60 :                             MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
     451              :                             if (pc != nullptr
     452           60 :                                     && (foeId == "" || pc->myTripId == foeId)
     453          115 :                                     && (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
     454           45 :                                 cand->setActive(false);
     455              :                             }
     456              :                         }
     457              :                     }
     458              :                 }
     459              :             }
     460              :         }
     461           25 :     }
     462           25 : }
     463              : 
     464              : 
     465              : void
     466            4 : TrafficLight::updateConstraints(const std::string& vehID, std::string tripId) {
     467              :     // Removes all constraints that can no longer be met because the route of
     468              :     // vehID does not pass the signal involved in the constraint with the given tripId.
     469              :     // This includes constraints on tripId as well as constraints where tripId is the foeId.
     470              : 
     471            4 :     MSBaseVehicle* veh = Helper::getVehicle(vehID);
     472            8 :     std::string curTripId = veh->getParameter().getParameter("tripId", veh->getID());
     473            4 :     tripId = tripId == "" ? curTripId : tripId;
     474              : 
     475              :     // find signals and tripId along the route of veh
     476              :     std::map<const MSRailSignal*, std::set<std::string> > onRoute;
     477            4 :     const ConstMSEdgeVector& route = veh->getRoute().getEdges();
     478            4 :     auto routeIt = veh->getCurrentRouteEdge();
     479           16 :     for (const MSStop& stop : veh->getStops()) {
     480           32 :         for (auto it = routeIt; it < stop.edge; it++) {
     481           20 :             const MSEdge* edge = *it;
     482           20 :             if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     483           12 :                 if (it + 1 != route.end()) {
     484           12 :                     const MSEdge* next = *(it + 1);
     485           12 :                     const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
     486           12 :                     if (link != nullptr && link->getTLLogic() != nullptr) {
     487            8 :                         const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
     488            8 :                         onRoute[s].insert(curTripId);
     489              :                     }
     490              :                 }
     491              :             }
     492              :         }
     493           12 :         if (stop.pars.tripId != "") {
     494              :             curTripId = stop.pars.tripId;
     495              :         }
     496           12 :         routeIt = stop.edge;
     497              :     }
     498            8 :     for (auto it = routeIt; it < route.end(); it++) {
     499            4 :         const MSEdge* edge = *it;
     500            4 :         if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     501            0 :             if (it + 1 != route.end()) {
     502            0 :                 const MSEdge* next = *(it + 1);
     503            0 :                 const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
     504            0 :                 if (link != nullptr && link->getTLLogic() != nullptr) {
     505            0 :                     const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
     506            0 :                     onRoute[s].insert(curTripId);
     507              :                 }
     508              :             }
     509              :         }
     510              :     }
     511              :     //for (auto item : onRoute) {
     512              :     //    std::cout << " s=" << item.first->getID() << " @" << item.first <<  " ids=" << toString(item.second) << "\n";
     513              :     //}
     514              : 
     515              :     // check relevance for all active contraints
     516           28 :     for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
     517              : 
     518              :         // record outdated constraints on and by the vehicle
     519              :         std::vector<MSRailSignalConstraint*> onVeh;
     520              :         std::vector<std::pair<std::string, MSRailSignalConstraint*> > byVeh;
     521              : 
     522           40 :         for (auto item : s->getConstraints()) {
     523           32 :             for (MSRailSignalConstraint* cand : item.second) {
     524           16 :                 MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
     525           16 :                 if (pc != nullptr && !pc->cleared() && pc->isActive()) {
     526           16 :                     if (item.first == tripId) {
     527            8 :                         if (onRoute[s].count(tripId) == 0) {
     528              :                             // constraint on our veh no longer relevant
     529            4 :                             onVeh.push_back(cand);
     530              :                         }
     531            8 :                     } else if (pc->myTripId == tripId) {
     532            8 :                         if (onRoute[pc->myFoeSignal].count(tripId) == 0) {
     533              :                             // constraint by our veh no longer relevant
     534            4 :                             byVeh.push_back(std::make_pair(item.first, cand));
     535              :                         }
     536              :                     }
     537              :                 }
     538              :             }
     539              :         }
     540           28 :         for (MSRailSignalConstraint* c : onVeh) {
     541            4 :             s->removeConstraint(tripId, c);
     542              :         }
     543           28 :         for (auto item : byVeh) {
     544            4 :             s->removeConstraint(item.first, item.second);
     545              :         }
     546           24 :     }
     547            4 : }
     548              : 
     549              : 
     550              : std::vector<TraCISignalConstraint>
     551          249 : TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
     552              :     std::vector<TraCISignalConstraint> result;
     553              :     // find circular constraints (deadlock)
     554              :     // foeId is now constrainted by tripId and assumed to follow tripId on the
     555              :     // same track without possibility of overtaking
     556              :     // we look for a third vehicle foeId2 where
     557              :     // tripId waits for foeId2 and foeId2 waits on foeId
     558              :     std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
     559              :     std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
     560              :     std::set<std::string> foeId2Cands1;
     561              :     std::set<std::string> foeId2Cands2;
     562         1390 :     for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
     563         2247 :         for (auto item : s->getConstraints()) {
     564         1998 :             for (MSRailSignalConstraint* cand : item.second) {
     565          892 :                 MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
     566          892 :                 if (pc != nullptr && !pc->cleared() && pc->isActive()) {
     567          880 :                     if (item.first == tripId) {
     568              :                         // tripId waits for foe2
     569              :                         // @could there by more than one constraint on tripId by this foe2?
     570          150 :                         libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
     571          150 :                         constraintsOnTripId[pc->myTripId] = tsc;
     572              :                         foeId2Cands1.insert(pc->myTripId);
     573          300 :                         for (std::string& futureFoe2Id : getFutureTripIds(pc->myTripId)) {
     574              :                             foeId2Cands1.insert(futureFoe2Id);
     575              :                             //tsc.foeId = futureFoe2Id; // if we do this, the constraint to swap will not be found
     576            0 :                             constraintsOnTripId[futureFoe2Id] = tsc;
     577          150 :                         }
     578          880 :                     } else if (pc->myTripId == foeId) {
     579              :                         // foeId2 waits for foe
     580          126 :                         libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
     581          126 :                         constrainedByFoeId[item.first] = tsc;
     582              :                         foeId2Cands2.insert(item.first);
     583          257 :                         for (std::string& futureTripId : getFutureTripIds(item.first)) {
     584              :                             foeId2Cands2.insert(futureTripId);
     585              :                             //tsc.tripId = futureTripId; // if we do this, the constraint to swap will not be found
     586            5 :                             constrainedByFoeId[futureTripId] = tsc;
     587          126 :                         }
     588          126 :                     }
     589              :                 }
     590              :             }
     591              :         }
     592              :     }
     593              : #ifdef DEBUG_CONSTRAINT_DEADLOCK
     594              :     std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << " tlsID=" << tlsID << "\n";
     595              :     std::cout << "  foeId2Cands1=" << toString(foeId2Cands1) << "\n";
     596              :     std::cout << "  foeId2Cands2=" << toString(foeId2Cands2) << "\n";
     597              : #endif
     598          249 :     if (foeId2Cands1.size() > 0) {
     599              :         // foe2 might be constrained implicitly by foe due to following on the same track
     600              :         // in this case foe must be on the route of foe2 between its current position and foeSignal
     601              : 
     602              :         // we have to check this first because it also affects foeInsertion
     603              :         // constraints if the foe is already inserted but hasn't yet passed the
     604              :         // signal (cleared == false).
     605          125 :         SUMOVehicle* foe = getVehicleByTripId(foeId);
     606          125 :         if (foe != nullptr) {
     607          119 :             const MSEdge* foeEdge = foe->getEdge();
     608          119 :             const double foePos = foe->getPositionOnLane();
     609          222 :             for (const std::string& foeId2 : foeId2Cands1) {
     610              :                 // tripId waits for foeId2
     611          132 :                 SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
     612          132 :                 if (foe2 != nullptr) {
     613          127 :                     const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
     614          127 :                     const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
     615              :                     bool foeAhead = false;
     616          227 :                     for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
     617          186 :                         const MSEdge* e = foe2Route[i];
     618          220 :                         if (e == foeEdge &&
     619           59 :                                 ((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
     620           25 :                                  || (foe->hasDeparted() && !foe2->hasDeparted())
     621           25 :                                  || (!foe->hasDeparted() && !foe2->hasDeparted() &&
     622           25 :                                      (foe->getParameter().depart < foe2->getParameter().depart
     623           15 :                                       || (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
     624              :                                 )) {
     625              :                             foeAhead = true;
     626              : #ifdef DEBUG_CONSTRAINT_DEADLOCK
     627              :                             std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
     628              :                             std::cout << "  foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
     629              :                                       << " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
     630              :                                       //<< " foePos=" << foePos << " foe2Pos=" << foe2->getPositionOnLane()
     631              :                                       << " " << constraintsOnTripId[foeId2].getString() << "\n";
     632              : #endif
     633              :                             break;
     634              :                         }
     635          157 :                         if (e->getToJunction()->getID() == foeSignal
     636          157 :                                 || e->getToJunction()->getID() == c.foeSignal) {
     637              :                             break;
     638              :                         }
     639              :                     }
     640          127 :                     if (foeAhead) {
     641              :                         // foe cannot wait for foe2 (since it's behind). Instead foe2 must wait for tripId
     642              :                         TraCISignalConstraint nc; // constraint after swap
     643           29 :                         nc.tripId = c.foeId;
     644           29 :                         nc.foeId = c.tripId;
     645           29 :                         nc.signalId = c.foeSignal;
     646           29 :                         nc.foeSignal = c.signalId;
     647           29 :                         nc.limit = c.limit;
     648           29 :                         nc.type = c.type;
     649           29 :                         nc.mustWait = true; // ???
     650           29 :                         nc.active = true;
     651              :                         nc.param = c.param;
     652           29 :                         swapParameters(nc);
     653           29 :                         result.push_back(nc);
     654              :                         // let foe wait for foe2
     655           29 :                         std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
     656           29 :                         result.insert(result.end(), result2.begin(), result2.end());
     657              : 
     658              :                         // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
     659           29 :                         const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
     660           29 :                         result.insert(result.end(), result4.begin(), result4.end());
     661              :                         return result;
     662           29 :                     }
     663              :                 }
     664              :             }
     665              :         }
     666              :     }
     667              : 
     668          220 :     if (foeId2Cands2.size() > 0) {
     669              :         // tripId might be constrained implicitly by foe2 due to following on the same track
     670              :         // in this case foe2 must be on the route of tripId between its current position and tlsID
     671              :         // if foe2 then waits for foe, deadlock occurs
     672              : 
     673          101 :         SUMOVehicle* ego = getVehicleByTripId(tripId);
     674          101 :         if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
     675              :             std::set<const MSEdge*> egoToSignal;
     676           16 :             const double egoPos = ego->getPositionOnLane();
     677           16 :             const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
     678           26 :             for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
     679           26 :                 const MSEdge* e = egoRoute[i];
     680              :                 egoToSignal.insert(e);
     681           26 :                 if (e->getToJunction()->getID() == tlsID) {
     682              :                     break;
     683              :                 }
     684              :             }
     685              : 
     686           27 :             for (const std::string& foeId2 : foeId2Cands2) {
     687              :                 // foeId2 waits for foe
     688           16 :                 SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
     689              :                 //std::cout << "  foe2=" << foe2->getID() << " edge=" << foe2->getEdge()->getID() << " egoToSignal=" << toString(egoToSignal) << "\n";
     690           16 :                 if (foe2 != nullptr) {
     691           16 :                     if (egoToSignal.count(foe2->getEdge()) != 0
     692           10 :                             && (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
     693            5 :                         const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
     694              : #ifdef DEBUG_CONSTRAINT_DEADLOCK
     695              :                         std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
     696              :                         std::cout << "  egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
     697              :                                   << " " << c.getString() << "\n";
     698              : #endif
     699              :                         // foe is already waiting for tripId (ego) and should also wait for foeId2
     700              :                         TraCISignalConstraint nc; // constraint after swap
     701            5 :                         nc.tripId = c.foeId;
     702            5 :                         nc.foeId = c.tripId;
     703            5 :                         nc.signalId = c.foeSignal;
     704            5 :                         nc.foeSignal = c.signalId;
     705            5 :                         nc.limit = c.limit;
     706            5 :                         nc.type = c.type;
     707            5 :                         nc.mustWait = true; // ???
     708            5 :                         nc.active = true;
     709              :                         nc.param = c.param;
     710            5 :                         swapParameters(nc);
     711            5 :                         result.push_back(nc);
     712              :                         // let foe wait for foe2
     713            5 :                         std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
     714            5 :                         result.insert(result.end(), result2.begin(), result2.end());
     715              : 
     716              :                         // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
     717            5 :                         const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
     718            5 :                         result.insert(result.end(), result4.begin(), result4.end());
     719              :                         return result;
     720            5 :                     }
     721              :                 }
     722              :             }
     723           85 :         } else if (ego != nullptr) {
     724          237 :             WRITE_WARNINGF(TL("Cannot check for all deadlocks on swapConstraints because the route for vehicle '%' is not computed yet"), ego->getID());
     725              :         }
     726              :     }
     727              : 
     728              :     // find deadlock in explicit constraints
     729              :     std::vector<std::string> foeIds2;
     730          215 :     std::set_intersection(
     731              :         foeId2Cands1.begin(), foeId2Cands1.end(),
     732              :         foeId2Cands2.begin(), foeId2Cands2.end(),
     733              :         std::back_inserter(foeIds2));
     734              : #ifdef DEBUG_CONSTRAINT_DEADLOCK
     735              :     std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
     736              :     for (const std::string& foeId2 : foeIds2) {
     737              :         std::cout << "  deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
     738              :     }
     739              : #endif
     740          215 :     if (foeIds2.size() > 0) {
     741           66 :         TraCISignalConstraint c = constrainedByFoeId[foeIds2.front()];
     742           66 :         if (c.type == MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR) {
     743              :             // avoid swapping insertion constraint
     744           10 :             c = constraintsOnTripId[foeIds2.front()];
     745              :         }
     746              :         TraCISignalConstraint nc; // constraint after swap
     747              :         nc.tripId = c.foeId;
     748              :         nc.foeId = c.tripId;
     749              :         nc.signalId = c.foeSignal;
     750              :         nc.foeSignal = c.signalId;
     751           66 :         nc.limit = c.limit;
     752           66 :         nc.type = c.type;
     753           66 :         nc.mustWait = true; // ???
     754           66 :         nc.active = true;
     755              :         nc.param = c.param;
     756           66 :         swapParameters(nc);
     757           66 :         result.push_back(nc);
     758              :         // let foe wait for foe2
     759           66 :         const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
     760           66 :         result.insert(result.end(), result2.begin(), result2.end());
     761           66 :         if (foeIds2.size() > 1) {
     762              :             // calling swapConstraints once may result in further swaps so we have to recheck for remaining deadlocks anew
     763            5 :             const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
     764            5 :             result.insert(result.end(), result3.begin(), result3.end());
     765            5 :         }
     766           66 :     }
     767              :     return result;
     768          215 : }
     769              : 
     770              : 
     771              : SUMOVehicle*
     772          374 : TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
     773          374 :     MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
     774          795 :     for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
     775          778 :         SUMOVehicle* veh = i->second;
     776         1556 :         if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
     777              :             return veh;
     778              :         }
     779              :     }
     780              :     return nullptr;
     781              : }
     782              : 
     783              : 
     784              : std::vector<std::string>
     785          276 : TrafficLight::getFutureTripIds(const std::string vehID) {
     786              :     std::vector<std::string> result;
     787          276 :     MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(vehID));
     788          255 :     if (veh) {
     789          510 :         std::string tripId = veh->getParameter().getParameter("tripId");
     790          255 :         if (tripId != "") {
     791            0 :             result.push_back(tripId);
     792              :         }
     793          270 :         for (const MSStop& stop : veh->getStops()) {
     794           15 :             if (stop.pars.tripId != "") {
     795            5 :                 result.push_back(stop.pars.tripId);
     796              :             }
     797              :         }
     798              :     }
     799          276 :     return result;
     800            0 : }
     801              : 
     802              : 
     803              : std::string
     804         4998 : TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
     805         4998 :     MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
     806         9996 :     if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
     807            2 :         throw TraCIException("'" + tlsID + "' is not a NEMA controller");
     808              :     }
     809         9994 :     return tll->getParameter(paramName, "");
     810              : }
     811              : 
     812              : 
     813          102 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(TrafficLight)
     814              : 
     815              : 
     816              : void
     817           38 : TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
     818           38 :     Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
     819           38 : }
     820              : 
     821              : 
     822              : void
     823         1663 : TrafficLight::setPhase(const std::string& tlsID, const int index) {
     824         1663 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
     825         1662 :     if (index < 0 || active->getPhaseNumber() <= index) {
     826            4 :         throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
     827            6 :                              + toString(active->getPhaseNumber() - 1) + "].");
     828              :     }
     829         1660 :     const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
     830         1660 :     const SUMOTime duration = active->getPhase(index).duration;
     831         1660 :     active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
     832         1660 : }
     833              : 
     834              : void
     835           14 : TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
     836           14 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
     837           14 :     const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
     838           14 : }
     839              : 
     840              : 
     841              : void
     842           29 : TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
     843              :     try {
     844           29 :         Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
     845            1 :     } catch (ProcessError& e) {
     846            2 :         throw TraCIException(e.what());
     847            1 :     }
     848           28 : }
     849              : 
     850              : 
     851              : void
     852           33 : TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
     853           33 :     MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
     854           33 :     const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
     855           33 :     active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
     856           33 : }
     857              : 
     858              : 
     859              : void
     860           67 : TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
     861           67 :     MSTLLogicControl::TLSLogicVariants& vars = Helper::getTLS(tlsID);
     862              :     // make sure index and phaseNo are consistent
     863           67 :     if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
     864            2 :         throw TraCIException("set program: parameter index must be less than parameter phase number.");
     865              :     }
     866              :     std::vector<MSPhaseDefinition*> phases;
     867          341 :     for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
     868          275 :         MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
     869          275 :         sumoPhase->minDuration = TIME2STEPS(phase->minDur);
     870          275 :         sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
     871          275 :         sumoPhase->nextPhases = phase->next;
     872          275 :         phases.push_back(sumoPhase);
     873              :     }
     874           66 :     if (vars.getLogic(logic.programID) == nullptr) {
     875           41 :         MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
     876           41 :         int step = logic.currentPhaseIndex;
     877           41 :         const std::string basePath = "";
     878              :         MSTrafficLightLogic* tlLogic = nullptr;
     879           41 :         SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
     880           41 :         switch ((TrafficLightType)logic.type) {
     881            9 :             case TrafficLightType::ACTUATED:
     882              :                 tlLogic = new MSActuatedTrafficLightLogic(tlc,
     883              :                         tlsID, logic.programID, 0,
     884              :                         phases, step, nextSwitch,
     885           18 :                         logic.subParameter, basePath);
     886            9 :                 break;
     887            0 :             case TrafficLightType::NEMA:
     888              :                 tlLogic = new NEMALogic(tlc,
     889              :                                         tlsID, logic.programID, 0,
     890              :                                         phases, step, nextSwitch,
     891            0 :                                         logic.subParameter, basePath);
     892              :                 break;
     893            4 :             case TrafficLightType::DELAYBASED:
     894              :                 tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
     895              :                         tlsID, logic.programID, 0,
     896              :                         phases, step, nextSwitch,
     897            4 :                         logic.subParameter, basePath);
     898              :                 break;
     899           28 :             case TrafficLightType::STATIC:
     900              :                 tlLogic = new MSSimpleTrafficLightLogic(tlc,
     901              :                                                         tlsID, logic.programID, 0, TrafficLightType::STATIC,
     902              :                                                         phases, step, nextSwitch,
     903           28 :                                                         logic.subParameter);
     904              :                 break;
     905            0 :             default:
     906            0 :                 throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
     907              :         }
     908              :         try {
     909           41 :             if (!vars.addLogic(logic.programID, tlLogic, true, true)) {
     910            0 :                 throw TraCIException("Could not add traffic light logic '" + logic.programID + "'");
     911              :             }
     912            0 :         } catch (const ProcessError& e) {
     913            0 :             throw TraCIException(e.what());
     914            0 :         }
     915              :         // XXX pass GUIDetectorBuilder when running with gui
     916           82 :         NLDetectorBuilder db(*MSNet::getInstance());
     917           41 :         tlLogic->init(db);
     918           41 :         MSNet::getInstance()->createTLWrapper(tlLogic);
     919              :     } else {
     920           25 :         MSSimpleTrafficLightLogic* tlLogic = static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID));
     921           25 :         tlLogic->setPhases(phases, logic.currentPhaseIndex);
     922           25 :         tlLogic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
     923           25 :         vars.executeOnSwitchActions();
     924              :     }
     925           66 : }
     926              : 
     927              : 
     928              : void
     929          175 : TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
     930          175 :     MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
     931          350 :     if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
     932            8 :         throw TraCIException("'" + tlsID + "' is not a NEMA controller");
     933              :     }
     934          171 :     tll->setParameter(paramName, value);
     935          171 : }
     936              : 
     937          332 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(TrafficLight, TL)
     938              : 
     939              : void
     940            0 : TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
     941            0 :     setParameter(tlsID, "NEMA.splits", toString(splits));
     942            0 : }
     943              : 
     944              : void
     945            2 : TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
     946            4 :     setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
     947            2 : }
     948              : 
     949              : void
     950            0 : TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
     951            0 :     setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
     952            0 : }
     953              : 
     954              : void
     955            0 : TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
     956            0 :     setParameter(tlsID, "NEMA.offset", toString(offset));
     957            0 : }
     958              : 
     959              : 
     960              : libsumo::TraCISignalConstraint
     961         1290 : TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint) {
     962              :     TraCISignalConstraint c;
     963         1290 :     c.tripId = tripId;
     964         1290 :     MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(constraint);
     965         1290 :     if (pc == nullptr) {
     966              :         // unsupported constraint
     967            0 :         c.type = -1;
     968              :     } else {
     969         1290 :         c.signalId = tlsID;
     970         1290 :         c.foeId = pc->myTripId;
     971         1290 :         c.foeSignal = pc->myFoeSignal->getID();
     972         1290 :         c.limit = pc->myLimit;
     973         1290 :         c.type = pc->getType();
     974         1290 :         c.mustWait = !pc->cleared() && pc->isActive();
     975         1290 :         c.active = pc->isActive();
     976         1290 :         c.param = constraint->getParametersMap();
     977              :     }
     978         1290 :     return c;
     979            0 : }
     980              : 
     981              : 
     982              : std::shared_ptr<VariableWrapper>
     983          270 : TrafficLight::makeWrapper() {
     984          270 :     return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
     985              : }
     986              : 
     987              : 
     988              : bool
     989        73683 : TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
     990        73683 :     switch (variable) {
     991          674 :         case TRACI_ID_LIST:
     992          674 :             return wrapper->wrapStringList(objID, variable, getIDList());
     993           22 :         case ID_COUNT:
     994           22 :             return wrapper->wrapInt(objID, variable, getIDCount());
     995           75 :         case TL_RED_YELLOW_GREEN_STATE:
     996          148 :             return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
     997           65 :         case TL_COMPLETE_DEFINITION_RYG:
     998           65 :             return wrapper->wrapLogicVector(objID, variable, getAllProgramLogics(objID));
     999           34 :         case TL_CONTROLLED_LANES:
    1000           34 :             return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
    1001           34 :         case TL_CONTROLLED_LINKS:
    1002           34 :             return wrapper->wrapLinkVectorVector(objID, variable, getControlledLinks(objID));
    1003        34214 :         case TL_CURRENT_PHASE:
    1004        34214 :             return wrapper->wrapInt(objID, variable, getPhase(objID));
    1005        17690 :         case VAR_NAME:
    1006        35380 :             return wrapper->wrapString(objID, variable, getPhaseName(objID));
    1007          596 :         case TL_CURRENT_PROGRAM:
    1008         1192 :             return wrapper->wrapString(objID, variable, getProgram(objID));
    1009           40 :         case TL_PHASE_DURATION:
    1010           40 :             return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
    1011          686 :         case TL_NEXT_SWITCH:
    1012          686 :             return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
    1013          563 :         case TL_SPENT_DURATION:
    1014          563 :             return wrapper->wrapDouble(objID, variable, getSpentDuration(objID));
    1015         1679 :         case VAR_PERSON_NUMBER:
    1016         3358 :             return wrapper->wrapInt(objID, variable, getServedPersonCount(objID, StoHelp::readTypedInt(*paramData)));
    1017         4530 :         case TL_BLOCKING_VEHICLES:
    1018         9060 :             return wrapper->wrapStringList(objID, variable, getBlockingVehicles(objID, StoHelp::readTypedInt(*paramData)));
    1019         4524 :         case TL_RIVAL_VEHICLES:
    1020         9048 :             return wrapper->wrapStringList(objID, variable, getRivalVehicles(objID, StoHelp::readTypedInt(*paramData)));
    1021         4524 :         case TL_PRIORITY_VEHICLES:
    1022         9048 :             return wrapper->wrapStringList(objID, variable, getPriorityVehicles(objID, StoHelp::readTypedInt(*paramData)));
    1023          737 :         case TL_CONSTRAINT:
    1024         1474 :             return wrapper->wrapSignalConstraintVector(objID, variable, getConstraints(objID, StoHelp::readTypedString(*paramData)));
    1025           14 :         case TL_CONSTRAINT_BYFOE:
    1026           28 :             return wrapper->wrapSignalConstraintVector(objID, variable, getConstraintsByFoe(objID, StoHelp::readTypedString(*paramData)));
    1027            2 :         case TL_CONTROLLED_JUNCTIONS:
    1028            2 :             return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
    1029         2857 :         case VAR_PARAMETER:
    1030         5713 :             return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
    1031           47 :         case VAR_PARAMETER_WITH_KEY:
    1032           94 :             return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
    1033              :         default:
    1034              :             return false;
    1035              :     }
    1036              : }
    1037              : }
    1038              : 
    1039              : 
    1040              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1