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