Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 878 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
56 : const std::vector<NBNode*>& junctions, const std::string& programID,
57 878 : SUMOTime offset, TrafficLightType type) :
58 : Named(id),
59 878 : myControlledNodes(junctions),
60 878 : mySubID(programID), myOffset(offset),
61 878 : myType(type),
62 878 : myNeedsContRelationReady(false),
63 1756 : myExtraConflictsReady(false) {
64 : std::vector<NBNode*>::iterator i = myControlledNodes.begin();
65 2229 : while (i != myControlledNodes.end()) {
66 2599 : for (std::vector<NBNode*>::iterator j = i + 1; j != myControlledNodes.end();) {
67 1248 : if (*i == *j) {
68 : j = myControlledNodes.erase(j);
69 : } else {
70 : j++;
71 : }
72 : }
73 : i++;
74 : }
75 878 : std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
76 2470 : for (NBNode* const node : junctions) {
77 1592 : node->addTrafficLight(this);
78 : }
79 878 : }
80 :
81 :
82 5837 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id,
83 5837 : NBNode* junction, const std::string& programID, SUMOTime offset, TrafficLightType type) :
84 : Named(id),
85 5837 : mySubID(programID),
86 5837 : myOffset(offset),
87 5837 : myType(type),
88 5837 : myNeedsContRelationReady(false),
89 5837 : myExtraConflictsReady(false) {
90 5837 : addNode(junction);
91 5837 : }
92 :
93 :
94 814 : NBTrafficLightDefinition::NBTrafficLightDefinition(const std::string& id, const std::string& programID,
95 814 : SUMOTime offset, TrafficLightType type) :
96 : Named(id),
97 814 : mySubID(programID),
98 814 : myOffset(offset),
99 814 : myType(type),
100 814 : myNeedsContRelationReady(false),
101 814 : myExtraConflictsReady(false) {
102 814 : }
103 :
104 :
105 22587 : NBTrafficLightDefinition::~NBTrafficLightDefinition() {}
106 :
107 :
108 : NBTrafficLightLogic*
109 3131 : NBTrafficLightDefinition::compute(const OptionsCont& oc) {
110 : // it is not really a traffic light if no incoming edge exists
111 3131 : if (amInvalid()) {
112 : // make a copy of myControlledNodes because it will be modified;
113 65 : std::vector<NBNode*> nodes = myControlledNodes;
114 130 : for (auto it : nodes) {
115 65 : it->removeTrafficLight(this);
116 : }
117 195 : WRITE_WARNINGF(TL("The traffic light '%' does not control any links; it will not be build."), getID());
118 : return nullptr;
119 65 : }
120 : // compute the time needed to brake
121 3066 : 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 6132 : if (!oc.isDefault("tls.yellow.time")) {
125 4 : brakingTime = oc.getInt("tls.yellow.time");
126 : }
127 3066 : NBTrafficLightLogic* ret = myCompute(brakingTime);
128 3066 : ret->updateParameters(getParametersMap());
129 3066 : return ret;
130 : }
131 :
132 :
133 : bool
134 2290 : NBTrafficLightDefinition::amInvalid() const {
135 2290 : return myControlledLinks.size() == 0;
136 : }
137 :
138 :
139 : int
140 3078 : NBTrafficLightDefinition::computeBrakingTime(double minDecel) const {
141 3078 : if (myIncomingEdges.empty()) {
142 : // don't crash
143 : return MIN_YELLOW_SECONDS;
144 : }
145 3078 : const double vmax = NBContHelper::maxSpeed(myIncomingEdges);
146 3078 : 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 5495 : 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 170 : return (int)(1.8 + vmax / 2 / minDecel);
155 : }
156 : }
157 :
158 :
159 : void
160 6368 : NBTrafficLightDefinition::setParticipantsInformation() {
161 : // collect the information about participating edges and links
162 6368 : collectEdges();
163 6368 : collectLinks();
164 6368 : }
165 :
166 : std::set<NBEdge*>
167 11584 : NBTrafficLightDefinition::collectReachable(EdgeVector outer, const EdgeVector& within, bool checkControlled) {
168 : std::set<NBEdge*> reachable;
169 40815 : while (outer.size() > 0) {
170 29231 : NBEdge* from = outer.back();
171 : outer.pop_back();
172 : std::vector<NBEdge::Connection>& cons = from->getConnections();
173 102664 : for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); k++) {
174 73433 : NBEdge* to = (*k).toEdge;
175 70579 : if (reachable.count(to) == 0 &&
176 74175 : (find(within.begin(), within.end(), to) != within.end()) &&
177 742 : (!checkControlled || from->mayBeTLSControlled((*k).fromLane, to, (*k).toLane))) {
178 : reachable.insert(to);
179 1469 : outer.push_back(to);
180 : }
181 : }
182 : }
183 11584 : return reachable;
184 : }
185 :
186 :
187 : void
188 5792 : NBTrafficLightDefinition::collectEdges() {
189 : myIncomingEdges.clear();
190 : myEdgesWithin.clear();
191 : EdgeVector myOutgoing;
192 : // collect the edges from the participating nodes
193 11747 : for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
194 5955 : const EdgeVector& incoming = (*i)->getIncomingEdges();
195 5955 : copy(incoming.begin(), incoming.end(), back_inserter(myIncomingEdges));
196 5955 : 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 20477 : 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 14685 : EdgeVector::iterator k = std::find(myOutgoing.begin(), myOutgoing.end(), edge);
206 14685 : if (k != myOutgoing.end()) {
207 804 : myEdgesWithin.push_back(edge);
208 : } else {
209 13881 : outer.push_back(edge);
210 : }
211 : }
212 : // collect edges that are reachable from the outside via controlled connections
213 5792 : std::set<NBEdge*> reachable = collectReachable(outer, myEdgesWithin, true);
214 : // collect edges that are reachable from the outside regardless of controllability
215 5792 : std::set<NBEdge*> reachable2 = collectReachable(outer, myEdgesWithin, false);
216 :
217 11584 : const bool uncontrolledWithin = OptionsCont::getOptions().getBool("tls.uncontrolled-within");
218 6596 : for (EdgeVector::iterator j = myEdgesWithin.begin(); j != myEdgesWithin.end(); ++j) {
219 804 : 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 741 : if (uncontrolledWithin && myControlledInnerEdges.count(edge->getID()) == 0) {
226 38 : myIncomingEdges.erase(find(myIncomingEdges.begin(), myIncomingEdges.end(), edge));
227 : }
228 : }
229 60 : if (reachable2.count(edge) == 0 && edge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD, true) >= 0
230 6 : && getID() != DummyID) {
231 24 : WRITE_WARNINGF(TL("Unreachable edge '%' within tlLogic '%'"), edge->getID(), getID());
232 : }
233 : }
234 5792 : }
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 878978 : 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 878978 : 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 878978 : find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorFrom));
287 : std::vector<NBNode*>::const_iterator outgoing =
288 878978 : find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(possProhibitedTo));
289 : assert(incoming != myControlledNodes.end());
290 878978 : NBNode* incnode = *incoming;
291 878978 : NBNode* outnode = *outgoing;
292 : EdgeVector::const_iterator i;
293 :
294 : #ifdef DEBUG_RIGHT_OF_WAY
295 : if (DEBUGCOND) {
296 : std::cout << "forbids tls=" << getID() << " from=" << possProhibitedFrom->getID() << " to=" << possProhibitedTo->getID() << " foeFrom=" << possProhibitorFrom->getID() << " foeTo=" << possProhibitorTo->getID() << " rnslp=" << regardNonSignalisedLowerPriority << " sameNodeOnly=" << sameNodeOnly;
297 : }
298 : #endif
299 878978 : if (incnode != outnode) {
300 170275 : 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 95023 : const EdgeVector& ev1 = possProhibitedTo->getConnectedEdges();
310 : // go through the following edge,
311 : // check whether one of these connections is prohibited
312 223953 : for (i = ev1.begin(); i != ev1.end(); ++i) {
313 : std::vector<NBNode*>::const_iterator outgoing2 =
314 130028 : find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_outgoing_finder(*i));
315 130028 : if (outgoing2 == myControlledNodes.end()) {
316 84759 : continue;
317 : }
318 45269 : NBNode* outnode2 = *outgoing2;
319 45269 : if (incnode != outnode2) {
320 30578 : continue;
321 : }
322 14691 : if (incnode->getDirection(possProhibitedTo, *i) != LinkDirection::STRAIGHT) {
323 8486 : continue;
324 : }
325 6205 : bool ret1 = incnode->foes(possProhibitorFrom, possProhibitorTo,
326 : possProhibitedTo, *i);
327 6205 : bool ret2 = incnode->forbids(possProhibitorFrom, possProhibitorTo,
328 : possProhibitedTo, *i,
329 : regardNonSignalisedLowerPriority);
330 6205 : bool ret = ret1 || ret2;
331 6205 : 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 93925 : const EdgeVector& ev2 = possProhibitorTo->getConnectedEdges();
342 : // go through the following edge,
343 : // check whether one of these connections is prohibited
344 220986 : for (i = ev2.begin(); i != ev2.end(); ++i) {
345 : std::vector<NBNode*>::const_iterator incoming2 =
346 128617 : find_if(myControlledNodes.begin(), myControlledNodes.end(), NBContHelper::node_with_incoming_finder(possProhibitorTo));
347 128617 : if (incoming2 == myControlledNodes.end()) {
348 83342 : continue;
349 : }
350 45275 : NBNode* incnode2 = *incoming2;
351 45275 : if (incnode2 != outnode) {
352 30164 : continue;
353 : }
354 15111 : if (incnode2->getDirection(possProhibitorTo, *i) != LinkDirection::STRAIGHT) {
355 8507 : continue;
356 : }
357 6604 : bool ret1 = incnode2->foes(possProhibitorTo, *i,
358 : possProhibitedFrom, possProhibitedTo);
359 6604 : bool ret2 = incnode2->forbids(possProhibitorTo, *i,
360 : possProhibitedFrom, possProhibitedTo,
361 : regardNonSignalisedLowerPriority);
362 6604 : bool ret = ret1 || ret2;
363 6604 : 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 95023 : }
379 : // both links are located at the same node
380 : // check using this node's information
381 708703 : 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 218948 : NBTrafficLightDefinition::foes(const NBEdge* const from1, const NBEdge* const to1,
395 : const NBEdge* const from2, const NBEdge* const to2) const {
396 218948 : 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 218948 : find_if(myControlledNodes.begin(), myControlledNodes.end(),
402 : NBContHelper::node_with_incoming_finder(from1));
403 : std::vector<NBNode*>::const_iterator outgoing =
404 218948 : find_if(myControlledNodes.begin(), myControlledNodes.end(),
405 : NBContHelper::node_with_outgoing_finder(to1));
406 : assert(incoming != myControlledNodes.end());
407 218948 : NBNode* incnode = *incoming;
408 218948 : NBNode* outnode = *outgoing;
409 218948 : if (incnode != outnode) {
410 : return false;
411 : }
412 218948 : return incnode->foes(from1, to1, from2, to2);
413 : }
414 :
415 :
416 : void
417 21173 : NBTrafficLightDefinition::addNode(NBNode* node) {
418 21173 : if (std::find(myControlledNodes.begin(), myControlledNodes.end(), node) == myControlledNodes.end()) {
419 6900 : myControlledNodes.push_back(node);
420 6900 : std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
421 : }
422 21173 : node->addTrafficLight(this);
423 21173 : }
424 :
425 :
426 : void
427 5813 : NBTrafficLightDefinition::removeNode(NBNode* node) {
428 5813 : std::vector<NBNode*>::iterator i = std::find(myControlledNodes.begin(), myControlledNodes.end(), node);
429 5813 : if (i != myControlledNodes.end()) {
430 5572 : myControlledNodes.erase(i);
431 : }
432 : // !!! remove in node?
433 5813 : }
434 :
435 :
436 : void
437 47 : NBTrafficLightDefinition::addControlledInnerEdges(const std::vector<std::string>& edges) {
438 : myControlledInnerEdges.insert(edges.begin(), edges.end());
439 47 : }
440 :
441 :
442 : std::vector<std::string>
443 125 : NBTrafficLightDefinition::getControlledInnerEdges() const {
444 125 : return std::vector<std::string>(myControlledInnerEdges.begin(), myControlledInnerEdges.end());
445 : }
446 :
447 :
448 : const EdgeVector&
449 3669 : NBTrafficLightDefinition::getIncomingEdges() const {
450 3669 : return myIncomingEdges;
451 : }
452 :
453 :
454 : void
455 5624 : 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 18167 : for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
460 12543 : NBEdge* incoming = *i;
461 : int noLanes = incoming->getNumLanes();
462 34976 : for (int j = 0; j < noLanes; j++) {
463 22433 : std::vector<NBEdge::Connection> connected = incoming->getConnectionsFromLane(j);
464 53729 : for (std::vector<NBEdge::Connection>::iterator k = connected.begin(); k != connected.end(); k++) {
465 : const NBEdge::Connection& el = *k;
466 31296 : if (incoming->mayBeTLSControlled(el.fromLane, el.toEdge, el.toLane)) {
467 31127 : 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 31127 : && isRailway(incoming->getPermissions())) {
472 : // railways stay uncontrolled at rail crossing but they
473 : // must be registered in MSRailCrossing
474 576 : into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, -1));
475 : } else if (incoming->getToNode()->getType() == SumoXMLNodeType::RAIL_SIGNAL
476 2241 : && 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 30864 : && (incoming->getBidiEdge() == el.toEdge)
481 : ) {
482 : // turnarounds stay uncontrolled at rail signal
483 30814 : } 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 60570 : into.push_back(NBConnection(incoming, el.fromLane, el.toEdge, el.toLane, tlIndex++));
487 30285 : if (el.indirectLeft) {
488 9 : indirectLeft.push_back((int)into.size() - 1);
489 : }
490 : }
491 : }
492 : }
493 22433 : }
494 : }
495 5624 : if (indirectLeft.size() > 0) {
496 : // assign linkIndex2 to indirect left turns
497 12 : for (int i : indirectLeft) {
498 9 : NBConnection& c = into[i];
499 : // find straight connection with the same toEdge
500 127 : for (const NBConnection& c2 : into) {
501 126 : if (c2.getTo() == c.getTo() && c2.getFrom() != c.getFrom()) {
502 25 : LinkDirection dir = c.getFrom()->getToNode()->getDirection(c2.getFrom(), c2.getTo());
503 25 : if (dir == LinkDirection::STRAIGHT) {
504 : c.setTLIndex2(c2.getTLIndex());
505 : break;
506 : }
507 : }
508 : }
509 : }
510 : }
511 :
512 5624 : if (into.size() > 0 && tlIndex == 0) {
513 447 : WRITE_WARNINGF(TL("The rail crossing '%' does not have any roads."), getID());
514 : }
515 5624 : }
516 :
517 : bool
518 2216 : NBTrafficLightDefinition::railSignalUncontrolled(const NBEdge* in, const NBEdge* out) {
519 : const NBNode* n = in->getToNode();
520 2216 : 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 76789 : NBTrafficLightDefinition::needsCont(const NBEdge* fromE, const NBEdge* toE, const NBEdge* otherFromE, const NBEdge* otherToE) const {
537 76789 : if (!myNeedsContRelationReady) {
538 319 : initNeedsContRelation();
539 : assert(myNeedsContRelationReady);
540 : }
541 76789 : return std::find(myNeedsContRelation.begin(), myNeedsContRelation.end(),
542 76789 : 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 170682 : NBTrafficLightDefinition::initExtraConflicts() const {
562 170682 : if (!myExtraConflictsReady) {
563 755 : NBOwnTLDef dummy(DummyID, myControlledNodes, 0, TrafficLightType::STATIC);
564 755 : dummy.setParticipantsInformation();
565 755 : NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
566 755 : delete tllDummy;
567 : myExtraConflicts = dummy.myExtraConflicts;
568 1984 : for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
569 1229 : (*i)->removeTrafficLight(&dummy);
570 : }
571 755 : myExtraConflictsReady = true;
572 : //std::cout << " extraConflicts tls=" << getID() << " pro=" << getProgramID() << "\n";
573 : //for (auto item : myExtraConflicts) {
574 : // std::cout << " " << item.first << ", " << item.second << "\n";
575 : //}
576 755 : }
577 170682 : }
578 :
579 :
580 : bool
581 169839 : NBTrafficLightDefinition::extraConflict(int index, int foeIndex) const {
582 169839 : initExtraConflicts();
583 169839 : return std::find(myExtraConflicts.begin(), myExtraConflicts.end(), std::make_pair(index, foeIndex)) != myExtraConflicts.end();
584 : }
585 :
586 : std::string
587 0 : NBTrafficLightDefinition::getDescription() const {
588 0 : return getID() + ':' + getProgramID() + '@' + toString(this);
589 : }
590 :
591 :
592 : /****************************************************************************/
|