LCOV - code coverage report
Current view: top level - src/netbuild - NBTrafficLightDefinition.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 213 226 94.2 %
Date: 2024-05-06 15:32:35 Functions: 24 28 85.7 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    NBTrafficLightDefinition.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    Sept 2002
      19             : ///
      20             : // The base class for traffic light logic definitions
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <vector>
      25             : #include <string>
      26             : #include <algorithm>
      27             : #include <cassert>
      28             : #include <iterator>
      29             : #include <utils/common/MsgHandler.h>
      30             : #include <utils/common/ToString.h>
      31             : #include "NBTrafficLightDefinition.h"
      32             : #include <utils/options/OptionsCont.h>
      33             : #include "NBLinkPossibilityMatrix.h"
      34             : #include "NBTrafficLightLogic.h"
      35             : #include "NBOwnTLDef.h"
      36             : #include "NBContHelper.h"
      37             : 
      38             : //#define DEBUG_RIGHT_OF_WAY
      39             : #define DEBUGCOND true
      40             : 
      41             : // ===========================================================================
      42             : // static members
      43             : // ===========================================================================
      44             : const std::string NBTrafficLightDefinition::DefaultProgramID = "0";
      45             : const std::string NBTrafficLightDefinition::DummyID = "dummy";
      46             : const SUMOTime NBTrafficLightDefinition::UNSPECIFIED_DURATION(-1);
      47             : const int NBTrafficLightDefinition::MIN_YELLOW_SECONDS(3);
      48             : const std::string NBTrafficLightDefinition::OSM_DIRECTION("osm:direction");
      49             : const std::string NBTrafficLightDefinition::OSM_SIGNAL_DIRECTION("railway:signal:direction");
      50             : 
      51             : 
      52             : // ===========================================================================
      53             : // method definitions
      54             : // ===========================================================================
      55         184 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
      56             :         const std::vector<NBNode*>& junctions, const std::string& programID,
      57         184 :         SUMOTime offset, TrafficLightType type) :
      58             :     Named(id),
      59         184 :     myControlledNodes(junctions),
      60         184 :     mySubID(programID), myOffset(offset),
      61         184 :     myType(type),
      62         184 :     myNeedsContRelationReady(false),
      63         368 :     myRightOnRedConflictsReady(false) {
      64             :     std::vector<NBNode*>::iterator i = myControlledNodes.begin();
      65         684 :     while (i != myControlledNodes.end()) {
      66        1543 :         for (std::vector<NBNode*>::iterator j = i + 1; j != myControlledNodes.end();) {
      67        1043 :             if (*i == *j) {
      68             :                 j = myControlledNodes.erase(j);
      69             :             } else {
      70             :                 j++;
      71             :             }
      72             :         }
      73             :         i++;
      74             :     }
      75         184 :     std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
      76         925 :     for (NBNode* const node : junctions) {
      77         741 :         node->addTrafficLight(this);
      78             :     }
      79         184 : }
      80             : 
      81             : 
      82        7268 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
      83        7268 :         NBNode* junction, const std::string& programID, SUMOTime offset, TrafficLightType type) :
      84             :     Named(id),
      85        7268 :     mySubID(programID),
      86        7268 :     myOffset(offset),
      87        7268 :     myType(type),
      88        7268 :     myNeedsContRelationReady(false),
      89        7268 :     myRightOnRedConflictsReady(false) {
      90        7268 :     addNode(junction);
      91        7268 : }
      92             : 
      93             : 
      94         925 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id, const std::string& programID,
      95         925 :         SUMOTime offset, TrafficLightType type) :
      96             :     Named(id),
      97         925 :     mySubID(programID),
      98         925 :     myOffset(offset),
      99         925 :     myType(type),
     100         925 :     myNeedsContRelationReady(false),
     101         925 :     myRightOnRedConflictsReady(false) {
     102         925 : }
     103             : 
     104             : 
     105       25131 : NBTrafficLightDefinition::~NBTrafficLightDefinition() {}
     106             : 
     107             : 
     108             : NBTrafficLightLogic*
     109        3707 : NBTrafficLightDefinition::compute(const OptionsCont& oc) {
     110             :     // it is not really a traffic light if no incoming edge exists
     111        3707 :     if (amInvalid()) {
     112             :         // make a copy of myControlledNodes because it will be modified;
     113          69 :         std::vector<NBNode*> nodes = myControlledNodes;
     114         138 :         for (auto it : nodes) {
     115          69 :             it->removeTrafficLight(this);
     116             :         }
     117         213 :         WRITE_WARNINGF(TL("The traffic light '%' does not control any links; it will not be build."), getID());
     118             :         return nullptr;
     119             :     }
     120             :     // compute the time needed to brake
     121        3638 :     int brakingTime = computeBrakingTime(oc.getFloat("tls.yellow.min-decel"));
     122             :     // perform the computation depending on whether the traffic light
     123             :     //  definition was loaded or shall be computed new completely
     124        7276 :     if (!oc.isDefault("tls.yellow.time")) {
     125           0 :         brakingTime = oc.getInt("tls.yellow.time");
     126             :     }
     127        3638 :     NBTrafficLightLogic* ret = myCompute(brakingTime);
     128        3638 :     ret->updateParameters(getParametersMap());
     129        3638 :     return ret;
     130             : }
     131             : 
     132             : 
     133             : bool
     134        2733 : NBTrafficLightDefinition::amInvalid() const {
     135        2733 :     return myControlledLinks.size() == 0;
     136             : }
     137             : 
     138             : 
     139             : int
     140        3650 : NBTrafficLightDefinition::computeBrakingTime(double minDecel) const {
     141        3650 :     if (myIncomingEdges.empty()) {
     142             :         // don't crash
     143             :         return MIN_YELLOW_SECONDS;
     144             :     }
     145        3650 :     const double vmax = NBContHelper::maxSpeed(myIncomingEdges);
     146        3650 :     if (vmax < 71 / 3.6) {
     147             :         // up to 50kmh: 3 seconds , 60km/h: 4, 70kmh: 5
     148             :         // @note: these are German regulations, other countries may differ
     149        6559 :         return MIN_YELLOW_SECONDS + (int)MAX2(0.0, (floor((vmax - 50 / 3.6) * 0.37)));
     150             :     } else {
     151             :         // above 70km/h we use a function that grows according to the "natural"
     152             :         // formula (vmax / 2 * minDecel) but continues smoothly where the german
     153             :         // rules leave of
     154         199 :         return (int)(1.8 + vmax / 2 / minDecel);
     155             :     }
     156             : }
     157             : 
     158             : 
     159             : void
     160        6628 : NBTrafficLightDefinition::setParticipantsInformation() {
     161             :     // collect the information about participating edges and links
     162        6628 :     collectEdges();
     163        6628 :     collectLinks();
     164        6628 : }
     165             : 
     166             : std::set<NBEdge*>
     167       11616 : NBTrafficLightDefinition::collectReachable(EdgeVector outer, const EdgeVector& within, bool checkControlled) {
     168             :     std::set<NBEdge*> reachable;
     169       38634 :     while (outer.size() > 0) {
     170       27018 :         NBEdge* from = outer.back();
     171             :         outer.pop_back();
     172             :         std::vector<NBEdge::Connection>& cons = from->getConnections();
     173       91252 :         for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); k++) {
     174       64234 :             NBEdge* to = (*k).toEdge;
     175       62688 :             if (reachable.count(to) == 0 &&
     176       64566 :                     (find(within.begin(), within.end(), to) != within.end()) &&
     177         332 :                     (!checkControlled || from->mayBeTLSControlled((*k).fromLane, to, (*k).toLane))) {
     178             :                 reachable.insert(to);
     179         664 :                 outer.push_back(to);
     180             :             }
     181             :         }
     182             :     }
     183       11616 :     return reachable;
     184             : }
     185             : 
     186             : 
     187             : void
     188        5808 : NBTrafficLightDefinition::collectEdges() {
     189        5808 :     myIncomingEdges.clear();
     190        5808 :     myEdgesWithin.clear();
     191             :     EdgeVector myOutgoing;
     192             :     // collect the edges from the participating nodes
     193       11132 :     for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     194        5324 :         const EdgeVector& incoming = (*i)->getIncomingEdges();
     195             :         copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
     196        5324 :         const EdgeVector& outgoing = (*i)->getOutgoingEdges();
     197             :         copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
     198             :     }
     199             :     EdgeVector outer;
     200             :     // check which of the edges are completely within the junction
     201             :     //  add them to the list of edges lying within the node
     202       19371 :     for (NBEdge* edge : myIncomingEdges) {
     203             :         edge->setInsideTLS(false); // reset
     204             :         // an edge lies within the logic if it is outgoing as well as incoming
     205       13563 :         EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
     206       13563 :         if (k != myOutgoing.end()) {
     207         386 :             myEdgesWithin.push_back(edge);
     208             :         } else  {
     209       13177 :             outer.push_back(edge);
     210             :         }
     211             :     }
     212             :     // collect edges that are reachable from the outside via controlled connections
     213        5808 :     std::set<NBEdge*> reachable = collectReachable(outer, myEdgesWithin, true);
     214             :     // collect edges that are reachable from the outside regardless of controllability
     215        5808 :     std::set<NBEdge*> reachable2 = collectReachable(outer, myEdgesWithin, false);
     216             : 
     217       11616 :     const bool uncontrolledWithin = OptionsCont::getOptions().getBool("tls.uncontrolled-within");
     218        6194 :     for (EdgeVector::iterator j = myEdgesWithin.begin(); j != myEdgesWithin.end(); ++j) {
     219         386 :         NBEdge* edge = *j;
     220             :         // edges that are marked as 'inner' will not get their own phase when
     221             :         // computing traffic light logics (unless they cannot be reached from the outside at all)
     222             :         if (reachable.count(edge) == 1) {
     223             :             edge->setInsideTLS(true);
     224             :             // legacy behavior
     225         340 :             if (uncontrolledWithin && myControlledInnerEdges.count(edge->getID()) == 0) {
     226          23 :                 myIncomingEdges.erase(find(myIncomingEdges.begin(), myIncomingEdges.end(), edge));
     227             :             }
     228             :         }
     229          46 :         if (reachable2.count(edge) == 0 && edge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true) >= 0
     230           5 :                 && getID() != DummyID) {
     231          25 :             WRITE_WARNINGF(TL("Unreachable edge '%' within tlLogic '%'"), edge->getID(), getID());
     232             :         }
     233             :     }
     234        5808 : }
     235             : 
     236             : 
     237             : bool
     238           0 : NBTrafficLightDefinition::mustBrake(const NBEdge* const from, const NBEdge* const to) const {
     239             :     std::vector<NBNode*>::const_iterator i =
     240           0 :         find_if(myControlledNodes.begin(), myControlledNodes.end(),
     241             :                 NBContHelper::node_with_incoming_finder(from));
     242             :     assert(i != myControlledNodes.end());
     243           0 :     NBNode* node = *i;
     244           0 :     if (!node->hasOutgoing(to)) {
     245             :         return true; // !!!
     246             :     }
     247             :     // @todo recheck relevance of lane indices
     248           0 :     return node->mustBrake(from, to, -1, -1, true);
     249             : }
     250             : 
     251             : 
     252             : bool
     253           0 : NBTrafficLightDefinition::mustBrake(const NBEdge* const possProhibitedFrom,
     254             :                                     const NBEdge* const possProhibitedTo,
     255             :                                     const NBEdge* const possProhibitorFrom,
     256             :                                     const NBEdge* const possProhibitorTo,
     257             :                                     bool regardNonSignalisedLowerPriority) const {
     258           0 :     return forbids(possProhibitorFrom, possProhibitorTo,
     259             :                    possProhibitedFrom, possProhibitedTo,
     260           0 :                    regardNonSignalisedLowerPriority);
     261             : }
     262             : 
     263             : 
     264             : bool
     265        1778 : NBTrafficLightDefinition::mustBrake(const NBConnection& possProhibited,
     266             :                                     const NBConnection& possProhibitor,
     267             :                                     bool regardNonSignalisedLowerPriority) const {
     268        1778 :     return forbids(possProhibitor.getFrom(), possProhibitor.getTo(),
     269        1778 :                    possProhibited.getFrom(), possProhibited.getTo(),
     270        1778 :                    regardNonSignalisedLowerPriority);
     271             : }
     272             : 
     273             : 
     274             : bool
     275      899420 : NBTrafficLightDefinition::forbids(const NBEdge* const possProhibitorFrom,
     276             :                                   const NBEdge* const possProhibitorTo,
     277             :                                   const NBEdge* const possProhibitedFrom,
     278             :                                   const NBEdge* const possProhibitedTo,
     279             :                                   bool regardNonSignalisedLowerPriority,
     280             :                                   bool sameNodeOnly) const {
     281      899420 :     if (possProhibitorFrom == nullptr || possProhibitorTo == nullptr || possProhibitedFrom == nullptr || possProhibitedTo == nullptr) {
     282             :         return false;
     283             :     }
     284             :     // retrieve both nodes
     285             :     std::vector<NBNode*>::const_iterator incoming =
     286      899420 :         find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorFrom));
     287             :     std::vector<NBNode*>::const_iterator outgoing =
     288      899420 :         find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(possProhibitedTo));
     289             :     assert(incoming != myControlledNodes.end());
     290      899420 :     NBNode* incnode = *incoming;
     291      899420 :     NBNode* outnode = *outgoing;
     292             :     EdgeVector::const_iterator i;
     293             : 
     294             : #ifdef DEBUG_RIGHT_OF_WAY
     295             :     if (DEBUGCOND) {
     296             :         std::cout << "foribds tls=" << getID() << " from=" << possProhibitedFrom->getID() << " to=" << possProhibitedTo->getID() << " foeFrom=" << possProhibitorFrom->getID() << " foeTo=" << possProhibitorTo->getID() << " rnslp=" << regardNonSignalisedLowerPriority << " sameNodeOnly=" << sameNodeOnly;
     297             :     }
     298             : #endif
     299      899420 :     if (incnode != outnode) {
     300      140932 :         if (sameNodeOnly) {
     301             : #ifdef DEBUG_RIGHT_OF_WAY
     302             :             if (DEBUGCOND) {
     303             :                 std::cout << "   differentNodes: allows (no check)\n";
     304             :             }
     305             : #endif
     306             :             return false;
     307             :         }
     308             :         // the links are located at different nodes
     309       80159 :         const EdgeVector& ev1 = possProhibitedTo->getConnectedEdges();
     310             :         // go through the following edge,
     311             :         //  check whether one of these connections is prohibited
     312      190615 :         for (i = ev1.begin(); i != ev1.end(); ++i) {
     313             :             std::vector<NBNode*>::const_iterator outgoing2 =
     314      111110 :                 find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(*i));
     315      111110 :             if (outgoing2 == myControlledNodes.end()) {
     316       73028 :                 continue;
     317             :             }
     318       38082 :             NBNode* outnode2 = *outgoing2;
     319       38082 :             if (incnode != outnode2) {
     320       26774 :                 continue;
     321             :             }
     322       11308 :             if (incnode->getDirection(possProhibitedTo, *i) != LinkDirection::STRAIGHT) {
     323        6539 :                 continue;
     324             :             }
     325        4769 :             bool ret1 = incnode->foes(possProhibitorFrom, possProhibitorTo,
     326             :                                       possProhibitedTo, *i);
     327        4769 :             bool ret2 = incnode->forbids(possProhibitorFrom, possProhibitorTo,
     328             :                                          possProhibitedTo, *i,
     329             :                                          regardNonSignalisedLowerPriority);
     330        4769 :             bool ret = ret1 || ret2;
     331        4769 :             if (ret) {
     332             : #ifdef DEBUG_RIGHT_OF_WAY
     333             :                 if (DEBUGCOND) {
     334             :                     std::cout << "   differentNodes: forbids\n";
     335             :                 }
     336             : #endif
     337             :                 return true;
     338             :             }
     339             :         }
     340             : 
     341       79505 :         const EdgeVector& ev2 = possProhibitorTo->getConnectedEdges();
     342             :         // go through the following edge,
     343             :         //  check whether one of these connections is prohibited
     344      188826 :         for (i = ev2.begin(); i != ev2.end(); ++i) {
     345             :             std::vector<NBNode*>::const_iterator incoming2 =
     346      110371 :                 find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorTo));
     347      110371 :             if (incoming2 == myControlledNodes.end()) {
     348       71855 :                 continue;
     349             :             }
     350       38516 :             NBNode* incnode2 = *incoming2;
     351       38516 :             if (incnode2 != outnode) {
     352       26593 :                 continue;
     353             :             }
     354       11923 :             if (incnode2->getDirection(possProhibitorTo, *i) != LinkDirection::STRAIGHT) {
     355        6761 :                 continue;
     356             :             }
     357        5162 :             bool ret1 = incnode2->foes(possProhibitorTo, *i,
     358             :                                        possProhibitedFrom, possProhibitedTo);
     359        5162 :             bool ret2 = incnode2->forbids(possProhibitorTo, *i,
     360             :                                           possProhibitedFrom, possProhibitedTo,
     361             :                                           regardNonSignalisedLowerPriority);
     362        5162 :             bool ret = ret1 || ret2;
     363        5162 :             if (ret) {
     364             : #ifdef DEBUG_RIGHT_OF_WAY
     365             :                 if (DEBUGCOND) {
     366             :                     std::cout << "   differentNodes: forbids (2)\n";
     367             :                 }
     368             : #endif
     369             :                 return true;
     370             :             }
     371             :         }
     372             : #ifdef DEBUG_RIGHT_OF_WAY
     373             :         if (DEBUGCOND) {
     374             :             std::cout << "   differentNodes: allows\n";
     375             :         }
     376             : #endif
     377             :         return false;
     378             :     }
     379             :     // both links are located at the same node
     380             :     //  check using this node's information
     381      758488 :     const bool result = incnode->forbids(possProhibitorFrom, possProhibitorTo,
     382             :                                          possProhibitedFrom, possProhibitedTo,
     383             :                                          regardNonSignalisedLowerPriority);
     384             : #ifdef DEBUG_RIGHT_OF_WAY
     385             :     if (DEBUGCOND) {
     386             :         std::cout << "   sameNodes: " << (result ? "forbids" : "allows") << "\n";
     387             :     }
     388             : #endif
     389             :     return result;
     390             : }
     391             : 
     392             : 
     393             : bool
     394      177378 : NBTrafficLightDefinition::foes(const NBEdge* const from1, const NBEdge* const to1,
     395             :                                const NBEdge* const from2, const NBEdge* const to2) const {
     396      177378 :     if (to1 == nullptr || to2 == nullptr) {
     397             :         return false;
     398             :     }
     399             :     // retrieve both nodes (it is possible that a connection
     400             :     std::vector<NBNode*>::const_iterator incoming =
     401      177378 :         find_if(myControlledNodes.begin(), myControlledNodes.end(),
     402             :                 NBContHelper::node_with_incoming_finder(from1));
     403             :     std::vector<NBNode*>::const_iterator outgoing =
     404      177378 :         find_if(myControlledNodes.begin(), myControlledNodes.end(),
     405             :                 NBContHelper::node_with_outgoing_finder(to1));
     406             :     assert(incoming != myControlledNodes.end());
     407      177378 :     NBNode* incnode = *incoming;
     408      177378 :     NBNode* outnode = *outgoing;
     409      177378 :     if (incnode != outnode) {
     410             :         return false;
     411             :     }
     412      177378 :     return incnode->foes(from1, to1, from2, to2);
     413             : }
     414             : 
     415             : 
     416             : void
     417       24855 : NBTrafficLightDefinition::addNode(NBNode* node) {
     418       24855 :     if (std::find(myControlledNodes.begin(), myControlledNodes.end(), node) == myControlledNodes.end()) {
     419        8480 :         myControlledNodes.push_back(node);
     420        8480 :         std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
     421             :     }
     422       24855 :     node->addTrafficLight(this);
     423       24855 : }
     424             : 
     425             : 
     426             : void
     427        6093 : NBTrafficLightDefinition::removeNode(NBNode* node) {
     428        6093 :     std::vector<NBNode*>::iterator i = std::find(myControlledNodes.begin(), myControlledNodes.end(), node);
     429        6093 :     if (i != myControlledNodes.end()) {
     430        5852 :         myControlledNodes.erase(i);
     431             :     }
     432             :     // !!! remove in node?
     433        6093 : }
     434             : 
     435             : 
     436             : void
     437          43 : NBTrafficLightDefinition::addControlledInnerEdges(const std::vector<std::string>& edges) {
     438             :     myControlledInnerEdges.insert(edges.begin(), edges.end());
     439          43 : }
     440             : 
     441             : 
     442             : std::vector<std::string>
     443         157 : NBTrafficLightDefinition::getControlledInnerEdges() const {
     444         157 :     return std::vector<std::string>(myControlledInnerEdges.begin(), myControlledInnerEdges.end());
     445             : }
     446             : 
     447             : 
     448             : const EdgeVector&
     449        3468 : NBTrafficLightDefinition::getIncomingEdges() const {
     450        3468 :     return myIncomingEdges;
     451             : }
     452             : 
     453             : 
     454             : void
     455        5766 : NBTrafficLightDefinition::collectAllLinks(NBConnectionVector& into) {
     456             :     int tlIndex = 0;
     457             :     // build the list of links which are controlled by the traffic light
     458             :     std::vector<int> indirectLeft;
     459       18229 :     for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
     460       12463 :         NBEdge* incoming = *i;
     461             :         int noLanes = incoming->getNumLanes();
     462       32917 :         for (int j = 0; j < noLanes; j++) {
     463       20454 :             std::vector<NBEdge::Connection> connected = incoming->getConnectionsFromLane(j);
     464       49699 :             for (std::vector<NBEdge::Connection>::iterator k = connected.begin(); k != connected.end(); k++) {
     465             :                 const NBEdge::Connection& el = *k;
     466       29245 :                 if (incoming->mayBeTLSControlled(el.fromLane, el.toEdge, el.toLane)) {
     467       29228 :                     if (el.toEdge != nullptr && el.toLane >= (int) el.toEdge->getNumLanes()) {
     468           0 :                         throw ProcessError("Connection '" + incoming->getID() + "_" + toString(j) + "->" + el.toEdge->getID() + "_" + toString(el.toLane) + "' yields in a not existing lane.");
     469             :                     }
     470             :                     if (incoming->getToNode()->getType() == SumoXMLNodeType::RAIL_CROSSING
     471       29228 :                             && isRailway(incoming->getPermissions())) {
     472             :                         // railways stay uncontrolled at rail crossing but they
     473             :                         // must be registered in MSRailCrossing
     474         994 :                         into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, -1));
     475             :                     } else if (incoming->getToNode()->getType() == SumoXMLNodeType::RAIL_SIGNAL
     476        2454 :                                && incoming->getToNode()->getDirection(incoming, el.toEdge) == LinkDirection::TURN
     477             :                                // assume explicit connections at sharp turn-arounds are either for reversal or due to a geometry glitch
     478             :                                // (the might also be due to faulty connection
     479             :                                // input but they would not come from guessing)
     480       28762 :                                && (incoming->getBidiEdge() == el.toEdge)
     481             :                               ) {
     482             :                         // turnarounds stay uncontrolled at rail signal
     483       28700 :                     } else if (incoming->getToNode()->getType() == SumoXMLNodeType::RAIL_SIGNAL && railSignalUncontrolled(incoming, el.toEdge)) {
     484             :                         // rail signals may stay uncontrolled in a particular direction
     485             :                     } else {
     486       56226 :                         into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, tlIndex++));
     487       28113 :                         if (el.indirectLeft) {
     488           4 :                             indirectLeft.push_back((int)into.size() - 1);
     489             :                         }
     490             :                     }
     491             :                 }
     492             :             }
     493       20454 :         }
     494             :     }
     495        5766 :     if (indirectLeft.size() > 0) {
     496             :         // assign linkIndex2 to indirect left turns
     497           5 :         for (int i : indirectLeft) {
     498           4 :             NBConnection& c = into[i];
     499             :             // find straight connection with the same toEdge
     500          50 :             for (const NBConnection& c2 : into) {
     501          50 :                 if (c2.getTo() == c.getTo() && c2.getFrom() != c.getFrom()) {
     502          10 :                     LinkDirection dir =  c.getFrom()->getToNode()->getDirection(c2.getFrom(), c2.getTo());
     503          10 :                     if (dir == LinkDirection::STRAIGHT) {
     504             :                         c.setTLIndex2(c2.getTLIndex());
     505             :                         break;
     506             :                     }
     507             :                 }
     508             :             }
     509             :         }
     510             :     }
     511             : 
     512        5766 :     if (into.size() > 0 && tlIndex == 0) {
     513         956 :         WRITE_WARNINGF(TL("The rail crossing '%' does not have any roads."), getID());
     514             :     }
     515        5766 : }
     516             : 
     517             : bool
     518        2423 : NBTrafficLightDefinition::railSignalUncontrolled(const NBEdge* in, const NBEdge* out) {
     519             :     const NBNode* n = in->getToNode();
     520        2423 :     if (n->hasParameter(OSM_SIGNAL_DIRECTION) && in->hasParameter(OSM_DIRECTION) && out->hasParameter(OSM_DIRECTION)) {
     521        1633 :         if (in->getParameter(OSM_DIRECTION) == out->getParameter(OSM_DIRECTION)) {
     522        3266 :             if (n->getParameter(OSM_SIGNAL_DIRECTION) != in->getParameter(OSM_DIRECTION)) {
     523         587 :                 return true;
     524             :             }
     525             :         } else {
     526           0 :             WRITE_WARNINGF(TL("Could not interpret rail signal direction at junction '%' due to inconsistent directions of edge '%' (%) and edge '%' (%)"),
     527             :                     n->getID(),
     528             :                     in->getID(), in->getParameter(OSM_DIRECTION),
     529             :                     out->getID(), out->getParameter(OSM_DIRECTION));
     530             :         }
     531             :     }
     532             :     return false;
     533             : }
     534             : 
     535             : bool
     536       80671 : NBTrafficLightDefinition::needsCont(const NBEdge* fromE, const NBEdge* toE, const NBEdge* otherFromE, const NBEdge* otherToE) const {
     537       80671 :     if (!myNeedsContRelationReady) {
     538         448 :         initNeedsContRelation();
     539             :         assert(myNeedsContRelationReady);
     540             :     }
     541       80671 :     return std::find(myNeedsContRelation.begin(), myNeedsContRelation.end(),
     542       80671 :                      StreamPair(fromE, toE, otherFromE, otherToE)) != myNeedsContRelation.end();
     543             : }
     544             : 
     545             : 
     546             : void
     547           3 : NBTrafficLightDefinition::initNeedsContRelation() const {
     548           3 :     if (!amInvalid()) {
     549           3 :         NBOwnTLDef dummy(DummyID, myControlledNodes, 0, TrafficLightType::STATIC);
     550           3 :         dummy.initNeedsContRelation();
     551             :         myNeedsContRelation = dummy.myNeedsContRelation;
     552           6 :         for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     553           3 :             (*i)->removeTrafficLight(&dummy);
     554             :         }
     555           3 :     }
     556           3 :     myNeedsContRelationReady = true;
     557           3 : }
     558             : 
     559             : 
     560             : void
     561      211118 : NBTrafficLightDefinition::initRightOnRedConflicts() const {
     562      211118 :     if (!myRightOnRedConflictsReady) {
     563          26 :         NBOwnTLDef dummy(DummyID, myControlledNodes, 0, TrafficLightType::STATIC);
     564          26 :         dummy.setParticipantsInformation();
     565          26 :         NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
     566          26 :         delete tllDummy;
     567             :         myRightOnRedConflicts = dummy.myRightOnRedConflicts;
     568         303 :         for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     569         277 :             (*i)->removeTrafficLight(&dummy);
     570             :         }
     571          26 :         myRightOnRedConflictsReady = true;
     572             :         //std::cout << " rightOnRedConflicts tls=" << getID() << " pro=" << getProgramID() << "\n";
     573             :         //for (RightOnRedConflicts::const_iterator it = myRightOnRedConflicts.begin(); it != myRightOnRedConflicts.end(); ++it) {
     574             :         //    std::cout << "   " << it->first << ", " << it->second << "\n";
     575             :         //}
     576          26 :     }
     577      211118 : }
     578             : 
     579             : 
     580             : bool
     581      211115 : NBTrafficLightDefinition::rightOnRedConflict(int index, int foeIndex) const {
     582      211115 :     initRightOnRedConflicts();
     583      211115 :     return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
     584             : }
     585             : 
     586             : std::string
     587           0 : NBTrafficLightDefinition::getDescription() const {
     588           0 :     return getID() + ':' + getProgramID() + '@' + toString(this);
     589             : }
     590             : 
     591             : 
     592             : /****************************************************************************/

Generated by: LCOV version 1.14