LCOV - code coverage report
Current view: top level - src/netbuild - NBTrafficLightDefinition.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.7 % 226 214
Test Date: 2024-12-21 15:45:41 Functions: 85.7 % 28 24

            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          147 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
      56              :         const std::vector<NBNode*>& junctions, const std::string& programID,
      57          147 :         SUMOTime offset, TrafficLightType type) :
      58              :     Named(id),
      59          147 :     myControlledNodes(junctions),
      60          147 :     mySubID(programID), myOffset(offset),
      61          147 :     myType(type),
      62          147 :     myNeedsContRelationReady(false),
      63          294 :     myRightOnRedConflictsReady(false) {
      64              :     std::vector<NBNode*>::iterator i = myControlledNodes.begin();
      65          543 :     while (i != myControlledNodes.end()) {
      66         1333 :         for (std::vector<NBNode*>::iterator j = i + 1; j != myControlledNodes.end();) {
      67          937 :             if (*i == *j) {
      68              :                 j = myControlledNodes.erase(j);
      69              :             } else {
      70              :                 j++;
      71              :             }
      72              :         }
      73              :         i++;
      74              :     }
      75          147 :     std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
      76          784 :     for (NBNode* const node : junctions) {
      77          637 :         node->addTrafficLight(this);
      78              :     }
      79          147 : }
      80              : 
      81              : 
      82         5520 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
      83         5520 :         NBNode* junction, const std::string& programID, SUMOTime offset, TrafficLightType type) :
      84              :     Named(id),
      85         5520 :     mySubID(programID),
      86         5520 :     myOffset(offset),
      87         5520 :     myType(type),
      88         5520 :     myNeedsContRelationReady(false),
      89         5520 :     myRightOnRedConflictsReady(false) {
      90         5520 :     addNode(junction);
      91         5520 : }
      92              : 
      93              : 
      94          595 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id, const std::string& programID,
      95          595 :         SUMOTime offset, TrafficLightType type) :
      96              :     Named(id),
      97          595 :     mySubID(programID),
      98          595 :     myOffset(offset),
      99          595 :     myType(type),
     100          595 :     myNeedsContRelationReady(false),
     101          595 :     myRightOnRedConflictsReady(false) {
     102          595 : }
     103              : 
     104              : 
     105        18786 : NBTrafficLightDefinition::~NBTrafficLightDefinition() {}
     106              : 
     107              : 
     108              : NBTrafficLightLogic*
     109         2866 : NBTrafficLightDefinition::compute(const OptionsCont& oc) {
     110              :     // it is not really a traffic light if no incoming edge exists
     111         2866 :     if (amInvalid()) {
     112              :         // make a copy of myControlledNodes because it will be modified;
     113           66 :         std::vector<NBNode*> nodes = myControlledNodes;
     114          132 :         for (auto it : nodes) {
     115           66 :             it->removeTrafficLight(this);
     116              :         }
     117          198 :         WRITE_WARNINGF(TL("The traffic light '%' does not control any links; it will not be build."), getID());
     118              :         return nullptr;
     119           66 :     }
     120              :     // compute the time needed to brake
     121         2800 :     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         5600 :     if (!oc.isDefault("tls.yellow.time")) {
     125            4 :         brakingTime = oc.getInt("tls.yellow.time");
     126              :     }
     127         2800 :     NBTrafficLightLogic* ret = myCompute(brakingTime);
     128         2800 :     ret->updateParameters(getParametersMap());
     129         2800 :     return ret;
     130              : }
     131              : 
     132              : 
     133              : bool
     134         2243 : NBTrafficLightDefinition::amInvalid() const {
     135         2243 :     return myControlledLinks.size() == 0;
     136              : }
     137              : 
     138              : 
     139              : int
     140         2812 : NBTrafficLightDefinition::computeBrakingTime(double minDecel) const {
     141         2812 :     if (myIncomingEdges.empty()) {
     142              :         // don't crash
     143              :         return MIN_YELLOW_SECONDS;
     144              :     }
     145         2812 :     const double vmax = NBContHelper::maxSpeed(myIncomingEdges);
     146         2812 :     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         4992 :         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          162 :         return (int)(1.8 + vmax / 2 / minDecel);
     155              :     }
     156              : }
     157              : 
     158              : 
     159              : void
     160         5125 : NBTrafficLightDefinition::setParticipantsInformation() {
     161              :     // collect the information about participating edges and links
     162         5125 :     collectEdges();
     163         5125 :     collectLinks();
     164         5125 : }
     165              : 
     166              : std::set<NBEdge*>
     167         9282 : NBTrafficLightDefinition::collectReachable(EdgeVector outer, const EdgeVector& within, bool checkControlled) {
     168              :     std::set<NBEdge*> reachable;
     169        31198 :     while (outer.size() > 0) {
     170        21916 :         NBEdge* from = outer.back();
     171              :         outer.pop_back();
     172              :         std::vector<NBEdge::Connection>& cons = from->getConnections();
     173        75340 :         for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); k++) {
     174        53424 :             NBEdge* to = (*k).toEdge;
     175        51994 :             if (reachable.count(to) == 0 &&
     176        53726 :                     (find(within.begin(), within.end(), to) != within.end()) &&
     177          302 :                     (!checkControlled || from->mayBeTLSControlled((*k).fromLane, to, (*k).toLane))) {
     178              :                 reachable.insert(to);
     179          604 :                 outer.push_back(to);
     180              :             }
     181              :         }
     182              :     }
     183         9282 :     return reachable;
     184              : }
     185              : 
     186              : 
     187              : void
     188         4641 : NBTrafficLightDefinition::collectEdges() {
     189              :     myIncomingEdges.clear();
     190              :     myEdgesWithin.clear();
     191              :     EdgeVector myOutgoing;
     192              :     // collect the edges from the participating nodes
     193         9045 :     for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     194         4404 :         const EdgeVector& incoming = (*i)->getIncomingEdges();
     195         4404 :         copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
     196         4404 :         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        15639 :     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        10998 :         EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
     206        10998 :         if (k != myOutgoing.end()) {
     207          342 :             myEdgesWithin.push_back(edge);
     208              :         } else  {
     209        10656 :             outer.push_back(edge);
     210              :         }
     211              :     }
     212              :     // collect edges that are reachable from the outside via controlled connections
     213         4641 :     std::set<NBEdge*> reachable = collectReachable(outer, myEdgesWithin, true);
     214              :     // collect edges that are reachable from the outside regardless of controllability
     215         4641 :     std::set<NBEdge*> reachable2 = collectReachable(outer, myEdgesWithin, false);
     216              : 
     217         9282 :     const bool uncontrolledWithin = OptionsCont::getOptions().getBool("tls.uncontrolled-within");
     218         4983 :     for (EdgeVector::iterator j = myEdgesWithin.begin(); j != myEdgesWithin.end(); ++j) {
     219          342 :         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          310 :             if (uncontrolledWithin && myControlledInnerEdges.count(edge->getID()) == 0) {
     226           23 :                 myIncomingEdges.erase(find(myIncomingEdges.begin(), myIncomingEdges.end(), edge));
     227              :             }
     228              :         }
     229           32 :         if (reachable2.count(edge) == 0 && edge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true) >= 0
     230            5 :                 && getID() != DummyID) {
     231           20 :             WRITE_WARNINGF(TL("Unreachable edge '%' within tlLogic '%'"), edge->getID(), getID());
     232              :         }
     233              :     }
     234         4641 : }
     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       765608 : 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       765608 :     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       765608 :         find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorFrom));
     287              :     std::vector<NBNode*>::const_iterator outgoing =
     288       765608 :         find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(possProhibitedTo));
     289              :     assert(incoming != myControlledNodes.end());
     290       765608 :     NBNode* incnode = *incoming;
     291       765608 :     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       765608 :     if (incnode != outnode) {
     300       137680 :         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        77081 :         const EdgeVector& ev1 = possProhibitedTo->getConnectedEdges();
     310              :         // go through the following edge,
     311              :         //  check whether one of these connections is prohibited
     312       179283 :         for (i = ev1.begin(); i != ev1.end(); ++i) {
     313              :             std::vector<NBNode*>::const_iterator outgoing2 =
     314       102800 :                 find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(*i));
     315       102800 :             if (outgoing2 == myControlledNodes.end()) {
     316        64894 :                 continue;
     317              :             }
     318        37906 :             NBNode* outnode2 = *outgoing2;
     319        37906 :             if (incnode != outnode2) {
     320        27182 :                 continue;
     321              :             }
     322        10724 :             if (incnode->getDirection(possProhibitedTo, *i) != LinkDirection::STRAIGHT) {
     323         6409 :                 continue;
     324              :             }
     325         4315 :             bool ret1 = incnode->foes(possProhibitorFrom, possProhibitorTo,
     326              :                                       possProhibitedTo, *i);
     327         4315 :             bool ret2 = incnode->forbids(possProhibitorFrom, possProhibitorTo,
     328              :                                          possProhibitedTo, *i,
     329              :                                          regardNonSignalisedLowerPriority);
     330         4315 :             bool ret = ret1 || ret2;
     331         4315 :             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        76483 :         const EdgeVector& ev2 = possProhibitorTo->getConnectedEdges();
     342              :         // go through the following edge,
     343              :         //  check whether one of these connections is prohibited
     344       177866 :         for (i = ev2.begin(); i != ev2.end(); ++i) {
     345              :             std::vector<NBNode*>::const_iterator incoming2 =
     346       102263 :                 find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorTo));
     347       102263 :             if (incoming2 == myControlledNodes.end()) {
     348        64053 :                 continue;
     349              :             }
     350        38210 :             NBNode* incnode2 = *incoming2;
     351        38210 :             if (incnode2 != outnode) {
     352        26997 :                 continue;
     353              :             }
     354        11213 :             if (incnode2->getDirection(possProhibitorTo, *i) != LinkDirection::STRAIGHT) {
     355         6619 :                 continue;
     356              :             }
     357         4594 :             bool ret1 = incnode2->foes(possProhibitorTo, *i,
     358              :                                        possProhibitedFrom, possProhibitedTo);
     359         4594 :             bool ret2 = incnode2->forbids(possProhibitorTo, *i,
     360              :                                           possProhibitedFrom, possProhibitedTo,
     361              :                                           regardNonSignalisedLowerPriority);
     362         4594 :             bool ret = ret1 || ret2;
     363         4594 :             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        77081 :     }
     379              :     // both links are located at the same node
     380              :     //  check using this node's information
     381       627928 :     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       185728 : NBTrafficLightDefinition::foes(const NBEdge* const from1, const NBEdge* const to1,
     395              :                                const NBEdge* const from2, const NBEdge* const to2) const {
     396       185728 :     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       185728 :         find_if(myControlledNodes.begin(), myControlledNodes.end(),
     402              :                 NBContHelper::node_with_incoming_finder(from1));
     403              :     std::vector<NBNode*>::const_iterator outgoing =
     404       185728 :         find_if(myControlledNodes.begin(), myControlledNodes.end(),
     405              :                 NBContHelper::node_with_outgoing_finder(to1));
     406              :     assert(incoming != myControlledNodes.end());
     407       185728 :     NBNode* incnode = *incoming;
     408       185728 :     NBNode* outnode = *outgoing;
     409       185728 :     if (incnode != outnode) {
     410              :         return false;
     411              :     }
     412       185728 :     return incnode->foes(from1, to1, from2, to2);
     413              : }
     414              : 
     415              : 
     416              : void
     417        16963 : NBTrafficLightDefinition::addNode(NBNode* node) {
     418        16963 :     if (std::find(myControlledNodes.begin(), myControlledNodes.end(), node) == myControlledNodes.end()) {
     419         6285 :         myControlledNodes.push_back(node);
     420         6285 :         std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
     421              :     }
     422        16963 :     node->addTrafficLight(this);
     423        16963 : }
     424              : 
     425              : 
     426              : void
     427         4585 : NBTrafficLightDefinition::removeNode(NBNode* node) {
     428         4585 :     std::vector<NBNode*>::iterator i = std::find(myControlledNodes.begin(), myControlledNodes.end(), node);
     429         4585 :     if (i != myControlledNodes.end()) {
     430         4344 :         myControlledNodes.erase(i);
     431              :     }
     432              :     // !!! remove in node?
     433         4585 : }
     434              : 
     435              : 
     436              : void
     437           46 : NBTrafficLightDefinition::addControlledInnerEdges(const std::vector<std::string>& edges) {
     438              :     myControlledInnerEdges.insert(edges.begin(), edges.end());
     439           46 : }
     440              : 
     441              : 
     442              : std::vector<std::string>
     443          124 : NBTrafficLightDefinition::getControlledInnerEdges() const {
     444          124 :     return std::vector<std::string>(myControlledInnerEdges.begin(), myControlledInnerEdges.end());
     445              : }
     446              : 
     447              : 
     448              : const EdgeVector&
     449         2806 : NBTrafficLightDefinition::getIncomingEdges() const {
     450         2806 :     return myIncomingEdges;
     451              : }
     452              : 
     453              : 
     454              : void
     455         4599 : 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        14497 :     for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
     460         9898 :         NBEdge* incoming = *i;
     461              :         int noLanes = incoming->getNumLanes();
     462        26589 :         for (int j = 0; j < noLanes; j++) {
     463        16691 :             std::vector<NBEdge::Connection> connected = incoming->getConnectionsFromLane(j);
     464        40531 :             for (std::vector<NBEdge::Connection>::iterator k = connected.begin(); k != connected.end(); k++) {
     465              :                 const NBEdge::Connection& el = *k;
     466        23840 :                 if (incoming->mayBeTLSControlled(el.fromLane, el.toEdge, el.toLane)) {
     467        23818 :                     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        23818 :                             && isRailway(incoming->getPermissions())) {
     472              :                         // railways stay uncontrolled at rail crossing but they
     473              :                         // must be registered in MSRailCrossing
     474          572 :                         into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, -1));
     475              :                     } else if (incoming->getToNode()->getType() == SumoXMLNodeType::RAIL_SIGNAL
     476         2103 :                                && 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        23557 :                                && (incoming->getBidiEdge() == el.toEdge)
     481              :                               ) {
     482              :                         // turnarounds stay uncontrolled at rail signal
     483        23507 :                     } 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        45956 :                         into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, tlIndex++));
     487        22978 :                         if (el.indirectLeft) {
     488            4 :                             indirectLeft.push_back((int)into.size() - 1);
     489              :                         }
     490              :                     }
     491              :                 }
     492              :             }
     493        16691 :         }
     494              :     }
     495         4599 :     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         4599 :     if (into.size() > 0 && tlIndex == 0) {
     513          450 :         WRITE_WARNINGF(TL("The rail crossing '%' does not have any roads."), getID());
     514              :     }
     515         4599 : }
     516              : 
     517              : bool
     518         2078 : NBTrafficLightDefinition::railSignalUncontrolled(const NBEdge* in, const NBEdge* out) {
     519              :     const NBNode* n = in->getToNode();
     520         2078 :     if (n->hasParameter(OSM_SIGNAL_DIRECTION) && in->hasParameter(OSM_DIRECTION) && out->hasParameter(OSM_DIRECTION)) {
     521         4125 :         if (in->getParameter(OSM_DIRECTION) == out->getParameter(OSM_DIRECTION)) {
     522         4125 :             if (n->getParameter(OSM_SIGNAL_DIRECTION) != in->getParameter(OSM_DIRECTION)) {
     523              :                 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        68817 : NBTrafficLightDefinition::needsCont(const NBEdge* fromE, const NBEdge* toE, const NBEdge* otherFromE, const NBEdge* otherToE) const {
     537        68817 :     if (!myNeedsContRelationReady) {
     538          355 :         initNeedsContRelation();
     539              :         assert(myNeedsContRelationReady);
     540              :     }
     541        68817 :     return std::find(myNeedsContRelation.begin(), myNeedsContRelation.end(),
     542        68817 :                      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       165990 : NBTrafficLightDefinition::initRightOnRedConflicts() const {
     562       165990 :     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       165990 : }
     578              : 
     579              : 
     580              : bool
     581       165987 : NBTrafficLightDefinition::rightOnRedConflict(int index, int foeIndex) const {
     582       165987 :     initRightOnRedConflicts();
     583       165987 :     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 2.0-1