LCOV - code coverage report
Current view: top level - src/netbuild - NBOwnTLDef.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 731 774 94.4 %
Date: 2024-05-07 15:28:01 Functions: 41 46 89.1 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-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    NBOwnTLDef.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Sascha Krieg
      18             : /// @author  Michael Behrisch
      19             : /// @date    Tue, 29.05.2005
      20             : ///
      21             : // A traffic light logics which must be computed (only nodes/edges are given)
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <vector>
      26             : #include <cassert>
      27             : #include <iterator>
      28             : #include "NBTrafficLightDefinition.h"
      29             : #include "NBNode.h"
      30             : #include "NBOwnTLDef.h"
      31             : #include "NBTrafficLightLogic.h"
      32             : #include <utils/common/MsgHandler.h>
      33             : #include <utils/common/UtilExceptions.h>
      34             : #include <utils/common/ToString.h>
      35             : #include <utils/common/StringUtils.h>
      36             : #include <utils/options/OptionsCont.h>
      37             : #include <utils/options/Option.h>
      38             : 
      39             : #define HEIGH_WEIGHT 2
      40             : #define LOW_WEIGHT .5;
      41             : 
      42             : #define MIN_GREEN_TIME 5
      43             : 
      44             : //#define DEBUG_STREAM_ORDERING
      45             : //#define DEBUG_PHASES
      46             : //#define DEBUG_CONTRELATION
      47             : #define DEBUGID  "C"
      48             : #define DEBUGCOND (getID() == DEBUGID)
      49             : #define DEBUGCOND2(obj) (obj->getID() == DEBUGID)
      50             : //#define DEBUGEDGE(edge) (edge->getID() == "23209153#1" || edge->getID() == "319583927#0")
      51             : //#define DEBUGCOND (true)
      52             : #define DEBUGEDGE(edge) (true)
      53             : 
      54             : // ===========================================================================
      55             : // static members
      56             : // ===========================================================================
      57             : const double NBOwnTLDef::MIN_SPEED_CROSSING_TIME(25 / 3.6);
      58             : 
      59             : 
      60             : // ===========================================================================
      61             : // member method definitions
      62             : // ===========================================================================
      63         184 : NBOwnTLDef::NBOwnTLDef(const std::string& id,
      64             :                        const std::vector<NBNode*>& junctions, SUMOTime offset,
      65         184 :                        TrafficLightType type) :
      66             :     NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
      67         184 :     myHaveSinglePhase(false),
      68         184 :     myLayout(TrafficLightLayout::DEFAULT) {
      69         184 : }
      70             : 
      71             : 
      72        7251 : NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
      73        7251 :                        TrafficLightType type) :
      74             :     NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
      75        7251 :     myHaveSinglePhase(false),
      76        7251 :     myLayout(TrafficLightLayout::DEFAULT) {
      77        7251 : }
      78             : 
      79             : 
      80           0 : NBOwnTLDef::NBOwnTLDef(const std::string& id, SUMOTime offset,
      81           0 :                        TrafficLightType type) :
      82             :     NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
      83           0 :     myHaveSinglePhase(false),
      84           0 :     myLayout(TrafficLightLayout::DEFAULT) {
      85           0 : }
      86             : 
      87             : 
      88       12101 : NBOwnTLDef::~NBOwnTLDef() {}
      89             : 
      90             : 
      91             : int
      92       11616 : NBOwnTLDef::getToPrio(const NBEdge* const e) {
      93       11616 :     return e->getJunctionPriority(e->getToNode());
      94             : }
      95             : 
      96             : 
      97             : double
      98      132846 : NBOwnTLDef::getDirectionalWeight(LinkDirection dir) {
      99      132846 :     switch (dir) {
     100             :         case LinkDirection::STRAIGHT:
     101             :         case LinkDirection::PARTLEFT:
     102             :         case LinkDirection::PARTRIGHT:
     103             :             return HEIGH_WEIGHT;
     104       62731 :         case LinkDirection::LEFT:
     105             :         case LinkDirection::RIGHT:
     106       62731 :             return LOW_WEIGHT;
     107             :         default:
     108             :             break;
     109             :     }
     110         100 :     return 0;
     111             : }
     112             : 
     113             : double
     114        8086 : NBOwnTLDef::computeUnblockedWeightedStreamNumber(const NBEdge* const e1, const NBEdge* const e2) {
     115             :     double val = 0;
     116       23214 :     for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
     117       15128 :         std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
     118       46299 :         for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
     119       31171 :             std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
     120       84471 :             for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
     121       53300 :                 if (e1->getTurnDestination() == (*e1c).toEdge) {
     122        6802 :                     continue;
     123             :                 }
     124      136745 :                 for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
     125       90247 :                     if (e2->getTurnDestination() == (*e2c).toEdge) {
     126       14282 :                         continue;
     127             :                     }
     128       75965 :                     const double sign = (forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)
     129       75965 :                                          || forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge, true)) ? -1 : 1;
     130             :                     double w1;
     131             :                     double w2;
     132       75965 :                     const int prio1 = e1->getJunctionPriority(e1->getToNode());
     133       75965 :                     const int prio2 = e2->getJunctionPriority(e2->getToNode());
     134       75965 :                     if (prio1 == prio2) {
     135       66423 :                         w1 = getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
     136       66423 :                         w2 = getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
     137             :                     } else {
     138        9542 :                         if (prio1 > prio2) {
     139             :                             w1 = HEIGH_WEIGHT;
     140             :                             w2 = LOW_WEIGHT;
     141             :                         } else {
     142             :                             w1 = LOW_WEIGHT;
     143             :                             w2 = HEIGH_WEIGHT;
     144             :                         }
     145        9542 :                         if (sign == -1) {
     146             :                             // extra penalty if edges with different junction priority are in conflict
     147        5885 :                             w1 *= 2;
     148        5885 :                             w2 *= 2;
     149             :                         }
     150             :                     }
     151       75965 :                     if (isRailway(e1->getPermissions()) != isRailway(e2->getPermissions())) {
     152        4670 :                         w1 *= 0.1;
     153        4670 :                         w2 *= 0.1;
     154             :                     }
     155       75965 :                     if ((e1->getPermissions() & SVC_PASSENGER) == 0) {
     156        8580 :                         w1 *= 0.1;
     157             :                     }
     158       75965 :                     if ((e2->getPermissions() & SVC_PASSENGER) == 0) {
     159        7550 :                         w2 *= 0.1;
     160             :                     }
     161       75965 :                     val += sign * w1;
     162       75965 :                     val += sign * w2;
     163             : #ifdef DEBUG_STREAM_ORDERING
     164             :                     if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
     165             :                         std::cout << "      sign=" << sign << " w1=" << w1 << " w2=" << w2 << " val=" << val
     166             :                                   << " c1=" << (*e1c).getDescription(e1)
     167             :                                   << " c2=" << (*e2c).getDescription(e2)
     168             :                                   << "\n";
     169             :                     }
     170             : #endif
     171             :                 }
     172             :             }
     173       31171 :         }
     174       15128 :     }
     175             : #ifdef DEBUG_STREAM_ORDERING
     176             :     if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
     177             :         std::cout << "     computeUnblockedWeightedStreamNumber e1=" << e1->getID() << " e2=" << e2->getID() << " val=" << val << "\n";
     178             :     }
     179             : #endif
     180        8086 :     return val;
     181             : }
     182             : 
     183             : 
     184             : std::pair<NBEdge*, NBEdge*>
     185        4397 : NBOwnTLDef::getBestCombination(const EdgeVector& edges) {
     186             :     std::pair<NBEdge*, NBEdge*> bestPair(static_cast<NBEdge*>(nullptr), static_cast<NBEdge*>(nullptr));
     187             :     double bestValue = -std::numeric_limits<double>::max();
     188       14549 :     for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     189       18238 :         for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
     190        8086 :             const double value = computeUnblockedWeightedStreamNumber(*i, *j);
     191        8086 :             if (value > bestValue) {
     192             :                 bestValue = value;
     193             :                 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     194        2629 :             } else if (value == bestValue) {
     195         446 :                 const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
     196         446 :                 const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
     197         446 :                 if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
     198          16 :                     if (bestPair.first->getID() < (*i)->getID()) {
     199             :                         bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     200             :                     }
     201         430 :                 } else if (oa < ca) {
     202             :                     bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     203             :                 }
     204             :             }
     205             :         }
     206             :     }
     207        4397 :     if (bestValue <= 0) {
     208             :         // do not group edges
     209         571 :         if (bestPair.first->getPriority() < bestPair.second->getPriority()) {
     210             :             std::swap(bestPair.first, bestPair.second);
     211             :         }
     212             :         bestPair.second = nullptr;
     213             :     }
     214             : #ifdef DEBUG_STREAM_ORDERING
     215             :     if (DEBUGCOND) {
     216             :         std::cout << "   getBestCombination bestValue=" << bestValue << "  best=" << Named::getIDSecure(bestPair.first) << ", " << Named::getIDSecure(bestPair.second) << "\n";
     217             :     }
     218             : #endif
     219        4397 :     return bestPair;
     220             : }
     221             : 
     222             : 
     223             : std::pair<NBEdge*, NBEdge*>
     224        6010 : NBOwnTLDef::getBestPair(EdgeVector& incoming) {
     225        6010 :     if (incoming.size() == 1) {
     226             :         // only one there - return the one
     227             :         std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(), static_cast<NBEdge*>(nullptr));
     228             :         incoming.clear();
     229        1613 :         return ret;
     230             :     }
     231             :     // determine the best combination
     232             :     //  by priority, first
     233             :     EdgeVector used;
     234        4397 :     std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
     235        4397 :     used.push_back(*incoming.begin()); // the first will definitely be used
     236             :     // get the ones with the same priority
     237        4397 :     int prio = getToPrio(*used.begin());
     238        9024 :     for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
     239        4627 :         used.push_back(*i);
     240             :     }
     241             :     //  if there only lower priorised, use these, too
     242        4397 :     if (used.size() < 2) {
     243         584 :         used = incoming;
     244             :     }
     245        4397 :     std::pair<NBEdge*, NBEdge*> ret = getBestCombination(used);
     246             : #ifdef DEBUG_STREAM_ORDERING
     247             :     if (DEBUGCOND) {
     248             :         std::cout << "getBestPair tls=" << getID() << " incoming=" << toString(incoming) << " prio=" << prio << " used=" << toString(used) << " best=" << Named::getIDSecure(ret.first) << ", " << Named::getIDSecure(ret.second) << "\n";
     249             :     }
     250             : #endif
     251             : 
     252        4397 :     incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
     253        4397 :     if (ret.second != nullptr) {
     254        3826 :         incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
     255             :     }
     256        4397 :     return ret;
     257             : }
     258             : 
     259             : bool
     260       12909 : NBOwnTLDef::hasStraightConnection(const NBEdge* fromEdge) {
     261       22794 :     for (const NBEdge::Connection& c : fromEdge->getConnections()) {
     262       19956 :         LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, c.toEdge);
     263       19956 :         if (dir == LinkDirection::STRAIGHT) {
     264             :             return true;
     265             :         }
     266             :     }
     267             :     return false;
     268             : }
     269             : 
     270             : NBTrafficLightLogic*
     271        2629 : NBOwnTLDef::myCompute(int brakingTimeSeconds) {
     272        2629 :     return computeLogicAndConts(brakingTimeSeconds);
     273             : }
     274             : 
     275             : 
     276             : NBTrafficLightLogic*
     277        3457 : NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
     278        3457 :     if (myControlledNodes.size() == 1) {
     279             :         // otherwise, use values from previous call to initNeedsContRelation
     280             :         myNeedsContRelation.clear();
     281             :     }
     282             :     myRightOnRedConflicts.clear();
     283        3457 :     const bool isNEMA = myType == TrafficLightType::NEMA;
     284        3457 :     const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
     285        6914 :     const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
     286        3728 :     const SUMOTime minMinDur = (myType == TrafficLightType::STATIC) ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
     287        3728 :     const SUMOTime maxDur = (myType == TrafficLightType::STATIC) ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
     288        3457 :     const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
     289             :     const SUMOTime latestEnd = UNSPECIFIED_DURATION;
     290             : 
     291             :     // things collect for NEMA phase building
     292             :     std::vector<std::pair<NBEdge*, NBEdge*> > chosenList;
     293             :     std::vector<std::string> straightStates;
     294             :     std::vector<std::string> leftStates;
     295             : 
     296             :     // build complete lists first
     297        3457 :     const EdgeVector& incoming = getIncomingEdges();
     298             :     EdgeVector fromEdges, toEdges;
     299             :     std::vector<bool> isTurnaround;
     300             :     std::vector<bool> hasTurnLane;
     301             :     std::vector<int> fromLanes;
     302             :     std::vector<int> toLanes;
     303             :     std::vector<SUMOTime> crossingTime;
     304             :     int totalNumLinks = 0;
     305       16366 :     for (NBEdge* const fromEdge : incoming) {
     306             :         const int numLanes = fromEdge->getNumLanes();
     307       12909 :         const bool edgeHasStraight = hasStraightConnection(fromEdge);
     308       37410 :         for (int i2 = 0; i2 < numLanes; i2++) {
     309             :             bool hasLeft = false;
     310             :             bool hasPartLeft = false;
     311             :             bool hasStraight = false;
     312             :             bool hasRight = false;
     313             :             bool hasTurnaround = false;
     314       64308 :             for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     315       39807 :                 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     316          26 :                     continue;
     317             :                 }
     318       39781 :                 fromEdges.push_back(fromEdge);
     319       39781 :                 fromLanes.push_back(i2);
     320       39781 :                 toLanes.push_back(approached.toLane);
     321       39781 :                 toEdges.push_back(approached.toEdge);
     322       16112 :                 if (approached.vmax < NUMERICAL_EPS || (fromEdge->getPermissions() & SVC_PASSENGER) == 0
     323       54982 :                         || (approached.toEdge->getPermissions() & SVC_PASSENGER) == 0) {
     324       24956 :                     crossingTime.push_back(0);
     325             :                 } else {
     326       18718 :                     crossingTime.push_back(TIME2STEPS((approached.length + approached.viaLength) / MAX2(approached.vmax, MIN_SPEED_CROSSING_TIME)));
     327             :                 }
     328             :                 // std::cout << fromEdge->getID() << " " << approached.toEdge->getID() << " " << (fromEdge->getPermissions() & SVC_PASSENGER) << " " << approached.length << " " << approached.viaLength << " " << approached.vmax << " " << crossingTime.back() << std::endl;
     329       39781 :                 if (approached.toEdge != nullptr) {
     330       39781 :                     isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
     331             :                 } else {
     332           0 :                     isTurnaround.push_back(true);
     333             :                 }
     334       39781 :                 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
     335             :                 if (dir == LinkDirection::STRAIGHT) {
     336             :                     hasStraight = true;
     337             :                 } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
     338             :                     hasRight = true;
     339             :                 } else if (dir == LinkDirection::LEFT) {
     340             :                     hasLeft = true;
     341             :                 } else if (dir == LinkDirection::PARTLEFT) {
     342             :                     hasPartLeft = true;
     343             :                 } else if (dir == LinkDirection::TURN) {
     344             :                     hasTurnaround = true;
     345             :                 }
     346       39781 :                 totalNumLinks++;
     347       24501 :             }
     348       64308 :             for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     349       39807 :                 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     350          26 :                     continue;
     351             :                 }
     352       39781 :                 hasTurnLane.push_back(
     353             :                     (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
     354       19329 :                     || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
     355       35997 :                     || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
     356       75422 :                     || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
     357       24501 :             }
     358             :             //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
     359             :         }
     360             :     }
     361             :     // collect crossings
     362             :     std::vector<NBNode::Crossing*> crossings;
     363        7352 :     for (NBNode* const node : myControlledNodes) {
     364        3895 :         const std::vector<NBNode::Crossing*>& c = node->getCrossings();
     365        3895 :         if (!onlyConts) {
     366             :             // set tl indices for crossings
     367        2905 :             node->setCrossingTLIndices(getID(), totalNumLinks);
     368             :         }
     369             :         copy(c.begin(), c.end(), std::back_inserter(crossings));
     370        3895 :         totalNumLinks += (int)c.size();
     371             :     }
     372             : 
     373        3457 :     NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
     374        3457 :     EdgeVector toProc = getConnectedOuterEdges(incoming);
     375        3457 :     const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
     376        3457 :     SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
     377        3457 :     const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
     378        3457 :     const bool noMixed = OptionsCont::getOptions().getBool("tls.no-mixed");
     379             :     // left-turn phases do not work well for joined tls, so we build incoming instead
     380        3457 :     if (myLayout == TrafficLightLayout::DEFAULT) {
     381             :         // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
     382        2647 :         myLayout = SUMOXMLDefinitions::TrafficLightLayouts.get(OptionsCont::getOptions().getString("tls.layout"));
     383             :     }
     384        3457 :     const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
     385             : 
     386             :     // build all phases
     387             :     std::vector<int> greenPhases; // indices of green phases
     388        3457 :     std::vector<bool> hadGreenMajor(totalNumLinks, false);
     389       10206 :     while (toProc.size() > 0) {
     390             :         bool groupTram = false;
     391             :         bool groupOther = false;
     392        6749 :         std::pair<NBEdge*, NBEdge*> chosen;
     393             :         std::set<const NBEdge*> chosenSet;
     394        6749 :         if (groupOpposites) {
     395        6548 :             if (incoming.size() == 2) {
     396             :                 // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
     397             :                 // @node: this heuristic could be extended to also check the number of outgoing edges
     398         762 :                 double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
     399             :                 // angle would be 180 for straight opposing incoming edges
     400         762 :                 if (angle < 135) {
     401             :                     chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
     402             :                     toProc.erase(toProc.begin());
     403             :                 } else {
     404         224 :                     chosen = getBestPair(toProc);
     405             :                 }
     406             :             } else {
     407        5786 :                 chosen = getBestPair(toProc);
     408        5786 :                 if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
     409             :                     groupTram = true;
     410         381 :                     for (auto it = toProc.begin(); it != toProc.end();) {
     411         223 :                         if ((*it)->getPermissions() == SVC_TRAM) {
     412             :                             it = toProc.erase(it);
     413             :                         } else {
     414             :                             it++;
     415             :                         }
     416             :                     }
     417             :                 }
     418             :             }
     419             :         } else {
     420         201 :             NBEdge* chosenEdge = toProc[0];
     421             :             chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
     422             :             toProc.erase(toProc.begin());
     423         201 :             SVCPermissions perms = chosenEdge->getPermissions();
     424         201 :             if (perms == SVC_TRAM) {
     425             :                 groupTram = true;
     426         199 :             } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
     427             :                 groupOther = true;
     428             :             }
     429             :             // group all edges with the same permissions into a single phase (later)
     430         201 :             if (groupTram || groupOther) {
     431          32 :                 for (auto it = toProc.begin(); it != toProc.end();) {
     432          26 :                     if ((*it)->getPermissions() == perms) {
     433             :                         it = toProc.erase(it);
     434             :                     } else {
     435             :                         it++;
     436             :                     }
     437             :                 }
     438             :             }
     439             :         }
     440             :         int pos = 0;
     441             :         std::string state(totalNumLinks, 'r');
     442             : #ifdef DEBUG_PHASES
     443             :         if (DEBUGCOND) {
     444             :             std::cout << " computing " << getID() << " prog=" << getProgramID() << " cho1=" << Named::getIDSecure(chosen.first) << " cho2=" << Named::getIDSecure(chosen.second) << " toProc=" << toString(toProc) << " bentPrio=" << chosen.first->getToNode()->isBentPriority() << "\n";
     445             :         }
     446             : #endif
     447        6749 :         chosenList.push_back(chosen);
     448             :         chosenSet.insert(chosen.first);
     449        6749 :         if (chosen.second != nullptr) {
     450             :             chosenSet.insert(chosen.second);
     451             :         }
     452             :         // find parallel bike edge for the chosen (passenger) edges
     453       17370 :         for (const NBEdge* e : chosenSet) {
     454       10621 :             if ((e->getPermissions() & SVC_PASSENGER) != 0) {
     455             :                 std::vector<NBEdge*> parallelBikeEdges;
     456       19201 :                 for (NBEdge* cand : toProc) {
     457        9626 :                     if ((cand->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE) {
     458         273 :                         double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
     459         273 :                         if (angle < 30) {
     460             :                             // roughly parallel
     461          77 :                             parallelBikeEdges.push_back(cand);
     462             :                         }
     463             :                     }
     464             :                 }
     465        9652 :                 for (NBEdge* be : parallelBikeEdges) {
     466             : #ifdef DEBUG_PHASES
     467             :                     if (DEBUGCOND) {
     468             :                         std::cout << " chosen=" << e->getID() << " be=" << be->getID() << "\n";
     469             :                     }
     470             : #endif
     471             :                     chosenSet.insert(be);
     472          77 :                     toProc.erase(std::find(toProc.begin(), toProc.end(), be));
     473             :                 }
     474             :             }
     475             :         }
     476             :         // plain straight movers
     477             :         double maxSpeed = 0;
     478             :         bool haveGreen = false;
     479       38035 :         for (const NBEdge* const fromEdge : incoming) {
     480             :             const bool inChosen = chosenSet.count(fromEdge) != 0;
     481             :             const int numLanes = fromEdge->getNumLanes();
     482       88318 :             for (int i2 = 0; i2 < numLanes; i2++) {
     483      151453 :                 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     484       94421 :                     if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     485          68 :                         continue;
     486             :                     }
     487       94353 :                     if (inChosen) {
     488       38590 :                         state[pos] = 'G';
     489             :                         haveGreen = true;
     490       38590 :                         maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
     491             :                     } else {
     492       55763 :                         state[pos] = 'r';
     493             :                     }
     494       94353 :                     ++pos;
     495       57032 :                 }
     496             :             }
     497             :         }
     498        6749 :         if (!haveGreen) {
     499             :             continue;
     500             :         }
     501             : 
     502             : #ifdef DEBUG_PHASES
     503             :         if (DEBUGCOND) {
     504             :             std::cout << " state after plain straight movers " << state << "\n";
     505             :         }
     506             : #endif
     507        6743 :         if (!isNEMA) {
     508             :             // correct behaviour for those that are not in chosen, but may drive, though
     509       13396 :             state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     510             : #ifdef DEBUG_PHASES
     511             :             if (DEBUGCOND) {
     512             :                 std::cout << " state after allowing compatible " << state << "\n";
     513             :             }
     514             : #endif
     515        6698 :             if (groupTram) {
     516         320 :                 state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
     517        6538 :             } else if (groupOther) {
     518           8 :                 state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
     519             :             }
     520             : #ifdef DEBUG_PHASES
     521             :             if (DEBUGCOND) {
     522             :                 std::cout << " state after grouping by vClass " << state << " (groupTram=" << groupTram << " groupOther=" << groupOther << ")\n";
     523             :             }
     524             : #endif
     525        6698 :             if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
     526       13006 :                 state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
     527             :             }
     528             : #ifdef DEBUG_PHASES
     529             :             if (DEBUGCOND) {
     530             :                 std::cout << " state after finding allowUnrelated " << state << "\n";
     531             :             }
     532             : #endif
     533             :         }
     534             :         // correct behaviour for those that have to wait (mainly left-mover)
     535        6743 :         bool haveForbiddenLeftMover = false;
     536        6743 :         std::vector<bool> rightTurnConflicts(pos, false);
     537        6743 :         std::vector<bool> mergeConflicts(pos, false);
     538       13486 :         state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     539      101062 :         for (int i1 = 0; i1 < pos; ++i1) {
     540       94319 :             if (state[i1] == 'G') {
     541             :                 hadGreenMajor[i1] = true;
     542             :             }
     543             :         }
     544             : #ifdef DEBUG_PHASES
     545             :         if (DEBUGCOND) {
     546             :             std::cout << " state after correcting left movers=" << state << "\n";
     547             :         }
     548             : #endif
     549             : 
     550        6743 :         std::vector<bool> leftGreen(pos, false);
     551             :         // check whether at least one left-turn lane exist
     552             :         bool foundLeftTurnLane = false;
     553      101062 :         for (int i1 = 0; i1 < pos; ++i1) {
     554       94319 :             if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
     555             :                 foundLeftTurnLane = true;
     556             :             }
     557             :         }
     558        3151 :         const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
     559        7867 :                                           && groupOpposites && !groupTram && !groupOther);
     560             : 
     561             :         // find indices for exclusive left green phase and apply option minor-left.max-speed
     562      101062 :         for (int i1 = 0; i1 < pos; ++i1) {
     563       94319 :             if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
     564             :                     // only activate turn-around together with a real left-turn
     565      106193 :                     && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
     566             :                 leftGreen[i1] = true;
     567       10441 :                 if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
     568         232 :                     if (buildLeftGreenPhase) {
     569          77 :                         state[i1] = 'r';
     570             :                         //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
     571         155 :                     } else if (!isTurnaround[i1]) {
     572         348 :                         WRITE_WARNINGF(TL("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
     573             :                                        fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
     574             :                     }
     575             :                 }
     576             :             }
     577             :         }
     578             : 
     579             : #ifdef DEBUG_PHASES
     580             :         if (DEBUGCOND) {
     581             :             std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
     582             :                       << "   \nrtC=" << toString(rightTurnConflicts)
     583             :                       << "   \nmC=" << toString(mergeConflicts)
     584             :                       << "   \nhTL=" << toString(hasTurnLane)
     585             :                       << "   \nlGr=" << toString(leftGreen)
     586             :                       << "\n";
     587             :         }
     588             : #endif
     589        6743 :         straightStates.push_back(state);
     590             : 
     591             :         const std::string vehicleState = state; // backup state before pedestrian modifications
     592        6743 :         greenPhases.push_back((int)logic->getPhases().size());
     593             : 
     594             :         // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
     595        6743 :         const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
     596        6743 :         SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
     597        6743 :         if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
     598             :             // shorter minDuration for tram phase (only if the phase is
     599             :             // exclusively for tram)
     600             :             bool tramExclusive = true;
     601        2194 :             for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
     602        2043 :                 if (state[i1] == 'G') {
     603         647 :                     SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
     604         647 :                     if (linkPerm != SVC_TRAM) {
     605             :                         tramExclusive = false;
     606             :                         break;
     607             :                     }
     608             :                 }
     609             :             }
     610         344 :             if (tramExclusive) {
     611             :                 // one tram per actuated phase
     612             :                 minDur = TIME2STEPS(1);
     613             :             }
     614             :         }
     615             : 
     616       13486 :         state = addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
     617             :         // pedestrians have 'r' from here on
     618       11303 :         for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
     619        4560 :             state[i1] = 'r';
     620             :         }
     621        6743 :         if (brakingTime > 0) {
     622             :             SUMOTime maxCross = 0;
     623             :             // build yellow (straight)
     624       82545 :             for (int i1 = 0; i1 < pos; ++i1) {
     625       77414 :                 if (state[i1] != 'G' && state[i1] != 'g') {
     626       42426 :                     continue;
     627             :                 }
     628       11208 :                 if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
     629       11208 :                         && buildLeftGreenPhase
     630        4023 :                         && !rightTurnConflicts[i1]
     631        3869 :                         && !mergeConflicts[i1]
     632       38825 :                         && leftGreen[i1]) {
     633        3670 :                     continue;
     634             :                 }
     635       31318 :                 state[i1] = 'y';
     636       31318 :                 maxCross = MAX2(maxCross, crossingTime[i1]);
     637             :             }
     638             :             // add step
     639       10262 :             logic->addStep(brakingTime, state);
     640             :             // add optional all-red state
     641        5131 :             if (!buildLeftGreenPhase) {
     642        4167 :                 if (myLayout == TrafficLightLayout::ALTERNATE_ONEWAY) {
     643          10 :                     allRedTime = computeEscapeTime(state, fromEdges, toEdges);
     644             :                 }
     645        4167 :                 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     646             :             }
     647             :         }
     648             : 
     649             : 
     650        6743 :         if (buildLeftGreenPhase) {
     651             :             // build left green
     652       22253 :             for (int i1 = 0; i1 < pos; ++i1) {
     653       21146 :                 if (state[i1] == 'Y' || state[i1] == 'y') {
     654        5464 :                     state[i1] = 'r';
     655        5464 :                     continue;
     656             :                 }
     657       15682 :                 if (leftGreen[i1]) {
     658        4161 :                     state[i1] = 'G';
     659             :                 }
     660             :             }
     661        1107 :             leftStates.push_back(state);
     662        2214 :             state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     663        2214 :             state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     664        1107 :             bool buildMixedGreenPhase = false;
     665        1107 :             std::vector<bool> mixedGreen(pos, false);
     666             :             const std::string oldState = state;
     667        1107 :             if (noMixed) {
     668          20 :                 state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
     669             :             }
     670        1107 :             if (state != oldState) {
     671         120 :                 for (int i1 = 0; i1 < pos; ++i1) {
     672         112 :                     if (mixedGreen[i1]) {
     673             :                         // patch previous yellow and allred phase
     674           8 :                         int yellowIndex = (int)logic->getPhases().size() - 1;
     675           8 :                         if (allRedTime > 0) {
     676           0 :                             logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
     677             :                         }
     678           8 :                         if (brakingTime > 0) {
     679           8 :                             logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
     680             :                         }
     681             :                     }
     682             :                 }
     683          16 :                 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     684             :             }
     685             : 
     686             :             // add step
     687        2214 :             logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
     688             : 
     689             :             // build left yellow
     690        1107 :             if (brakingTime > 0) {
     691             :                 SUMOTime maxCross = 0;
     692       19558 :                 for (int i1 = 0; i1 < pos; ++i1) {
     693       18594 :                     if (state[i1] != 'G' && state[i1] != 'g') {
     694       14472 :                         continue;
     695             :                     }
     696        4122 :                     state[i1] = 'y';
     697        4122 :                     maxCross = MAX2(maxCross, crossingTime[i1]);
     698             :                 }
     699             :                 // add step
     700        1928 :                 logic->addStep(brakingTime, state);
     701             :                 // add optional all-red state
     702         964 :                 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     703             :             }
     704             : 
     705        1107 :             if (buildMixedGreenPhase) {
     706             :                 // build mixed green
     707             :                 // @todo if there is no left green phase we might want to build two
     708             :                 // mixed-green phases but then we should consider avoid a common
     709             :                 // opposite phase for this direction
     710             : 
     711          68 :                 for (int i1 = 0; i1 < pos; ++i1) {
     712          64 :                     if (state[i1] == 'Y' || state[i1] == 'y') {
     713          16 :                         state[i1] = 'r';
     714          16 :                         continue;
     715             :                     }
     716          48 :                     if (mixedGreen[i1]) {
     717           4 :                         state[i1] = 'G';
     718             :                     }
     719             :                 }
     720           8 :                 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     721           8 :                 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     722             : 
     723             :                 // add step
     724           8 :                 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
     725             : 
     726             :                 // build mixed yellow
     727           4 :                 if (brakingTime > 0) {
     728             :                     SUMOTime maxCross = 0;
     729          68 :                     for (int i1 = 0; i1 < pos; ++i1) {
     730          64 :                         if (state[i1] != 'G' && state[i1] != 'g') {
     731          48 :                             continue;
     732             :                         }
     733          16 :                         state[i1] = 'y';
     734          16 :                         maxCross = MAX2(maxCross, crossingTime[i1]);
     735             :                     }
     736             :                     // add step
     737           8 :                     logic->addStep(brakingTime, state);
     738             :                     // add optional all-red state
     739           4 :                     buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     740             :                 }
     741             :             }
     742             : 
     743        5636 :         } else if (isNEMA) {
     744             :             std::string& s = straightStates.back();
     745             :             std::string leftState = s;
     746         193 :             for (int ii = 0; ii < pos; ++ii) {
     747         176 :                 if (s[ii] != 'r') {
     748          80 :                     NBEdge* fromEdge = fromEdges[ii];
     749          80 :                     NBEdge* toEdge = toEdges[ii];
     750          80 :                     LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, toEdge);
     751          80 :                     if (hasTurnLane[ii] && (dir == LinkDirection::LEFT || dir == LinkDirection::TURN)) {
     752          13 :                         s[ii] = 'r';
     753          13 :                         leftState[ii] = 'G';
     754             :                     } else {
     755          67 :                         leftState[ii] = 'r';
     756             :                     }
     757             :                 }
     758             :             }
     759          17 :             leftStates.push_back(leftState);
     760             :         }
     761             :         // fix edges within joined traffic lights that did not get the green light yet
     762        6743 :         if (myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0) {
     763         196 :             addGreenWithin(logic, fromEdges, toProc);
     764             :         }
     765             :     }
     766             :     // fix pedestrian crossings that did not get the green light yet
     767        3457 :     if (crossings.size() > 0) {
     768         441 :         addPedestrianScramble(logic, totalNumLinks, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
     769             :     }
     770             :     // add optional red phase if there were no foes
     771         954 :     if (logic->getPhases().size() == 2 && brakingTime > 0
     772        5101 :             && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
     773         690 :         const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
     774        2070 :         logic->addStep(redTime, std::string(totalNumLinks, 'r'));
     775             :     }
     776             :     // fix states to account for custom crossing link indices
     777        3457 :     if (crossings.size() > 0 && !onlyConts) {
     778         327 :         checkCustomCrossingIndices(logic);
     779             :     }
     780             : 
     781        3457 :     if (myLayout == TrafficLightLayout::ALTERNATE_ONEWAY) {
     782             :         // exiting the oneway section should always be possible
     783           4 :         deactivateInsideEdges(logic, fromEdges);
     784             :     }
     785        3457 :     if (isNEMA) {
     786          23 :         NBTrafficLightLogic* nemaLogic = buildNemaPhases(fromEdges, toEdges, crossings, chosenList, straightStates, leftStates);
     787          23 :         if (nemaLogic == nullptr) {
     788           6 :             WRITE_WARNINGF(TL("Generating NEMA phases is not support for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"), getID(), incoming.size());
     789             :             logic->setType(TrafficLightType::ACTUATED);
     790           2 :             setType(TrafficLightType::ACTUATED);
     791             :         } else {
     792          21 :             delete logic;
     793             :             logic = nemaLogic;
     794             :         }
     795             :     }
     796             : 
     797        3457 :     SUMOTime totalDuration = logic->getDuration();
     798             : 
     799        3482 :     if ((OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) && !isNEMA) {
     800        3432 :         const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
     801             :         // adapt to cycle time by changing the duration of the green phases
     802             :         SUMOTime minGreenDuration = SUMOTime_MAX;
     803       10122 :         for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
     804        6690 :             const SUMOTime dur = logic->getPhases()[*it].duration;
     805             :             minGreenDuration = MIN2(minGreenDuration, dur);
     806             :         }
     807        3432 :         const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
     808        3432 :         const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
     809             :         //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
     810        3432 :         if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
     811        3429 :                 || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
     812        6861 :                 || greenPhases.size() == 0) {
     813           3 :             if (getID() != DummyID) {
     814          11 :                 WRITE_WARNINGF(TL("The traffic light '%' cannot be adapted to a cycle time of %."), getID(), time2string(cycleTime));
     815             :             }
     816             :             // @todo use a multiple of cycleTime ?
     817             :         } else {
     818       10083 :             for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
     819        8596 :                 logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
     820             :             }
     821        3429 :             if (greenPhases.size() > 0) {
     822        3615 :                 logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
     823             :             }
     824        3429 :             totalDuration = logic->getDuration();
     825             :         }
     826             :     }
     827             : 
     828             :     // check for coherent signal sequence and remove yellow if preceded and followed by green
     829             :     const std::vector<NBTrafficLightLogic::PhaseDefinition>& allPhases = logic->getPhases();
     830        3457 :     const int phaseCount = (int)allPhases.size();
     831             :     const int stateSize = (int)logic->getNumLinks();
     832       19489 :     for (int i = 0; i < phaseCount; ++i) {
     833       16032 :         std::string currState = allPhases[i].state;
     834       16032 :         const int prevIndex = (i == 0) ? phaseCount - 1 : i - 1;
     835       16032 :         const std::string prevState = allPhases[prevIndex].state;
     836       16032 :         const std::string nextState = allPhases[(i + 1) % phaseCount].state;
     837             :         bool updatedState = false;
     838      267227 :         for (int i1 = 0; i1 < stateSize; ++i1) {
     839      251195 :             if (currState[i1] == 'y' && (nextState[i1] == 'g' || nextState[i1] == 'G') && (prevState[i1] == 'g' || prevState[i1] == 'G')) {
     840        2463 :                 LinkState ls = (nextState[i1] == prevState[i1]) ? (LinkState)prevState[i1] : (LinkState)'g';
     841        2463 :                 logic->setPhaseState(i, i1, ls);
     842             :                 updatedState = true;
     843             :             }
     844             :         }
     845             :         UNUSED_PARAMETER(updatedState);  // disable warning
     846             : #ifdef DEBUG_PHASES
     847             :         if (DEBUGCOND) {
     848             :             if (updatedState) {
     849             :                 std::cout << getID() << " state of phase index " << i <<  " was patched due to yellow in between green\n";
     850             :             }
     851             : 
     852             :         }
     853             : #endif
     854             :     }
     855             : 
     856             : 
     857        3457 :     myRightOnRedConflictsReady = true;
     858             :     // this computation only makes sense for single nodes
     859        3457 :     myNeedsContRelationReady = (myControlledNodes.size() == 1);
     860        3457 :     if (totalDuration > 0) {
     861        3457 :         if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA) {
     862          17 :             WRITE_WARNINGF(TL("The traffic light '%' has a high cycle time of %."), getID(), time2string(totalDuration));
     863             :         }
     864        3457 :         logic->closeBuilding();
     865             :         return logic;
     866             :     } else {
     867           0 :         delete logic;
     868           0 :         return nullptr;
     869             :     }
     870        3457 : }
     871             : 
     872             : 
     873             : bool
     874        3698 : NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
     875             :     assert(to != 0);
     876        6442 :     for (auto c : crossings) {
     877             :         const NBNode::Crossing& cross = *c;
     878             :         // only check connections at this crossings node
     879        3707 :         if (to->getFromNode() == cross.node) {
     880        7420 :             for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
     881        5162 :                 const NBEdge* edge = *it_e;
     882        5162 :                 if (edge == from || edge == to) {
     883             :                     return true;
     884             :                 }
     885             :             }
     886             :         }
     887             :     }
     888             :     return false;
     889             : }
     890             : 
     891             : 
     892             : std::string
     893        6892 : NBOwnTLDef::addPedestrianPhases(NBTrafficLightLogic* logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur,
     894             :                                 const SUMOTime earliestEnd, const SUMOTime latestEnd,
     895             :                                 std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
     896             :     // compute based on length of the crossing if not set by the user
     897       13784 :     const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
     898             :     // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
     899       20676 :     const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
     900             :     const std::string orig = state;
     901        6892 :     state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
     902        6892 :     if (orig == state) {
     903             :         // add step
     904       11848 :         logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
     905             :     } else {
     906         968 :         const SUMOTime pedTime = greenTime - pedClearingTime;
     907         968 :         if (pedTime >= minPedTime) {
     908             :             // ensure clearing time for pedestrians
     909         945 :             const int pedStates = (int)crossings.size();
     910        1890 :             logic->addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
     911             : #ifdef DEBUG_PHASES
     912             :             if (DEBUGCOND2(logic)) {
     913             :                 std::cout << " intermidate state for addPedestrianPhases " << state << "\n";
     914             :             }
     915             : #endif
     916        1890 :             state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
     917        1890 :             logic->addStep(pedClearingTime, state);
     918             :         } else {
     919             :             state = orig;
     920             :             // not safe for pedestrians.
     921          46 :             logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
     922             :         }
     923             :     }
     924             : #ifdef DEBUG_PHASES
     925             :     if (DEBUGCOND2(logic)) {
     926             :         std::cout << " state after addPedestrianPhases " << state << "\n";
     927             :     }
     928             : #endif
     929        6892 :     return state;
     930             : }
     931             : 
     932             : 
     933             : std::string
     934        6892 : NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
     935             :     std::string result = state;
     936        6892 :     const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
     937       11761 :     for (int ic = 0; ic < (int)crossings.size(); ++ic) {
     938        4869 :         const int i1 = pos + ic;
     939        4869 :         const NBNode::Crossing& cross = *crossings[ic];
     940             :         bool isForbidden = false;
     941       70277 :         for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
     942             :             // only check connections at this crossings node
     943       65408 :             if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
     944      144492 :                 for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
     945       89091 :                     const NBEdge* edge = *it;
     946       89091 :                     const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
     947       89091 :                     if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
     948       28834 :                             (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
     949             :                         isForbidden = true;
     950             :                         break;
     951             :                     }
     952             :                 }
     953             :             }
     954             :         }
     955        4869 :         if (!isForbidden) {
     956        2780 :             result[i1] = 'G';
     957             :         } else {
     958        2089 :             result[i1] = 'r';
     959             :         }
     960             :     }
     961             : 
     962             :     // correct behaviour for roads that are in conflict with a pedestrian crossing
     963      102428 :     for (int i1 = 0; i1 < pos; ++i1) {
     964       95536 :         if (result[i1] == 'G') {
     965       51042 :             for (int ic = 0; ic < (int)crossings.size(); ++ic) {
     966       21400 :                 const NBNode::Crossing& crossing = *crossings[ic];
     967       21400 :                 if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
     968       18906 :                     const int i2 = pos + ic;
     969       18906 :                     if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
     970        1308 :                         result[i1] = 'g';
     971        1308 :                         break;
     972             :                     }
     973             :                 }
     974             :             }
     975             :         }
     976             :     }
     977        6892 :     return result;
     978             : }
     979             : 
     980             : 
     981             : std::string
     982          76 : NBOwnTLDef::patchNEMAStateForCrossings(const std::string& state,
     983             :                                        const std::vector<NBNode::Crossing*>& crossings,
     984             :                                        const EdgeVector& fromEdges,
     985             :                                        const EdgeVector& toEdges,
     986             :                                        const NBEdge* greenEdge, NBEdge* otherChosen) {
     987             :     std::string result = state;
     988          76 :     const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
     989          76 :     const EdgeVector& all = greenEdge->getToNode()->getEdges();
     990          76 :     EdgeVector::const_iterator start = std::find(all.begin(), all.end(), greenEdge);
     991             : 
     992             :     // permit crossings over edges between the current green edge and it's straight continuation
     993          76 :     const NBEdge* endEdge = nullptr;
     994         614 :     for (int i = 0; i < (int)state.size(); i++) {
     995         602 :         if (state[i] == 'G' && fromEdges[i] == greenEdge
     996         742 :                 && greenEdge->getToNode()->getDirection(greenEdge, toEdges[i]) == LinkDirection::STRAIGHT) {
     997             :             // straight edge found
     998          64 :             endEdge = toEdges[i];
     999          64 :             break;
    1000             :         }
    1001             :     }
    1002          76 :     if (endEdge == nullptr) {
    1003          12 :         endEdge = otherChosen;
    1004             :     }
    1005          76 :     if (endEdge == nullptr) {
    1006             :         // try to find the reverse edge of the green edge
    1007           8 :         auto itCW = start;
    1008           8 :         NBContHelper::nextCW(all, itCW);
    1009           8 :         if ((*itCW)->getFromNode() == greenEdge->getToNode()) {
    1010           8 :             endEdge = *itCW;
    1011             :         }
    1012             :     }
    1013          76 :     if (endEdge == nullptr) {
    1014             :         // at least prevent an infinite loop
    1015           0 :         endEdge = greenEdge;
    1016             :     }
    1017             :     //std::cout << " patchNEMAStateForCrossings green=" << greenEdge->getID() << " other=" << Named::getIDSecure(otherChosen) << " end=" << Named::getIDSecure(end) << " all=" << toString(all) << "\n";
    1018             : 
    1019          76 :     EdgeVector::const_iterator end = std::find(all.begin(), all.end(), endEdge);
    1020          76 :     auto it = start;
    1021          76 :     NBContHelper::nextCCW(all, it);
    1022         232 :     for (; it != end; NBContHelper::nextCCW(all, it)) {
    1023         256 :         for (int ic = 0; ic < (int)crossings.size(); ++ic) {
    1024         100 :             const int i1 = pos + ic;
    1025         100 :             const NBNode::Crossing& cross = *crossings[ic];
    1026         258 :             for (const NBEdge* crossed : cross.edges) {
    1027             :                 //std::cout << "   cand=" << (*it)->getID() << " crossed=" << crossed->getID() << "\n";
    1028         186 :                 if (crossed == *it) {
    1029          28 :                     result[i1] = 'G';
    1030          28 :                     break;
    1031             :                 }
    1032             :             }
    1033             :         }
    1034             :     }
    1035             :     // correct behaviour for roads that are in conflict with a pedestrian crossing
    1036        1156 :     for (int i1 = 0; i1 < pos; ++i1) {
    1037        1080 :         if (result[i1] == 'G') {
    1038         208 :             for (int ic = 0; ic < (int)crossings.size(); ++ic) {
    1039          72 :                 const NBNode::Crossing& crossing = *crossings[ic];
    1040          72 :                 const int i2 = pos + ic;
    1041          72 :                 if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
    1042          12 :                     result[i1] = 'g';
    1043          12 :                     break;
    1044             :                 }
    1045             :             }
    1046             :         }
    1047             :     }
    1048          76 :     return result;
    1049             : }
    1050             : 
    1051             : 
    1052             : void
    1053        5750 : NBOwnTLDef::collectLinks() {
    1054        5750 :     myControlledLinks.clear();
    1055        5750 :     collectAllLinks(myControlledLinks);
    1056        5750 : }
    1057             : 
    1058             : 
    1059             : void
    1060        4922 : NBOwnTLDef::setTLControllingInformation() const {
    1061             :     // set the information about the link's positions within the tl into the
    1062             :     //  edges the links are starting at, respectively
    1063       26616 :     for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
    1064             :         const NBConnection& conn = *j;
    1065       21694 :         NBEdge* edge = conn.getFrom();
    1066       21694 :         edge->setControllingTLInformation(conn, getID());
    1067             :     }
    1068        4922 : }
    1069             : 
    1070             : 
    1071             : void
    1072           0 : NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
    1073           0 :                          const EdgeVector& /*outgoing*/) {}
    1074             : 
    1075             : 
    1076             : void
    1077        5773 : NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
    1078        5773 :                            NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
    1079             : 
    1080             : 
    1081             : void
    1082         270 : NBOwnTLDef::initNeedsContRelation() const {
    1083         270 :     if (!myNeedsContRelationReady) {
    1084         270 :         if (myControlledNodes.size() > 0) {
    1085             :             // setParticipantsInformation resets myAmInTLS so we need to make a copy
    1086             :             std::vector<bool> edgeInsideTLS;
    1087        2520 :             for (const NBEdge* e : myIncomingEdges) {
    1088        2250 :                 edgeInsideTLS.push_back(e->isInsideTLS());
    1089             :             }
    1090             :             // we use a dummy node just to maintain const-correctness
    1091             :             myNeedsContRelation.clear();
    1092        1022 :             for (NBNode* n : myControlledNodes) {
    1093         752 :                 NBOwnTLDef dummy(DummyID, n, 0, TrafficLightType::STATIC);
    1094         752 :                 dummy.setParticipantsInformation();
    1095         752 :                 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
    1096         752 :                 delete tllDummy;
    1097         752 :                 myNeedsContRelation.insert(dummy.myNeedsContRelation.begin(), dummy.myNeedsContRelation.end());
    1098         752 :                 n->removeTrafficLight(&dummy);
    1099         752 :             }
    1100         270 :             if (myControlledNodes.size() > 1) {
    1101             :                 int i = 0;
    1102        2517 :                 for (NBEdge* e : myIncomingEdges) {
    1103             :                     e->setInsideTLS(edgeInsideTLS[i]);
    1104        2250 :                     i++;
    1105             :                 }
    1106             :             }
    1107             : #ifdef DEBUG_CONTRELATION
    1108             :             if (DEBUGCOND) {
    1109             :                 std::cout << " contRelations at " << getID() << " prog=" << getProgramID() << ":\n";
    1110             :                 for (const StreamPair& s : myNeedsContRelation) {
    1111             :                     std::cout << "   " << s.from1->getID() << "->" << s.to1->getID() << " foe " << s.from2->getID() << "->" << s.to2->getID() << "\n";
    1112             :                 }
    1113             :             }
    1114             : #endif
    1115             : 
    1116             :         }
    1117         270 :         myNeedsContRelationReady = true;
    1118             :     }
    1119         270 : }
    1120             : 
    1121             : 
    1122             : EdgeVector
    1123        3457 : NBOwnTLDef::getConnectedOuterEdges(const EdgeVector& incoming) {
    1124        3457 :     EdgeVector result = incoming;
    1125       16366 :     for (EdgeVector::iterator it = result.begin(); it != result.end();) {
    1126       12909 :         if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
    1127             :             it = result.erase(it);
    1128             :         } else {
    1129             :             ++it;
    1130             :         }
    1131             :     }
    1132        3457 :     return result;
    1133             : }
    1134             : 
    1135             : 
    1136             : std::string
    1137        7817 : NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1138             :                             const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
    1139       15634 :     state = allowSingleEdge(state, fromEdges);
    1140             : #ifdef DEBUG_PHASES
    1141             :     if (DEBUGCOND) {
    1142             :         std::cout << " state after allowSingle " << state << "\n";
    1143             :     }
    1144             : #endif
    1145        7817 :     if (myControlledNodes.size() > 1) {
    1146        1588 :         state = allowFollowers(state, fromEdges, toEdges);
    1147             : #ifdef DEBUG_PHASES
    1148             :         if (DEBUGCOND) {
    1149             :             std::cout << " state after allowFollowers " << state << "\n";
    1150             :         }
    1151             : #endif
    1152        1588 :         state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
    1153             : #ifdef DEBUG_PHASES
    1154             :         if (DEBUGCOND) {
    1155             :             std::cout << " state after allowPredecessors " << state << "\n";
    1156             :         }
    1157             : #endif
    1158             :     }
    1159        7817 :     return state;
    1160             : }
    1161             : 
    1162             : 
    1163             : std::string
    1164        7817 : NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
    1165             :     // if only one edge has green, ensure sure that all connections from that edge are green
    1166        7817 :     const int size = (int)fromEdges.size();
    1167             :     NBEdge* greenEdge = nullptr;
    1168       93494 :     for (int i1 = 0; i1 < size; ++i1) {
    1169       90426 :         if (state[i1] == 'G') {
    1170       30254 :             if (greenEdge == nullptr) {
    1171        7817 :                 greenEdge = fromEdges[i1];
    1172       22437 :             } else if (greenEdge != fromEdges[i1]) {
    1173             :                 return state;
    1174             :             }
    1175             :         }
    1176             :     }
    1177        3068 :     if (greenEdge != nullptr) {
    1178       35822 :         for (int i1 = 0; i1 < size; ++i1) {
    1179       32754 :             if (fromEdges[i1] == greenEdge) {
    1180        8956 :                 state[i1] = 'G';
    1181             :             }
    1182             :         }
    1183             :     }
    1184             :     return state;
    1185             : }
    1186             : 
    1187             : 
    1188             : std::string
    1189         794 : NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
    1190             :     // check continuation within joined traffic lights
    1191             :     bool check = true;
    1192        2037 :     while (check) {
    1193             :         check = false;
    1194       29217 :         for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1195       27974 :             if (state[i1] == 'G') {
    1196        7208 :                 continue;
    1197             :             }
    1198       20766 :             if (forbidden(state, i1, fromEdges, toEdges, true)) {
    1199        7892 :                 continue;
    1200             :             }
    1201             :             bool followsChosen = false;
    1202      484711 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1203      473606 :                 if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
    1204             :                     followsChosen = true;
    1205             :                     break;
    1206             :                 }
    1207             :             }
    1208       12874 :             if (followsChosen) {
    1209        1769 :                 state[i1] = 'G';
    1210             :                 check = true;
    1211             :             }
    1212             :         }
    1213             :     }
    1214         794 :     return state;
    1215             : }
    1216             : 
    1217             : 
    1218             : std::string
    1219         794 : NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1220             :                               const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
    1221             :     // also allow predecessors of chosen edges if the lanes match and there is no conflict
    1222             :     // (must be done after the followers are done because followers are less specific)
    1223             :     bool check = true;
    1224        1604 :     while (check) {
    1225             :         check = false;
    1226       18570 :         for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1227       17760 :             if (state[i1] == 'G') {
    1228        5199 :                 continue;
    1229             :             }
    1230       12561 :             if (forbidden(state, i1, fromEdges, toEdges, false)) {
    1231        6538 :                 continue;
    1232             :             }
    1233             :             bool preceedsChosen = false;
    1234      255926 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1235      249923 :                 if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
    1236      250011 :                         && fromLanes[i2] == toLanes[i1]) {
    1237             :                     preceedsChosen = true;
    1238             :                     break;
    1239             :                 }
    1240             :             }
    1241        6023 :             if (preceedsChosen) {
    1242          20 :                 state[i1] = 'G';
    1243             :                 check = true;
    1244             :             }
    1245             :         }
    1246             :     }
    1247         794 :     return state;
    1248             : }
    1249             : 
    1250             : 
    1251             : std::string
    1252        6503 : NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1253             :                            const std::vector<bool>& isTurnaround,
    1254             :                            const std::vector<NBNode::Crossing*>& crossings) {
    1255       94407 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1256       87904 :         if (state[i1] == 'G') {
    1257       39218 :             continue;
    1258             :         }
    1259             :         bool isForbidden = false;
    1260      389499 :         for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1261      523720 :             if (state[i2] == 'G' && !isTurnaround[i2] &&
    1262      250437 :                     (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1263             :                 isForbidden = true;
    1264             :                 break;
    1265             :             }
    1266             :         }
    1267       48686 :         if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
    1268        2735 :             state[i1] = 'G';
    1269             :         }
    1270             :     }
    1271        6503 :     return state;
    1272             : }
    1273             : 
    1274             : 
    1275             : std::string
    1276         164 : NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
    1277        2185 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1278        2021 :         SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
    1279        2021 :         if ((linkPerm & ~perm) == 0) {
    1280         560 :             state[i1] = 'G';
    1281             :         }
    1282             :     }
    1283         164 :     return state;
    1284             : }
    1285             : 
    1286             : 
    1287             : bool
    1288       33327 : NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges, bool allowCont) {
    1289      952090 :     for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1290      933193 :         if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
    1291       28530 :             if (!allowCont || (
    1292       20233 :                         !needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
    1293        9237 :                         !needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
    1294       14430 :                 return true;
    1295             :             }
    1296             :         }
    1297             :     }
    1298             :     return false;
    1299             : }
    1300             : 
    1301             : 
    1302             : std::string
    1303        7854 : NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1304             :                                const std::vector<bool>& isTurnaround,
    1305             :                                const std::vector<int>& fromLanes,
    1306             :                                const std::vector<int>& toLanes,
    1307             :                                const std::vector<bool>& hadGreenMajor,
    1308             :                                bool& haveForbiddenLeftMover,
    1309             :                                std::vector<bool>& rightTurnConflicts,
    1310             :                                std::vector<bool>& mergeConflicts) {
    1311        7854 :     const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
    1312      123383 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1313      115529 :         if (state[i1] == 'G') {
    1314      949985 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1315      901218 :                 if ((state[i2] == 'G' || state[i2] == 'g')) {
    1316      418761 :                     if (NBNode::rightTurnConflict(
    1317             :                                 fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
    1318             :                         rightTurnConflicts[i1] = true;
    1319             :                     }
    1320      418761 :                     if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
    1321       33231 :                         state[i1] = 'g';
    1322       33231 :                         if (myControlledNodes.size() == 1) {
    1323       31247 :                             myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
    1324             : #ifdef DEBUG_CONTRELATION
    1325             :                             if (DEBUGCOND) {
    1326             :                                 std::cout << getID() << " p=" << getProgramID() << " contRel: " << fromEdges[i1]->getID() << "->" << toEdges[i1]->getID()
    1327             :                                           << " foe " << fromEdges[i2]->getID() << "->" << toEdges[i2]->getID() << "\n";
    1328             :                             }
    1329             : #endif
    1330             :                         }
    1331       33231 :                         if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
    1332       18899 :                             haveForbiddenLeftMover = true;
    1333             :                         }
    1334      385530 :                     } else if (fromEdges[i1] == fromEdges[i2]
    1335      191378 :                                && fromLanes[i1] != fromLanes[i2]
    1336       77601 :                                && toEdges[i1] == toEdges[i2]
    1337       21457 :                                && toLanes[i1] == toLanes[i2]
    1338      385972 :                                && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
    1339             :                         mergeConflicts[i1] = true;
    1340         218 :                         state[i1] = 'g';
    1341             :                     }
    1342             :                 }
    1343             :             }
    1344             :         }
    1345      115529 :         if (state[i1] == 'r') {
    1346       66816 :             if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
    1347         212 :                     fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
    1348          48 :                 state[i1] = 's';
    1349             :                 // do not allow right-on-red when in conflict with exclusive left-turn phase
    1350         720 :                 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1351         917 :                     if (state[i2] == 'G' && !isTurnaround[i2] &&
    1352         440 :                             (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
    1353         207 :                              forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1354          64 :                         const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
    1355          64 :                         if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
    1356          12 :                             state[i1] = 'r';
    1357          12 :                             break;
    1358             :                         }
    1359             :                     }
    1360             :                 }
    1361          48 :                 if (state[i1] == 's') {
    1362             :                     // handle right-on-red conflicts
    1363         612 :                     for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1364         784 :                         if (state[i2] == 'G' && !isTurnaround[i2] &&
    1365         390 :                                 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
    1366         182 :                                  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1367          52 :                             myRightOnRedConflicts.insert(std::make_pair(i1, i2));
    1368             :                         }
    1369             :                     }
    1370             :                 }
    1371             :             }
    1372             :         }
    1373             :     }
    1374        7854 :     return state;
    1375             : }
    1376             : 
    1377             : 
    1378             : std::string
    1379          10 : NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
    1380             :                          const std::vector<int>& fromLanes,
    1381             :                          bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
    1382         152 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1383         142 :         if ((state[i1] == 'G' || state[i1] == 'g')) {
    1384         368 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1385         320 :                 if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
    1386         360 :                         && state[i2] != 'G' && state[i2] != 'g') {
    1387          12 :                     state[i1] = state[i2];
    1388             :                     //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
    1389             :                     mixedGreen[i1] = true;
    1390          12 :                     if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
    1391           4 :                         buildMixedGreenPhase = true;
    1392             :                     }
    1393             :                 }
    1394             :             }
    1395             :         }
    1396             :     }
    1397          10 :     return state;
    1398             : }
    1399             : 
    1400             : 
    1401             : void
    1402         196 : NBOwnTLDef::addGreenWithin(NBTrafficLightLogic* logic, const EdgeVector& fromEdges, EdgeVector& toProc) {
    1403         196 :     std::vector<bool> foundGreen(fromEdges.size(), false);
    1404        1596 :     for (const auto& phase : logic->getPhases()) {
    1405             :         const std::string state = phase.state;
    1406       33790 :         for (int j = 0; j < (int)fromEdges.size(); j++) {
    1407       32390 :             LinkState ls = (LinkState)state[j];
    1408       32390 :             if (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR) {
    1409             :                 foundGreen[j] = true;
    1410             :             }
    1411             :         }
    1412             :     }
    1413        4128 :     for (int j = 0; j < (int)foundGreen.size(); j++) {
    1414        3932 :         if (!foundGreen[j]) {
    1415          11 :             NBEdge* e = fromEdges[j];
    1416          11 :             if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
    1417           6 :                 toProc.push_back(e);
    1418             :             }
    1419             :         }
    1420             :     }
    1421         196 : }
    1422             : 
    1423             : 
    1424             : void
    1425         447 : NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int totalNumLinks, SUMOTime /* greenTime */, SUMOTime brakingTime,
    1426             :                                   const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
    1427         447 :     const int vehLinks = totalNumLinks - (int)crossings.size();
    1428         447 :     std::vector<bool> foundGreen(crossings.size(), false);
    1429             :     const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
    1430        3365 :     for (int i = 0; i < (int)phases.size(); i++) {
    1431        2918 :         const std::string state = phases[i].state;
    1432       17229 :         for (int j = 0; j < (int)crossings.size(); j++) {
    1433       14311 :             LinkState ls = (LinkState)state[vehLinks + j];
    1434       14311 :             if (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR) {
    1435             :                 foundGreen[j] = true;
    1436             :             }
    1437             :         }
    1438             :     }
    1439             : #ifdef DEBUG_PHASES
    1440             :     if (DEBUGCOND2(logic)) {
    1441             :         std::cout << " foundCrossingGreen=" << toString(foundGreen) << "\n";
    1442             :     }
    1443             : #endif
    1444        2004 :     for (int j = 0; j < (int)foundGreen.size(); j++) {
    1445        1662 :         if (!foundGreen[j]) {
    1446             :             // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
    1447         105 :             if (phases.size() > 0) {
    1448             :                 bool needYellowPhase = false;
    1449             :                 std::string state = phases.back().state;
    1450         790 :                 for (int i1 = 0; i1 < vehLinks; ++i1) {
    1451         685 :                     if (state[i1] == 'G' || state[i1] == 'g') {
    1452         202 :                         state[i1] = 'y';
    1453             :                         needYellowPhase = true;
    1454             :                     }
    1455             :                 }
    1456             :                 // add yellow step
    1457         105 :                 if (needYellowPhase && brakingTime > 0) {
    1458           0 :                     logic->addStep(brakingTime, state);
    1459             :                 }
    1460             :             }
    1461         210 :             const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
    1462         210 :             const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
    1463         210 :             addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION,
    1464         105 :                                 UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(totalNumLinks, 'r'), crossings, fromEdges, toEdges);
    1465         105 :             break;
    1466             :         }
    1467             :     }
    1468         447 : }
    1469             : 
    1470             : 
    1471             : void
    1472        5135 : NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
    1473        5135 :     if (allRedTime > 0) {
    1474             :         // build all-red phase
    1475             :         std::string allRedState = state;
    1476        7864 :         for (int i = 0; i < (int)state.size(); i++) {
    1477        7502 :             if (allRedState[i] == 'Y' || allRedState[i] == 'y') {
    1478        2136 :                 allRedState[i] = 'r';
    1479             :             }
    1480             :         }
    1481         724 :         logic->addStep(TIME2STEPS(ceil(STEPS2TIME(allRedTime))), allRedState);
    1482             :     }
    1483        5135 : }
    1484             : 
    1485             : 
    1486             : void
    1487         327 : NBOwnTLDef::checkCustomCrossingIndices(NBTrafficLightLogic* logic) const {
    1488             :     int minCustomIndex = -1;
    1489             :     int maxCustomIndex = -1;
    1490             :     // collect crossings
    1491         691 :     for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
    1492         364 :         const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
    1493        1721 :         for (auto crossing : c) {
    1494        1357 :             minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
    1495        1357 :             minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
    1496             :             maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
    1497             :             maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
    1498             :         }
    1499             :     }
    1500             :     // custom crossing linkIndex could lead to longer states. ensure that every index has a state
    1501         327 :     if (maxCustomIndex >= logic->getNumLinks()) {
    1502           9 :         logic->setStateLength(maxCustomIndex + 1);
    1503             :     }
    1504             :     // XXX shorter state vectors are possible as well
    1505             :     // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
    1506             :     // XXX initialize the backward index to the same state as the forward index
    1507         327 : }
    1508             : 
    1509             : void
    1510           0 : NBOwnTLDef::fixSuperfluousYellow(NBTrafficLightLogic* logic) const {
    1511             :     // assume that yellow states last at most one phase
    1512             :     const int n = logic->getNumLinks();
    1513           0 :     const int p = (int)logic->getPhases().size();
    1514           0 :     for (int i1 = 0; i1 < n; ++i1) {
    1515           0 :         LinkState prev = (LinkState)logic->getPhases().back().state[i1];
    1516           0 :         for (int i2 = 0; i2 < p; ++i2) {
    1517           0 :             LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
    1518           0 :             LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
    1519           0 :             if (cur == LINKSTATE_TL_YELLOW_MINOR
    1520           0 :                     && (prev == LINKSTATE_TL_GREEN_MAJOR || prev == LINKSTATE_TL_YELLOW_MINOR)
    1521           0 :                     && next == LINKSTATE_TL_GREEN_MAJOR) {
    1522           0 :                 logic->setPhaseState(i2, i1, prev);
    1523             :             }
    1524             :             prev = cur;
    1525             :         }
    1526             :     }
    1527           0 : }
    1528             : 
    1529             : 
    1530             : void
    1531           0 : NBOwnTLDef::deactivateAlwaysGreen(NBTrafficLightLogic* logic) const {
    1532             :     const int n = logic->getNumLinks();
    1533           0 :     std::vector<bool> alwaysGreen(n, true);
    1534           0 :     for (int i1 = 0; i1 < n; ++i1) {
    1535           0 :         for (const auto& phase : logic->getPhases()) {
    1536           0 :             if (phase.state[i1] != 'G') {
    1537             :                 alwaysGreen[i1] = false;
    1538           0 :                 break;
    1539             :             }
    1540             :         }
    1541             :     }
    1542           0 :     const int p = (int)logic->getPhases().size();
    1543           0 :     for (int i1 = 0; i1 < n; ++i1) {
    1544           0 :         if (alwaysGreen[i1]) {
    1545           0 :             for (int i2 = 0; i2 < p; ++i2) {
    1546           0 :                 logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
    1547             :             }
    1548             :         }
    1549             :     }
    1550           0 : }
    1551             : 
    1552             : 
    1553             : void
    1554           4 : NBOwnTLDef::deactivateInsideEdges(NBTrafficLightLogic* logic, const EdgeVector& fromEdges) const {
    1555             :     const int n = logic->getNumLinks();
    1556           4 :     const int p = (int)logic->getPhases().size();
    1557          38 :     for (int i1 = 0; i1 < n; ++i1) {
    1558          34 :         if (fromEdges[i1]->isInsideTLS()) {
    1559         188 :             for (int i2 = 0; i2 < p; ++i2) {
    1560         168 :                 logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
    1561             :             }
    1562             :         }
    1563             :     }
    1564           4 : }
    1565             : 
    1566             : 
    1567             : SUMOTime
    1568          10 : NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
    1569          10 :     const int n = (int)state.size();
    1570             :     double maxTime = 0;
    1571         104 :     for (int i1 = 0; i1 < n; ++i1) {
    1572          94 :         if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
    1573         160 :             for (int i2 = 0; i2 < n; ++i2) {
    1574         146 :                 if (fromEdges[i2]->isInsideTLS()) {
    1575          88 :                     double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
    1576          88 :                     double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
    1577             :                     maxTime = MAX2(maxTime, time);
    1578             :                 }
    1579             :             }
    1580             :         }
    1581             :     }
    1582             :     // give some slack
    1583          10 :     return TIME2STEPS(floor(maxTime * 1.2 + 5));
    1584             : }
    1585             : 
    1586             : 
    1587             : int
    1588           0 : NBOwnTLDef::getMaxIndex() {
    1589           0 :     setParticipantsInformation();
    1590           0 :     NBTrafficLightLogic* logic = compute(OptionsCont::getOptions());
    1591           0 :     if (logic != nullptr) {
    1592           0 :         return logic->getNumLinks() - 1;
    1593             :     } else {
    1594             :         return -1;
    1595             :     }
    1596             : }
    1597             : 
    1598             : 
    1599             : bool
    1600         104 : NBOwnTLDef::corridorLike() const {
    1601         104 :     if (getID() == DummyID) {
    1602             :         // avoid infinite recursion
    1603             :         return true;
    1604             :     }
    1605             :     assert(myControlledNodes.size() >= 2);
    1606          50 :     NBOwnTLDef dummy(DummyID, myControlledNodes, 0, TrafficLightType::STATIC);
    1607          50 :     dummy.setParticipantsInformation();
    1608          50 :     NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
    1609             :     int greenPhases = 0;
    1610         209 :     for (const auto& phase : tllDummy->getPhases()) {
    1611         159 :         if (phase.state.find_first_of("gG") != std::string::npos) {
    1612         155 :             greenPhases++;
    1613             :         }
    1614             :     }
    1615          50 :     delete tllDummy;
    1616         252 :     for (const auto& controlledNode : myControlledNodes) {
    1617         202 :         controlledNode->removeTrafficLight(&dummy);
    1618             :     }
    1619          50 :     return greenPhases <= 2;
    1620          50 : }
    1621             : 
    1622             : 
    1623             : NBTrafficLightLogic*
    1624          23 : NBOwnTLDef::buildNemaPhases(
    1625             :     const EdgeVector& fromEdges,
    1626             :     const EdgeVector& toEdges,
    1627             :     const std::vector<NBNode::Crossing*>& crossings,
    1628             :     const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
    1629             :     const std::vector<std::string>& straightStates,
    1630             :     const std::vector<std::string>& leftStates) {
    1631          23 :     if (chosenList.size() != 2) {
    1632             :         return nullptr;
    1633             :     }
    1634          22 :     const SUMOTime dur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
    1635          22 :     const SUMOTime vehExt = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.vehExt"));
    1636          22 :     const SUMOTime yellow = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.yellow"));
    1637          22 :     const SUMOTime red = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.red"));
    1638          22 :     const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
    1639          22 :     const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
    1640          22 :     const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
    1641             :     const SUMOTime latestEnd = UNSPECIFIED_DURATION;
    1642             : 
    1643          22 :     const int totalNumLinks = (int)straightStates[0].size();
    1644          22 :     NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
    1645          22 :     std::vector<int> ring1({1, 2, 3, 4});
    1646          22 :     std::vector<int> ring2({5, 6, 7, 8});
    1647          22 :     std::vector<int> barrier1({4, 8});
    1648          22 :     std::vector<int> barrier2({2, 6});
    1649          22 :     int phaseNameLeft = 1;
    1650          64 :     for (int i = 0; i < (int)chosenList.size(); i++) {
    1651          43 :         NBEdge* e1 = chosenList[i].first;
    1652             :         assert(e1 != nullptr);
    1653          43 :         NBEdge* e2 = chosenList[i].second;
    1654          43 :         if (i < (int)leftStates.size()) {
    1655          86 :             std::string left1 = filterState(leftStates[i], fromEdges, e1);
    1656          43 :             if (left1 != "") {
    1657          70 :                 logic->addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft));
    1658             :             }
    1659             :         }
    1660          43 :         if (e2 != nullptr) {
    1661          34 :             std::string straight2 = filterState(straightStates[i], fromEdges, e2);
    1662          68 :             straight2 = patchNEMAStateForCrossings(straight2, crossings, fromEdges, toEdges, e2, e1);
    1663             : 
    1664          68 :             logic->addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 1));
    1665          34 :             if (i < (int)leftStates.size()) {
    1666          68 :                 std::string left2 = filterState(leftStates[i], fromEdges, e2);
    1667          34 :                 if (left2 != "") {
    1668          44 :                     logic->addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 4));
    1669             :                 }
    1670             :             }
    1671             : 
    1672             :         }
    1673          86 :         std::string straight1 = filterState(straightStates[i], fromEdges, e1);
    1674          43 :         if (straight1 == "") {
    1675           1 :             delete logic;
    1676             :             return nullptr;
    1677             :         }
    1678          84 :         straight1 = patchNEMAStateForCrossings(straight1, crossings, fromEdges, toEdges, e1, e2);
    1679          84 :         logic->addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 5));
    1680          42 :         phaseNameLeft += 2;
    1681             :     }
    1682             :     std::map<int, int> names; // nema phase name -> sumo phase index
    1683         153 :     for (int i = 0; i < (int)logic->getPhases().size(); i++) {
    1684         132 :         names[StringUtils::toInt(logic->getPhases()[i].name)] = i;
    1685             :     }
    1686             : 
    1687          21 :     filterMissingNames(ring1, names, false);
    1688          21 :     filterMissingNames(ring2, names, false);
    1689          21 :     filterMissingNames(barrier1, names, true);
    1690          21 :     filterMissingNames(barrier2, names, true);
    1691          21 :     if (ring1[2] == 0 && ring1[3] == 0) {
    1692           2 :         ring1[3] = 8;
    1693             :     }
    1694          21 :     fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
    1695          21 :     fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
    1696             : 
    1697          42 :     logic->setParameter("ring1", joinToString(ring1, ","));
    1698          42 :     logic->setParameter("ring2", joinToString(ring2, ","));
    1699          42 :     logic->setParameter("barrierPhases", joinToString(barrier1, ","));
    1700          42 :     logic->setParameter("barrier2Phases", joinToString(barrier2, ","));
    1701             :     return logic;
    1702             : }
    1703             : 
    1704             : 
    1705             : std::string
    1706         154 : NBOwnTLDef::filterState(std::string state, const EdgeVector& fromEdges, const NBEdge* e) {
    1707             :     bool haveGreen = false;
    1708        2318 :     for (int j = 0; j < (int)fromEdges.size(); j++) {
    1709        2164 :         if (fromEdges[j] != e) {
    1710        1586 :             state[j] = 'r';
    1711         578 :         } else if (state[j] != 'r') {
    1712             :             haveGreen = true;
    1713             :         }
    1714             :     }
    1715         154 :     if (haveGreen) {
    1716             :         return state;
    1717             :     } else {
    1718          21 :         return "";
    1719             :     }
    1720             : }
    1721             : 
    1722             : void
    1723          84 : NBOwnTLDef::filterMissingNames(std::vector<int>& vec, const std::map<int, int>& names, bool isBarrier) {
    1724         336 :     for (int i = 0; i < (int)vec.size(); i++) {
    1725         252 :         if (names.count(vec[i]) == 0) {
    1726          44 :             if (isBarrier) {
    1727           8 :                 if (names.count(vec[i] - 1) > 0) {
    1728           6 :                     vec[i] = vec[i] - 1;
    1729             :                 } else {
    1730           2 :                     vec[i] = 8;
    1731             :                 }
    1732             :             } else {
    1733          36 :                 vec[i] = 0;
    1734             :             }
    1735             :         }
    1736             :     }
    1737          84 : }
    1738             : 
    1739             : void
    1740          42 : NBOwnTLDef::fixDurationSum(NBTrafficLightLogic* logic, const std::map<int, int>& names, int ring1a, int ring1b, int ring2a, int ring2b) {
    1741             :     std::set<int> ring1existing;
    1742             :     std::set<int> ring2existing;
    1743             :     if (names.count(ring1a) != 0) {
    1744             :         ring1existing.insert(ring1a);
    1745             :     }
    1746             :     if (names.count(ring1b) != 0) {
    1747             :         ring1existing.insert(ring1b);
    1748             :     }
    1749             :     if (names.count(ring2a) != 0) {
    1750             :         ring2existing.insert(ring2a);
    1751             :     }
    1752             :     if (names.count(ring2b) != 0) {
    1753             :         ring2existing.insert(ring2b);
    1754             :     }
    1755          42 :     if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
    1756             :             ring1existing.size() != ring2existing.size()) {
    1757             :         int pI; // sumo phase index
    1758           6 :         if (ring1existing.size() < ring2existing.size()) {
    1759           0 :             pI = names.find(*ring1existing.begin())->second;
    1760             :         } else {
    1761           6 :             pI = names.find(*ring2existing.begin())->second;
    1762             :         }
    1763           6 :         const auto& p = logic->getPhases()[pI];
    1764           6 :         SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
    1765           6 :         logic->setPhaseMaxDuration(pI, newMaxDur);
    1766             :     }
    1767          42 : }
    1768             : 
    1769             : /****************************************************************************/

Generated by: LCOV version 1.14