LCOV - code coverage report
Current view: top level - src/libsumo - TrafficLight.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 474 527 89.9 %
Date: 2024-04-27 15:34:54 Functions: 50 56 89.3 %

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

Generated by: LCOV version 1.14