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