LCOV - code coverage report
Current view: top level - src/netbuild - NBOwnTLDef.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.3 % 796 751
Test Date: 2026-03-02 16:00:03 Functions: 89.1 % 46 41

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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          884 : NBOwnTLDef::NBOwnTLDef(const std::string& id,
      64              :                        const std::vector<NBNode*>& junctions, SUMOTime offset,
      65          884 :                        TrafficLightType type) :
      66              :     NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
      67          884 :     myHaveSinglePhase(false),
      68          884 :     myLayout(TrafficLightLayout::DEFAULT) {
      69          884 : }
      70              : 
      71              : 
      72         5834 : NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
      73         5834 :                        TrafficLightType type) :
      74              :     NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
      75         5834 :     myHaveSinglePhase(false),
      76         5834 :     myLayout(TrafficLightLayout::DEFAULT) {
      77         5834 : }
      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        10271 : NBOwnTLDef::~NBOwnTLDef() {}
      89              : 
      90              : 
      91              : int
      92        11111 : NBOwnTLDef::getToPrio(const NBEdge* const e) {
      93        11111 :     return e->getJunctionPriority(e->getToNode());
      94              : }
      95              : 
      96              : 
      97              : double
      98       124320 : NBOwnTLDef::getDirectionalWeight(LinkDirection dir) {
      99       124320 :     switch (dir) {
     100              :         case LinkDirection::STRAIGHT:
     101              :         case LinkDirection::PARTLEFT:
     102              :         case LinkDirection::PARTRIGHT:
     103              :             return HEIGH_WEIGHT;
     104        55724 :         case LinkDirection::LEFT:
     105              :         case LinkDirection::RIGHT:
     106        55724 :             return LOW_WEIGHT;
     107              :         default:
     108              :             break;
     109              :     }
     110            0 :     return 0;
     111              : }
     112              : 
     113              : double
     114         8072 : NBOwnTLDef::computeUnblockedWeightedStreamNumber(const NBEdge* const e1, const NBEdge* const e2) {
     115              :     double val = 0;
     116        23235 :     for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
     117        15163 :         std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
     118        46178 :         for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
     119        31015 :             std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
     120        79852 :             for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
     121        48837 :                 if (e1->getTurnDestination() == (*e1c).toEdge) {
     122         5346 :                     continue;
     123              :                 }
     124       121764 :                 for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
     125        78273 :                     if (e2->getTurnDestination() == (*e2c).toEdge) {
     126        10415 :                         continue;
     127              :                     }
     128        67858 :                     const double sign = (forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)
     129        67858 :                                          || forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge, true)) ? -1 : 1;
     130              :                     double w1;
     131              :                     double w2;
     132        67858 :                     const int prio1 = e1->getJunctionPriority(e1->getToNode());
     133        67858 :                     const int prio2 = e2->getJunctionPriority(e2->getToNode());
     134        67858 :                     if (prio1 == prio2) {
     135        62160 :                         w1 = getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
     136        62160 :                         w2 = getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
     137              :                     } else {
     138         5698 :                         if (prio1 > prio2) {
     139              :                             w1 = HEIGH_WEIGHT;
     140              :                             w2 = LOW_WEIGHT;
     141              :                         } else {
     142              :                             w1 = LOW_WEIGHT;
     143              :                             w2 = HEIGH_WEIGHT;
     144              :                         }
     145         5698 :                         if (sign == -1) {
     146              :                             // extra penalty if edges with different junction priority are in conflict
     147         3431 :                             w1 *= 2;
     148         3431 :                             w2 *= 2;
     149              :                         }
     150              :                     }
     151        67858 :                     if (isRailway(e1->getPermissions()) != isRailway(e2->getPermissions())) {
     152         2429 :                         w1 *= 0.1;
     153         2429 :                         w2 *= 0.1;
     154              :                     }
     155        67858 :                     if ((e1->getPermissions() & SVC_PASSENGER) == 0) {
     156         7511 :                         w1 *= 0.1;
     157              :                     }
     158        67858 :                     if ((e2->getPermissions() & SVC_PASSENGER) == 0) {
     159         6584 :                         w2 *= 0.1;
     160              :                     }
     161        67858 :                     val += sign * w1;
     162        67858 :                     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        31015 :         }
     174        15163 :     }
     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         8072 :     return val;
     181              : }
     182              : 
     183              : 
     184              : std::pair<NBEdge*, NBEdge*>
     185         4142 : 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        13566 :     for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
     189        17496 :         for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
     190         8072 :             const double value = computeUnblockedWeightedStreamNumber(*i, *j);
     191         8072 :             if (value > bestValue) {
     192              :                 bestValue = value;
     193              :                 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     194         3142 :             } else if (value == bestValue) {
     195          909 :                 const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
     196          909 :                 const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
     197          909 :                 if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
     198           12 :                     if (bestPair.first->getID() < (*i)->getID()) {
     199              :                         bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     200              :                     }
     201          897 :                 } else if (oa < ca) {
     202              :                     bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
     203              :                 }
     204              :             }
     205              :         }
     206              :     }
     207         4142 :     if (bestValue < 0 || (bestValue == 0 && !hasStraightConnection(bestPair.first) && !hasStraightConnection(bestPair.second))) {
     208              :         // do not group edges
     209          422 :         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         4142 :     return bestPair;
     220              : }
     221              : 
     222              : 
     223              : std::pair<NBEdge*, NBEdge*>
     224         5808 : NBOwnTLDef::getBestPair(EdgeVector& incoming) {
     225         5808 :     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         1666 :         return ret;
     230              :     }
     231              :     // determine the best combination
     232              :     //  by priority, first
     233              :     EdgeVector used;
     234         4142 :     std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
     235         4142 :     used.push_back(*incoming.begin()); // the first will definitely be used
     236              :     // get the ones with the same priority
     237         4142 :     int prio = getToPrio(*used.begin());
     238         8723 :     for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
     239         4581 :         used.push_back(*i);
     240              :     }
     241              :     //  if there only lower priorised, use these, too
     242         4142 :     if (used.size() < 2) {
     243          407 :         used = incoming;
     244              :     }
     245         4142 :     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         4142 :     incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
     253         4142 :     if (ret.second != nullptr) {
     254         3720 :         incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
     255              :     }
     256         4142 :     return ret;
     257         4142 : }
     258              : 
     259              : bool
     260        12552 : NBOwnTLDef::hasStraightConnection(const NBEdge* fromEdge) {
     261        22419 :     for (const NBEdge::Connection& c : fromEdge->getConnections()) {
     262        20125 :         LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, c.toEdge);
     263        20125 :         if (dir == LinkDirection::STRAIGHT) {
     264              :             return true;
     265              :         }
     266              :     }
     267              :     return false;
     268              : }
     269              : 
     270              : NBTrafficLightLogic*
     271         2195 : NBOwnTLDef::myCompute(int brakingTimeSeconds) {
     272         2195 :     if (myControlledNodes.size() > 1) {
     273              :         // call this first so that the following call to computeLogicAndConts resets linkIndices
     274          128 :         initNeedsContRelation();
     275              :         // reset insideTLS info
     276          128 :         collectEdges();
     277              :     }
     278         2195 :     return computeLogicAndConts(brakingTimeSeconds);
     279              : }
     280              : 
     281              : 
     282              : NBTrafficLightLogic*
     283         3663 : NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
     284         3663 :     if (myControlledNodes.size() == 1) {
     285              :         // otherwise, use values from previous call to initNeedsContRelation
     286              :         myNeedsContRelation.clear();
     287              :     }
     288              :     myExtraConflicts.clear();
     289         3663 :     const bool isNEMA = myType == TrafficLightType::NEMA;
     290         3663 :     const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
     291         3663 :     const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
     292         3860 :     const SUMOTime minMinDur = (myType == TrafficLightType::STATIC) ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
     293         3860 :     const SUMOTime maxDur = (myType == TrafficLightType::STATIC) ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
     294         3663 :     const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
     295              :     const SUMOTime latestEnd = UNSPECIFIED_DURATION;
     296         3663 :     const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
     297         3663 :     SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
     298         3663 :     const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
     299         3663 :     const bool noMixed = OptionsCont::getOptions().getBool("tls.no-mixed");
     300              :     // left-turn phases do not work well for joined tls, so we build incoming instead
     301         3663 :     if (myLayout == TrafficLightLayout::DEFAULT) {
     302              :         // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
     303         6070 :         myLayout = SUMOXMLDefinitions::TrafficLightLayouts.get(OptionsCont::getOptions().getString("tls.layout"));
     304              :     }
     305              :     // corridorLike() resets crossing indices so should be called first
     306         3663 :     const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
     307              : 
     308              :     // things collect for NEMA phase building
     309              :     std::vector<std::pair<NBEdge*, NBEdge*> > chosenList;
     310              :     std::vector<std::string> straightStates;
     311              :     std::vector<std::string> leftStates;
     312              : 
     313              :     // build complete lists first
     314         3663 :     const EdgeVector& incoming = getIncomingEdges();
     315              :     EdgeVector fromEdges, toEdges;
     316              :     std::vector<bool> isTurnaround;
     317              :     std::vector<bool> hasTurnLane;
     318              :     std::vector<int> fromLanes;
     319              :     std::vector<int> toLanes;
     320              :     std::vector<SUMOTime> crossingTime;
     321              :     int totalNumLinks = 0;
     322        16085 :     for (NBEdge* const fromEdge : incoming) {
     323              :         const int numLanes = fromEdge->getNumLanes();
     324        12422 :         const bool edgeHasStraight = hasStraightConnection(fromEdge);
     325        37610 :         for (int i2 = 0; i2 < numLanes; i2++) {
     326              :             bool hasLeft = false;
     327              :             bool hasPartLeft = false;
     328              :             bool hasStraight = false;
     329              :             bool hasRight = false;
     330              :             bool hasTurnaround = false;
     331        64037 :             for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     332        38849 :                 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     333           57 :                     continue;
     334              :                 }
     335        38792 :                 fromEdges.push_back(fromEdge);
     336        38792 :                 fromLanes.push_back(i2);
     337        38792 :                 toLanes.push_back(approached.toLane);
     338        38792 :                 toEdges.push_back(approached.toEdge);
     339        11255 :                 if (approached.vmax < NUMERICAL_EPS || (fromEdge->getPermissions() & SVC_PASSENGER) == 0
     340        49401 :                         || (approached.toEdge->getPermissions() & SVC_PASSENGER) == 0) {
     341        28533 :                     crossingTime.push_back(0);
     342              :                 } else {
     343        12930 :                     crossingTime.push_back(TIME2STEPS((approached.length + approached.viaLength) / MAX2(approached.vmax, MIN_SPEED_CROSSING_TIME)));
     344              :                 }
     345              :                 // std::cout << fromEdge->getID() << " " << approached.toEdge->getID() << " " << (fromEdge->getPermissions() & SVC_PASSENGER) << " " << approached.length << " " << approached.viaLength << " " << approached.vmax << " " << crossingTime.back() << std::endl;
     346        38792 :                 if (approached.toEdge != nullptr) {
     347        38792 :                     isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
     348              :                 } else {
     349            0 :                     isTurnaround.push_back(true);
     350              :                 }
     351        38792 :                 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
     352              :                 if (dir == LinkDirection::STRAIGHT) {
     353              :                     hasStraight = true;
     354              :                 } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
     355              :                     hasRight = true;
     356              :                 } else if (dir == LinkDirection::LEFT) {
     357              :                     hasLeft = true;
     358              :                 } else if (dir == LinkDirection::PARTLEFT) {
     359              :                     hasPartLeft = true;
     360              :                 } else if (dir == LinkDirection::TURN) {
     361              :                     hasTurnaround = true;
     362              :                 }
     363        38792 :                 totalNumLinks++;
     364        25188 :             }
     365        64037 :             for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     366        38849 :                 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     367           57 :                     continue;
     368              :                 }
     369        38792 :                 hasTurnLane.push_back(
     370              :                     (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
     371        17187 :                     || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
     372        34694 :                     || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
     373        73037 :                     || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
     374        25188 :             }
     375              :             //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
     376              :         }
     377              :     }
     378              :     // collect crossings
     379              :     std::vector<NBNode::Crossing*> crossings;
     380         7906 :     for (NBNode* const node : myControlledNodes) {
     381         4243 :         const std::vector<NBNode::Crossing*>& c = node->getCrossings();
     382         4243 :         node->setCrossingTLIndices(getID(), totalNumLinks, onlyConts);
     383         4243 :         totalNumLinks = MAX2(totalNumLinks, maxCrossingIndex(node) + 1);
     384              :         copy(c.begin(), c.end(), std::back_inserter(crossings));
     385         4243 :     }
     386              : 
     387         3663 :     NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
     388         3663 :     EdgeVector toProc = getConnectedOuterEdges(incoming);
     389              : 
     390              :     // build all phases
     391              :     std::vector<int> greenPhases; // indices of green phases
     392         3663 :     std::vector<bool> hadGreenMajor(totalNumLinks, false);
     393        10649 :     while (toProc.size() > 0) {
     394              :         bool groupTram = false;
     395              :         bool groupOther = false;
     396         6986 :         std::pair<NBEdge*, NBEdge*> chosen;
     397              :         std::set<const NBEdge*> chosenSet;
     398         6986 :         if (groupOpposites) {
     399         6777 :             if (incoming.size() == 2) {
     400              :                 // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
     401              :                 // @node: this heuristic could be extended to also check the number of outgoing edges
     402         1240 :                 double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
     403              :                 // angle would be 180 for straight opposing incoming edges
     404         1240 :                 if (angle < 135) {
     405              :                     chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
     406              :                     toProc.erase(toProc.begin());
     407              :                 } else {
     408          271 :                     chosen = getBestPair(toProc);
     409              :                 }
     410              :             } else {
     411         5537 :                 chosen = getBestPair(toProc);
     412         5537 :                 if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
     413              :                     groupTram = true;
     414          101 :                     for (auto it = toProc.begin(); it != toProc.end();) {
     415           42 :                         if ((*it)->getPermissions() == SVC_TRAM) {
     416              :                             it = toProc.erase(it);
     417              :                         } else {
     418              :                             it++;
     419              :                         }
     420              :                     }
     421              :                 }
     422              :             }
     423              :         } else {
     424          209 :             NBEdge* chosenEdge = toProc[0];
     425              :             chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
     426              :             toProc.erase(toProc.begin());
     427          209 :             SVCPermissions perms = chosenEdge->getPermissions();
     428          209 :             if (perms == SVC_TRAM) {
     429              :                 groupTram = true;
     430          205 :             } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
     431           36 :                 if (OptionsCont::getOptions().getBool("tls.ignore-internal-junction-jam")) {
     432              :                     // otherwise, we can get a mutual conflict for minor green
     433              :                     // streams which would create deadlock
     434              :                     groupOther = true;
     435              :                 }
     436              :             }
     437              :             // group all edges with the same permissions into a single phase (later)
     438          209 :             if (groupTram || groupOther) {
     439           44 :                 for (auto it = toProc.begin(); it != toProc.end();) {
     440           36 :                     if ((*it)->getPermissions() == perms) {
     441              :                         it = toProc.erase(it);
     442              :                     } else {
     443              :                         it++;
     444              :                     }
     445              :                 }
     446              :             }
     447              :         }
     448              :         int pos = 0;
     449              :         std::string state(totalNumLinks, 'r');
     450              : #ifdef DEBUG_PHASES
     451              :         if (DEBUGCOND) {
     452              :             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";
     453              :         }
     454              : #endif
     455         6986 :         chosenList.push_back(chosen);
     456              :         chosenSet.insert(chosen.first);
     457         6986 :         if (chosen.second != nullptr) {
     458              :             chosenSet.insert(chosen.second);
     459              :         }
     460              :         // find parallel bike edge for the chosen (passenger) edges
     461        17759 :         for (const NBEdge* e : chosenSet) {
     462        10773 :             if ((e->getPermissions() & SVC_PASSENGER) != 0) {
     463              :                 std::vector<NBEdge*> parallelBikeEdges;
     464        19684 :                 for (NBEdge* cand : toProc) {
     465         9653 :                     if ((cand->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE) {
     466          317 :                         double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
     467          317 :                         if (angle < 30) {
     468              :                             // roughly parallel
     469          109 :                             parallelBikeEdges.push_back(cand);
     470              :                         }
     471              :                     }
     472              :                 }
     473        10140 :                 for (NBEdge* be : parallelBikeEdges) {
     474              : #ifdef DEBUG_PHASES
     475              :                     if (DEBUGCOND) {
     476              :                         std::cout << " chosen=" << e->getID() << " be=" << be->getID() << "\n";
     477              :                     }
     478              : #endif
     479              :                     chosenSet.insert(be);
     480          109 :                     toProc.erase(std::find(toProc.begin(), toProc.end(), be));
     481              :                 }
     482        10031 :             }
     483              :         }
     484              :         // plain straight movers
     485              :         double maxSpeed = 0;
     486              :         bool haveGreen = false;
     487        36283 :         for (const NBEdge* const fromEdge : incoming) {
     488              :             const bool inChosen = chosenSet.count(fromEdge) != 0;
     489              :             const int numLanes = fromEdge->getNumLanes();
     490        86895 :             for (int i2 = 0; i2 < numLanes; i2++) {
     491       148134 :                 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
     492        90536 :                     if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
     493          137 :                         continue;
     494              :                     }
     495        90399 :                     if (inChosen) {
     496        37357 :                         state[pos] = 'G';
     497              :                         haveGreen = true;
     498        37357 :                         maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
     499              :                     } else {
     500        53042 :                         state[pos] = 'r';
     501              :                     }
     502        90399 :                     ++pos;
     503        57598 :                 }
     504              :             }
     505              :         }
     506         6986 :         if (!haveGreen) {
     507              :             continue;
     508              :         }
     509              : 
     510              : #ifdef DEBUG_PHASES
     511              :         if (DEBUGCOND) {
     512              :             std::cout << " state after plain straight movers " << state << "\n";
     513              :         }
     514              : #endif
     515         6979 :         if (!isNEMA) {
     516              :             // correct behaviour for those that are not in chosen, but may drive, though
     517         6928 :             state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     518              : #ifdef DEBUG_PHASES
     519              :             if (DEBUGCOND) {
     520              :                 std::cout << " state after allowing compatible " << state << "\n";
     521              :             }
     522              : #endif
     523         6928 :             if (groupTram) {
     524          126 :                 state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
     525         6865 :             } else if (groupOther) {
     526            8 :                 state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
     527              :             }
     528              : #ifdef DEBUG_PHASES
     529              :             if (DEBUGCOND) {
     530              :                 std::cout << " state after grouping by vClass " << state << " (groupTram=" << groupTram << " groupOther=" << groupOther << ")\n";
     531              :             }
     532              : #endif
     533         6928 :             if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
     534        13450 :                 state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
     535              :             }
     536              : #ifdef DEBUG_PHASES
     537              :             if (DEBUGCOND) {
     538              :                 std::cout << " state after finding allowUnrelated " << state << "\n";
     539              :             }
     540              : #endif
     541              :         }
     542              :         // correct behaviour for those that have to wait (mainly left-mover)
     543         6979 :         bool haveForbiddenLeftMover = false;
     544         6979 :         std::vector<bool> rightTurnConflicts(pos, false);
     545         6979 :         std::vector<bool> mergeConflicts(pos, false);
     546         6979 :         state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     547        97341 :         for (int i1 = 0; i1 < pos; ++i1) {
     548        90362 :             if (state[i1] == 'G') {
     549              :                 hadGreenMajor[i1] = true;
     550              :             }
     551              :         }
     552              : #ifdef DEBUG_PHASES
     553              :         if (DEBUGCOND) {
     554              :             std::cout << " state after correcting left movers=" << state << "\n";
     555              :         }
     556              : #endif
     557              : 
     558         6979 :         std::vector<bool> leftGreen(pos, false);
     559              :         // check whether at least one left-turn lane exist
     560              :         bool foundLeftTurnLane = false;
     561        97341 :         for (int i1 = 0; i1 < pos; ++i1) {
     562        90362 :             if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
     563              :                 foundLeftTurnLane = true;
     564              :             }
     565              :         }
     566         2923 :         const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
     567         8116 :                                           && groupOpposites && !groupTram && !groupOther);
     568              : 
     569              :         // find indices for exclusive left green phase and apply option minor-left.max-speed
     570        97341 :         for (int i1 = 0; i1 < pos; ++i1) {
     571        90362 :             if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
     572              :                     // only activate turn-around together with a real left-turn
     573       100897 :                     && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
     574              :                 leftGreen[i1] = true;
     575         9384 :                 if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
     576          235 :                     if (buildLeftGreenPhase) {
     577           50 :                         state[i1] = 'r';
     578              :                         //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
     579          185 :                     } else if (!isTurnaround[i1]) {
     580          412 :                         WRITE_WARNINGF(TL("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
     581              :                                        fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
     582              :                     }
     583              :                 }
     584              :             }
     585              :         }
     586              : 
     587              : #ifdef DEBUG_PHASES
     588              :         if (DEBUGCOND) {
     589              :             std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
     590              :                       << "   \nrtC=" << toString(rightTurnConflicts)
     591              :                       << "   \nmC=" << toString(mergeConflicts)
     592              :                       << "   \nhTL=" << toString(hasTurnLane)
     593              :                       << "   \nlGr=" << toString(leftGreen)
     594              :                       << "\n";
     595              :         }
     596              : #endif
     597         6979 :         straightStates.push_back(state);
     598              : 
     599              :         const std::string vehicleState = state; // backup state before pedestrian modifications
     600         6979 :         greenPhases.push_back((int)logic->getPhases().size());
     601              : 
     602              :         // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
     603         6979 :         const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
     604         7013 :         SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
     605         6979 :         if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
     606              :             // shorter minDuration for tram phase (only if the phase is
     607              :             // exclusively for tram)
     608              :             bool tramExclusive = true;
     609         1081 :             for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
     610         1007 :                 if (state[i1] == 'G') {
     611          297 :                     SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
     612          297 :                     if (linkPerm != SVC_TRAM) {
     613              :                         tramExclusive = false;
     614              :                         break;
     615              :                     }
     616              :                 }
     617              :             }
     618          175 :             if (tramExclusive) {
     619              :                 // one tram per actuated phase
     620              :                 minDur = TIME2STEPS(1);
     621              :             }
     622              :         }
     623              : 
     624         6979 :         state = addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
     625              :         // pedestrians have 'r' from here on
     626        10028 :         for (int i1 = pos; i1 < (int)state.size(); ++i1) {
     627         3049 :             state[i1] = 'r';
     628              :         }
     629         6979 :         if (brakingTime > 0) {
     630              :             SUMOTime maxCross = 0;
     631              :             // build yellow (straight)
     632        65420 :             for (int i1 = 0; i1 < pos; ++i1) {
     633        61308 :                 if (state[i1] != 'G' && state[i1] != 'g') {
     634        33633 :                     continue;
     635              :                 }
     636         8742 :                 if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
     637         8742 :                         && buildLeftGreenPhase
     638         3388 :                         && !rightTurnConflicts[i1]
     639         3283 :                         && !mergeConflicts[i1]
     640        30932 :                         && leftGreen[i1]) {
     641         3130 :                     continue;
     642              :                 }
     643        24545 :                 state[i1] = 'y';
     644        24545 :                 maxCross = MAX2(maxCross, crossingTime[i1]);
     645              :             }
     646              :             // add step
     647         4112 :             logic->addStep(brakingTime, state);
     648              :             // add optional all-red state
     649         4112 :             if (!buildLeftGreenPhase) {
     650         3302 :                 if (myLayout == TrafficLightLayout::ALTERNATE_ONEWAY) {
     651           24 :                     allRedTime = computeEscapeTime(state, fromEdges, toEdges);
     652              :                 }
     653         3302 :                 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     654              :             }
     655              :         }
     656              : 
     657              : 
     658         6979 :         if (buildLeftGreenPhase) {
     659              :             // build left green
     660        21150 :             for (int i1 = 0; i1 < pos; ++i1) {
     661        20023 :                 if (state[i1] == 'Y' || state[i1] == 'y') {
     662         4457 :                     state[i1] = 'r';
     663         4457 :                     continue;
     664              :                 }
     665        15566 :                 if (leftGreen[i1]) {
     666         4192 :                     state[i1] = 'G';
     667              :                 }
     668              :             }
     669         1127 :             leftStates.push_back(state);
     670         2254 :             state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     671         1127 :             state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     672         1127 :             bool buildMixedGreenPhase = false;
     673         1127 :             std::vector<bool> mixedGreen(pos, false);
     674              :             const std::string oldState = state;
     675         1127 :             if (noMixed) {
     676           20 :                 state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
     677              :             }
     678         1127 :             if (state != oldState) {
     679          120 :                 for (int i1 = 0; i1 < pos; ++i1) {
     680          112 :                     if (mixedGreen[i1]) {
     681              :                         // patch previous yellow and allred phase
     682            8 :                         int yellowIndex = (int)logic->getPhases().size() - 1;
     683            8 :                         if (allRedTime > 0) {
     684            0 :                             logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
     685              :                         }
     686            8 :                         if (brakingTime > 0) {
     687            8 :                             logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
     688              :                         }
     689              :                     }
     690              :                 }
     691           16 :                 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     692              :             }
     693              : 
     694              :             // add step
     695         2254 :             logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
     696              : 
     697              :             // build left yellow
     698         1127 :             if (brakingTime > 0) {
     699              :                 SUMOTime maxCross = 0;
     700        16167 :                 for (int i1 = 0; i1 < pos; ++i1) {
     701        15357 :                     if (state[i1] != 'G' && state[i1] != 'g') {
     702        11842 :                         continue;
     703              :                     }
     704         3515 :                     state[i1] = 'y';
     705         3515 :                     maxCross = MAX2(maxCross, crossingTime[i1]);
     706              :                 }
     707              :                 // add step
     708          810 :                 logic->addStep(brakingTime, state);
     709              :                 // add optional all-red state
     710          810 :                 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     711              :             }
     712              : 
     713         1127 :             if (buildMixedGreenPhase) {
     714              :                 // build mixed green
     715              :                 // @todo if there is no left green phase we might want to build two
     716              :                 // mixed-green phases but then we should consider avoid a common
     717              :                 // opposite phase for this direction
     718              : 
     719           68 :                 for (int i1 = 0; i1 < pos; ++i1) {
     720           64 :                     if (state[i1] == 'Y' || state[i1] == 'y') {
     721           16 :                         state[i1] = 'r';
     722           16 :                         continue;
     723              :                     }
     724           48 :                     if (mixedGreen[i1]) {
     725            4 :                         state[i1] = 'G';
     726              :                     }
     727              :                 }
     728            8 :                 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
     729            8 :                 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
     730              : 
     731              :                 // add step
     732            8 :                 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
     733              : 
     734              :                 // build mixed yellow
     735            4 :                 if (brakingTime > 0) {
     736              :                     SUMOTime maxCross = 0;
     737           68 :                     for (int i1 = 0; i1 < pos; ++i1) {
     738           64 :                         if (state[i1] != 'G' && state[i1] != 'g') {
     739           48 :                             continue;
     740              :                         }
     741           16 :                         state[i1] = 'y';
     742           16 :                         maxCross = MAX2(maxCross, crossingTime[i1]);
     743              :                     }
     744              :                     // add step
     745            4 :                     logic->addStep(brakingTime, state);
     746              :                     // add optional all-red state
     747            4 :                     buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
     748              :                 }
     749              :             }
     750              : 
     751         5852 :         } else if (isNEMA) {
     752              :             std::string& s = straightStates.back();
     753              :             std::string leftState = s;
     754          211 :             for (int ii = 0; ii < pos; ++ii) {
     755          192 :                 if (s[ii] != 'r') {
     756           88 :                     NBEdge* fromEdge = fromEdges[ii];
     757           88 :                     NBEdge* toEdge = toEdges[ii];
     758           88 :                     LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, toEdge);
     759           88 :                     if (hasTurnLane[ii] && (dir == LinkDirection::LEFT || dir == LinkDirection::TURN)) {
     760           13 :                         s[ii] = 'r';
     761           13 :                         leftState[ii] = 'G';
     762              :                     } else {
     763           75 :                         leftState[ii] = 'r';
     764              :                     }
     765              :                 }
     766              :             }
     767           19 :             leftStates.push_back(leftState);
     768              :         }
     769              :         // fix edges within joined traffic lights that did not get the green light yet
     770         6979 :         if (myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0 && !onlyConts) {
     771          116 :             addGreenWithin(logic, fromEdges, toProc);
     772              :         }
     773              :     }
     774              :     // fix pedestrian crossings that did not get the green light yet
     775         3663 :     if (crossings.size() > 0) {
     776          324 :         addPedestrianScramble(logic, totalNumLinks, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
     777              :     }
     778              :     // add optional red phase if there were no foes
     779         1346 :     if (logic->getPhases().size() == 2 && brakingTime > 0
     780         5665 :             && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
     781          656 :         const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
     782         1968 :         logic->addStep(redTime, std::string(totalNumLinks, 'r'));
     783              :     }
     784              : 
     785         3663 :     if (myLayout == TrafficLightLayout::ALTERNATE_ONEWAY) {
     786              :         // exiting the oneway section should always be possible
     787           11 :         deactivateInsideEdges(logic, fromEdges);
     788              :     }
     789         3663 :     if (isNEMA) {
     790           26 :         NBTrafficLightLogic* nemaLogic = buildNemaPhases(fromEdges, toEdges, crossings, chosenList, straightStates, leftStates);
     791           26 :         if (nemaLogic == nullptr) {
     792            6 :             WRITE_WARNINGF(TL("Generating NEMA phases is not supported for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"), getID(), incoming.size());
     793              :             logic->setType(TrafficLightType::ACTUATED);
     794            2 :             setType(TrafficLightType::ACTUATED);
     795              :         } else {
     796           24 :             delete logic;
     797              :             logic = nemaLogic;
     798              :         }
     799              :     }
     800              : 
     801         3663 :     SUMOTime totalDuration = logic->getDuration();
     802              : 
     803         3691 :     if ((OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) && !isNEMA) {
     804         3635 :         const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
     805              :         // adapt to cycle time by changing the duration of the green phases
     806              :         SUMOTime minGreenDuration = SUMOTime_MAX;
     807        10555 :         for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
     808         6920 :             const SUMOTime dur = logic->getPhases()[*it].duration;
     809              :             minGreenDuration = MIN2(minGreenDuration, dur);
     810              :         }
     811         3635 :         const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
     812         3635 :         const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
     813              :         //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
     814         3635 :         if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
     815         3630 :                 || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
     816         7259 :                 || greenPhases.size() == 0) {
     817           11 :             if (getID() != DummyID) {
     818           30 :                 WRITE_WARNINGF(TL("The traffic light '%' cannot be adapted to a cycle time of %."), getID(), time2string(cycleTime));
     819              :             }
     820              :             // @todo use a multiple of cycleTime ?
     821              :         } else {
     822        10452 :             for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
     823         8407 :                 logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
     824              :             }
     825         3624 :             if (greenPhases.size() > 0) {
     826         3711 :                 logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
     827              :             }
     828         3624 :             totalDuration = logic->getDuration();
     829              :         }
     830              :     }
     831              : 
     832              :     // check for coherent signal sequence and remove yellow if preceded and followed by green
     833              :     const std::vector<NBTrafficLightLogic::PhaseDefinition>& allPhases = logic->getPhases();
     834         3663 :     const int phaseCount = (int)allPhases.size();
     835              :     const int stateSize = (int)logic->getNumLinks();
     836        18332 :     for (int i = 0; i < phaseCount; ++i) {
     837        14669 :         std::string currState = allPhases[i].state;
     838        14669 :         const int prevIndex = (i == 0) ? phaseCount - 1 : i - 1;
     839        14669 :         const std::string prevState = allPhases[prevIndex].state;
     840        14669 :         const std::string nextState = allPhases[(i + 1) % phaseCount].state;
     841              :         bool updatedState = false;
     842       229665 :         for (int i1 = 0; i1 < stateSize; ++i1) {
     843       214996 :             if (currState[i1] == 'y' && (nextState[i1] == prevState[i1] || nextState[i1] == 'G') && (prevState[i1] == 'g' || prevState[i1] == 'G')) {
     844         1898 :                 logic->setPhaseState(i, i1, (LinkState)prevState[i1]);
     845              :                 updatedState = true;
     846              :             }
     847              :         }
     848              :         UNUSED_PARAMETER(updatedState);  // disable warning
     849              : #ifdef DEBUG_PHASES
     850              :         if (DEBUGCOND) {
     851              :             if (updatedState) {
     852              :                 std::cout << getID() << " state of phase index " << i <<  " was patched due to yellow in between green\n";
     853              :             }
     854              : 
     855              :         }
     856              : #endif
     857              :     }
     858              : 
     859              : 
     860         3663 :     myExtraConflictsReady = true;
     861              :     // this computation only makes sense for single nodes
     862         3663 :     if (myControlledNodes.size() == 1) {
     863         3330 :         myNeedsContRelationReady = true;
     864              :     }
     865         3663 :     if (totalDuration > 0) {
     866         3663 :         if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA && getID() != DummyID) {
     867           36 :             WRITE_WARNINGF(TL("The traffic light '%' has a high cycle time of %."), getID(), time2string(totalDuration));
     868              :         }
     869         3663 :         logic->closeBuilding();
     870              :         return logic;
     871              :     } else {
     872            0 :         delete logic;
     873            0 :         return nullptr;
     874              :     }
     875         7326 : }
     876              : 
     877              : 
     878              : bool
     879         3734 : NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
     880              :     assert(to != 0);
     881         5248 :     for (auto c : crossings) {
     882              :         const NBNode::Crossing& cross = *c;
     883              :         // only check connections at this crossings node
     884         2064 :         if (to->getFromNode() == cross.node) {
     885         3843 :             for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
     886         2702 :                 const NBEdge* edge = *it_e;
     887         2702 :                 if (edge == from || edge == to) {
     888              :                     return true;
     889              :                 }
     890              :             }
     891              :         }
     892              :     }
     893              :     return false;
     894              : }
     895              : 
     896              : 
     897              : std::string
     898         7105 : NBOwnTLDef::addPedestrianPhases(NBTrafficLightLogic* logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur,
     899              :                                 const SUMOTime earliestEnd, const SUMOTime latestEnd,
     900              :                                 std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
     901              :     // compute based on length of the crossing if not set by the user
     902         7105 :     const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
     903              :     // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
     904         7105 :     const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
     905              :     const std::string orig = state;
     906         7105 :     state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
     907         7105 :     if (orig == state) {
     908              :         // add step
     909        12868 :         logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
     910              :     } else {
     911          671 :         const SUMOTime pedTime = greenTime - pedClearingTime;
     912          671 :         if (pedTime >= minPedTime) {
     913              :             // ensure clearing time for pedestrians
     914              :             const bool isSimpleActuatedCrossing = logic->getType() == TrafficLightType::ACTUATED
     915          648 :                                                   && minDur == UNSPECIFIED_DURATION && logic->getPhases().size() == 2;
     916              :             if (isSimpleActuatedCrossing) {
     917              :                 // permit green phase to extend when there are no pedestrians
     918           19 :                 logic->setPhaseNext(0, {0, 1});
     919              :             }
     920         1296 :             logic->addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
     921              : #ifdef DEBUG_PHASES
     922              :             if (DEBUGCOND2(logic)) {
     923              :                 std::cout << " intermidate state for addPedestrianPhases " << state << "\n";
     924              :             }
     925              : #endif
     926         3623 :             for (auto cross : crossings) {
     927         2975 :                 if (cross->tlLinkIndex >= (int)fromEdges.size() || fromEdges[cross->tlLinkIndex] == nullptr) {
     928         2925 :                     state[cross->tlLinkIndex] = 'r';
     929              :                 }
     930         2975 :                 if (cross->tlLinkIndex2 >= 0 && (cross->tlLinkIndex2 >= (int)fromEdges.size() || fromEdges[cross->tlLinkIndex2] == nullptr)) {
     931           64 :                     state[cross->tlLinkIndex2] = 'r';
     932              :                 }
     933              :             }
     934          648 :             logic->addStep(pedClearingTime, state);
     935              :         } else {
     936              :             state = orig;
     937              :             // not safe for pedestrians.
     938           46 :             logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
     939              :         }
     940              :     }
     941              : #ifdef DEBUG_PHASES
     942              :     if (DEBUGCOND2(logic)) {
     943              :         std::cout << " state after addPedestrianPhases " << state << "\n";
     944              :     }
     945              : #endif
     946        14210 :     return state;
     947              : }
     948              : 
     949              : 
     950              : std::string
     951         7105 : NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
     952              :     std::string result = state;
     953        10349 :     for (const NBNode::Crossing* cross : crossings) {
     954              :         bool isForbidden = false;
     955        46843 :         for (int i2 = 0; i2 < (int)fromEdges.size() && !isForbidden; ++i2) {
     956              :             // only check connections at this crossings node
     957        43599 :             if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross->node) {
     958        98073 :                 for (EdgeVector::const_iterator it = cross->edges.begin(); it != cross->edges.end(); ++it) {
     959        61409 :                     const NBEdge* edge = *it;
     960        61409 :                     const LinkDirection i2dir = cross->node->getDirection(fromEdges[i2], toEdges[i2]);
     961        61409 :                     if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
     962        20156 :                             (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
     963              :                         isForbidden = true;
     964              :                         break;
     965              :                     }
     966              :                 }
     967              :             }
     968              :         }
     969         3244 :         const int i1 = cross->tlLinkIndex;
     970              :         assert(i1 >= 0 && i1 < (int)result.size());
     971         3244 :         const char newState = isForbidden ? 'r' : 'G';
     972         3244 :         if (i1 < (int)toEdges.size() && toEdges[i1] != nullptr && (result[i1] != newState || !isForbidden)) {
     973           66 :             if (cross->tlID != DummyID) {
     974           54 :                 WRITE_WARNINGF(TL("Custom crossing linkIndex % conflicts with vehicular connections at tlLogic '%'"), i1, cross->tlID);
     975              :             }
     976              :         } else {
     977         3178 :             result[i1] = newState;
     978              :         }
     979         3244 :         if (cross->tlLinkIndex2 >= 0) {
     980              :             const int i2 = cross->tlLinkIndex2;
     981           82 :             if (i2 < (int)toEdges.size() && toEdges[i2] != nullptr && (result[i2] != newState || !isForbidden)) {
     982           13 :                 if (cross->tlID != DummyID) {
     983           24 :                     WRITE_WARNINGF(TL("Custom crossing linkIndex2 % conflicts with vehicular connections at tlLogic '%'"), i2, cross->tlID);
     984              :                 }
     985              :             } else {
     986           69 :                 result[i2] = newState;
     987              :             }
     988              :         }
     989              :     }
     990              : 
     991              :     // correct behaviour for roads that are in conflict with a pedestrian crossing
     992              :     assert(fromEdges.size() <= result.size());
     993        91531 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
     994        91531 :         if (result[i1] == 'G') {
     995        45236 :             for (const NBNode::Crossing* cross : crossings) {
     996        14431 :                 const int i2 = cross->tlLinkIndex;
     997        14431 :                 const int i3 = cross->tlLinkIndex2;
     998        14431 :                 if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == cross->node) {
     999        12754 :                     if ((result[i2] == 'G' || (i3 >= 0 && result[i3] == 'G'))
    1000        12770 :                             && cross->node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], *cross)) {
    1001          991 :                         result[i1] = 'g';
    1002          991 :                         break;
    1003              :                     }
    1004              :                 }
    1005              :             }
    1006              :         }
    1007              :     }
    1008         7105 :     return result;
    1009              : }
    1010              : 
    1011              : 
    1012              : std::string
    1013           86 : NBOwnTLDef::patchNEMAStateForCrossings(const std::string& state,
    1014              :                                        const std::vector<NBNode::Crossing*>& crossings,
    1015              :                                        const EdgeVector& fromEdges,
    1016              :                                        const EdgeVector& toEdges,
    1017              :                                        const NBEdge* greenEdge, NBEdge* otherChosen) {
    1018              :     std::string result = state;
    1019           86 :     const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
    1020           86 :     const EdgeVector& all = greenEdge->getToNode()->getEdges();
    1021           86 :     EdgeVector::const_iterator start = std::find(all.begin(), all.end(), greenEdge);
    1022              : 
    1023              :     // permit crossings over edges between the current green edge and it's straight continuation
    1024           86 :     const NBEdge* endEdge = nullptr;
    1025          653 :     for (int i = 0; i < (int)state.size(); i++) {
    1026          641 :         if (state[i] == 'G' && fromEdges[i] == greenEdge
    1027          792 :                 && greenEdge->getToNode()->getDirection(greenEdge, toEdges[i]) == LinkDirection::STRAIGHT) {
    1028              :             // straight edge found
    1029           74 :             endEdge = toEdges[i];
    1030           74 :             break;
    1031              :         }
    1032              :     }
    1033           86 :     if (endEdge == nullptr) {
    1034           12 :         endEdge = otherChosen;
    1035              :     }
    1036           86 :     if (endEdge == nullptr) {
    1037              :         // try to find the reverse edge of the green edge
    1038            8 :         auto itCW = start;
    1039            8 :         NBContHelper::nextCW(all, itCW);
    1040            8 :         if ((*itCW)->getFromNode() == greenEdge->getToNode()) {
    1041            8 :             endEdge = *itCW;
    1042              :         }
    1043              :     }
    1044           86 :     if (endEdge == nullptr) {
    1045              :         // at least prevent an infinite loop
    1046            0 :         endEdge = greenEdge;
    1047              :     }
    1048              :     //std::cout << " patchNEMAStateForCrossings green=" << greenEdge->getID() << " other=" << Named::getIDSecure(otherChosen) << " end=" << Named::getIDSecure(end) << " all=" << toString(all) << "\n";
    1049              : 
    1050           86 :     EdgeVector::const_iterator end = std::find(all.begin(), all.end(), endEdge);
    1051           86 :     if (end == all.end()) {
    1052              :         // at least prevent an infinite loop
    1053            0 :         end = start;
    1054              :     }
    1055           86 :     auto it = start;
    1056           86 :     NBContHelper::nextCCW(all, it);
    1057          260 :     for (; it != end; NBContHelper::nextCCW(all, it)) {
    1058          274 :         for (int ic = 0; ic < (int)crossings.size(); ++ic) {
    1059          100 :             const int i1 = pos + ic;
    1060          100 :             const NBNode::Crossing& cross = *crossings[ic];
    1061          258 :             for (const NBEdge* crossed : cross.edges) {
    1062              :                 //std::cout << "   cand=" << (*it)->getID() << " crossed=" << crossed->getID() << "\n";
    1063          186 :                 if (crossed == *it) {
    1064           28 :                     result[i1] = 'G';
    1065           28 :                     break;
    1066              :                 }
    1067              :             }
    1068              :         }
    1069              :     }
    1070              :     // correct behaviour for roads that are in conflict with a pedestrian crossing
    1071         1246 :     for (int i1 = 0; i1 < pos; ++i1) {
    1072         1160 :         if (result[i1] == 'G') {
    1073          224 :             for (int ic = 0; ic < (int)crossings.size(); ++ic) {
    1074           72 :                 const NBNode::Crossing& crossing = *crossings[ic];
    1075           72 :                 const int i2 = pos + ic;
    1076           72 :                 if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
    1077           12 :                     result[i1] = 'g';
    1078           12 :                     break;
    1079              :                 }
    1080              :             }
    1081              :         }
    1082              :     }
    1083           86 :     return result;
    1084              : }
    1085              : 
    1086              : 
    1087              : void
    1088         5627 : NBOwnTLDef::collectLinks() {
    1089              :     myControlledLinks.clear();
    1090         5627 :     collectAllLinks(myControlledLinks);
    1091         5627 : }
    1092              : 
    1093              : 
    1094              : void
    1095         4159 : NBOwnTLDef::setTLControllingInformation() const {
    1096              :     // set the information about the link's positions within the tl into the
    1097              :     //  edges the links are starting at, respectively
    1098        22065 :     for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
    1099              :         const NBConnection& conn = *j;
    1100        17906 :         NBEdge* edge = conn.getFrom();
    1101        17906 :         edge->setControllingTLInformation(conn, getID());
    1102              :     }
    1103         4159 : }
    1104              : 
    1105              : 
    1106              : void
    1107            0 : NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
    1108            0 :                          const EdgeVector& /*outgoing*/) {}
    1109              : 
    1110              : 
    1111              : void
    1112         4186 : NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
    1113         4186 :                            NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
    1114              : 
    1115              : 
    1116              : void
    1117          288 : NBOwnTLDef::initNeedsContRelation() const {
    1118          288 :     if (!myNeedsContRelationReady) {
    1119          242 :         if (myControlledNodes.size() > 0) {
    1120              :             // we use a dummy node just to maintain const-correctness
    1121              :             myNeedsContRelation.clear();
    1122          910 :             for (NBNode* n : myControlledNodes) {
    1123          668 :                 NBOwnTLDef dummy(DummyID, n, 0, TrafficLightType::STATIC);
    1124          668 :                 dummy.setParticipantsInformation();
    1125          668 :                 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
    1126          668 :                 delete tllDummy;
    1127          668 :                 myNeedsContRelation.insert(dummy.myNeedsContRelation.begin(), dummy.myNeedsContRelation.end());
    1128          668 :                 n->removeTrafficLight(&dummy);
    1129          668 :             }
    1130              : #ifdef DEBUG_CONTRELATION
    1131              :             if (DEBUGCOND) {
    1132              :                 std::cout << " contRelations at " << getID() << " prog=" << getProgramID() << ":\n";
    1133              :                 for (const StreamPair& s : myNeedsContRelation) {
    1134              :                     std::cout << "   " << s.from1->getID() << "->" << s.to1->getID() << " foe " << s.from2->getID() << "->" << s.to2->getID() << "\n";
    1135              :                 }
    1136              :             }
    1137              : #endif
    1138              : 
    1139              :         }
    1140          242 :         myNeedsContRelationReady = true;
    1141              :     }
    1142          288 : }
    1143              : 
    1144              : 
    1145              : EdgeVector
    1146         3663 : NBOwnTLDef::getConnectedOuterEdges(const EdgeVector& incoming) {
    1147         3663 :     EdgeVector result = incoming;
    1148        16085 :     for (EdgeVector::iterator it = result.begin(); it != result.end();) {
    1149        12422 :         if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
    1150              :             it = result.erase(it);
    1151              :         } else {
    1152              :             ++it;
    1153              :         }
    1154              :     }
    1155         3663 :     return result;
    1156              : }
    1157              : 
    1158              : 
    1159              : std::string
    1160         8067 : NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1161              :                             const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
    1162        16134 :     state = allowSingleEdge(state, fromEdges);
    1163              : #ifdef DEBUG_PHASES
    1164              :     if (DEBUGCOND) {
    1165              :         std::cout << " state after allowSingle " << state << "\n";
    1166              :     }
    1167              : #endif
    1168         8067 :     if (myControlledNodes.size() > 1) {
    1169         2044 :         state = allowFollowers(state, fromEdges, toEdges);
    1170              : #ifdef DEBUG_PHASES
    1171              :         if (DEBUGCOND) {
    1172              :             std::cout << " state after allowFollowers " << state << "\n";
    1173              :         }
    1174              : #endif
    1175         2044 :         state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
    1176              : #ifdef DEBUG_PHASES
    1177              :         if (DEBUGCOND) {
    1178              :             std::cout << " state after allowPredecessors " << state << "\n";
    1179              :         }
    1180              : #endif
    1181              :     }
    1182         8067 :     return state;
    1183              : }
    1184              : 
    1185              : 
    1186              : std::string
    1187         8067 : NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
    1188              :     // if only one edge has green, ensure sure that all connections from that edge are green
    1189         8067 :     const int size = (int)fromEdges.size();
    1190              :     NBEdge* greenEdge = nullptr;
    1191        89194 :     for (int i1 = 0; i1 < size; ++i1) {
    1192        85810 :         if (state[i1] == 'G') {
    1193        30233 :             if (greenEdge == nullptr) {
    1194         8067 :                 greenEdge = fromEdges[i1];
    1195        22166 :             } else if (greenEdge != fromEdges[i1]) {
    1196         4683 :                 return state;
    1197              :             }
    1198              :         }
    1199              :     }
    1200         3384 :     if (greenEdge != nullptr) {
    1201        35708 :         for (int i1 = 0; i1 < size; ++i1) {
    1202        32324 :             if (fromEdges[i1] == greenEdge) {
    1203         9677 :                 state[i1] = 'G';
    1204              :             }
    1205              :         }
    1206              :     }
    1207         3384 :     return state;
    1208              : }
    1209              : 
    1210              : 
    1211              : std::string
    1212         1022 : NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
    1213              :     // check continuation within joined traffic lights
    1214              :     bool check = true;
    1215         2628 :     while (check) {
    1216              :         check = false;
    1217        37140 :         for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1218        35534 :             if (state[i1] == 'G') {
    1219         9884 :                 continue;
    1220              :             }
    1221        25650 :             if (forbidden(state, i1, fromEdges, toEdges, true)) {
    1222        10152 :                 continue;
    1223              :             }
    1224              :             bool followsChosen = false;
    1225       604426 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1226       591027 :                 if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
    1227              :                     followsChosen = true;
    1228              :                     break;
    1229              :                 }
    1230              :             }
    1231        15498 :             if (followsChosen) {
    1232         2099 :                 state[i1] = 'G';
    1233              :                 check = true;
    1234              :             }
    1235              :         }
    1236              :     }
    1237         1022 :     return state;
    1238              : }
    1239              : 
    1240              : 
    1241              : std::string
    1242         1022 : NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1243              :                               const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
    1244              :     // also allow predecessors of chosen edges if the lanes match and there is no conflict
    1245              :     // (must be done after the followers are done because followers are less specific)
    1246              :     bool check = true;
    1247         2057 :     while (check) {
    1248              :         check = false;
    1249        23060 :         for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1250        22025 :             if (state[i1] == 'G') {
    1251         6911 :                 continue;
    1252              :             }
    1253        15114 :             if (forbidden(state, i1, fromEdges, toEdges, false)) {
    1254         8334 :                 continue;
    1255              :             }
    1256              :             bool preceedsChosen = false;
    1257       283514 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1258       276752 :                 if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
    1259       276831 :                         && fromLanes[i2] == toLanes[i1]) {
    1260              :                     preceedsChosen = true;
    1261              :                     break;
    1262              :                 }
    1263              :             }
    1264         6780 :             if (preceedsChosen) {
    1265           18 :                 state[i1] = 'G';
    1266              :                 check = true;
    1267              :             }
    1268              :         }
    1269              :     }
    1270         1022 :     return state;
    1271              : }
    1272              : 
    1273              : 
    1274              : std::string
    1275         6725 : NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1276              :                            const std::vector<bool>& isTurnaround,
    1277              :                            const std::vector<NBNode::Crossing*>& crossings) {
    1278        89688 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1279        82963 :         if (state[i1] == 'G') {
    1280        38007 :             continue;
    1281              :         }
    1282              :         bool isForbidden = false;
    1283       361992 :         for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1284       491657 :             if (state[i2] == 'G' && !isTurnaround[i2] &&
    1285       243843 :                     (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1286              :                 isForbidden = true;
    1287              :                 break;
    1288              :             }
    1289              :         }
    1290        44956 :         if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
    1291         3184 :             state[i1] = 'G';
    1292              :         }
    1293              :     }
    1294         6725 :     return state;
    1295              : }
    1296              : 
    1297              : 
    1298              : std::string
    1299           67 : NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
    1300          937 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1301          870 :         SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
    1302          870 :         if ((linkPerm & ~perm) == 0) {
    1303          279 :             state[i1] = 'G';
    1304              :         }
    1305              :     }
    1306           67 :     return state;
    1307              : }
    1308              : 
    1309              : 
    1310              : bool
    1311        40764 : NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges, bool allowCont) {
    1312      1187613 :     for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1313      1165335 :         if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
    1314        40802 :             if (!allowCont || (
    1315        29161 :                         !needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
    1316        12927 :                         !needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
    1317        18486 :                 return true;
    1318              :             }
    1319              :         }
    1320              :     }
    1321              :     return false;
    1322              : }
    1323              : 
    1324              : 
    1325              : std::string
    1326         8110 : NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
    1327              :                                const std::vector<bool>& isTurnaround,
    1328              :                                const std::vector<int>& fromLanes,
    1329              :                                const std::vector<int>& toLanes,
    1330              :                                const std::vector<bool>& hadGreenMajor,
    1331              :                                bool& haveForbiddenLeftMover,
    1332              :                                std::vector<bool>& rightTurnConflicts,
    1333              :                                std::vector<bool>& mergeConflicts) {
    1334         8110 :     const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
    1335       118559 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1336       110449 :         if (state[i1] == 'G') {
    1337       932459 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1338       883587 :                 if ((state[i2] == 'G' || state[i2] == 'g')) {
    1339       424792 :                     if (NBNode::rightTurnConflict(
    1340              :                                 fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
    1341              :                         rightTurnConflicts[i1] = true;
    1342              :                     }
    1343       424792 :                     if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
    1344        31648 :                         state[i1] = 'g';
    1345        31648 :                         if (myControlledNodes.size() == 1) {
    1346        28667 :                             myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
    1347              : #ifdef DEBUG_CONTRELATION
    1348              :                             if (DEBUGCOND) {
    1349              :                                 std::cout << getID() << " p=" << getProgramID() << " contRel: " << fromEdges[i1]->getID() << "->" << toEdges[i1]->getID()
    1350              :                                           << " foe " << fromEdges[i2]->getID() << "->" << toEdges[i2]->getID() << "\n";
    1351              :                             }
    1352              : #endif
    1353              :                         }
    1354        31648 :                         if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
    1355        19260 :                             haveForbiddenLeftMover = true;
    1356              :                         }
    1357       393144 :                     } else if (fromEdges[i1] == fromEdges[i2]
    1358       185509 :                                && fromLanes[i1] != fromLanes[i2]
    1359        79928 :                                && toEdges[i1] == toEdges[i2]
    1360        22505 :                                && toLanes[i1] == toLanes[i2]
    1361       393450 :                                && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
    1362              :                         mergeConflicts[i1] = true;
    1363          148 :                         state[i1] = 'g';
    1364              :                     }
    1365              :                 }
    1366              :             }
    1367              :         }
    1368       110449 :         if (state[i1] == 'r') {
    1369        61759 :             if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
    1370          261 :                     fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
    1371           56 :                 state[i1] = 's';
    1372              :                 // do not allow right-on-red when in conflict with exclusive left-turn phase
    1373          824 :                 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1374         1046 :                     if (state[i2] == 'G' && !isTurnaround[i2] &&
    1375          499 :                             (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
    1376          233 :                              forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1377           74 :                         const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
    1378           74 :                         if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
    1379           12 :                             state[i1] = 'r';
    1380           12 :                             break;
    1381              :                         }
    1382              :                     }
    1383              :                 }
    1384           56 :                 if (state[i1] == 's') {
    1385              :                     // handle right-on-red conflicts
    1386          716 :                     for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1387          913 :                         if (state[i2] == 'G' && !isTurnaround[i2] &&
    1388          449 :                                 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
    1389          208 :                                  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
    1390           62 :                             myExtraConflicts.insert(std::make_pair(i1, i2));
    1391              :                         }
    1392              :                     }
    1393              :                 }
    1394              :             }
    1395              :         }
    1396              :     }
    1397         8110 :     return state;
    1398              : }
    1399              : 
    1400              : 
    1401              : std::string
    1402           10 : NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
    1403              :                          const std::vector<int>& fromLanes,
    1404              :                          bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
    1405          152 :     for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1406          142 :         if ((state[i1] == 'G' || state[i1] == 'g')) {
    1407          368 :             for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
    1408          320 :                 if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
    1409          360 :                         && state[i2] != 'G' && state[i2] != 'g') {
    1410           12 :                     state[i1] = state[i2];
    1411              :                     //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
    1412              :                     mixedGreen[i1] = true;
    1413           12 :                     if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
    1414            4 :                         buildMixedGreenPhase = true;
    1415              :                     }
    1416              :                 }
    1417              :             }
    1418              :         }
    1419              :     }
    1420           10 :     return state;
    1421              : }
    1422              : 
    1423              : 
    1424              : void
    1425          116 : NBOwnTLDef::addGreenWithin(NBTrafficLightLogic* logic, const EdgeVector& fromEdges, EdgeVector& toProc) {
    1426          116 :     std::vector<bool> foundGreen(fromEdges.size(), false);
    1427         1111 :     for (const auto& phase : logic->getPhases()) {
    1428              :         const std::string state = phase.state;
    1429        27200 :         for (int j = 0; j < (int)fromEdges.size(); j++) {
    1430        26205 :             LinkState ls = (LinkState)state[j];
    1431        26205 :             if (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR) {
    1432              :                 foundGreen[j] = true;
    1433              :             }
    1434              :         }
    1435              :     }
    1436         5040 :     for (int j = 0; j < (int)foundGreen.size(); j++) {
    1437         2462 :         if (!foundGreen[j]) {
    1438            4 :             NBEdge* e = fromEdges[j];
    1439            4 :             if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
    1440            3 :                 toProc.push_back(e);
    1441              :             }
    1442              :         }
    1443              :     }
    1444          116 : }
    1445              : 
    1446              : 
    1447              : void
    1448          331 : NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int totalNumLinks, SUMOTime /* greenTime */, SUMOTime brakingTime,
    1449              :                                   const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
    1450              :     // check both indices for each crossing (they may have green in different phases)
    1451          331 :     std::vector<bool> foundGreen(crossings.size() * 2, false);
    1452              :     const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
    1453         2356 :     for (int i = 0; i < (int)phases.size(); i++) {
    1454         2025 :         const std::string state = phases[i].state;
    1455              :         int j = 0;
    1456        11503 :         for (auto cross : crossings) {
    1457         9478 :             LinkState ls = (LinkState)state[cross->tlLinkIndex];
    1458         9478 :             LinkState ls2 = cross->tlLinkIndex2 >= 0 ? (LinkState)state[cross->tlLinkIndex2] : ls;
    1459         9478 :             if (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR) {
    1460              :                 foundGreen[j] = true;
    1461              :             }
    1462         9478 :             if (ls2 == LINKSTATE_TL_GREEN_MAJOR || ls2 == LINKSTATE_TL_GREEN_MINOR) {
    1463         1631 :                 foundGreen[j + crossings.size()] = true;
    1464              :             }
    1465         9478 :             j++;
    1466              :         }
    1467              :     }
    1468              : #ifdef DEBUG_PHASES
    1469              :     if (DEBUGCOND2(logic)) {
    1470              :         std::cout << " foundCrossingGreen=" << toString(foundGreen) << "\n";
    1471              :     }
    1472              : #endif
    1473         4587 :     for (int j = 0; j < (int)foundGreen.size(); j++) {
    1474         2206 :         if (!foundGreen[j]) {
    1475              :             // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
    1476           78 :             if (phases.size() > 0) {
    1477              :                 bool needYellowPhase = false;
    1478              :                 std::string state = phases.back().state;
    1479          707 :                 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
    1480          629 :                     if (state[i1] == 'G' || state[i1] == 'g') {
    1481           99 :                         state[i1] = 'y';
    1482              :                         needYellowPhase = true;
    1483              :                     }
    1484              :                 }
    1485              :                 // add yellow step
    1486           78 :                 if (needYellowPhase && brakingTime > 0) {
    1487            0 :                     logic->addStep(brakingTime, state);
    1488              :                 }
    1489              :             }
    1490           78 :             const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
    1491           78 :             const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
    1492           78 :             addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION,
    1493           78 :                                 UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(totalNumLinks, 'r'), crossings, fromEdges, toEdges);
    1494           78 :             break;
    1495              :         }
    1496              :     }
    1497          331 : }
    1498              : 
    1499              : 
    1500              : void
    1501         4116 : NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
    1502         4116 :     if (allRedTime > 0) {
    1503              :         // build all-red phase
    1504              :         std::string allRedState = state;
    1505         6053 :         for (int i = 0; i < (int)state.size(); i++) {
    1506         5777 :             if (allRedState[i] == 'Y' || allRedState[i] == 'y') {
    1507         1678 :                 allRedState[i] = 'r';
    1508              :             }
    1509              :         }
    1510          276 :         logic->addStep(TIME2STEPS(ceil(STEPS2TIME(allRedTime))), allRedState);
    1511              :     }
    1512         4116 : }
    1513              : 
    1514              : 
    1515              : int
    1516         4243 : NBOwnTLDef::maxCrossingIndex(const NBNode* node) const {
    1517              :     int result = 0;
    1518         5470 :     for (auto crossing : node->getCrossings()) {
    1519         1227 :         result = MAX2(result, crossing->tlLinkIndex);
    1520         1227 :         result = MAX2(result, crossing->tlLinkIndex2);
    1521         4243 :     }
    1522         4243 :     return result;
    1523              : }
    1524              : 
    1525              : void
    1526            0 : NBOwnTLDef::fixSuperfluousYellow(NBTrafficLightLogic* logic) const {
    1527              :     // assume that yellow states last at most one phase
    1528              :     const int n = logic->getNumLinks();
    1529            0 :     const int p = (int)logic->getPhases().size();
    1530            0 :     for (int i1 = 0; i1 < n; ++i1) {
    1531            0 :         LinkState prev = (LinkState)logic->getPhases().back().state[i1];
    1532            0 :         for (int i2 = 0; i2 < p; ++i2) {
    1533            0 :             LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
    1534            0 :             LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
    1535            0 :             if (cur == LINKSTATE_TL_YELLOW_MINOR
    1536            0 :                     && (prev == LINKSTATE_TL_GREEN_MAJOR || prev == LINKSTATE_TL_YELLOW_MINOR)
    1537            0 :                     && next == LINKSTATE_TL_GREEN_MAJOR) {
    1538            0 :                 logic->setPhaseState(i2, i1, prev);
    1539              :             }
    1540              :             prev = cur;
    1541              :         }
    1542              :     }
    1543            0 : }
    1544              : 
    1545              : 
    1546              : void
    1547            0 : NBOwnTLDef::deactivateAlwaysGreen(NBTrafficLightLogic* logic) const {
    1548              :     const int n = logic->getNumLinks();
    1549            0 :     std::vector<bool> alwaysGreen(n, true);
    1550            0 :     for (int i1 = 0; i1 < n; ++i1) {
    1551            0 :         for (const auto& phase : logic->getPhases()) {
    1552            0 :             if (phase.state[i1] != 'G') {
    1553              :                 alwaysGreen[i1] = false;
    1554            0 :                 break;
    1555              :             }
    1556              :         }
    1557              :     }
    1558            0 :     const int p = (int)logic->getPhases().size();
    1559            0 :     for (int i1 = 0; i1 < n; ++i1) {
    1560            0 :         if (alwaysGreen[i1]) {
    1561            0 :             for (int i2 = 0; i2 < p; ++i2) {
    1562            0 :                 logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
    1563              :             }
    1564              :         }
    1565              :     }
    1566            0 : }
    1567              : 
    1568              : 
    1569              : void
    1570           11 : NBOwnTLDef::deactivateInsideEdges(NBTrafficLightLogic* logic, const EdgeVector& fromEdges) const {
    1571           11 :     const int n = (int)fromEdges.size();
    1572           11 :     const int p = (int)logic->getPhases().size();
    1573           89 :     for (int i1 = 0; i1 < n; ++i1) {
    1574           78 :         if (fromEdges[i1]->isInsideTLS()) {
    1575          470 :             for (int i2 = 0; i2 < p; ++i2) {
    1576          428 :                 logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
    1577              :             }
    1578              :         }
    1579              :     }
    1580           11 : }
    1581              : 
    1582              : 
    1583              : SUMOTime
    1584           24 : NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
    1585           24 :     const int n = (int)fromEdges.size();
    1586              :     double maxTime = 0;
    1587          232 :     for (int i1 = 0; i1 < n; ++i1) {
    1588          208 :         if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
    1589          344 :             for (int i2 = 0; i2 < n; ++i2) {
    1590          312 :                 if (fromEdges[i2]->isInsideTLS()) {
    1591          180 :                     double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
    1592          180 :                     double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
    1593              :                     maxTime = MAX2(maxTime, time);
    1594              :                 }
    1595              :             }
    1596              :         }
    1597              :     }
    1598              :     // give some slack
    1599           24 :     return TIME2STEPS(floor(maxTime * 1.2 + 5));
    1600              : }
    1601              : 
    1602              : 
    1603              : int
    1604            0 : NBOwnTLDef::getMaxIndex() {
    1605            0 :     setParticipantsInformation();
    1606            0 :     NBTrafficLightLogic* logic = compute(OptionsCont::getOptions());
    1607            0 :     if (logic != nullptr) {
    1608            0 :         return logic->getNumLinks() - 1;
    1609              :     } else {
    1610              :         return -1;
    1611              :     }
    1612              : }
    1613              : 
    1614              : 
    1615              : bool
    1616          133 : NBOwnTLDef::corridorLike() const {
    1617          133 :     if (getID() == DummyID) {
    1618              :         // avoid infinite recursion
    1619              :         return true;
    1620              :     }
    1621              :     // setParticipantsInformation resets myAmInTLS so we need to make a copy
    1622              :     std::vector<bool> edgeInsideTLS;
    1623          441 :     for (const NBEdge* e : myIncomingEdges) {
    1624          399 :         edgeInsideTLS.push_back(e->isInsideTLS());
    1625              :     }
    1626              :     assert(myControlledNodes.size() >= 2);
    1627           42 :     NBOwnTLDef dummy(DummyID, myControlledNodes, 0, TrafficLightType::STATIC);
    1628           42 :     dummy.setParticipantsInformation();
    1629           42 :     NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
    1630              :     int greenPhases = 0;
    1631          162 :     for (const auto& phase : tllDummy->getPhases()) {
    1632          120 :         if (phase.state.find_first_of("gG") != std::string::npos) {
    1633          120 :             greenPhases++;
    1634              :         }
    1635              :     }
    1636           42 :     delete tllDummy;
    1637          212 :     for (const auto& controlledNode : myControlledNodes) {
    1638          170 :         controlledNode->removeTrafficLight(&dummy);
    1639              :     }
    1640              :     int i = 0;
    1641          441 :     for (NBEdge* e : myIncomingEdges) {
    1642              :         e->setInsideTLS(edgeInsideTLS[i]);
    1643          399 :         i++;
    1644              :     }
    1645           42 :     return greenPhases <= 2;
    1646           42 : }
    1647              : 
    1648              : 
    1649              : NBTrafficLightLogic*
    1650           26 : NBOwnTLDef::buildNemaPhases(
    1651              :     const EdgeVector& fromEdges,
    1652              :     const EdgeVector& toEdges,
    1653              :     const std::vector<NBNode::Crossing*>& crossings,
    1654              :     const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
    1655              :     const std::vector<std::string>& straightStates,
    1656              :     const std::vector<std::string>& leftStates) {
    1657           26 :     if (chosenList.size() != 2) {
    1658              :         return nullptr;
    1659              :     }
    1660           25 :     const SUMOTime dur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
    1661           25 :     const SUMOTime vehExt = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.vehExt"));
    1662           25 :     const SUMOTime yellow = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.yellow"));
    1663           25 :     const SUMOTime red = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.red"));
    1664           25 :     const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
    1665           25 :     const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
    1666           25 :     const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
    1667              :     const SUMOTime latestEnd = UNSPECIFIED_DURATION;
    1668              : 
    1669           25 :     const int totalNumLinks = (int)straightStates[0].size();
    1670           25 :     NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
    1671           25 :     std::vector<int> ring1({1, 2, 3, 4});
    1672           25 :     std::vector<int> ring2({5, 6, 7, 8});
    1673           25 :     std::vector<int> barrier1({4, 8});
    1674           25 :     std::vector<int> barrier2({2, 6});
    1675           25 :     int phaseNameLeft = 1;
    1676           73 :     for (int i = 0; i < (int)chosenList.size(); i++) {
    1677           49 :         NBEdge* e1 = chosenList[i].first;
    1678              :         assert(e1 != nullptr);
    1679           49 :         NBEdge* e2 = chosenList[i].second;
    1680           49 :         if (i < (int)leftStates.size()) {
    1681           98 :             std::string left1 = filterState(leftStates[i], fromEdges, e1);
    1682           49 :             if (left1 != "") {
    1683           78 :                 logic->addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft));
    1684              :             }
    1685              :         }
    1686           49 :         if (e2 != nullptr) {
    1687           38 :             std::string straight2 = filterState(straightStates[i], fromEdges, e2);
    1688           76 :             straight2 = patchNEMAStateForCrossings(straight2, crossings, fromEdges, toEdges, e2, e1);
    1689              : 
    1690           76 :             logic->addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 1));
    1691           38 :             if (i < (int)leftStates.size()) {
    1692           76 :                 std::string left2 = filterState(leftStates[i], fromEdges, e2);
    1693           38 :                 if (left2 != "") {
    1694           52 :                     logic->addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 4));
    1695              :                 }
    1696              :             }
    1697              : 
    1698              :         }
    1699           49 :         std::string straight1 = filterState(straightStates[i], fromEdges, e1);
    1700           49 :         if (straight1 == "") {
    1701            1 :             delete logic;
    1702              :             return nullptr;
    1703              :         }
    1704           96 :         straight1 = patchNEMAStateForCrossings(straight1, crossings, fromEdges, toEdges, e1, e2);
    1705           96 :         logic->addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 5));
    1706           48 :         phaseNameLeft += 2;
    1707              :     }
    1708              :     std::map<int, int> names; // nema phase name -> sumo phase index
    1709          174 :     for (int i = 0; i < (int)logic->getPhases().size(); i++) {
    1710          150 :         names[StringUtils::toInt(logic->getPhases()[i].name)] = i;
    1711              :     }
    1712              : 
    1713           24 :     filterMissingNames(ring1, names, false);
    1714           24 :     filterMissingNames(ring2, names, false);
    1715           24 :     filterMissingNames(barrier1, names, true, 8);
    1716           24 :     filterMissingNames(barrier2, names, true, 6);
    1717           24 :     if (ring1[0] == 0 && ring1[1] == 0) {
    1718            1 :         ring1[1] = 6;
    1719              :     }
    1720           24 :     if (ring1[2] == 0 && ring1[3] == 0) {
    1721            3 :         ring1[3] = 8;
    1722              :     }
    1723           24 :     fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
    1724           24 :     fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
    1725              : 
    1726           48 :     logic->setParameter("ring1", joinToString(ring1, ","));
    1727           48 :     logic->setParameter("ring2", joinToString(ring2, ","));
    1728           48 :     logic->setParameter("barrierPhases", joinToString(barrier1, ","));
    1729           48 :     logic->setParameter("barrier2Phases", joinToString(barrier2, ","));
    1730              :     return logic;
    1731           25 : }
    1732              : 
    1733              : 
    1734              : std::string
    1735          174 : NBOwnTLDef::filterState(std::string state, const EdgeVector& fromEdges, const NBEdge* e) {
    1736              :     bool haveGreen = false;
    1737         2498 :     for (int j = 0; j < (int)fromEdges.size(); j++) {
    1738         2324 :         if (fromEdges[j] != e) {
    1739         1698 :             state[j] = 'r';
    1740          626 :         } else if (state[j] != 'r') {
    1741              :             haveGreen = true;
    1742              :         }
    1743              :     }
    1744          174 :     if (haveGreen) {
    1745          151 :         return state;
    1746              :     } else {
    1747           23 :         return "";
    1748              :     }
    1749              : }
    1750              : 
    1751              : void
    1752           96 : NBOwnTLDef::filterMissingNames(std::vector<int>& vec, const std::map<int, int>& names, bool isBarrier, int barrierDefault) {
    1753          384 :     for (int i = 0; i < (int)vec.size(); i++) {
    1754          288 :         if (names.count(vec[i]) == 0) {
    1755           52 :             if (isBarrier) {
    1756           10 :                 if (names.count(vec[i] - 1) > 0) {
    1757            6 :                     vec[i] = vec[i] - 1;
    1758              :                 } else {
    1759            4 :                     vec[i] = barrierDefault;
    1760              :                 }
    1761              :             } else {
    1762           42 :                 vec[i] = 0;
    1763              :             }
    1764              :         }
    1765              :     }
    1766           96 : }
    1767              : 
    1768              : void
    1769           48 : NBOwnTLDef::fixDurationSum(NBTrafficLightLogic* logic, const std::map<int, int>& names, int ring1a, int ring1b, int ring2a, int ring2b) {
    1770              :     std::set<int> ring1existing;
    1771              :     std::set<int> ring2existing;
    1772              :     if (names.count(ring1a) != 0) {
    1773              :         ring1existing.insert(ring1a);
    1774              :     }
    1775              :     if (names.count(ring1b) != 0) {
    1776              :         ring1existing.insert(ring1b);
    1777              :     }
    1778              :     if (names.count(ring2a) != 0) {
    1779              :         ring2existing.insert(ring2a);
    1780              :     }
    1781              :     if (names.count(ring2b) != 0) {
    1782              :         ring2existing.insert(ring2b);
    1783              :     }
    1784           48 :     if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
    1785              :             ring1existing.size() != ring2existing.size()) {
    1786              :         int pI; // sumo phase index
    1787            6 :         if (ring1existing.size() < ring2existing.size()) {
    1788            0 :             pI = names.find(*ring1existing.begin())->second;
    1789              :         } else {
    1790            6 :             pI = names.find(*ring2existing.begin())->second;
    1791              :         }
    1792            6 :         const auto& p = logic->getPhases()[pI];
    1793            6 :         SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
    1794            6 :         logic->setPhaseMaxDuration(pI, newMaxDur);
    1795              :     }
    1796           48 : }
    1797              : 
    1798              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1