LCOV - code coverage report
Current view: top level - src/netbuild - NBLoadedSUMOTLDef.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 370 423 87.5 %
Date: 2024-05-07 15:28:01 Functions: 35 40 87.5 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2011-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    NBLoadedSUMOTLDef.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Michael Behrisch
      17             : /// @author  Jakob Erdmann
      18             : /// @date    Mar 2011
      19             : ///
      20             : // A complete traffic light logic loaded from a sumo-net. (opted to reimplement
      21             : // since NBLoadedTLDef is quite vissim specific)
      22             : /****************************************************************************/
      23             : #include <config.h>
      24             : 
      25             : #include <vector>
      26             : #include <set>
      27             : #include <cassert>
      28             : #include <iterator>
      29             : #include <utils/common/MsgHandler.h>
      30             : #include <utils/common/ToString.h>
      31             : #include <utils/options/OptionsCont.h>
      32             : #include "NBTrafficLightLogic.h"
      33             : #include "NBOwnTLDef.h"
      34             : #include "NBTrafficLightDefinition.h"
      35             : #include "NBLoadedSUMOTLDef.h"
      36             : #include "NBNetBuilder.h"
      37             : #include "NBOwnTLDef.h"
      38             : #include "NBNode.h"
      39             : 
      40             : //#define DEBUG_RECONSTRUCTION
      41             : 
      42             : // ===========================================================================
      43             : // method definitions
      44             : // ===========================================================================
      45             : 
      46         879 : NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(const std::string& id, const std::string& programID,
      47         879 :                                      SUMOTime offset, TrafficLightType type) :
      48             :     NBTrafficLightDefinition(id, programID, offset, type),
      49         879 :     myTLLogic(nullptr),
      50         879 :     myReconstructAddedConnections(false),
      51         879 :     myReconstructRemovedConnections(false),
      52         879 :     myPhasesLoaded(false) {
      53         879 :     myTLLogic = new NBTrafficLightLogic(id, programID, 0, offset, type);
      54         879 : }
      55             : 
      56             : 
      57          13 : NBLoadedSUMOTLDef::NBLoadedSUMOTLDef(const NBTrafficLightDefinition& def, const NBTrafficLightLogic& logic) :
      58             :     // allow for adding a new program for the same def: take the offset and programID from the new logic
      59             :     NBTrafficLightDefinition(def.getID(), logic.getProgramID(), logic.getOffset(), def.getType()),
      60          13 :     myTLLogic(new NBTrafficLightLogic(logic)),
      61          13 :     myReconstructAddedConnections(false),
      62          13 :     myReconstructRemovedConnections(false),
      63          26 :     myPhasesLoaded(false) {
      64             :     assert(def.getType() == logic.getType());
      65          13 :     myControlledLinks = def.getControlledLinks();
      66          13 :     myControlledNodes = def.getNodes();
      67          13 :     const NBLoadedSUMOTLDef* sumoDef = dynamic_cast<const NBLoadedSUMOTLDef*>(&def);
      68          13 :     updateParameters(def.getParametersMap());
      69          13 :     if (sumoDef != nullptr) {
      70          11 :         myReconstructAddedConnections = sumoDef->myReconstructAddedConnections;
      71          11 :         myReconstructRemovedConnections = sumoDef->myReconstructRemovedConnections;
      72             :     }
      73          13 : }
      74             : 
      75             : 
      76        1784 : NBLoadedSUMOTLDef::~NBLoadedSUMOTLDef() {
      77         892 :     delete myTLLogic;
      78        1784 : }
      79             : 
      80             : 
      81             : NBTrafficLightLogic*
      82         974 : NBLoadedSUMOTLDef::myCompute(int brakingTimeSeconds) {
      83             :     // @todo what to do with those parameters?
      84             :     UNUSED_PARAMETER(brakingTimeSeconds);
      85         974 :     reconstructLogic();
      86         974 :     myTLLogic->closeBuilding(false);
      87         974 :     patchIfCrossingsAdded();
      88         974 :     myTLLogic->closeBuilding();
      89         974 :     return new NBTrafficLightLogic(myTLLogic);
      90             : }
      91             : 
      92             : 
      93             : void
      94        8408 : NBLoadedSUMOTLDef::addConnection(NBEdge* from, NBEdge* to, int fromLane, int toLane, int linkIndex, int linkIndex2, bool reconstruct) {
      95             :     assert(myTLLogic->getNumLinks() > 0); // logic should be loaded by now
      96        8408 :     if (linkIndex >= myTLLogic->getNumLinks()) {
      97           0 :         throw ProcessError("Invalid linkIndex " + toString(linkIndex) + " in connection from edge '" + from->getID() +
      98           0 :                            "' to edge '" + to->getID() + "' for traffic light '" + getID() +
      99           0 :                            "' with " + toString(myTLLogic->getNumLinks()) + " links.");
     100             :     }
     101        8408 :     if (linkIndex2 >= myTLLogic->getNumLinks()) {
     102           0 :         throw ProcessError("Invalid linkIndex2 " + toString(linkIndex2) + " in connection from edge '" + from->getID() +
     103           0 :                            "' to edge '" + to->getID() + "' for traffic light '" + getID() +
     104           0 :                            "' with " + toString(myTLLogic->getNumLinks()) + " links.");
     105             :     }
     106        8408 :     NBConnection conn(from, fromLane, to, toLane, linkIndex, linkIndex2);
     107             :     // avoid duplicates
     108        8408 :     auto newEnd = remove_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(conn));
     109             :     // remove_if does not remove, only re-order
     110        8408 :     myControlledLinks.erase(newEnd, myControlledLinks.end());
     111        8408 :     myControlledLinks.push_back(conn);
     112        8408 :     addNode(from->getToNode());
     113        8408 :     addNode(to->getFromNode());
     114             :     // added connections are definitely controlled. make sure none are removed because they lie within the tl
     115             :     // myControlledInnerEdges.insert(from->getID()); // @todo recheck: this appears to be obsolete
     116             :     // set this information now so that it can be used while loading diffs
     117        8408 :     from->setControllingTLInformation(conn, getID());
     118        8408 :     myReconstructAddedConnections |= reconstruct;
     119        8408 : }
     120             : 
     121             : void
     122          88 : NBLoadedSUMOTLDef::setID(const std::string& newID) {
     123             :     Named::setID(newID);
     124          88 :     myTLLogic->setID(newID);
     125          88 : }
     126             : 
     127             : void
     128           0 : NBLoadedSUMOTLDef::setProgramID(const std::string& programID) {
     129             :     NBTrafficLightDefinition::setProgramID(programID);
     130           0 :     myTLLogic->setProgramID(programID);
     131           0 : }
     132             : 
     133             : 
     134             : void
     135         896 : NBLoadedSUMOTLDef::setTLControllingInformation() const {
     136         896 :     if (myReconstructAddedConnections) {
     137           5 :         NBOwnTLDef dummy(DummyID, myControlledNodes, 0, getType());
     138           5 :         dummy.setParticipantsInformation();
     139           5 :         dummy.setTLControllingInformation();
     140          10 :         for (NBNode* const n : myControlledNodes) {
     141           5 :             n->removeTrafficLight(&dummy);
     142             :         }
     143           5 :     }
     144         896 :     if (myReconstructRemovedConnections) {
     145             :         return; // will be called again in reconstructLogic()
     146             :     }
     147             :     // if nodes have been removed our links may have been invalidated as well
     148             :     // since no logic will be built anyway there is no reason to inform any edges
     149         875 :     if (amInvalid()) {
     150             :         return;
     151             :     }
     152             :     // set the information about the link's positions within the tl into the
     153             :     //  edges the links are starting at, respectively
     154        9338 :     for (const NBConnection& c : myControlledLinks) {
     155        8471 :         if (c.getTLIndex() >= myTLLogic->getNumLinks()) {
     156           2 :             throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
     157           4 :                                "' with " + toString(myTLLogic->getNumLinks()) + " links.");
     158             :         }
     159        8470 :         NBEdge* edge = c.getFrom();
     160        8470 :         if (edge != nullptr && edge->getNumLanes() > c.getFromLane()) {
     161             :             // logic may have yet to be reconstructed
     162        8465 :             edge->setControllingTLInformation(c, getID());
     163             :         }
     164             :     }
     165             : }
     166             : 
     167             : 
     168             : void
     169           0 : NBLoadedSUMOTLDef::remapRemoved(NBEdge*, const EdgeVector&, const EdgeVector&) {}
     170             : 
     171             : 
     172             : void
     173          74 : NBLoadedSUMOTLDef::replaceRemoved(NBEdge* removed, int removedLane, NBEdge* by, int byLane, bool incoming) {
     174         961 :     for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
     175         887 :         if (incoming) {
     176         591 :             (*it).replaceFrom(removed, removedLane, by, byLane);
     177             :         } else {
     178         296 :             (*it).replaceTo(removed, removedLane, by, byLane);
     179             :         }
     180             :     }
     181          74 : }
     182             : 
     183             : 
     184             : void
     185        5325 : NBLoadedSUMOTLDef::addPhase(const SUMOTime duration, const std::string& state, const SUMOTime minDur, const SUMOTime maxDur,
     186             :                             const SUMOTime earliestEnd, const SUMOTime latestEnd, const SUMOTime vehExt, const SUMOTime yellow,
     187             :                             const SUMOTime red, const std::vector<int>& next, const std::string& name) {
     188        5325 :     myTLLogic->addStep(duration, state, minDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, name, next);
     189        5324 : }
     190             : 
     191             : 
     192             : bool
     193       61259 : NBLoadedSUMOTLDef::amInvalid() const {
     194       61259 :     if (myControlledLinks.size() == 0) {
     195             :         return true;
     196             :     }
     197       61254 :     if (myIncomingEdges.size() == 0) {
     198           2 :         return true;
     199             :     }
     200             :     return false;
     201             : }
     202             : 
     203             : 
     204             : void
     205         144 : NBLoadedSUMOTLDef::removeConnection(const NBConnection& conn, bool reconstruct) {
     206        1375 :     for (auto it = myControlledLinks.begin(); it != myControlledLinks.end();) {
     207        1623 :         if ((it->getFrom() == conn.getFrom() &&
     208         516 :                 it->getTo() == conn.getTo() &&
     209         212 :                 it->getFromLane() == conn.getFromLane() &&
     210          88 :                 it->getToLane() == conn.getToLane())
     211        1542 :                 || (it->getTLIndex() == conn.getTLIndex() &&
     212          18 :                     conn.getTLIndex() != conn.InvalidTlIndex &&
     213          14 :                     (it->getFrom() == nullptr || it->getTo() == nullptr))) {
     214          90 :             if (reconstruct) {
     215          59 :                 myReconstructRemovedConnections = true;
     216             :                 it++;
     217             :             } else {
     218          31 :                 it = myControlledLinks.erase(it);
     219             :             }
     220             :         } else {
     221             :             it++;
     222             :         }
     223             :     }
     224         144 : }
     225             : 
     226             : 
     227             : void
     228           6 : NBLoadedSUMOTLDef::setOffset(SUMOTime offset) {
     229           6 :     myOffset = offset;
     230           6 :     myTLLogic->setOffset(offset);
     231           6 : }
     232             : 
     233             : 
     234             : void
     235           7 : NBLoadedSUMOTLDef::setType(TrafficLightType type) {
     236           7 :     myType = type;
     237           7 :     myTLLogic->setType(type);
     238           7 : }
     239             : 
     240             : 
     241             : void
     242         878 : NBLoadedSUMOTLDef::collectEdges() {
     243         878 :     if (myControlledLinks.size() == 0) {
     244          14 :         NBTrafficLightDefinition::collectEdges();
     245             :     }
     246         878 :     myIncomingEdges.clear();
     247             :     EdgeVector myOutgoing;
     248             :     // collect the edges from the participating nodes
     249        2010 :     for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     250        1132 :         const EdgeVector& incoming = (*i)->getIncomingEdges();
     251             :         copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
     252        1132 :         const EdgeVector& outgoing = (*i)->getOutgoingEdges();
     253             :         copy(outgoing.begin(), outgoing.end(), back_inserter(myOutgoing));
     254             :     }
     255             :     // check which of the edges are completely within the junction
     256             :     // and which are uncontrolled as well (we already know myControlledLinks)
     257        3658 :     for (EdgeVector::iterator j = myIncomingEdges.begin(); j != myIncomingEdges.end();) {
     258        2780 :         NBEdge* edge = *j;
     259             :         edge->setInsideTLS(false); // reset
     260             :         // an edge lies within the logic if it is outgoing as well as incoming
     261        2780 :         EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
     262        2780 :         if (k != myOutgoing.end()) {
     263         218 :             if (myControlledInnerEdges.count(edge->getID()) == 0) {
     264             :                 bool controlled = false;
     265        1338 :                 for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
     266        1334 :                     if ((*it).getFrom() == edge) {
     267             :                         controlled = true;
     268             :                         break;
     269             :                     }
     270             :                 }
     271         218 :                 if (controlled) {
     272         214 :                     myControlledInnerEdges.insert(edge->getID());
     273             :                 } else {
     274           4 :                     myEdgesWithin.push_back(edge);
     275           4 :                     edge->setInsideTLS(true);
     276             :                     ++j; //j = myIncomingEdges.erase(j);
     277           4 :                     continue;
     278             :                 }
     279             :             }
     280             :         }
     281             :         ++j;
     282             :     }
     283         878 : }
     284             : 
     285             : 
     286             : void
     287         878 : NBLoadedSUMOTLDef::collectLinks() {
     288         878 :     if (myControlledLinks.size() == 0) {
     289             :         // maybe we only loaded a different program for a default traffic light.
     290             :         // Try to build links now.
     291          14 :         collectAllLinks(myControlledLinks);
     292             :     }
     293         878 : }
     294             : 
     295             : 
     296             : /// @brief patches signal plans by modifying lane indices
     297             : void
     298          16 : NBLoadedSUMOTLDef::shiftTLConnectionLaneIndex(NBEdge* edge, int offset, int threshold) {
     299             :     // avoid shifting twice if the edge is incoming and outgoing to a joined TLS
     300             :     if (myShifted.count(edge) == 0) {
     301             :         /// XXX what if an edge should really be shifted twice?
     302             :         myShifted.insert(edge);
     303         224 :         for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
     304         208 :             (*it).shiftLaneIndex(edge, offset, threshold);
     305             :         }
     306             :     }
     307          16 : }
     308             : 
     309             : void
     310         974 : NBLoadedSUMOTLDef::patchIfCrossingsAdded() {
     311         974 :     const int size = myTLLogic->getNumLinks();
     312             :     int noLinksAll = 0;
     313       11157 :     for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
     314             :         const NBConnection& c = *it;
     315       10183 :         if (c.getTLIndex() != NBConnection::InvalidTlIndex) {
     316       10183 :             noLinksAll = MAX2(noLinksAll, (int)c.getTLIndex() + 1);
     317             :         }
     318             :     }
     319             :     const int numNormalLinks = noLinksAll;
     320             :     int oldCrossings = 0;
     321             :     // collect crossings
     322             :     bool customIndex = false;
     323             :     std::vector<NBNode::Crossing*> crossings;
     324        2224 :     for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     325        1250 :         const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
     326             :         // set tl indices for crossings
     327        1250 :         customIndex |= (*i)->setCrossingTLIndices(getID(), noLinksAll);
     328             :         copy(c.begin(), c.end(), std::back_inserter(crossings));
     329        1250 :         noLinksAll += (int)c.size();
     330        1250 :         oldCrossings += (*i)->numCrossingsFromSumoNet();
     331             :     }
     332         974 :     if ((int)crossings.size() != oldCrossings) {
     333          15 :         std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
     334             :         // do not rebuilt crossing states there are custom indices and the state string is long enough
     335          15 :         if (phases.size() > 0 && (
     336          15 :                     (int)(phases.front().state.size()) < noLinksAll ||
     337           4 :                     ((int)(phases.front().state.size()) > noLinksAll && !customIndex))) {
     338             :             // collect edges
     339           6 :             EdgeVector fromEdges(size, (NBEdge*)nullptr);
     340           6 :             EdgeVector toEdges(size, (NBEdge*)nullptr);
     341           6 :             std::vector<int> fromLanes(size, 0);
     342           6 :             collectEdgeVectors(fromEdges, toEdges, fromLanes);
     343             :             const std::string crossingDefaultState(crossings.size(), 'r');
     344             : 
     345             :             // rebuild the logic (see NBOwnTLDef.cpp::myCompute)
     346           6 :             NBTrafficLightLogic* newLogic = new NBTrafficLightLogic(getID(), getProgramID(), 0, myOffset, myType);
     347          18 :             SUMOTime brakingTime = TIME2STEPS(computeBrakingTime(OptionsCont::getOptions().getFloat("tls.yellow.min-decel")));
     348             :             //std::cout << "patchIfCrossingsAdded for " << getID() << " numPhases=" << phases.size() << "\n";
     349          50 :             for (const auto& phase : phases) {
     350          88 :                 const std::string state = phase.state.substr(0, numNormalLinks) + crossingDefaultState;
     351          88 :                 NBOwnTLDef::addPedestrianPhases(newLogic, phase.duration, phase.minDur, phase.maxDur, phase.earliestEnd, phase.latestEnd,
     352             :                                                 state, crossings, fromEdges, toEdges);
     353             :             }
     354           6 :             NBOwnTLDef::addPedestrianScramble(newLogic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
     355             : 
     356           6 :             delete myTLLogic;
     357           6 :             myTLLogic = newLogic;
     358           9 :         } else if (phases.size() == 0) {
     359           0 :             WRITE_WARNINGF(TL("Could not patch tlLogic '%' for changed crossings"), getID());
     360             :         }
     361          15 :     }
     362         974 : }
     363             : 
     364             : 
     365             : void
     366           6 : NBLoadedSUMOTLDef::collectEdgeVectors(EdgeVector& fromEdges, EdgeVector& toEdges, std::vector<int>& fromLanes) const {
     367             :     assert(fromEdges.size() > 0);
     368             :     assert(fromEdges.size() == toEdges.size());
     369           6 :     const int size = (int)fromEdges.size();
     370             : 
     371          72 :     for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
     372             :         const NBConnection& c = *it;
     373          66 :         if (c.getTLIndex() != NBConnection::InvalidTlIndex) {
     374          66 :             if (c.getTLIndex() >= size) {
     375           0 :                 throw ProcessError("Invalid linkIndex " + toString(c.getTLIndex()) + " for traffic light '" + getID() +
     376           0 :                                    "' with " + toString(size) + " links.");
     377             :             }
     378          66 :             fromEdges[c.getTLIndex()] = c.getFrom();
     379          66 :             toEdges[c.getTLIndex()] = c.getTo();
     380          66 :             fromLanes[c.getTLIndex()] = c.getFromLane();
     381             :         }
     382             :     }
     383           6 : }
     384             : 
     385             : 
     386             : void
     387         835 : NBLoadedSUMOTLDef::initNeedsContRelation() const {
     388         835 :     if (!amInvalid() && !myNeedsContRelationReady) {
     389             :         myNeedsContRelation.clear();
     390             :         myRightOnRedConflicts.clear();
     391         835 :         if (myType == TrafficLightType::NEMA) {
     392           3 :             NBTrafficLightDefinition::initNeedsContRelation();
     393           3 :             NBTrafficLightDefinition::initRightOnRedConflicts();
     394             :         } else {
     395         832 :             const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
     396         832 :             const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = myTLLogic->getPhases();
     397        5151 :             for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
     398             :                 const std::string state = (*it).state;
     399       53228 :                 for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
     400             :                     const NBConnection& c1 = *it1;
     401             :                     const int i1 = c1.getTLIndex();
     402       48909 :                     if (i1 == NBConnection::InvalidTlIndex || (state[i1] != 'g' && state[i1] != 's') || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
     403             :                         continue;
     404             :                     }
     405       49290 :                     for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
     406             :                         const NBConnection& c2 = *it2;
     407             :                         const int i2 = c2.getTLIndex();
     408             :                         if (i2 != NBConnection::InvalidTlIndex
     409       46594 :                                 && i2 != i1
     410       43718 :                                 && (state[i2] == 'G' || state[i2] == 'g')
     411       63277 :                                 && c2.getFrom() != nullptr && c2.getTo() != nullptr) {
     412       50001 :                             const bool rightTurnConflict = NBNode::rightTurnConflict(
     413       33334 :                                                                c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
     414       16667 :                             const bool forbidden = forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin);
     415       16667 :                             const bool isFoes = foes(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo()) && !c2.getFrom()->isTurningDirectionAt(c2.getTo());
     416       16667 :                             if (forbidden || rightTurnConflict) {
     417        7328 :                                 myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
     418             :                             }
     419       16667 :                             if (isFoes && state[i1] == 's') {
     420          16 :                                 myRightOnRedConflicts.insert(std::make_pair(i1, i2));
     421             :                                 //std::cout << getID() << " prog=" << getProgramID() << " phase=" << (it - phases.begin()) << " rightOnRedConflict i1=" << i1 << " i2=" << i2 << "\n";
     422             :                             }
     423             :                             //std::cout << getID() << " i1=" << i1 << " i2=" << i2 << " rightTurnConflict=" << rightTurnConflict << " forbidden=" << forbidden << " isFoes=" << isFoes << "\n";
     424             :                         }
     425             :                     }
     426             :                 }
     427             :             }
     428         832 :         }
     429             :     }
     430         835 :     myNeedsContRelationReady = true;
     431         835 :     myRightOnRedConflictsReady = true;
     432         835 : }
     433             : 
     434             : 
     435             : bool
     436       58572 : NBLoadedSUMOTLDef::rightOnRedConflict(int index, int foeIndex) const {
     437       58572 :     if (amInvalid()) {
     438             :         return false;
     439             :     }
     440       58572 :     if (!myRightOnRedConflictsReady) {
     441         654 :         initNeedsContRelation();
     442             :         assert(myRightOnRedConflictsReady);
     443             :     }
     444       58572 :     return std::find(myRightOnRedConflicts.begin(), myRightOnRedConflicts.end(), std::make_pair(index, foeIndex)) != myRightOnRedConflicts.end();
     445             : }
     446             : 
     447             : 
     448             : void
     449          12 : NBLoadedSUMOTLDef::registerModifications(bool addedConnections, bool removedConnections) {
     450          12 :     myReconstructAddedConnections |= addedConnections;
     451          12 :     myReconstructRemovedConnections |= removedConnections;
     452          12 : }
     453             : 
     454             : void
     455         974 : NBLoadedSUMOTLDef::reconstructLogic() {
     456         974 :     const bool netedit = NBNetBuilder::runningNetedit();
     457             : #ifdef DEBUG_RECONSTRUCTION
     458             :     bool debugPrintModified = myReconstructAddedConnections || myReconstructRemovedConnections;
     459             :     std::cout << getID() << " reconstructLogic added=" << myReconstructAddedConnections
     460             :               << " removed=" << myReconstructRemovedConnections
     461             :               << " valid=" << hasValidIndices()
     462             :               << " phasesLoaded=" << myPhasesLoaded
     463             :               << " oldLinks:\n";
     464             :     for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
     465             :         std::cout << "    " << *it << "\n";
     466             :     }
     467             : #endif
     468         974 :     if (myReconstructAddedConnections) {
     469           5 :         myReconstructAddedConnections = false;
     470             :         // do not rebuild the logic when running netedit and all links are already covered by the program
     471           5 :         if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
     472             :             // rebuild the logic from scratch
     473             :             // XXX if a connection with the same from- and to-edge already exisits, its states could be copied instead
     474           3 :             NBOwnTLDef dummy(DummyID, myControlledNodes, 0, getType());
     475           3 :             dummy.setParticipantsInformation();
     476             :             dummy.setProgramID(getProgramID());
     477           3 :             dummy.setTLControllingInformation();
     478           3 :             NBTrafficLightLogic* newLogic = dummy.compute(OptionsCont::getOptions());
     479           3 :             myIncomingEdges = dummy.getIncomingEdges();
     480           3 :             myControlledLinks = dummy.getControlledLinks();
     481           6 :             for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
     482           3 :                 (*i)->removeTrafficLight(&dummy);
     483             :             }
     484           3 :             delete myTLLogic;
     485           3 :             myTLLogic = newLogic;
     486           3 :             if (newLogic != nullptr) {
     487           3 :                 newLogic->setID(getID());
     488             :                 newLogic->setType(getType());
     489             :                 newLogic->setOffset(getOffset());
     490           3 :                 setTLControllingInformation();
     491             :                 // reset crossing custom indices
     492           6 :                 for (NBNode* n : myControlledNodes) {
     493           3 :                     for (NBNode::Crossing* c : n->getCrossings()) {
     494           0 :                         c->customTLIndex = NBConnection::InvalidTlIndex;
     495             :                     }
     496             :                 }
     497             : 
     498             :             }
     499           3 :         } else {
     500           2 :             setTLControllingInformation();
     501             :         }
     502             :     }
     503         974 :     if (myReconstructRemovedConnections) {
     504          10 :         myReconstructRemovedConnections = false;
     505             :         // for each connection, check whether it is still valid
     506         143 :         for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end();) {
     507         133 :             const NBConnection con = (*it);
     508             :             if (// edge still exists
     509         266 :                 std::find(myIncomingEdges.begin(), myIncomingEdges.end(), con.getFrom()) != myIncomingEdges.end()
     510             :                 // connection still exists
     511         133 :                 && con.getFrom()->hasConnectionTo(con.getTo(), con.getToLane(), con.getFromLane())
     512             :                 // connection is still set to be controlled
     513         254 :                 && con.getFrom()->mayBeTLSControlled(con.getFromLane(), con.getTo(), con.getToLane())) {
     514             :                 it++;
     515             :             } else {
     516             :                 // remove connection
     517             :                 const int removed = con.getTLIndex();
     518          12 :                 it = myControlledLinks.erase(it);
     519             :                 // no automatic modificaions when running netedit
     520          12 :                 if (!myPhasesLoaded && !(netedit && hasValidIndices())) {
     521             :                     // shift index off successive connections and remove entry from all phases if the tlIndex was only used by this connection
     522             :                     bool exclusive = true;
     523         115 :                     for (NBConnection& other : myControlledLinks) {
     524         109 :                         if (other != con && other.getTLIndex() == removed) {
     525             :                             exclusive = false;
     526             :                             break;
     527             :                         }
     528             :                     }
     529          12 :                     if (exclusive) {
     530             :                         // shift indices above the removed index downward
     531          97 :                         for (NBConnection& other : myControlledLinks) {
     532          91 :                             if (other.getTLIndex() > removed) {
     533          18 :                                 other.setTLIndex(other.getTLIndex() - 1);
     534             :                             }
     535             :                         }
     536             :                         // shift crossing custom indices above the removed index downward
     537          12 :                         for (NBNode* n : myControlledNodes) {
     538           6 :                             for (NBNode::Crossing* c : n->getCrossings()) {
     539           0 :                                 if (c->customTLIndex > removed) {
     540           0 :                                     c->customTLIndex--;
     541             :                                 }
     542             :                             }
     543             :                         }
     544             :                         // rebuild the logic
     545           6 :                         NBTrafficLightLogic* newLogic = new NBTrafficLightLogic(getID(), getProgramID(), 0, myOffset, myType);
     546          50 :                         for (const NBTrafficLightLogic::PhaseDefinition& phase : myTLLogic->getPhases()) {
     547             :                             std::string newState = phase.state;
     548             :                             newState.erase(newState.begin() + removed);
     549          88 :                             newLogic->addStep(phase.duration, newState);
     550             :                         }
     551           6 :                         delete myTLLogic;
     552           6 :                         myTLLogic = newLogic;
     553             :                     }
     554             :                 }
     555             :             }
     556         133 :         }
     557          10 :         setTLControllingInformation();
     558             :     }
     559             : #ifdef DEBUG_RECONSTRUCTION
     560             :     if (debugPrintModified) {
     561             :         std::cout << " newLinks:\n";
     562             :         for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); ++it) {
     563             :             std::cout << "    " << *it << "\n";
     564             :         }
     565             :     }
     566             : #endif
     567         974 : }
     568             : 
     569             : 
     570             : int
     571           4 : NBLoadedSUMOTLDef::getMaxIndex() {
     572             :     int maxIndex = -1;
     573          59 :     for (const NBConnection& c : myControlledLinks) {
     574             :         maxIndex = MAX2(maxIndex, c.getTLIndex());
     575             :         maxIndex = MAX2(maxIndex, c.getTLIndex2());
     576             :     }
     577           8 :     for (NBNode* n : myControlledNodes) {
     578           6 :         for (NBNode::Crossing* c : n->getCrossings()) {
     579           2 :             maxIndex = MAX2(maxIndex, c->tlLinkIndex);
     580           2 :             maxIndex = MAX2(maxIndex, c->tlLinkIndex2);
     581             :         }
     582             :     }
     583           4 :     return maxIndex;
     584             : }
     585             : 
     586             : 
     587             : int
     588           4 : NBLoadedSUMOTLDef::getMaxValidIndex() {
     589           4 :     return myTLLogic->getNumLinks() - 1;
     590             : }
     591             : 
     592             : 
     593             : bool
     594           0 : NBLoadedSUMOTLDef::hasValidIndices() const {
     595           0 :     for (const NBConnection& c : myControlledLinks) {
     596           0 :         if (c.getTLIndex() == NBConnection::InvalidTlIndex) {
     597             :             return false;
     598             :         }
     599             :     }
     600           0 :     for (NBNode* n : myControlledNodes) {
     601           0 :         for (NBNode::Crossing* c : n->getCrossings()) {
     602           0 :             if (c->tlLinkIndex == NBConnection::InvalidTlIndex) {
     603             :                 return false;
     604             :             }
     605             :         }
     606             :     }
     607             :     // method getMaxIndex() is const but cannot be declare as such due to inheritance
     608           0 :     return const_cast<NBLoadedSUMOTLDef*>(this)->getMaxIndex() < myTLLogic->getNumLinks();
     609             : }
     610             : 
     611             : 
     612             : std::string
     613         268 : NBLoadedSUMOTLDef::getStates(int index) {
     614             :     assert(index >= 0);
     615             :     assert(index <= getMaxValidIndex());
     616             :     std::string result;
     617        2082 :     for (auto& pd : myTLLogic->getPhases()) {
     618        1814 :         result += pd.state[index];
     619             :     }
     620         268 :     return result;
     621             : }
     622             : 
     623             : bool
     624        8228 : NBLoadedSUMOTLDef::isUsed(int index) const {
     625       56551 :     for (const NBConnection& c : myControlledLinks) {
     626       56416 :         if (c.getTLIndex() == index || c.getTLIndex2() == index) {
     627             :             return true;
     628             :         }
     629             :     }
     630         181 :     for (NBNode* n : myControlledNodes) {
     631         274 :         for (NBNode::Crossing* c : n->getCrossings()) {
     632         228 :             if (c->tlLinkIndex == index || c->tlLinkIndex2 == index) {
     633             :                 return true;
     634             :             }
     635             :         }
     636             :     }
     637             :     return false;
     638             : }
     639             : 
     640             : std::set<const NBEdge*>
     641          78 : NBLoadedSUMOTLDef::getEdgesUsingIndex(int index) const {
     642             :     std::set<const NBEdge*> result;
     643        1304 :     for (const NBConnection& c : myControlledLinks) {
     644        1226 :         if (c.getTLIndex() == index || c.getTLIndex2() == index) {
     645          74 :             result.insert(c.getFrom());
     646             :         }
     647             :     }
     648          78 :     return result;
     649             : }
     650             : 
     651             : 
     652             : void
     653          59 : NBLoadedSUMOTLDef::replaceIndex(int oldIndex, int newIndex) {
     654          59 :     if (oldIndex == newIndex) {
     655             :         return;
     656             :     }
     657         913 :     for (NBConnection& c : myControlledLinks) {
     658         858 :         if (c.getTLIndex() == oldIndex) {
     659             :             c.setTLIndex(newIndex);
     660             :         }
     661         858 :         if (c.getTLIndex2() == oldIndex) {
     662             :             c.setTLIndex2(newIndex);
     663             :         }
     664             :     }
     665         110 :     for (NBNode* n : myControlledNodes) {
     666          69 :         for (NBNode::Crossing* c : n->getCrossings()) {
     667          14 :             if (c->tlLinkIndex == oldIndex) {
     668           2 :                 c->tlLinkIndex = newIndex;
     669             :             }
     670          14 :             if (c->tlLinkIndex2 == oldIndex) {
     671           2 :                 c->tlLinkIndex2 = newIndex;
     672             :             }
     673             :         }
     674             :     }
     675             : }
     676             : 
     677             : void
     678           4 : NBLoadedSUMOTLDef::groupSignals() {
     679           4 :     const int maxIndex = getMaxIndex();
     680             :     std::vector<int> unusedIndices;
     681          63 :     for (int i = 0; i <= maxIndex; i++) {
     682          59 :         if (isUsed(i)) {
     683          30 :             std::set<const NBEdge*> edges = getEdgesUsingIndex(i);
     684             :             // compactify
     685          30 :             replaceIndex(i, i - (int)unusedIndices.size());
     686          30 :             if (edges.size() == 0) {
     687             :                 // do not group pedestrian crossing signals
     688             :                 continue;
     689             :             }
     690          26 :             std::string states = getStates(i);
     691         240 :             for (int j = i + 1; j <= maxIndex; j++) {
     692             :                 // only group signals from the same edges as is commonly done by
     693             :                 // traffic engineers
     694         262 :                 if (states == getStates(j) && edges == getEdgesUsingIndex(j)) {
     695          29 :                     replaceIndex(j, i - (int)unusedIndices.size());
     696             :                 }
     697             :             }
     698             :         } else {
     699          29 :             unusedIndices.push_back(i);
     700             :         }
     701             :     }
     702          33 :     for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
     703          29 :         myTLLogic->deleteStateIndex(unusedIndices[i]);
     704             :     }
     705           4 :     cleanupStates();
     706             :     //std::cout << "oldMaxIndex=" << maxIndex << " newMaxIndex=" << getMaxIndex() << " unused=" << toString(unusedIndices) << "\n";
     707           4 :     setTLControllingInformation();
     708             :     // patch crossing indices
     709           8 :     for (NBNode* n : myControlledNodes) {
     710           6 :         for (NBNode::Crossing* c : n->getCrossings()) {
     711           6 :             for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
     712           4 :                 if (c->customTLIndex > i) {
     713           4 :                     c->customTLIndex--;
     714             :                 }
     715           4 :                 if (c->customTLIndex2 > i) {
     716           4 :                     c->customTLIndex2--;
     717             :                 }
     718             :             }
     719             :         }
     720             :     }
     721           4 : }
     722             : 
     723             : void
     724           2 : NBLoadedSUMOTLDef::ungroupSignals() {
     725             :     NBConnectionVector defaultOrdering;
     726           2 :     collectAllLinks(defaultOrdering);
     727             :     std::vector<std::string> states; // organized per link rather than phase
     728             :     int index = 0;
     729          26 :     for (NBConnection& c : defaultOrdering) {
     730          24 :         NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
     731          24 :         states.push_back(getStates(c2.getTLIndex()));
     732          24 :         c2.setTLIndex(index++);
     733             :     }
     734           4 :     for (NBNode* n : myControlledNodes) {
     735           4 :         for (NBNode::Crossing* c : n->getCrossings()) {
     736           2 :             states.push_back(getStates(c->tlLinkIndex));
     737           2 :             c->customTLIndex = index++;
     738           2 :             if (c->tlLinkIndex2 != NBConnection::InvalidTlIndex) {
     739           2 :                 states.push_back(getStates(c->tlLinkIndex2));
     740           2 :                 c->customTLIndex2 = index++;
     741             :             }
     742             :         }
     743             :     }
     744           2 :     myTLLogic->setStateLength(index);
     745          30 :     for (int i = 0; i < (int)states.size(); i++) {
     746         228 :         for (int p = 0; p < (int)states[i].size(); p++) {
     747         200 :             myTLLogic->setPhaseState(p, i, (LinkState)states[i][p]);
     748             :         }
     749             :     }
     750           2 :     setTLControllingInformation();
     751           2 : }
     752             : 
     753             : 
     754             : void
     755           0 : NBLoadedSUMOTLDef::copyIndices(NBTrafficLightDefinition* def) {
     756             :     std::map<int, std::string> oldStates; // organized per link index rather than phase
     757             :     std::map<int, std::string> newStates; // organized per link index rather than phase
     758           0 :     for (NBConnection& c : def->getControlledLinks()) {
     759           0 :         NBConnection& c2 = *find_if(myControlledLinks.begin(), myControlledLinks.end(), connection_equal(c));
     760           0 :         const int oldIndex = c2.getTLIndex();
     761           0 :         const int newIndex = c.getTLIndex();
     762           0 :         std::string states = getStates(oldIndex);
     763           0 :         oldStates[oldIndex] = states;
     764           0 :         if (newStates.count(newIndex) != 0 && newStates[newIndex] != states) {
     765           0 :             WRITE_WARNING("Signal groups from program '" + def->getProgramID() + "' are incompatible with the states of program '" + getProgramID() + "' at tlLogic '" + getID()
     766             :                           + "'. Possibly unsafe program.");
     767             :         } else {
     768           0 :             newStates[newIndex] = states;
     769             :         }
     770           0 :         c2.setTLIndex(newIndex);
     771             :     }
     772           0 :     const int maxIndex = getMaxIndex();
     773           0 :     myTLLogic->setStateLength(maxIndex + 1);
     774           0 :     for (int i = 0; i < (int)newStates.size(); i++) {
     775           0 :         for (int p = 0; p < (int)newStates[i].size(); p++) {
     776           0 :             myTLLogic->setPhaseState(p, i, (LinkState)newStates[i][p]);
     777             :         }
     778             :     }
     779           0 :     setTLControllingInformation();
     780           0 : }
     781             : 
     782             : 
     783             : bool
     784           4 : NBLoadedSUMOTLDef::cleanupStates() {
     785           4 :     const int maxIndex = getMaxValidIndex();
     786             :     std::vector<int> unusedIndices;
     787          34 :     for (int i = 0; i <= maxIndex; i++) {
     788          30 :         if (isUsed(i)) {
     789          30 :             if (unusedIndices.size() > 0) {
     790           0 :                 replaceIndex(i, i - (int)unusedIndices.size());
     791             :             }
     792             :         } else {
     793           0 :             unusedIndices.push_back(i);
     794             :         }
     795             :     }
     796           4 :     for (int i = (int)unusedIndices.size() - 1; i >= 0; i--) {
     797           0 :         myTLLogic->deleteStateIndex(unusedIndices[i]);
     798             :     }
     799           4 :     if (unusedIndices.size() > 0) {
     800           0 :         myTLLogic->setStateLength(maxIndex + 1 - (int)unusedIndices.size());
     801           0 :         setTLControllingInformation();
     802             :         return true;
     803             :     } else {
     804             :         return false;
     805             :     }
     806             : }
     807             : 
     808             : 
     809             : void
     810           0 : NBLoadedSUMOTLDef::joinLogic(NBTrafficLightDefinition* def) {
     811           0 :     def->setParticipantsInformation();
     812           0 :     def->compute(OptionsCont::getOptions());
     813           0 :     const int maxIndex = MAX2(getMaxIndex(), def->getMaxIndex());
     814           0 :     myTLLogic->setStateLength(maxIndex + 1);
     815           0 :     myControlledLinks.insert(myControlledLinks.end(), def->getControlledLinks().begin(), def->getControlledLinks().end());
     816           0 : }
     817             : 
     818             : bool
     819           2 : NBLoadedSUMOTLDef::usingSignalGroups() const {
     820             :     // count how often each index is used
     821             :     std::map<int, int> indexUsage;
     822          26 :     for (const NBConnection& c : myControlledLinks) {
     823          24 :         indexUsage[c.getTLIndex()]++;
     824             :     }
     825           4 :     for (NBNode* n : myControlledNodes) {
     826           4 :         for (NBNode::Crossing* c : n->getCrossings()) {
     827           2 :             indexUsage[c->tlLinkIndex]++;
     828           2 :             indexUsage[c->tlLinkIndex2]++;
     829             :         }
     830             :     }
     831           2 :     for (auto it : indexUsage) {
     832           2 :         if (it.first >= 0 && it.second > 1) {
     833             :             return true;
     834             :         }
     835             :     }
     836             :     return false;
     837             : }
     838             : 
     839             : void
     840           1 : NBLoadedSUMOTLDef::guessMinMaxDuration() {
     841             :     bool hasMinMaxDur = false;
     842           9 :     for (auto phase : myTLLogic->getPhases()) {
     843           8 :         if (phase.maxDur != UNSPECIFIED_DURATION) {
     844             :             //std::cout << " phase=" << phase.state << " maxDur=" << phase.maxDur << "\n";
     845             :             hasMinMaxDur = true;
     846             :         }
     847           8 :     }
     848           1 :     if (!hasMinMaxDur) {
     849           1 :         const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
     850           1 :         const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
     851             :         std::set<int> yellowIndices;
     852           9 :         for (auto phase : myTLLogic->getPhases()) {
     853         168 :             for (int i = 0; i < (int)phase.state.size(); i++) {
     854         160 :                 if (phase.state[i] == 'y' || phase.state[i] == 'Y') {
     855             :                     yellowIndices.insert(i);
     856             :                 }
     857             :             }
     858           8 :         }
     859           9 :         for (int ip = 0; ip < (int)myTLLogic->getPhases().size(); ip++) {
     860             :             bool needMinMaxDur = false;
     861           8 :             auto phase = myTLLogic->getPhases()[ip];
     862             :             std::set<int> greenIndices;
     863           8 :             if (phase.state.find_first_of("yY") != std::string::npos) {
     864             :                 continue;
     865             :             }
     866          84 :             for (int i = 0; i < (int)phase.state.size(); i++) {
     867          80 :                 if (yellowIndices.count(i) != 0 && phase.state[i] == 'G') {
     868             :                     needMinMaxDur = true;
     869             :                     greenIndices.insert(i);
     870             :                 }
     871             :             }
     872           4 :             if (needMinMaxDur) {
     873             :                 double maxSpeed = 0;
     874          84 :                 for (NBConnection& c : myControlledLinks) {
     875             :                     if (greenIndices.count(c.getTLIndex()) != 0) {
     876          20 :                         maxSpeed = MAX2(maxSpeed, c.getFrom()->getLaneSpeed(c.getFromLane()));
     877             :                     }
     878             :                 }
     879             :                 // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
     880           4 :                 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
     881           4 :                 SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
     882           4 :                 myTLLogic->setPhaseMinDuration(ip, minDur);
     883           4 :                 myTLLogic->setPhaseMaxDuration(ip, maxDur);
     884             :             }
     885           8 :         }
     886             :     }
     887           1 : }
     888             : 
     889             : 
     890             : void
     891         844 : NBLoadedSUMOTLDef::finalChecks() const {
     892        8967 :     for (int i = 0; i < myTLLogic->getNumLinks(); i++) {
     893        8139 :         if (!isUsed(i)) {
     894          50 :             WRITE_WARNINGF(TL("Unused state in tlLogic '%', program '%' at tl-index %"), getID(), getProgramID(), i);
     895          16 :             break;
     896             :         }
     897             :     }
     898         844 : }
     899             : 
     900             : 
     901             : /****************************************************************************/

Generated by: LCOV version 1.14