LCOV - code coverage report
Current view: top level - src/libsumo - TrafficLight.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.3 % 524 473
Test Date: 2024-12-21 15:45:41 Functions: 89.3 % 56 50

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

Generated by: LCOV version 2.0-1