Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
NBOwnTLDef.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2023 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/****************************************************************************/
21// A traffic light logics which must be computed (only nodes/edges are given)
22/****************************************************************************/
23#include <config.h>
24
25#include <vector>
26#include <cassert>
27#include <iterator>
29#include "NBNode.h"
30#include "NBOwnTLDef.h"
31#include "NBTrafficLightLogic.h"
38
39#define HEIGH_WEIGHT 2
40#define LOW_WEIGHT .5;
41
42#define MIN_GREEN_TIME 5
43
44//#define DEBUG_STREAM_ORDERING
45//#define DEBUG_PHASES
46//#define DEBUG_CONTRELATION
47//#define DEBUGCOND (getID() == "cluster_251050941_280598736_280598739_28902891_3142549227_3142550438")
48//#define DEBUGEDGE(edge) (edge->getID() == "23209153#1" || edge->getID() == "319583927#0")
49#define DEBUGCOND (true)
50#define DEBUGEDGE(edge) (true)
51
52// ===========================================================================
53// static members
54// ===========================================================================
55const double NBOwnTLDef::MIN_SPEED_CROSSING_TIME(25 / 3.6);
56
57
58// ===========================================================================
59// member method definitions
60// ===========================================================================
61NBOwnTLDef::NBOwnTLDef(const std::string& id,
62 const std::vector<NBNode*>& junctions, SUMOTime offset,
63 TrafficLightType type) :
64 NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
65 myHaveSinglePhase(false),
66 myLayout(TrafficLightLayout::DEFAULT) {
67}
68
69
70NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
71 TrafficLightType type) :
72 NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
73 myHaveSinglePhase(false),
74 myLayout(TrafficLightLayout::DEFAULT) {
75}
76
77
78NBOwnTLDef::NBOwnTLDef(const std::string& id, SUMOTime offset,
79 TrafficLightType type) :
80 NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
81 myHaveSinglePhase(false),
82 myLayout(TrafficLightLayout::DEFAULT) {
83}
84
85
87
88
89int
91 return e->getJunctionPriority(e->getToNode());
92}
93
94
95double
97 switch (dir) {
101 return HEIGH_WEIGHT;
104 return LOW_WEIGHT;
105 default:
106 break;
107 }
108 return 0;
109}
110
111double
113 double val = 0;
114 for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
115 std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
116 for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
117 std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
118 for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
119 if (e1->getTurnDestination() == (*e1c).toEdge) {
120 continue;
121 }
122 for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
123 if (e2->getTurnDestination() == (*e2c).toEdge) {
124 continue;
125 }
126 const double sign = (forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)
127 || forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge, true)) ? -1 : 1;
128 double w1;
129 double w2;
130 const int prio1 = e1->getJunctionPriority(e1->getToNode());
131 const int prio2 = e2->getJunctionPriority(e2->getToNode());
132 if (prio1 == prio2) {
133 w1 = getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
134 w2 = getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
135 } else {
136 if (prio1 > prio2) {
137 w1 = HEIGH_WEIGHT;
138 w2 = LOW_WEIGHT;
139 } else {
140 w1 = LOW_WEIGHT;
141 w2 = HEIGH_WEIGHT;
142 }
143 if (sign == -1) {
144 // extra penalty if edges with different junction priority are in conflict
145 w1 *= 2;
146 w2 *= 2;
147 }
148 }
149 if (isRailway(e1->getPermissions()) != isRailway(e2->getPermissions())) {
150 w1 *= 0.1;
151 w2 *= 0.1;
152 }
153 if ((e1->getPermissions() & SVC_PASSENGER) == 0) {
154 w1 *= 0.1;
155 }
156 if ((e2->getPermissions() & SVC_PASSENGER) == 0) {
157 w2 *= 0.1;
158 }
159 val += sign * w1;
160 val += sign * w2;
161#ifdef DEBUG_STREAM_ORDERING
162 if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
163 std::cout << " sign=" << sign << " w1=" << w1 << " w2=" << w2 << " val=" << val
164 << " c1=" << (*e1c).getDescription(e1)
165 << " c2=" << (*e2c).getDescription(e2)
166 << "\n";
167 }
168#endif
169 }
170 }
171 }
172 }
173#ifdef DEBUG_STREAM_ORDERING
174 if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
175 std::cout << " computeUnblockedWeightedStreamNumber e1=" << e1->getID() << " e2=" << e2->getID() << " val=" << val << "\n";
176 }
177#endif
178 return val;
179}
180
181
182std::pair<NBEdge*, NBEdge*>
184 std::pair<NBEdge*, NBEdge*> bestPair(static_cast<NBEdge*>(nullptr), static_cast<NBEdge*>(nullptr));
185 double bestValue = -std::numeric_limits<double>::max();
186 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
187 for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
188 const double value = computeUnblockedWeightedStreamNumber(*i, *j);
189 if (value > bestValue) {
190 bestValue = value;
191 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
192 } else if (value == bestValue) {
193 const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
194 const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
195 if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
196 if (bestPair.first->getID() < (*i)->getID()) {
197 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
198 }
199 } else if (oa < ca) {
200 bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
201 }
202 }
203 }
204 }
205 if (bestValue <= 0) {
206 // do not group edges
207 if (bestPair.first->getPriority() < bestPair.second->getPriority()) {
208 std::swap(bestPair.first, bestPair.second);
209 }
210 bestPair.second = nullptr;
211 }
212#ifdef DEBUG_STREAM_ORDERING
213 if (DEBUGCOND) {
214 std::cout << " getBestCombination bestValue=" << bestValue << " best=" << Named::getIDSecure(bestPair.first) << ", " << Named::getIDSecure(bestPair.second) << "\n";
215 }
216#endif
217 return bestPair;
218}
219
220
221std::pair<NBEdge*, NBEdge*>
223 if (incoming.size() == 1) {
224 // only one there - return the one
225 std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(), static_cast<NBEdge*>(nullptr));
226 incoming.clear();
227 return ret;
228 }
229 // determine the best combination
230 // by priority, first
231 EdgeVector used;
232 std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
233 used.push_back(*incoming.begin()); // the first will definitely be used
234 // get the ones with the same priority
235 int prio = getToPrio(*used.begin());
236 for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
237 used.push_back(*i);
238 }
239 // if there only lower priorised, use these, too
240 if (used.size() < 2) {
241 used = incoming;
242 }
243 std::pair<NBEdge*, NBEdge*> ret = getBestCombination(used);
244#ifdef DEBUG_STREAM_ORDERING
245 if (DEBUGCOND) {
246 std::cout << "getBestPair tls=" << getID() << " incoming=" << toString(incoming) << " prio=" << prio << " used=" << toString(used) << " best=" << Named::getIDSecure(ret.first) << ", " << Named::getIDSecure(ret.second) << "\n";
247 }
248#endif
249
250 incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
251 if (ret.second != nullptr) {
252 incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
253 }
254 return ret;
255}
256
257bool
259 for (const NBEdge::Connection& c : fromEdge->getConnections()) {
260 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, c.toEdge);
261 if (dir == LinkDirection::STRAIGHT) {
262 return true;
263 }
264 }
265 return false;
266}
267
269NBOwnTLDef::myCompute(int brakingTimeSeconds) {
270 return computeLogicAndConts(brakingTimeSeconds);
271}
272
273
275NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
276 if (myControlledNodes.size() == 1) {
277 // otherwise, use values from previous call to initNeedsContRelation
278 myNeedsContRelation.clear();
279 }
280 myRightOnRedConflicts.clear();
281 const bool isNEMA = myType == TrafficLightType::NEMA;
282 const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
283 const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
284 const SUMOTime minMinDur = (myType == TrafficLightType::STATIC) ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
286 const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
287 const SUMOTime latestEnd = UNSPECIFIED_DURATION;
288
289 // things collect for NEMA phase building
290 std::vector<std::pair<NBEdge*, NBEdge*> > chosenList;
291 std::vector<std::string> straightStates;
292 std::vector<std::string> leftStates;
293
294 // build complete lists first
295 const EdgeVector& incoming = getIncomingEdges();
296 EdgeVector fromEdges, toEdges;
297 std::vector<bool> isTurnaround;
298 std::vector<bool> hasTurnLane;
299 std::vector<int> fromLanes;
300 std::vector<int> toLanes;
301 std::vector<SUMOTime> crossingTime;
302 int totalNumLinks = 0;
303 for (NBEdge* const fromEdge : incoming) {
304 const int numLanes = fromEdge->getNumLanes();
305 const bool edgeHasStraight = hasStraightConnection(fromEdge);
306 for (int i2 = 0; i2 < numLanes; i2++) {
307 bool hasLeft = false;
308 bool hasPartLeft = false;
309 bool hasStraight = false;
310 bool hasRight = false;
311 bool hasTurnaround = false;
312 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
313 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
314 continue;
315 }
316 fromEdges.push_back(fromEdge);
317 fromLanes.push_back(i2);
318 toLanes.push_back(approached.toLane);
319 toEdges.push_back(approached.toEdge);
320 if (approached.vmax < NUMERICAL_EPS || (fromEdge->getPermissions() & SVC_PASSENGER) == 0
321 || (approached.toEdge->getPermissions() & SVC_PASSENGER) == 0) {
322 crossingTime.push_back(0);
323 } else {
324 crossingTime.push_back(TIME2STEPS((approached.length + approached.viaLength) / MAX2(approached.vmax, MIN_SPEED_CROSSING_TIME)));
325 }
326 // std::cout << fromEdge->getID() << " " << approached.toEdge->getID() << " " << (fromEdge->getPermissions() & SVC_PASSENGER) << " " << approached.length << " " << approached.viaLength << " " << approached.vmax << " " << crossingTime.back() << std::endl;
327 if (approached.toEdge != nullptr) {
328 isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
329 } else {
330 isTurnaround.push_back(true);
331 }
332 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
333 if (dir == LinkDirection::STRAIGHT) {
334 hasStraight = true;
335 } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
336 hasRight = true;
337 } else if (dir == LinkDirection::LEFT) {
338 hasLeft = true;
339 } else if (dir == LinkDirection::PARTLEFT) {
340 hasPartLeft = true;
341 } else if (dir == LinkDirection::TURN) {
342 hasTurnaround = true;
343 }
344 totalNumLinks++;
345 }
346 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
347 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
348 continue;
349 }
350 hasTurnLane.push_back(
351 (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
352 || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
353 || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
354 || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
355 }
356 //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
357 }
358 }
359 // collect crossings
360 std::vector<NBNode::Crossing*> crossings;
361 for (NBNode* const node : myControlledNodes) {
362 const std::vector<NBNode::Crossing*>& c = node->getCrossings();
363 if (!onlyConts) {
364 // set tl indices for crossings
365 node->setCrossingTLIndices(getID(), totalNumLinks);
366 }
367 copy(c.begin(), c.end(), std::back_inserter(crossings));
368 totalNumLinks += (int)c.size();
369 }
370
371 NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
372 EdgeVector toProc = getConnectedOuterEdges(incoming);
373 const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
374 SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
375 const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
376 const bool noMixed = OptionsCont::getOptions().getBool("tls.no-mixed");
377 // left-turn phases do not work well for joined tls, so we build incoming instead
379 // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
381 }
382 const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
383
384 // build all phases
385 std::vector<int> greenPhases; // indices of green phases
386 std::vector<bool> hadGreenMajor(totalNumLinks, false);
387 while (toProc.size() > 0) {
388 bool groupTram = false;
389 bool groupOther = false;
390 std::pair<NBEdge*, NBEdge*> chosen;
391 std::set<const NBEdge*> chosenSet;
392 if (groupOpposites) {
393 if (incoming.size() == 2) {
394 // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
395 // @node: this heuristic could be extended to also check the number of outgoing edges
396 double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
397 // angle would be 180 for straight opposing incoming edges
398 if (angle < 135) {
399 chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
400 toProc.erase(toProc.begin());
401 } else {
402 chosen = getBestPair(toProc);
403 }
404 } else {
405 chosen = getBestPair(toProc);
406 if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
407 groupTram = true;
408 for (auto it = toProc.begin(); it != toProc.end();) {
409 if ((*it)->getPermissions() == SVC_TRAM) {
410 it = toProc.erase(it);
411 } else {
412 it++;
413 }
414 }
415 }
416 }
417 } else {
418 NBEdge* chosenEdge = toProc[0];
419 chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
420 toProc.erase(toProc.begin());
421 SVCPermissions perms = chosenEdge->getPermissions();
422 if (perms == SVC_TRAM) {
423 groupTram = true;
424 } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
425 groupOther = true;
426 }
427 // group all edges with the same permissions into a single phase (later)
428 if (groupTram || groupOther) {
429 for (auto it = toProc.begin(); it != toProc.end();) {
430 if ((*it)->getPermissions() == perms) {
431 it = toProc.erase(it);
432 } else {
433 it++;
434 }
435 }
436 }
437 }
438 int pos = 0;
439 std::string state(totalNumLinks, 'r');
440#ifdef DEBUG_PHASES
441 if (DEBUGCOND) {
442 std::cout << " computing " << getID() << " prog=" << getProgramID() << " cho1=" << Named::getIDSecure(chosen.first) << " cho2=" << Named::getIDSecure(chosen.second) << " toProc=" << toString(toProc) << " bentPrio=" << chosen.first->getToNode()->isBentPriority() << "\n";
443 }
444#endif
445 chosenList.push_back(chosen);
446 chosenSet.insert(chosen.first);
447 if (chosen.second != nullptr) {
448 chosenSet.insert(chosen.second);
449 }
450 // find parallel bike edge for the chosen (passenger) edges
451 for (const NBEdge* e : chosenSet) {
452 if ((e->getPermissions() & SVC_PASSENGER) != 0) {
453 std::vector<NBEdge*> parallelBikeEdges;
454 for (NBEdge* cand : toProc) {
455 if ((cand->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE) {
456 double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
457 if (angle < 30) {
458 // roughly parallel
459 parallelBikeEdges.push_back(cand);
460 }
461 }
462 }
463 for (NBEdge* be : parallelBikeEdges) {
464#ifdef DEBUG_PHASES
465 if (DEBUGCOND) {
466 std::cout << " chosen=" << e->getID() << " be=" << be->getID() << "\n";
467 }
468#endif
469 chosenSet.insert(be);
470 toProc.erase(std::find(toProc.begin(), toProc.end(), be));
471 }
472 }
473 }
474 // plain straight movers
475 double maxSpeed = 0;
476 bool haveGreen = false;
477 for (const NBEdge* const fromEdge : incoming) {
478 const bool inChosen = chosenSet.count(fromEdge) != 0;
479 const int numLanes = fromEdge->getNumLanes();
480 for (int i2 = 0; i2 < numLanes; i2++) {
481 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
482 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
483 continue;
484 }
485 if (inChosen) {
486 state[pos] = 'G';
487 haveGreen = true;
488 maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
489 } else {
490 state[pos] = 'r';
491 }
492 ++pos;
493 }
494 }
495 }
496 if (!haveGreen) {
497 continue;
498 }
499
500#ifdef DEBUG_PHASES
501 if (DEBUGCOND) {
502 std::cout << " state after plain straight movers " << state << "\n";
503 }
504#endif
505 if (!isNEMA) {
506 // correct behaviour for those that are not in chosen, but may drive, though
507 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
508#ifdef DEBUG_PHASES
509 if (DEBUGCOND) {
510 std::cout << " state after allowing compatible " << state << "\n";
511 }
512#endif
513 if (groupTram) {
514 state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
515 } else if (groupOther) {
516 state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
517 }
518#ifdef DEBUG_PHASES
519 if (DEBUGCOND) {
520 std::cout << " state after grouping by vClass " << state << "\n";
521 }
522#endif
523 if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
524 state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
525 }
526#ifdef DEBUG_PHASES
527 if (DEBUGCOND) {
528 std::cout << " state after finding allowUnrelated " << state << "\n";
529 }
530#endif
531 }
532 // correct behaviour for those that have to wait (mainly left-mover)
533 bool haveForbiddenLeftMover = false;
534 std::vector<bool> rightTurnConflicts(pos, false);
535 std::vector<bool> mergeConflicts(pos, false);
536 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
537 for (int i1 = 0; i1 < pos; ++i1) {
538 if (state[i1] == 'G') {
539 hadGreenMajor[i1] = true;
540 }
541 }
542#ifdef DEBUG_PHASES
543 if (DEBUGCOND) {
544 std::cout << " state after correcting left movers=" << state << "\n";
545 }
546#endif
547
548 std::vector<bool> leftGreen(pos, false);
549 // check whether at least one left-turn lane exist
550 bool foundLeftTurnLane = false;
551 for (int i1 = 0; i1 < pos; ++i1) {
552 if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
553 foundLeftTurnLane = true;
554 }
555 }
556 const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
557 && groupOpposites && !groupTram && !groupOther);
558
559 // find indices for exclusive left green phase and apply option minor-left.max-speed
560 for (int i1 = 0; i1 < pos; ++i1) {
561 if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
562 // only activate turn-around together with a real left-turn
563 && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
564 leftGreen[i1] = true;
565 if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
566 if (buildLeftGreenPhase) {
567 state[i1] = 'r';
568 //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
569 } else if (!isTurnaround[i1]) {
570 WRITE_WARNINGF(TL("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
571 fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
572 }
573 }
574 }
575 }
576
577#ifdef DEBUG_PHASES
578 if (DEBUGCOND) {
579 std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
580 << " \nrtC=" << toString(rightTurnConflicts)
581 << " \nmC=" << toString(mergeConflicts)
582 << " \nhTL=" << toString(hasTurnLane)
583 << " \nlGr=" << toString(leftGreen)
584 << "\n";
585 }
586#endif
587 straightStates.push_back(state);
588
589 const std::string vehicleState = state; // backup state before pedestrian modifications
590 greenPhases.push_back((int)logic->getPhases().size());
591
592 // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
593 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
594 SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
595 if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
596 // shorter minDuration for tram phase (only if the phase is
597 // exclusively for tram)
598 bool tramExclusive = true;
599 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
600 if (state[i1] == 'G') {
601 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
602 if (linkPerm != SVC_TRAM) {
603 tramExclusive = false;
604 break;
605 }
606 }
607 }
608 if (tramExclusive) {
609 // one tram per actuated phase
610 minDur = TIME2STEPS(1);
611 }
612 }
613
614 state = addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
615 // pedestrians have 'r' from here on
616 for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
617 state[i1] = 'r';
618 }
619 if (brakingTime > 0) {
620 SUMOTime maxCross = 0;
621 // build yellow (straight)
622 for (int i1 = 0; i1 < pos; ++i1) {
623 if (state[i1] != 'G' && state[i1] != 'g') {
624 continue;
625 }
626 if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
627 && buildLeftGreenPhase
628 && !rightTurnConflicts[i1]
629 && !mergeConflicts[i1]
630 && leftGreen[i1]) {
631 continue;
632 }
633 state[i1] = 'y';
634 maxCross = MAX2(maxCross, crossingTime[i1]);
635 }
636 // add step
637 logic->addStep(brakingTime, state);
638 // add optional all-red state
639 if (!buildLeftGreenPhase) {
641 allRedTime = computeEscapeTime(state, fromEdges, toEdges);
642 }
643 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
644 }
645 }
646
647
648 if (buildLeftGreenPhase) {
649 // build left green
650 for (int i1 = 0; i1 < pos; ++i1) {
651 if (state[i1] == 'Y' || state[i1] == 'y') {
652 state[i1] = 'r';
653 continue;
654 }
655 if (leftGreen[i1]) {
656 state[i1] = 'G';
657 }
658 }
659 leftStates.push_back(state);
660 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
661 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
662 bool buildMixedGreenPhase = false;
663 std::vector<bool> mixedGreen(pos, false);
664 const std::string oldState = state;
665 if (noMixed) {
666 state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
667 }
668 if (state != oldState) {
669 for (int i1 = 0; i1 < pos; ++i1) {
670 if (mixedGreen[i1]) {
671 // patch previous yellow and allred phase
672 int yellowIndex = (int)logic->getPhases().size() - 1;
673 if (allRedTime > 0) {
674 logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
675 }
676 if (brakingTime > 0) {
677 logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
678 }
679 }
680 }
681 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
682 }
683
684 // add step
685 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
686
687 // build left yellow
688 if (brakingTime > 0) {
689 SUMOTime maxCross = 0;
690 for (int i1 = 0; i1 < pos; ++i1) {
691 if (state[i1] != 'G' && state[i1] != 'g') {
692 continue;
693 }
694 state[i1] = 'y';
695 maxCross = MAX2(maxCross, crossingTime[i1]);
696 }
697 // add step
698 logic->addStep(brakingTime, state);
699 // add optional all-red state
700 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
701 }
702
703 if (buildMixedGreenPhase) {
704 // build mixed green
705 // @todo if there is no left green phase we might want to build two
706 // mixed-green phases but then we should consider avoid a common
707 // opposite phase for this direction
708
709 for (int i1 = 0; i1 < pos; ++i1) {
710 if (state[i1] == 'Y' || state[i1] == 'y') {
711 state[i1] = 'r';
712 continue;
713 }
714 if (mixedGreen[i1]) {
715 state[i1] = 'G';
716 }
717 }
718 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
719 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
720
721 // add step
722 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
723
724 // build mixed yellow
725 if (brakingTime > 0) {
726 SUMOTime maxCross = 0;
727 for (int i1 = 0; i1 < pos; ++i1) {
728 if (state[i1] != 'G' && state[i1] != 'g') {
729 continue;
730 }
731 state[i1] = 'y';
732 maxCross = MAX2(maxCross, crossingTime[i1]);
733 }
734 // add step
735 logic->addStep(brakingTime, state);
736 // add optional all-red state
737 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
738 }
739 }
740
741 } else if (isNEMA) {
742 std::string& s = straightStates.back();
743 std::string leftState = s;
744 for (int ii = 0; ii < pos; ++ii) {
745 if (s[ii] != 'r') {
746 NBEdge* fromEdge = fromEdges[ii];
747 NBEdge* toEdge = toEdges[ii];
748 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, toEdge);
749 if (hasTurnLane[ii] && (dir == LinkDirection::LEFT || dir == LinkDirection::TURN)) {
750 s[ii] = 'r';
751 leftState[ii] = 'G';
752 } else {
753 leftState[ii] = 'r';
754 }
755 }
756 }
757 leftStates.push_back(leftState);
758 }
759 // fix edges within joined traffic lights that did not get the green light yet
760 if (myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0) {
761 addGreenWithin(logic, fromEdges, toProc);
762 }
763 }
764 // fix pedestrian crossings that did not get the green light yet
765 if (crossings.size() > 0) {
766 addPedestrianScramble(logic, totalNumLinks, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
767 }
768 // add optional red phase if there were no foes
769 if (logic->getPhases().size() == 2 && brakingTime > 0
770 && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
771 const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
772 logic->addStep(redTime, std::string(totalNumLinks, 'r'));
773 }
774 // fix states to account for custom crossing link indices
775 if (crossings.size() > 0 && !onlyConts) {
777 }
778
780 // exiting the oneway section should always be possible
781 deactivateInsideEdges(logic, fromEdges);
782 }
783 if (isNEMA) {
784 NBTrafficLightLogic* nemaLogic = buildNemaPhases(fromEdges, chosenList, straightStates, leftStates);
785 if (nemaLogic == nullptr) {
786 WRITE_WARNINGF(TL("Generating NEMA phases is not support for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"), getID(), incoming.size());
789 } else {
790 delete logic;
791 logic = nemaLogic;
792 }
793 }
794
795 SUMOTime totalDuration = logic->getDuration();
796
797 if ((OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) && !isNEMA) {
798 const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
799 // adapt to cycle time by changing the duration of the green phases
800 SUMOTime minGreenDuration = SUMOTime_MAX;
801 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
802 const SUMOTime dur = logic->getPhases()[*it].duration;
803 minGreenDuration = MIN2(minGreenDuration, dur);
804 }
805 const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
806 const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
807 //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
808 if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
809 || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
810 || greenPhases.size() == 0) {
811 if (getID() != DummyID) {
812 WRITE_WARNINGF(TL("The traffic light '%' cannot be adapted to a cycle time of %."), getID(), time2string(cycleTime));
813 }
814 // @todo use a multiple of cycleTime ?
815 } else {
816 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
817 logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
818 }
819 if (greenPhases.size() > 0) {
820 logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
821 }
822 totalDuration = logic->getDuration();
823 }
824 }
825
827 // this computation only makes sense for single nodes
829 if (totalDuration > 0) {
830 if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA) {
831 WRITE_WARNINGF(TL("The traffic light '%' has a high cycle time of %."), getID(), time2string(totalDuration));
832 }
833 logic->closeBuilding();
834 return logic;
835 } else {
836 delete logic;
837 return nullptr;
838 }
839}
840
841
842bool
843NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
844 assert(to != 0);
845 for (auto c : crossings) {
846 const NBNode::Crossing& cross = *c;
847 // only check connections at this crossings node
848 if (to->getFromNode() == cross.node) {
849 for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
850 const NBEdge* edge = *it_e;
851 if (edge == from || edge == to) {
852 return true;
853 }
854 }
855 }
856 }
857 return false;
858}
859
860
861std::string
862NBOwnTLDef::addPedestrianPhases(NBTrafficLightLogic* logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur,
863 const SUMOTime earliestEnd, const SUMOTime latestEnd,
864 std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
865 // compute based on length of the crossing if not set by the user
866 const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
867 // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
868 const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
869 const std::string orig = state;
870 state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
871 if (orig == state) {
872 // add step
873 logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
874 } else {
875 const SUMOTime pedTime = greenTime - pedClearingTime;
876 if (pedTime >= minPedTime) {
877 // ensure clearing time for pedestrians
878 const int pedStates = (int)crossings.size();
879 logic->addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
880 state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
881 logic->addStep(pedClearingTime, state);
882 } else {
883 state = orig;
884 // not safe for pedestrians.
885 logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
886 }
887 }
888 return state;
889}
890
891
892std::string
893NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
894 std::string result = state;
895 const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
896 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
897 const int i1 = pos + ic;
898 const NBNode::Crossing& cross = *crossings[ic];
899 bool isForbidden = false;
900 for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
901 // only check connections at this crossings node
902 if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
903 for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
904 const NBEdge* edge = *it;
905 const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
906 if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
907 (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
908 isForbidden = true;
909 break;
910 }
911 }
912 }
913 }
914 if (!isForbidden) {
915 result[i1] = 'G';
916 } else {
917 result[i1] = 'r';
918 }
919 }
920
921 // correct behaviour for roads that are in conflict with a pedestrian crossing
922 for (int i1 = 0; i1 < pos; ++i1) {
923 if (result[i1] == 'G') {
924 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
925 const NBNode::Crossing& crossing = *crossings[ic];
926 if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
927 const int i2 = pos + ic;
928 if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
929 result[i1] = 'g';
930 break;
931 }
932 }
933 }
934 }
935 }
936 return result;
937}
938
939
940void
945
946
947void
949 // set the information about the link's positions within the tl into the
950 // edges the links are starting at, respectively
951 for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
952 const NBConnection& conn = *j;
953 NBEdge* edge = conn.getFrom();
954 edge->setControllingTLInformation(conn, getID());
955 }
956}
957
958
959void
960NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
961 const EdgeVector& /*outgoing*/) {}
962
963
964void
965NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
966 NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
967
968
969void
972 if (myControlledNodes.size() > 0) {
973 // setParticipantsInformation resets myAmInTLS so we need to make a copy
974 std::vector<bool> edgeInsideTLS;
975 for (const NBEdge* e : myIncomingEdges) {
976 edgeInsideTLS.push_back(e->isInsideTLS());
977 }
978 // we use a dummy node just to maintain const-correctness
979 myNeedsContRelation.clear();
980 for (NBNode* n : myControlledNodes) {
983 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
984 delete tllDummy;
985 myNeedsContRelation.insert(dummy.myNeedsContRelation.begin(), dummy.myNeedsContRelation.end());
986 n->removeTrafficLight(&dummy);
987 }
988 if (myControlledNodes.size() > 1) {
989 int i = 0;
990 for (NBEdge* e : myIncomingEdges) {
991 e->setInsideTLS(edgeInsideTLS[i]);
992 i++;
993 }
994 }
995#ifdef DEBUG_CONTRELATION
996 if (DEBUGCOND) {
997 std::cout << " contRelations at " << getID() << " prog=" << getProgramID() << ":\n";
998 for (const StreamPair& s : myNeedsContRelation) {
999 std::cout << " " << s.from1->getID() << "->" << s.to1->getID() << " foe " << s.from2->getID() << "->" << s.to2->getID() << "\n";
1000 }
1001 }
1002#endif
1003
1004 }
1006 }
1007}
1008
1009
1012 EdgeVector result = incoming;
1013 for (EdgeVector::iterator it = result.begin(); it != result.end();) {
1014 if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
1015 it = result.erase(it);
1016 } else {
1017 ++it;
1018 }
1019 }
1020 return result;
1021}
1022
1023
1024std::string
1025NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1026 const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1027 state = allowSingleEdge(state, fromEdges);
1028#ifdef DEBUG_PHASES
1029 if (DEBUGCOND) {
1030 std::cout << " state after allowSingle " << state << "\n";
1031 }
1032#endif
1033 if (myControlledNodes.size() > 1) {
1034 state = allowFollowers(state, fromEdges, toEdges);
1035#ifdef DEBUG_PHASES
1036 if (DEBUGCOND) {
1037 std::cout << " state after allowFollowers " << state << "\n";
1038 }
1039#endif
1040 state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
1041#ifdef DEBUG_PHASES
1042 if (DEBUGCOND) {
1043 std::cout << " state after allowPredecessors " << state << "\n";
1044 }
1045#endif
1046 }
1047 return state;
1048}
1049
1050
1051std::string
1052NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
1053 // if only one edge has green, ensure sure that all connections from that edge are green
1054 const int size = (int)fromEdges.size();
1055 NBEdge* greenEdge = nullptr;
1056 for (int i1 = 0; i1 < size; ++i1) {
1057 if (state[i1] == 'G') {
1058 if (greenEdge == nullptr) {
1059 greenEdge = fromEdges[i1];
1060 } else if (greenEdge != fromEdges[i1]) {
1061 return state;
1062 }
1063 }
1064 }
1065 if (greenEdge != nullptr) {
1066 for (int i1 = 0; i1 < size; ++i1) {
1067 if (fromEdges[i1] == greenEdge) {
1068 state[i1] = 'G';
1069 }
1070 }
1071 }
1072 return state;
1073}
1074
1075
1076std::string
1077NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1078 // check continuation within joined traffic lights
1079 bool check = true;
1080 while (check) {
1081 check = false;
1082 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1083 if (state[i1] == 'G') {
1084 continue;
1085 }
1086 if (forbidden(state, i1, fromEdges, toEdges, true)) {
1087 continue;
1088 }
1089 bool followsChosen = false;
1090 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1091 if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
1092 followsChosen = true;
1093 break;
1094 }
1095 }
1096 if (followsChosen) {
1097 state[i1] = 'G';
1098 check = true;
1099 }
1100 }
1101 }
1102 return state;
1103}
1104
1105
1106std::string
1107NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1108 const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1109 // also allow predecessors of chosen edges if the lanes match and there is no conflict
1110 // (must be done after the followers are done because followers are less specific)
1111 bool check = true;
1112 while (check) {
1113 check = false;
1114 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1115 if (state[i1] == 'G') {
1116 continue;
1117 }
1118 if (forbidden(state, i1, fromEdges, toEdges, false)) {
1119 continue;
1120 }
1121 bool preceedsChosen = false;
1122 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1123 if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
1124 && fromLanes[i2] == toLanes[i1]) {
1125 preceedsChosen = true;
1126 break;
1127 }
1128 }
1129 if (preceedsChosen) {
1130 state[i1] = 'G';
1131 check = true;
1132 }
1133 }
1134 }
1135 return state;
1136}
1137
1138
1139std::string
1140NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1141 const std::vector<bool>& isTurnaround,
1142 const std::vector<NBNode::Crossing*>& crossings) {
1143 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1144 if (state[i1] == 'G') {
1145 continue;
1146 }
1147 bool isForbidden = false;
1148 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1149 if (state[i2] == 'G' && !isTurnaround[i2] &&
1150 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1151 isForbidden = true;
1152 break;
1153 }
1154 }
1155 if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
1156 state[i1] = 'G';
1157 }
1158 }
1159 return state;
1160}
1161
1162
1163std::string
1164NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
1165 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1166 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
1167 if ((linkPerm & ~perm) == 0) {
1168 state[i1] = 'G';
1169 }
1170 }
1171 return state;
1172}
1173
1174
1175bool
1176NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges, bool allowCont) {
1177 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1178 if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
1179 if (!allowCont || (
1180 !needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
1181 !needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
1182 return true;
1183 }
1184 }
1185 }
1186 return false;
1187}
1188
1189
1190std::string
1191NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1192 const std::vector<bool>& isTurnaround,
1193 const std::vector<int>& fromLanes,
1194 const std::vector<int>& toLanes,
1195 const std::vector<bool>& hadGreenMajor,
1196 bool& haveForbiddenLeftMover,
1197 std::vector<bool>& rightTurnConflicts,
1198 std::vector<bool>& mergeConflicts) {
1199 const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
1200 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1201 if (state[i1] == 'G') {
1202 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1203 if ((state[i2] == 'G' || state[i2] == 'g')) {
1205 fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
1206 rightTurnConflicts[i1] = true;
1207 }
1208 if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
1209 state[i1] = 'g';
1210 if (myControlledNodes.size() == 1) {
1211 myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
1212 }
1213 if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
1214 haveForbiddenLeftMover = true;
1215 }
1216 } else if (fromEdges[i1] == fromEdges[i2]
1217 && fromLanes[i1] != fromLanes[i2]
1218 && toEdges[i1] == toEdges[i2]
1219 && toLanes[i1] == toLanes[i2]
1220 && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
1221 mergeConflicts[i1] = true;
1222 state[i1] = 'g';
1223 }
1224 }
1225 }
1226 }
1227 if (state[i1] == 'r') {
1228 if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
1229 fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
1230 state[i1] = 's';
1231 // do not allow right-on-red when in conflict with exclusive left-turn phase
1232 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1233 if (state[i2] == 'G' && !isTurnaround[i2] &&
1234 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1235 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1236 const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
1237 if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
1238 state[i1] = 'r';
1239 break;
1240 }
1241 }
1242 }
1243 if (state[i1] == 's') {
1244 // handle right-on-red conflicts
1245 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1246 if (state[i2] == 'G' && !isTurnaround[i2] &&
1247 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1248 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1249 myRightOnRedConflicts.insert(std::make_pair(i1, i2));
1250 }
1251 }
1252 }
1253 }
1254 }
1255 }
1256 return state;
1257}
1258
1259
1260std::string
1261NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
1262 const std::vector<int>& fromLanes,
1263 bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
1264 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1265 if ((state[i1] == 'G' || state[i1] == 'g')) {
1266 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1267 if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
1268 && state[i2] != 'G' && state[i2] != 'g') {
1269 state[i1] = state[i2];
1270 //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
1271 mixedGreen[i1] = true;
1272 if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
1273 buildMixedGreenPhase = true;
1274 }
1275 }
1276 }
1277 }
1278 }
1279 return state;
1280}
1281
1282
1283void
1285 std::vector<bool> foundGreen(fromEdges.size(), false);
1286 for (const auto& phase : logic->getPhases()) {
1287 const std::string state = phase.state;
1288 for (int j = 0; j < (int)fromEdges.size(); j++) {
1289 LinkState ls = (LinkState)state[j];
1291 foundGreen[j] = true;
1292 }
1293 }
1294 }
1295 for (int j = 0; j < (int)foundGreen.size(); j++) {
1296 if (!foundGreen[j]) {
1297 NBEdge* e = fromEdges[j];
1298 if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
1299 toProc.push_back(e);
1300 }
1301 }
1302 }
1303}
1304
1305
1306void
1307NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int totalNumLinks, SUMOTime /* greenTime */, SUMOTime brakingTime,
1308 const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1309 const int vehLinks = totalNumLinks - (int)crossings.size();
1310 std::vector<bool> foundGreen(crossings.size(), false);
1311 const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
1312 for (int i = 0; i < (int)phases.size(); i++) {
1313 const std::string state = phases[i].state;
1314 for (int j = 0; j < (int)crossings.size(); j++) {
1315 LinkState ls = (LinkState)state[vehLinks + j];
1317 foundGreen[j] = true;
1318 }
1319 }
1320 }
1321 for (int j = 0; j < (int)foundGreen.size(); j++) {
1322 if (!foundGreen[j]) {
1323 // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
1324 if (phases.size() > 0) {
1325 bool needYellowPhase = false;
1326 std::string state = phases.back().state;
1327 for (int i1 = 0; i1 < vehLinks; ++i1) {
1328 if (state[i1] == 'G' || state[i1] == 'g') {
1329 state[i1] = 'y';
1330 needYellowPhase = true;
1331 }
1332 }
1333 // add yellow step
1334 if (needYellowPhase && brakingTime > 0) {
1335 logic->addStep(brakingTime, state);
1336 }
1337 }
1338 const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
1339 const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
1340 addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION,
1341 UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(totalNumLinks, 'r'), crossings, fromEdges, toEdges);
1342 break;
1343 }
1344 }
1345}
1346
1347
1348void
1349NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
1350 if (allRedTime > 0) {
1351 // build all-red phase
1352 std::string allRedState = state;
1353 for (int i = 0; i < (int)state.size(); i++) {
1354 if (allRedState[i] == 'Y' || allRedState[i] == 'y') {
1355 allRedState[i] = 'r';
1356 }
1357 }
1358 logic->addStep(TIME2STEPS(ceil(STEPS2TIME(allRedTime))), allRedState);
1359 }
1360}
1361
1362
1363void
1365 int minCustomIndex = -1;
1366 int maxCustomIndex = -1;
1367 // collect crossings
1368 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1369 const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1370 for (auto crossing : c) {
1371 minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
1372 minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
1373 maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
1374 maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
1375 }
1376 }
1377 // custom crossing linkIndex could lead to longer states. ensure that every index has a state
1378 if (maxCustomIndex >= logic->getNumLinks()) {
1379 logic->setStateLength(maxCustomIndex + 1);
1380 }
1381 // XXX shorter state vectors are possible as well
1382 // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
1383 // XXX initialize the backward index to the same state as the forward index
1384}
1385
1386void
1388 // assume that yellow states last at most one phase
1389 const int n = logic->getNumLinks();
1390 const int p = (int)logic->getPhases().size();
1391 for (int i1 = 0; i1 < n; ++i1) {
1392 LinkState prev = (LinkState)logic->getPhases().back().state[i1];
1393 for (int i2 = 0; i2 < p; ++i2) {
1394 LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
1395 LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
1396 if (cur == LINKSTATE_TL_YELLOW_MINOR
1398 && next == LINKSTATE_TL_GREEN_MAJOR) {
1399 logic->setPhaseState(i2, i1, prev);
1400 }
1401 prev = cur;
1402 }
1403 }
1404}
1405
1406
1407void
1409 const int n = logic->getNumLinks();
1410 std::vector<bool> alwaysGreen(n, true);
1411 for (int i1 = 0; i1 < n; ++i1) {
1412 for (const auto& phase : logic->getPhases()) {
1413 if (phase.state[i1] != 'G') {
1414 alwaysGreen[i1] = false;
1415 break;
1416 }
1417 }
1418 }
1419 const int p = (int)logic->getPhases().size();
1420 for (int i1 = 0; i1 < n; ++i1) {
1421 if (alwaysGreen[i1]) {
1422 for (int i2 = 0; i2 < p; ++i2) {
1424 }
1425 }
1426 }
1427}
1428
1429
1430void
1432 const int n = logic->getNumLinks();
1433 const int p = (int)logic->getPhases().size();
1434 for (int i1 = 0; i1 < n; ++i1) {
1435 if (fromEdges[i1]->isInsideTLS()) {
1436 for (int i2 = 0; i2 < p; ++i2) {
1438 }
1439 }
1440 }
1441}
1442
1443
1445NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
1446 const int n = (int)state.size();
1447 double maxTime = 0;
1448 for (int i1 = 0; i1 < n; ++i1) {
1449 if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
1450 for (int i2 = 0; i2 < n; ++i2) {
1451 if (fromEdges[i2]->isInsideTLS()) {
1452 double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1453 double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1454 maxTime = MAX2(maxTime, time);
1455 }
1456 }
1457 }
1458 }
1459 // give some slack
1460 return TIME2STEPS(floor(maxTime * 1.2 + 5));
1461}
1462
1463
1464int
1468 if (logic != nullptr) {
1469 return logic->getNumLinks() - 1;
1470 } else {
1471 return -1;
1472 }
1473}
1474
1475
1476bool
1478 if (getID() == DummyID) {
1479 // avoid infinite recursion
1480 return true;
1481 }
1482 assert(myControlledNodes.size() >= 2);
1485 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1486 int greenPhases = 0;
1487 for (const auto& phase : tllDummy->getPhases()) {
1488 if (phase.state.find_first_of("gG") != std::string::npos) {
1489 greenPhases++;
1490 }
1491 }
1492 delete tllDummy;
1493 for (const auto& controlledNode : myControlledNodes) {
1494 controlledNode->removeTrafficLight(&dummy);
1495 }
1496 return greenPhases <= 2;
1497}
1498
1499
1502 const EdgeVector& fromEdges,
1503 const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
1504 const std::vector<std::string>& straightStates,
1505 const std::vector<std::string>& leftStates) {
1506 if (chosenList.size() != 2) {
1507 return nullptr;
1508 }
1509 const SUMOTime dur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
1510 const SUMOTime vehExt = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.vehExt"));
1511 const SUMOTime yellow = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.yellow"));
1512 const SUMOTime red = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.red"));
1513 const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
1514 const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
1515 const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
1516 const SUMOTime latestEnd = UNSPECIFIED_DURATION;
1517
1518 const int totalNumLinks = (int)straightStates[0].size();
1519 NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
1520 std::vector<int> ring1({1, 2, 3, 4});
1521 std::vector<int> ring2({5, 6, 7, 8});
1522 std::vector<int> barrier1({4, 8});
1523 std::vector<int> barrier2({2, 6});
1524 int phaseNameLeft = 1;
1525 for (int i = 0; i < (int)chosenList.size(); i++) {
1526 NBEdge* e1 = chosenList[i].first;
1527 assert(e1 != nullptr);
1528 NBEdge* e2 = chosenList[i].second;
1529 if (i < (int)leftStates.size()) {
1530 std::string left1 = filterState(leftStates[i], fromEdges, e1);
1531 if (left1 != "") {
1532 logic->addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft));
1533 }
1534 }
1535 if (e2 != nullptr) {
1536 std::string straight2 = filterState(straightStates[i], fromEdges, e2);
1537 logic->addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 1));
1538 if (i < (int)leftStates.size()) {
1539 std::string left2 = filterState(leftStates[i], fromEdges, e2);
1540 if (left2 != "") {
1541 logic->addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 4));
1542 }
1543 }
1544
1545 }
1546 std::string straight1 = filterState(straightStates[i], fromEdges, e1);
1547 if (straight1 == "") {
1548 delete logic;
1549 return nullptr;
1550 }
1551 logic->addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 5));
1552 phaseNameLeft += 2;
1553 }
1554 std::map<int, int> names; // nema phase name -> sumo phase index
1555 for (int i = 0; i < (int)logic->getPhases().size(); i++) {
1556 names[StringUtils::toInt(logic->getPhases()[i].name)] = i;
1557 }
1558
1559 filterMissingNames(ring1, names, false);
1560 filterMissingNames(ring2, names, false);
1561 filterMissingNames(barrier1, names, true);
1562 filterMissingNames(barrier2, names, true);
1563 if (ring1[2] == 0 && ring1[3] == 0) {
1564 ring1[3] = 8;
1565 }
1566 fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
1567 fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
1568
1569 logic->setParameter("ring1", joinToString(ring1, ","));
1570 logic->setParameter("ring2", joinToString(ring2, ","));
1571 logic->setParameter("barrierPhases", joinToString(barrier1, ","));
1572 logic->setParameter("barrier2Phases", joinToString(barrier2, ","));
1573 return logic;
1574}
1575
1576
1577std::string
1578NBOwnTLDef::filterState(std::string state, const EdgeVector& fromEdges, const NBEdge* e) {
1579 bool haveGreen = false;
1580 for (int j = 0; j < (int)state.size(); j++) {
1581 if (fromEdges[j] != e) {
1582 state[j] = 'r';
1583 } else if (state[j] != 'r') {
1584 haveGreen = true;
1585 }
1586 }
1587 if (haveGreen) {
1588 return state;
1589 } else {
1590 return "";
1591 }
1592}
1593
1594void
1595NBOwnTLDef::filterMissingNames(std::vector<int>& vec, const std::map<int, int>& names, bool isBarrier) {
1596 for (int i = 0; i < (int)vec.size(); i++) {
1597 if (names.count(vec[i]) == 0) {
1598 if (isBarrier) {
1599 if (names.count(vec[i] - 1) > 0) {
1600 vec[i] = vec[i] - 1;
1601 } else {
1602 vec[i] = 8;
1603 }
1604 } else {
1605 vec[i] = 0;
1606 }
1607 }
1608 }
1609}
1610
1611void
1612NBOwnTLDef::fixDurationSum(NBTrafficLightLogic* logic, const std::map<int, int>& names, int ring1a, int ring1b, int ring2a, int ring2b) {
1613 std::set<int> ring1existing;
1614 std::set<int> ring2existing;
1615 if (names.count(ring1a) != 0) {
1616 ring1existing.insert(ring1a);
1617 }
1618 if (names.count(ring1b) != 0) {
1619 ring1existing.insert(ring1b);
1620 }
1621 if (names.count(ring2a) != 0) {
1622 ring2existing.insert(ring2a);
1623 }
1624 if (names.count(ring2b) != 0) {
1625 ring2existing.insert(ring2b);
1626 }
1627 if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
1628 ring1existing.size() != ring2existing.size()) {
1629 int pI; // sumo phase index
1630 if (ring1existing.size() < ring2existing.size()) {
1631 pI = names.find(*ring1existing.begin())->second;
1632 } else {
1633 pI = names.find(*ring2existing.begin())->second;
1634 }
1635 const auto& p = logic->getPhases()[pI];
1636 SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
1637 logic->setPhaseMaxDuration(pI, newMaxDur);
1638 }
1639}
1640
1641/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
@ DEFAULT
default cursor
#define DEBUGCOND(PEDID)
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:271
#define TL(string)
Definition MsgHandler.h:287
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition NBCont.h:42
#define MIN_GREEN_TIME
#define HEIGH_WEIGHT
#define DEBUGEDGE(edge)
#define LOW_WEIGHT
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TIME2STEPS(x)
Definition SUMOTime.h:57
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightLayout
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_YELLOW_MINOR
The link has yellow light, has to brake anyway.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
@ LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
NBEdge * getFrom() const
returns the from-edge (start of the connection)
The representation of a single edge during network building.
Definition NBEdge.h:92
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition NBEdge.cpp:4232
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition NBEdge.h:1027
NBNode * getToNode() const
Returns the destination node of the edge.
Definition NBEdge.h:536
const std::string & getID() const
Definition NBEdge.h:1515
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition NBEdge.cpp:3578
int getNumLanes() const
Returns the number of lanes.
Definition NBEdge.h:510
std::vector< Connection > getConnectionsFromLane(int lane, const NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
Definition NBEdge.cpp:1221
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition NBEdge.cpp:2051
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition NBEdge.h:529
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition NBEdge.cpp:3861
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition NBHelpers.cpp:45
A definition of a pedestrian crossing.
Definition NBNode.h:135
const NBNode * node
The parent node of this crossing.
Definition NBNode.h:140
EdgeVector edges
The edges being crossed.
Definition NBNode.h:142
Represents a single node (junction) during network building.
Definition NBNode.h:66
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
Definition NBNode.cpp:2315
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition NBNode.cpp:2000
bool mustBrakeForCrossing(const NBEdge *const from, const NBEdge *const to, const Crossing &crossing) const
Returns the information whether the described flow must brake for the given crossing.
Definition NBNode.cpp:1981
Sorts edges by their priority within the node they end at.
Definition NBOwnTLDef.h:313
A traffic light logics which must be computed (only nodes/edges are given)
Definition NBOwnTLDef.h:44
void fixSuperfluousYellow(NBTrafficLightLogic *logic) const
avoid yellow signal between successive green (major) phases
std::string correctConflicting(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< int > &fromLanes, const std::vector< int > &toLanes, const std::vector< bool > &hadGreenMajor, bool &haveForbiddenLeftMover, std::vector< bool > &rightTurnConflicts, std::vector< bool > &mergeConflicts)
change 'G' to 'g' for conflicting connections
void checkCustomCrossingIndices(NBTrafficLightLogic *logic) const
fix states in regard to custom crossing indices
static std::string patchStateForCrossings(const std::string &state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
compute phase state in regard to pedestrian crossings
std::string allowByVClass(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, SVCPermissions perm)
int getMaxIndex()
Returns the maximum index controlled by this traffic light.
bool myHaveSinglePhase
Whether left-mover should not have an additional phase.
Definition NBOwnTLDef.h:330
bool corridorLike() const
test whether a joined tls with layout 'opposites' would be built without dedicated left-turn phase
SUMOTime computeEscapeTime(const std::string &state, const EdgeVector &fromEdges, const EdgeVector &toEdges) const
compute time to clear all vehicles from within an alternateOneWay layout
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces a removed edge/lane.
std::pair< NBEdge *, NBEdge * > getBestPair(EdgeVector &incoming)
Returns the combination of two edges from the given which has most unblocked streams.
~NBOwnTLDef()
Destructor.
void collectLinks()
Collects the links participating in this traffic light.
void deactivateAlwaysGreen(NBTrafficLightLogic *logic) const
switch of signal for links that are always green
static void addGreenWithin(NBTrafficLightLogic *logic, const EdgeVector &fromEdges, EdgeVector &toProc)
ensure inner edges all get the green light eventually
NBTrafficLightLogic * computeLogicAndConts(int brakingTimeSeconds, bool onlyConts=false)
helper function for myCompute
static bool hasCrossing(const NBEdge *from, const NBEdge *to, const std::vector< NBNode::Crossing * > &crossings)
compute whether the given connection is crossed by pedestrians
std::string allowPredecessors(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
void deactivateInsideEdges(NBTrafficLightLogic *logic, const EdgeVector &fromEdges) const
switch of signal for links that are inside a joined tls
double computeUnblockedWeightedStreamNumber(const NBEdge *const e1, const NBEdge *const e2)
Returns how many streams outgoing from the edges can pass the junction without being blocked.
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurrences of the removed edge in incoming/outgoing edges of all definitions.
int getToPrio(const NBEdge *const e)
Returns this edge's priority at the node it ends at.
NBTrafficLightLogic * buildNemaPhases(const EdgeVector &fromEdges, const std::vector< std::pair< NBEdge *, NBEdge * > > &chosenList, const std::vector< std::string > &straightStates, const std::vector< std::string > &leftStates)
std::string allowCompatible(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
allow connections that are compatible with the chosen edges
std::string correctMixed(std::string state, const EdgeVector &fromEdges, const std::vector< int > &fromLanes, bool &buildMixedGreenPhase, std::vector< bool > &mixedGreen)
prevent green and red from the same lane
void fixDurationSum(NBTrafficLightLogic *logic, const std::map< int, int > &names, int ring1a, int ring1b, int ring2a, int ring2b)
ensure that phase max durations before each barrier have the same sum in both rings
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
std::string filterState(std::string state, const EdgeVector &fromEdges, const NBEdge *e)
mask out all greens that do not originate at the given edge
std::string allowFollowers(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
void buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic *logic, const std::string &state)
double getDirectionalWeight(LinkDirection dir)
Returns the weight of a stream given its direction.
std::string allowSingleEdge(std::string state, const EdgeVector &fromEdges)
bool hasStraightConnection(const NBEdge *fromEdge)
check whether there is a straight connection from this edge
std::pair< NBEdge *, NBEdge * > getBestCombination(const EdgeVector &edges)
Returns the combination of two edges from the given which has most unblocked streams.
void initNeedsContRelation() const
static void addPedestrianScramble(NBTrafficLightLogic *logic, int totalNumLinks, SUMOTime greenTime, SUMOTime yellowTime, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add an additional pedestrian phase if there are crossings that did not get green yet
NBOwnTLDef(const std::string &id, const std::vector< NBNode * > &junctions, SUMOTime offset, TrafficLightType type)
Constructor.
static EdgeVector getConnectedOuterEdges(const EdgeVector &incoming)
get edges that have connections
void filterMissingNames(std::vector< int > &vec, const std::map< int, int > &names, bool isBarrier)
keep only valid NEMA phase names (for params)
TrafficLightLayout myLayout
the layout for generated signal plans
Definition NBOwnTLDef.h:333
bool forbidden(const std::string &state, int index, const EdgeVector &fromEdges, const EdgeVector &toEdges, bool allowCont)
whether the given index is forbidden by a green link in the current state
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur, const SUMOTime earliestEnd, const SUMOTime latestEnd, std::string state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add 1 or 2 phases depending on the presence of pedestrian crossings
std::string allowUnrelated(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< NBNode::Crossing * > &crossings)
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
static const double MIN_SPEED_CROSSING_TIME
minimum speed for computing time to cross intersection
Definition NBOwnTLDef.h:146
The base class for traffic light logic definitions.
const std::string & getProgramID() const
Returns the ProgramID.
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
bool needsCont(const NBEdge *fromE, const NBEdge *toE, const NBEdge *otherFromE, const NBEdge *otherToE) const
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
EdgeVector myIncomingEdges
The list of incoming edges.
NBTrafficLightLogic * compute(const OptionsCont &oc)
Computes the traffic light logic.
RightOnRedConflicts myRightOnRedConflicts
TrafficLightType myType
The algorithm type for the traffic light.
EdgeVector myEdgesWithin
The list of edges within the area controlled by the tls.
static const std::string DummyID
id for temporary definitions
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority, bool sameNodeOnly=false) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
NBConnectionVector myControlledLinks
The list of controlled links.
virtual void setType(TrafficLightType type)
set the algorithm type (static etc..)
virtual void setParticipantsInformation()
Builds the list of participating nodes/edges/links.
void collectAllLinks(NBConnectionVector &into)
helper method for use in NBOwnTLDef and NBLoadedSUMOTLDef
SUMOTime myOffset
The offset in the program.
static const SUMOTime UNSPECIFIED_DURATION
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
A SUMO-compliant built logic for a traffic light.
SUMOTime getDuration() const
Returns the duration of the complete cycle.
void closeBuilding(bool checkVarDurations=true)
closes the building process
void setPhaseDuration(int phaseIndex, SUMOTime duration)
Modifies the duration for an existing phase (used by netedit)
void setPhaseState(int phaseIndex, int tlIndex, LinkState linkState)
Modifies the state for an existing phase (used by netedit)
void setPhaseMaxDuration(int phaseIndex, SUMOTime duration)
Modifies the max duration for an existing phase (used by netedit)
int getNumLinks()
Returns the number of participating links.
void setType(TrafficLightType type)
set the algorithm type (static etc..)
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
void addStep(const SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", const int index=-1)
Adds a phase to the logic (static)
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
static StringBijection< TrafficLightLayout > TrafficLightLayouts
traffic light layouts
T get(const std::string &str) const
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
A structure which describes a connection between edges or lanes.
Definition NBEdge.h:201
data structure for caching needsCont information