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 if (OptionsCont::getOptions().getBool("tls.ignore-internal-junction-jam")) {
428 // otherwise, we can get a mutual conflict for minor green
429 // streams which would create deadlock
430 groupOther = true;
431 }
432 }
433 // group all edges with the same permissions into a single phase (later)
434 if (groupTram || groupOther) {
435 for (auto it = toProc.begin(); it != toProc.end();) {
436 if ((*it)->getPermissions() == perms) {
437 it = toProc.erase(it);
438 } else {
439 it++;
440 }
441 }
442 }
443 }
444 int pos = 0;
445 std::string state(totalNumLinks, 'r');
446#ifdef DEBUG_PHASES
447 if (DEBUGCOND) {
448 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";
449 }
450#endif
451 chosenList.push_back(chosen);
452 chosenSet.insert(chosen.first);
453 if (chosen.second != nullptr) {
454 chosenSet.insert(chosen.second);
455 }
456 // find parallel bike edge for the chosen (passenger) edges
457 for (const NBEdge* e : chosenSet) {
458 if ((e->getPermissions() & SVC_PASSENGER) != 0) {
459 std::vector<NBEdge*> parallelBikeEdges;
460 for (NBEdge* cand : toProc) {
461 if ((cand->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE) {
462 double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
463 if (angle < 30) {
464 // roughly parallel
465 parallelBikeEdges.push_back(cand);
466 }
467 }
468 }
469 for (NBEdge* be : parallelBikeEdges) {
470#ifdef DEBUG_PHASES
471 if (DEBUGCOND) {
472 std::cout << " chosen=" << e->getID() << " be=" << be->getID() << "\n";
473 }
474#endif
475 chosenSet.insert(be);
476 toProc.erase(std::find(toProc.begin(), toProc.end(), be));
477 }
478 }
479 }
480 // plain straight movers
481 double maxSpeed = 0;
482 bool haveGreen = false;
483 for (const NBEdge* const fromEdge : incoming) {
484 const bool inChosen = chosenSet.count(fromEdge) != 0;
485 const int numLanes = fromEdge->getNumLanes();
486 for (int i2 = 0; i2 < numLanes; i2++) {
487 for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
488 if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
489 continue;
490 }
491 if (inChosen) {
492 state[pos] = 'G';
493 haveGreen = true;
494 maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
495 } else {
496 state[pos] = 'r';
497 }
498 ++pos;
499 }
500 }
501 }
502 if (!haveGreen) {
503 continue;
504 }
505
506#ifdef DEBUG_PHASES
507 if (DEBUGCOND) {
508 std::cout << " state after plain straight movers " << state << "\n";
509 }
510#endif
511 if (!isNEMA) {
512 // correct behaviour for those that are not in chosen, but may drive, though
513 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
514#ifdef DEBUG_PHASES
515 if (DEBUGCOND) {
516 std::cout << " state after allowing compatible " << state << "\n";
517 }
518#endif
519 if (groupTram) {
520 state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
521 } else if (groupOther) {
522 state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
523 }
524#ifdef DEBUG_PHASES
525 if (DEBUGCOND) {
526 std::cout << " state after grouping by vClass " << state << " (groupTram=" << groupTram << " groupOther=" << groupOther << ")\n";
527 }
528#endif
529 if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
530 state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
531 }
532#ifdef DEBUG_PHASES
533 if (DEBUGCOND) {
534 std::cout << " state after finding allowUnrelated " << state << "\n";
535 }
536#endif
537 }
538 // correct behaviour for those that have to wait (mainly left-mover)
539 bool haveForbiddenLeftMover = false;
540 std::vector<bool> rightTurnConflicts(pos, false);
541 std::vector<bool> mergeConflicts(pos, false);
542 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
543 for (int i1 = 0; i1 < pos; ++i1) {
544 if (state[i1] == 'G') {
545 hadGreenMajor[i1] = true;
546 }
547 }
548#ifdef DEBUG_PHASES
549 if (DEBUGCOND) {
550 std::cout << " state after correcting left movers=" << state << "\n";
551 }
552#endif
553
554 std::vector<bool> leftGreen(pos, false);
555 // check whether at least one left-turn lane exist
556 bool foundLeftTurnLane = false;
557 for (int i1 = 0; i1 < pos; ++i1) {
558 if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
559 foundLeftTurnLane = true;
560 }
561 }
562 const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
563 && groupOpposites && !groupTram && !groupOther);
564
565 // find indices for exclusive left green phase and apply option minor-left.max-speed
566 for (int i1 = 0; i1 < pos; ++i1) {
567 if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
568 // only activate turn-around together with a real left-turn
569 && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
570 leftGreen[i1] = true;
571 if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
572 if (buildLeftGreenPhase) {
573 state[i1] = 'r';
574 //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
575 } else if (!isTurnaround[i1]) {
576 WRITE_WARNINGF(TL("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
577 fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
578 }
579 }
580 }
581 }
582
583#ifdef DEBUG_PHASES
584 if (DEBUGCOND) {
585 std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
586 << " \nrtC=" << toString(rightTurnConflicts)
587 << " \nmC=" << toString(mergeConflicts)
588 << " \nhTL=" << toString(hasTurnLane)
589 << " \nlGr=" << toString(leftGreen)
590 << "\n";
591 }
592#endif
593 straightStates.push_back(state);
594
595 const std::string vehicleState = state; // backup state before pedestrian modifications
596 greenPhases.push_back((int)logic->getPhases().size());
597
598 // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
599 const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
600 SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
601 if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
602 // shorter minDuration for tram phase (only if the phase is
603 // exclusively for tram)
604 bool tramExclusive = true;
605 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
606 if (state[i1] == 'G') {
607 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
608 if (linkPerm != SVC_TRAM) {
609 tramExclusive = false;
610 break;
611 }
612 }
613 }
614 if (tramExclusive) {
615 // one tram per actuated phase
616 minDur = TIME2STEPS(1);
617 }
618 }
619
620 state = addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
621 // pedestrians have 'r' from here on
622 for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
623 state[i1] = 'r';
624 }
625 if (brakingTime > 0) {
626 SUMOTime maxCross = 0;
627 // build yellow (straight)
628 for (int i1 = 0; i1 < pos; ++i1) {
629 if (state[i1] != 'G' && state[i1] != 'g') {
630 continue;
631 }
632 if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
633 && buildLeftGreenPhase
634 && !rightTurnConflicts[i1]
635 && !mergeConflicts[i1]
636 && leftGreen[i1]) {
637 continue;
638 }
639 state[i1] = 'y';
640 maxCross = MAX2(maxCross, crossingTime[i1]);
641 }
642 // add step
643 logic->addStep(brakingTime, state);
644 // add optional all-red state
645 if (!buildLeftGreenPhase) {
647 allRedTime = computeEscapeTime(state, fromEdges, toEdges);
648 }
649 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
650 }
651 }
652
653
654 if (buildLeftGreenPhase) {
655 // build left green
656 for (int i1 = 0; i1 < pos; ++i1) {
657 if (state[i1] == 'Y' || state[i1] == 'y') {
658 state[i1] = 'r';
659 continue;
660 }
661 if (leftGreen[i1]) {
662 state[i1] = 'G';
663 }
664 }
665 leftStates.push_back(state);
666 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
667 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
668 bool buildMixedGreenPhase = false;
669 std::vector<bool> mixedGreen(pos, false);
670 const std::string oldState = state;
671 if (noMixed) {
672 state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
673 }
674 if (state != oldState) {
675 for (int i1 = 0; i1 < pos; ++i1) {
676 if (mixedGreen[i1]) {
677 // patch previous yellow and allred phase
678 int yellowIndex = (int)logic->getPhases().size() - 1;
679 if (allRedTime > 0) {
680 logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
681 }
682 if (brakingTime > 0) {
683 logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
684 }
685 }
686 }
687 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
688 }
689
690 // add step
691 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
692
693 // build left yellow
694 if (brakingTime > 0) {
695 SUMOTime maxCross = 0;
696 for (int i1 = 0; i1 < pos; ++i1) {
697 if (state[i1] != 'G' && state[i1] != 'g') {
698 continue;
699 }
700 state[i1] = 'y';
701 maxCross = MAX2(maxCross, crossingTime[i1]);
702 }
703 // add step
704 logic->addStep(brakingTime, state);
705 // add optional all-red state
706 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
707 }
708
709 if (buildMixedGreenPhase) {
710 // build mixed green
711 // @todo if there is no left green phase we might want to build two
712 // mixed-green phases but then we should consider avoid a common
713 // opposite phase for this direction
714
715 for (int i1 = 0; i1 < pos; ++i1) {
716 if (state[i1] == 'Y' || state[i1] == 'y') {
717 state[i1] = 'r';
718 continue;
719 }
720 if (mixedGreen[i1]) {
721 state[i1] = 'G';
722 }
723 }
724 state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
725 state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
726
727 // add step
728 logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
729
730 // build mixed yellow
731 if (brakingTime > 0) {
732 SUMOTime maxCross = 0;
733 for (int i1 = 0; i1 < pos; ++i1) {
734 if (state[i1] != 'G' && state[i1] != 'g') {
735 continue;
736 }
737 state[i1] = 'y';
738 maxCross = MAX2(maxCross, crossingTime[i1]);
739 }
740 // add step
741 logic->addStep(brakingTime, state);
742 // add optional all-red state
743 buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
744 }
745 }
746
747 } else if (isNEMA) {
748 std::string& s = straightStates.back();
749 std::string leftState = s;
750 for (int ii = 0; ii < pos; ++ii) {
751 if (s[ii] != 'r') {
752 NBEdge* fromEdge = fromEdges[ii];
753 NBEdge* toEdge = toEdges[ii];
754 LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, toEdge);
755 if (hasTurnLane[ii] && (dir == LinkDirection::LEFT || dir == LinkDirection::TURN)) {
756 s[ii] = 'r';
757 leftState[ii] = 'G';
758 } else {
759 leftState[ii] = 'r';
760 }
761 }
762 }
763 leftStates.push_back(leftState);
764 }
765 // fix edges within joined traffic lights that did not get the green light yet
766 if (myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0) {
767 addGreenWithin(logic, fromEdges, toProc);
768 }
769 }
770 // fix pedestrian crossings that did not get the green light yet
771 if (crossings.size() > 0) {
772 addPedestrianScramble(logic, totalNumLinks, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
773 }
774 // add optional red phase if there were no foes
775 if (logic->getPhases().size() == 2 && brakingTime > 0
776 && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
777 const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
778 logic->addStep(redTime, std::string(totalNumLinks, 'r'));
779 }
780 // fix states to account for custom crossing link indices
781 if (crossings.size() > 0 && !onlyConts) {
783 }
784
786 // exiting the oneway section should always be possible
787 deactivateInsideEdges(logic, fromEdges);
788 }
789 if (isNEMA) {
790 NBTrafficLightLogic* nemaLogic = buildNemaPhases(fromEdges, toEdges, crossings, chosenList, straightStates, leftStates);
791 if (nemaLogic == nullptr) {
792 WRITE_WARNINGF(TL("Generating NEMA phases is not support for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"), getID(), incoming.size());
795 } else {
796 delete logic;
797 logic = nemaLogic;
798 }
799 }
800
801 SUMOTime totalDuration = logic->getDuration();
802
803 if ((OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) && !isNEMA) {
804 const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
805 // adapt to cycle time by changing the duration of the green phases
806 SUMOTime minGreenDuration = SUMOTime_MAX;
807 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
808 const SUMOTime dur = logic->getPhases()[*it].duration;
809 minGreenDuration = MIN2(minGreenDuration, dur);
810 }
811 const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
812 const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
813 //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
814 if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
815 || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
816 || greenPhases.size() == 0) {
817 if (getID() != DummyID) {
818 WRITE_WARNINGF(TL("The traffic light '%' cannot be adapted to a cycle time of %."), getID(), time2string(cycleTime));
819 }
820 // @todo use a multiple of cycleTime ?
821 } else {
822 for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
823 logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
824 }
825 if (greenPhases.size() > 0) {
826 logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
827 }
828 totalDuration = logic->getDuration();
829 }
830 }
831
832 // check for coherent signal sequence and remove yellow if preceded and followed by green
833 const std::vector<NBTrafficLightLogic::PhaseDefinition>& allPhases = logic->getPhases();
834 const int phaseCount = (int)allPhases.size();
835 const int stateSize = (int)logic->getNumLinks();
836 for (int i = 0; i < phaseCount; ++i) {
837 std::string currState = allPhases[i].state;
838 const int prevIndex = (i == 0) ? phaseCount - 1 : i - 1;
839 const std::string prevState = allPhases[prevIndex].state;
840 const std::string nextState = allPhases[(i + 1) % phaseCount].state;
841 bool updatedState = false;
842 for (int i1 = 0; i1 < stateSize; ++i1) {
843 if (currState[i1] == 'y' && (nextState[i1] == 'g' || nextState[i1] == 'G') && (prevState[i1] == 'g' || prevState[i1] == 'G')) {
844 LinkState ls = (nextState[i1] == prevState[i1]) ? (LinkState)prevState[i1] : (LinkState)'g';
845 logic->setPhaseState(i, i1, ls);
846 updatedState = true;
847 }
848 }
849 UNUSED_PARAMETER(updatedState); // disable warning
850#ifdef DEBUG_PHASES
851 if (DEBUGCOND) {
852 if (updatedState) {
853 std::cout << getID() << " state of phase index " << i << " was patched due to yellow in between green\n";
854 }
855
856 }
857#endif
858 }
859
860
862 // this computation only makes sense for single nodes
864 if (totalDuration > 0) {
865 if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA) {
866 WRITE_WARNINGF(TL("The traffic light '%' has a high cycle time of %."), getID(), time2string(totalDuration));
867 }
868 logic->closeBuilding();
869 return logic;
870 } else {
871 delete logic;
872 return nullptr;
873 }
874}
875
876
877bool
878NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
879 assert(to != 0);
880 for (auto c : crossings) {
881 const NBNode::Crossing& cross = *c;
882 // only check connections at this crossings node
883 if (to->getFromNode() == cross.node) {
884 for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
885 const NBEdge* edge = *it_e;
886 if (edge == from || edge == to) {
887 return true;
888 }
889 }
890 }
891 }
892 return false;
893}
894
895
896std::string
897NBOwnTLDef::addPedestrianPhases(NBTrafficLightLogic* logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur,
898 const SUMOTime earliestEnd, const SUMOTime latestEnd,
899 std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
900 // compute based on length of the crossing if not set by the user
901 const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
902 // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
903 const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
904 const std::string orig = state;
905 state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
906 if (orig == state) {
907 // add step
908 logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
909 } else {
910 const SUMOTime pedTime = greenTime - pedClearingTime;
911 if (pedTime >= minPedTime) {
912 // ensure clearing time for pedestrians
913 const int pedStates = (int)crossings.size();
914 const bool isSimpleActuatedCrossing = logic->getType() == TrafficLightType::ACTUATED
915 && minDur == UNSPECIFIED_DURATION && logic->getPhases().size() == 2;
916 if (isSimpleActuatedCrossing) {
917 // permit green phase to extend when there are no pedestrians
918 logic->setPhaseNext(0, {0, 1});
919 }
920 logic->addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
921#ifdef DEBUG_PHASES
922 if (DEBUGCOND2(logic)) {
923 std::cout << " intermidate state for addPedestrianPhases " << state << "\n";
924 }
925#endif
926 state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
927 logic->addStep(pedClearingTime, state);
928 } else {
929 state = orig;
930 // not safe for pedestrians.
931 logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
932 }
933 }
934#ifdef DEBUG_PHASES
935 if (DEBUGCOND2(logic)) {
936 std::cout << " state after addPedestrianPhases " << state << "\n";
937 }
938#endif
939 return state;
940}
941
942
943std::string
944NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
945 std::string result = state;
946 const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
947 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
948 const int i1 = pos + ic;
949 const NBNode::Crossing& cross = *crossings[ic];
950 bool isForbidden = false;
951 for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
952 // only check connections at this crossings node
953 if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
954 for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
955 const NBEdge* edge = *it;
956 const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
957 if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
958 (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
959 isForbidden = true;
960 break;
961 }
962 }
963 }
964 }
965 if (!isForbidden) {
966 result[i1] = 'G';
967 } else {
968 result[i1] = 'r';
969 }
970 }
971
972 // correct behaviour for roads that are in conflict with a pedestrian crossing
973 for (int i1 = 0; i1 < pos; ++i1) {
974 if (result[i1] == 'G') {
975 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
976 const NBNode::Crossing& crossing = *crossings[ic];
977 if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
978 const int i2 = pos + ic;
979 if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
980 result[i1] = 'g';
981 break;
982 }
983 }
984 }
985 }
986 }
987 return result;
988}
989
990
991std::string
993 const std::vector<NBNode::Crossing*>& crossings,
994 const EdgeVector& fromEdges,
995 const EdgeVector& toEdges,
996 const NBEdge* greenEdge, NBEdge* otherChosen) {
997 std::string result = state;
998 const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
999 const EdgeVector& all = greenEdge->getToNode()->getEdges();
1000 EdgeVector::const_iterator start = std::find(all.begin(), all.end(), greenEdge);
1001
1002 // permit crossings over edges between the current green edge and it's straight continuation
1003 const NBEdge* endEdge = nullptr;
1004 for (int i = 0; i < (int)state.size(); i++) {
1005 if (state[i] == 'G' && fromEdges[i] == greenEdge
1006 && greenEdge->getToNode()->getDirection(greenEdge, toEdges[i]) == LinkDirection::STRAIGHT) {
1007 // straight edge found
1008 endEdge = toEdges[i];
1009 break;
1010 }
1011 }
1012 if (endEdge == nullptr) {
1013 endEdge = otherChosen;
1014 }
1015 if (endEdge == nullptr) {
1016 // try to find the reverse edge of the green edge
1017 auto itCW = start;
1018 NBContHelper::nextCW(all, itCW);
1019 if ((*itCW)->getFromNode() == greenEdge->getToNode()) {
1020 endEdge = *itCW;
1021 }
1022 }
1023 if (endEdge == nullptr) {
1024 // at least prevent an infinite loop
1025 endEdge = greenEdge;
1026 }
1027 //std::cout << " patchNEMAStateForCrossings green=" << greenEdge->getID() << " other=" << Named::getIDSecure(otherChosen) << " end=" << Named::getIDSecure(end) << " all=" << toString(all) << "\n";
1028
1029 EdgeVector::const_iterator end = std::find(all.begin(), all.end(), endEdge);
1030 if (end == all.end()) {
1031 // at least prevent an infinite loop
1032 end = start;
1033 }
1034 auto it = start;
1035 NBContHelper::nextCCW(all, it);
1036 for (; it != end; NBContHelper::nextCCW(all, it)) {
1037 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
1038 const int i1 = pos + ic;
1039 const NBNode::Crossing& cross = *crossings[ic];
1040 for (const NBEdge* crossed : cross.edges) {
1041 //std::cout << " cand=" << (*it)->getID() << " crossed=" << crossed->getID() << "\n";
1042 if (crossed == *it) {
1043 result[i1] = 'G';
1044 break;
1045 }
1046 }
1047 }
1048 }
1049 // correct behaviour for roads that are in conflict with a pedestrian crossing
1050 for (int i1 = 0; i1 < pos; ++i1) {
1051 if (result[i1] == 'G') {
1052 for (int ic = 0; ic < (int)crossings.size(); ++ic) {
1053 const NBNode::Crossing& crossing = *crossings[ic];
1054 const int i2 = pos + ic;
1055 if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
1056 result[i1] = 'g';
1057 break;
1058 }
1059 }
1060 }
1061 }
1062 return result;
1063}
1064
1065
1066void
1071
1072
1073void
1075 // set the information about the link's positions within the tl into the
1076 // edges the links are starting at, respectively
1077 for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
1078 const NBConnection& conn = *j;
1079 NBEdge* edge = conn.getFrom();
1080 edge->setControllingTLInformation(conn, getID());
1081 }
1082}
1083
1084
1085void
1086NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
1087 const EdgeVector& /*outgoing*/) {}
1088
1089
1090void
1091NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
1092 NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
1093
1094
1095void
1098 if (myControlledNodes.size() > 0) {
1099 // setParticipantsInformation resets myAmInTLS so we need to make a copy
1100 std::vector<bool> edgeInsideTLS;
1101 for (const NBEdge* e : myIncomingEdges) {
1102 edgeInsideTLS.push_back(e->isInsideTLS());
1103 }
1104 // we use a dummy node just to maintain const-correctness
1105 myNeedsContRelation.clear();
1106 for (NBNode* n : myControlledNodes) {
1109 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1110 delete tllDummy;
1111 myNeedsContRelation.insert(dummy.myNeedsContRelation.begin(), dummy.myNeedsContRelation.end());
1112 n->removeTrafficLight(&dummy);
1113 }
1114 if (myControlledNodes.size() > 1) {
1115 int i = 0;
1116 for (NBEdge* e : myIncomingEdges) {
1117 e->setInsideTLS(edgeInsideTLS[i]);
1118 i++;
1119 }
1120 }
1121#ifdef DEBUG_CONTRELATION
1122 if (DEBUGCOND) {
1123 std::cout << " contRelations at " << getID() << " prog=" << getProgramID() << ":\n";
1124 for (const StreamPair& s : myNeedsContRelation) {
1125 std::cout << " " << s.from1->getID() << "->" << s.to1->getID() << " foe " << s.from2->getID() << "->" << s.to2->getID() << "\n";
1126 }
1127 }
1128#endif
1129
1130 }
1132 }
1133}
1134
1135
1138 EdgeVector result = incoming;
1139 for (EdgeVector::iterator it = result.begin(); it != result.end();) {
1140 if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
1141 it = result.erase(it);
1142 } else {
1143 ++it;
1144 }
1145 }
1146 return result;
1147}
1148
1149
1150std::string
1151NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1152 const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1153 state = allowSingleEdge(state, fromEdges);
1154#ifdef DEBUG_PHASES
1155 if (DEBUGCOND) {
1156 std::cout << " state after allowSingle " << state << "\n";
1157 }
1158#endif
1159 if (myControlledNodes.size() > 1) {
1160 state = allowFollowers(state, fromEdges, toEdges);
1161#ifdef DEBUG_PHASES
1162 if (DEBUGCOND) {
1163 std::cout << " state after allowFollowers " << state << "\n";
1164 }
1165#endif
1166 state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
1167#ifdef DEBUG_PHASES
1168 if (DEBUGCOND) {
1169 std::cout << " state after allowPredecessors " << state << "\n";
1170 }
1171#endif
1172 }
1173 return state;
1174}
1175
1176
1177std::string
1178NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
1179 // if only one edge has green, ensure sure that all connections from that edge are green
1180 const int size = (int)fromEdges.size();
1181 NBEdge* greenEdge = nullptr;
1182 for (int i1 = 0; i1 < size; ++i1) {
1183 if (state[i1] == 'G') {
1184 if (greenEdge == nullptr) {
1185 greenEdge = fromEdges[i1];
1186 } else if (greenEdge != fromEdges[i1]) {
1187 return state;
1188 }
1189 }
1190 }
1191 if (greenEdge != nullptr) {
1192 for (int i1 = 0; i1 < size; ++i1) {
1193 if (fromEdges[i1] == greenEdge) {
1194 state[i1] = 'G';
1195 }
1196 }
1197 }
1198 return state;
1199}
1200
1201
1202std::string
1203NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1204 // check continuation within joined traffic lights
1205 bool check = true;
1206 while (check) {
1207 check = false;
1208 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1209 if (state[i1] == 'G') {
1210 continue;
1211 }
1212 if (forbidden(state, i1, fromEdges, toEdges, true)) {
1213 continue;
1214 }
1215 bool followsChosen = false;
1216 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1217 if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
1218 followsChosen = true;
1219 break;
1220 }
1221 }
1222 if (followsChosen) {
1223 state[i1] = 'G';
1224 check = true;
1225 }
1226 }
1227 }
1228 return state;
1229}
1230
1231
1232std::string
1233NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1234 const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1235 // also allow predecessors of chosen edges if the lanes match and there is no conflict
1236 // (must be done after the followers are done because followers are less specific)
1237 bool check = true;
1238 while (check) {
1239 check = false;
1240 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1241 if (state[i1] == 'G') {
1242 continue;
1243 }
1244 if (forbidden(state, i1, fromEdges, toEdges, false)) {
1245 continue;
1246 }
1247 bool preceedsChosen = false;
1248 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1249 if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
1250 && fromLanes[i2] == toLanes[i1]) {
1251 preceedsChosen = true;
1252 break;
1253 }
1254 }
1255 if (preceedsChosen) {
1256 state[i1] = 'G';
1257 check = true;
1258 }
1259 }
1260 }
1261 return state;
1262}
1263
1264
1265std::string
1266NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1267 const std::vector<bool>& isTurnaround,
1268 const std::vector<NBNode::Crossing*>& crossings) {
1269 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1270 if (state[i1] == 'G') {
1271 continue;
1272 }
1273 bool isForbidden = false;
1274 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1275 if (state[i2] == 'G' && !isTurnaround[i2] &&
1276 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1277 isForbidden = true;
1278 break;
1279 }
1280 }
1281 if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
1282 state[i1] = 'G';
1283 }
1284 }
1285 return state;
1286}
1287
1288
1289std::string
1290NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
1291 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1292 SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
1293 if ((linkPerm & ~perm) == 0) {
1294 state[i1] = 'G';
1295 }
1296 }
1297 return state;
1298}
1299
1300
1301bool
1302NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges, bool allowCont) {
1303 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1304 if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
1305 if (!allowCont || (
1306 !needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
1307 !needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
1308 return true;
1309 }
1310 }
1311 }
1312 return false;
1313}
1314
1315
1316std::string
1317NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1318 const std::vector<bool>& isTurnaround,
1319 const std::vector<int>& fromLanes,
1320 const std::vector<int>& toLanes,
1321 const std::vector<bool>& hadGreenMajor,
1322 bool& haveForbiddenLeftMover,
1323 std::vector<bool>& rightTurnConflicts,
1324 std::vector<bool>& mergeConflicts) {
1325 const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
1326 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1327 if (state[i1] == 'G') {
1328 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1329 if ((state[i2] == 'G' || state[i2] == 'g')) {
1331 fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
1332 rightTurnConflicts[i1] = true;
1333 }
1334 if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
1335 state[i1] = 'g';
1336 if (myControlledNodes.size() == 1) {
1337 myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
1338#ifdef DEBUG_CONTRELATION
1339 if (DEBUGCOND) {
1340 std::cout << getID() << " p=" << getProgramID() << " contRel: " << fromEdges[i1]->getID() << "->" << toEdges[i1]->getID()
1341 << " foe " << fromEdges[i2]->getID() << "->" << toEdges[i2]->getID() << "\n";
1342 }
1343#endif
1344 }
1345 if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
1346 haveForbiddenLeftMover = true;
1347 }
1348 } else if (fromEdges[i1] == fromEdges[i2]
1349 && fromLanes[i1] != fromLanes[i2]
1350 && toEdges[i1] == toEdges[i2]
1351 && toLanes[i1] == toLanes[i2]
1352 && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
1353 mergeConflicts[i1] = true;
1354 state[i1] = 'g';
1355 }
1356 }
1357 }
1358 }
1359 if (state[i1] == 'r') {
1360 if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
1361 fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
1362 state[i1] = 's';
1363 // do not allow right-on-red when in conflict with exclusive left-turn phase
1364 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1365 if (state[i2] == 'G' && !isTurnaround[i2] &&
1366 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1367 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1368 const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
1369 if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
1370 state[i1] = 'r';
1371 break;
1372 }
1373 }
1374 }
1375 if (state[i1] == 's') {
1376 // handle right-on-red conflicts
1377 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1378 if (state[i2] == 'G' && !isTurnaround[i2] &&
1379 (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1380 forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1381 myRightOnRedConflicts.insert(std::make_pair(i1, i2));
1382 }
1383 }
1384 }
1385 }
1386 }
1387 }
1388 return state;
1389}
1390
1391
1392std::string
1393NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
1394 const std::vector<int>& fromLanes,
1395 bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
1396 for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1397 if ((state[i1] == 'G' || state[i1] == 'g')) {
1398 for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1399 if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
1400 && state[i2] != 'G' && state[i2] != 'g') {
1401 state[i1] = state[i2];
1402 //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
1403 mixedGreen[i1] = true;
1404 if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
1405 buildMixedGreenPhase = true;
1406 }
1407 }
1408 }
1409 }
1410 }
1411 return state;
1412}
1413
1414
1415void
1417 std::vector<bool> foundGreen(fromEdges.size(), false);
1418 for (const auto& phase : logic->getPhases()) {
1419 const std::string state = phase.state;
1420 for (int j = 0; j < (int)fromEdges.size(); j++) {
1421 LinkState ls = (LinkState)state[j];
1423 foundGreen[j] = true;
1424 }
1425 }
1426 }
1427 for (int j = 0; j < (int)foundGreen.size(); j++) {
1428 if (!foundGreen[j]) {
1429 NBEdge* e = fromEdges[j];
1430 if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
1431 toProc.push_back(e);
1432 }
1433 }
1434 }
1435}
1436
1437
1438void
1439NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int totalNumLinks, SUMOTime /* greenTime */, SUMOTime brakingTime,
1440 const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1441 const int vehLinks = totalNumLinks - (int)crossings.size();
1442 std::vector<bool> foundGreen(crossings.size(), false);
1443 const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
1444 for (int i = 0; i < (int)phases.size(); i++) {
1445 const std::string state = phases[i].state;
1446 for (int j = 0; j < (int)crossings.size(); j++) {
1447 LinkState ls = (LinkState)state[vehLinks + j];
1449 foundGreen[j] = true;
1450 }
1451 }
1452 }
1453#ifdef DEBUG_PHASES
1454 if (DEBUGCOND2(logic)) {
1455 std::cout << " foundCrossingGreen=" << toString(foundGreen) << "\n";
1456 }
1457#endif
1458 for (int j = 0; j < (int)foundGreen.size(); j++) {
1459 if (!foundGreen[j]) {
1460 // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
1461 if (phases.size() > 0) {
1462 bool needYellowPhase = false;
1463 std::string state = phases.back().state;
1464 for (int i1 = 0; i1 < vehLinks; ++i1) {
1465 if (state[i1] == 'G' || state[i1] == 'g') {
1466 state[i1] = 'y';
1467 needYellowPhase = true;
1468 }
1469 }
1470 // add yellow step
1471 if (needYellowPhase && brakingTime > 0) {
1472 logic->addStep(brakingTime, state);
1473 }
1474 }
1475 const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
1476 const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
1477 addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION,
1478 UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(totalNumLinks, 'r'), crossings, fromEdges, toEdges);
1479 break;
1480 }
1481 }
1482}
1483
1484
1485void
1486NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
1487 if (allRedTime > 0) {
1488 // build all-red phase
1489 std::string allRedState = state;
1490 for (int i = 0; i < (int)state.size(); i++) {
1491 if (allRedState[i] == 'Y' || allRedState[i] == 'y') {
1492 allRedState[i] = 'r';
1493 }
1494 }
1495 logic->addStep(TIME2STEPS(ceil(STEPS2TIME(allRedTime))), allRedState);
1496 }
1497}
1498
1499
1500void
1502 int minCustomIndex = -1;
1503 int maxCustomIndex = -1;
1504 // collect crossings
1505 for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1506 const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1507 for (auto crossing : c) {
1508 minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
1509 minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
1510 maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
1511 maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
1512 }
1513 }
1514 // custom crossing linkIndex could lead to longer states. ensure that every index has a state
1515 if (maxCustomIndex >= logic->getNumLinks()) {
1516 logic->setStateLength(maxCustomIndex + 1);
1517 }
1518 // XXX shorter state vectors are possible as well
1519 // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
1520 // XXX initialize the backward index to the same state as the forward index
1521}
1522
1523void
1525 // assume that yellow states last at most one phase
1526 const int n = logic->getNumLinks();
1527 const int p = (int)logic->getPhases().size();
1528 for (int i1 = 0; i1 < n; ++i1) {
1529 LinkState prev = (LinkState)logic->getPhases().back().state[i1];
1530 for (int i2 = 0; i2 < p; ++i2) {
1531 LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
1532 LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
1533 if (cur == LINKSTATE_TL_YELLOW_MINOR
1535 && next == LINKSTATE_TL_GREEN_MAJOR) {
1536 logic->setPhaseState(i2, i1, prev);
1537 }
1538 prev = cur;
1539 }
1540 }
1541}
1542
1543
1544void
1546 const int n = logic->getNumLinks();
1547 std::vector<bool> alwaysGreen(n, true);
1548 for (int i1 = 0; i1 < n; ++i1) {
1549 for (const auto& phase : logic->getPhases()) {
1550 if (phase.state[i1] != 'G') {
1551 alwaysGreen[i1] = false;
1552 break;
1553 }
1554 }
1555 }
1556 const int p = (int)logic->getPhases().size();
1557 for (int i1 = 0; i1 < n; ++i1) {
1558 if (alwaysGreen[i1]) {
1559 for (int i2 = 0; i2 < p; ++i2) {
1561 }
1562 }
1563 }
1564}
1565
1566
1567void
1569 const int n = (int)fromEdges.size();
1570 const int p = (int)logic->getPhases().size();
1571 for (int i1 = 0; i1 < n; ++i1) {
1572 if (fromEdges[i1]->isInsideTLS()) {
1573 for (int i2 = 0; i2 < p; ++i2) {
1575 }
1576 }
1577 }
1578}
1579
1580
1582NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
1583 const int n = (int)fromEdges.size();
1584 double maxTime = 0;
1585 for (int i1 = 0; i1 < n; ++i1) {
1586 if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
1587 for (int i2 = 0; i2 < n; ++i2) {
1588 if (fromEdges[i2]->isInsideTLS()) {
1589 double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1590 double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1591 maxTime = MAX2(maxTime, time);
1592 }
1593 }
1594 }
1595 }
1596 // give some slack
1597 return TIME2STEPS(floor(maxTime * 1.2 + 5));
1598}
1599
1600
1601int
1605 if (logic != nullptr) {
1606 return logic->getNumLinks() - 1;
1607 } else {
1608 return -1;
1609 }
1610}
1611
1612
1613bool
1615 if (getID() == DummyID) {
1616 // avoid infinite recursion
1617 return true;
1618 }
1619 assert(myControlledNodes.size() >= 2);
1622 NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1623 int greenPhases = 0;
1624 for (const auto& phase : tllDummy->getPhases()) {
1625 if (phase.state.find_first_of("gG") != std::string::npos) {
1626 greenPhases++;
1627 }
1628 }
1629 delete tllDummy;
1630 for (const auto& controlledNode : myControlledNodes) {
1631 controlledNode->removeTrafficLight(&dummy);
1632 }
1633 return greenPhases <= 2;
1634}
1635
1636
1639 const EdgeVector& fromEdges,
1640 const EdgeVector& toEdges,
1641 const std::vector<NBNode::Crossing*>& crossings,
1642 const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
1643 const std::vector<std::string>& straightStates,
1644 const std::vector<std::string>& leftStates) {
1645 if (chosenList.size() != 2) {
1646 return nullptr;
1647 }
1648 const SUMOTime dur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
1649 const SUMOTime vehExt = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.vehExt"));
1650 const SUMOTime yellow = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.yellow"));
1651 const SUMOTime red = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.red"));
1652 const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
1653 const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
1654 const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
1655 const SUMOTime latestEnd = UNSPECIFIED_DURATION;
1656
1657 const int totalNumLinks = (int)straightStates[0].size();
1658 NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
1659 std::vector<int> ring1({1, 2, 3, 4});
1660 std::vector<int> ring2({5, 6, 7, 8});
1661 std::vector<int> barrier1({4, 8});
1662 std::vector<int> barrier2({2, 6});
1663 int phaseNameLeft = 1;
1664 for (int i = 0; i < (int)chosenList.size(); i++) {
1665 NBEdge* e1 = chosenList[i].first;
1666 assert(e1 != nullptr);
1667 NBEdge* e2 = chosenList[i].second;
1668 if (i < (int)leftStates.size()) {
1669 std::string left1 = filterState(leftStates[i], fromEdges, e1);
1670 if (left1 != "") {
1671 logic->addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft));
1672 }
1673 }
1674 if (e2 != nullptr) {
1675 std::string straight2 = filterState(straightStates[i], fromEdges, e2);
1676 straight2 = patchNEMAStateForCrossings(straight2, crossings, fromEdges, toEdges, e2, e1);
1677
1678 logic->addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 1));
1679 if (i < (int)leftStates.size()) {
1680 std::string left2 = filterState(leftStates[i], fromEdges, e2);
1681 if (left2 != "") {
1682 logic->addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 4));
1683 }
1684 }
1685
1686 }
1687 std::string straight1 = filterState(straightStates[i], fromEdges, e1);
1688 if (straight1 == "") {
1689 delete logic;
1690 return nullptr;
1691 }
1692 straight1 = patchNEMAStateForCrossings(straight1, crossings, fromEdges, toEdges, e1, e2);
1693 logic->addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 5));
1694 phaseNameLeft += 2;
1695 }
1696 std::map<int, int> names; // nema phase name -> sumo phase index
1697 for (int i = 0; i < (int)logic->getPhases().size(); i++) {
1698 names[StringUtils::toInt(logic->getPhases()[i].name)] = i;
1699 }
1700
1701 filterMissingNames(ring1, names, false);
1702 filterMissingNames(ring2, names, false);
1703 filterMissingNames(barrier1, names, true, 8);
1704 filterMissingNames(barrier2, names, true, 6);
1705 if (ring1[0] == 0 && ring1[1] == 0) {
1706 ring1[1] = 6;
1707 }
1708 if (ring1[2] == 0 && ring1[3] == 0) {
1709 ring1[3] = 8;
1710 }
1711 fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
1712 fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
1713
1714 logic->setParameter("ring1", joinToString(ring1, ","));
1715 logic->setParameter("ring2", joinToString(ring2, ","));
1716 logic->setParameter("barrierPhases", joinToString(barrier1, ","));
1717 logic->setParameter("barrier2Phases", joinToString(barrier2, ","));
1718 return logic;
1719}
1720
1721
1722std::string
1723NBOwnTLDef::filterState(std::string state, const EdgeVector& fromEdges, const NBEdge* e) {
1724 bool haveGreen = false;
1725 for (int j = 0; j < (int)fromEdges.size(); j++) {
1726 if (fromEdges[j] != e) {
1727 state[j] = 'r';
1728 } else if (state[j] != 'r') {
1729 haveGreen = true;
1730 }
1731 }
1732 if (haveGreen) {
1733 return state;
1734 } else {
1735 return "";
1736 }
1737}
1738
1739void
1740NBOwnTLDef::filterMissingNames(std::vector<int>& vec, const std::map<int, int>& names, bool isBarrier, int barrierDefault) {
1741 for (int i = 0; i < (int)vec.size(); i++) {
1742 if (names.count(vec[i]) == 0) {
1743 if (isBarrier) {
1744 if (names.count(vec[i] - 1) > 0) {
1745 vec[i] = vec[i] - 1;
1746 } else {
1747 vec[i] = barrierDefault;
1748 }
1749 } else {
1750 vec[i] = 0;
1751 }
1752 }
1753 }
1754}
1755
1756void
1757NBOwnTLDef::fixDurationSum(NBTrafficLightLogic* logic, const std::map<int, int>& names, int ring1a, int ring1b, int ring2a, int ring2b) {
1758 std::set<int> ring1existing;
1759 std::set<int> ring2existing;
1760 if (names.count(ring1a) != 0) {
1761 ring1existing.insert(ring1a);
1762 }
1763 if (names.count(ring1b) != 0) {
1764 ring1existing.insert(ring1b);
1765 }
1766 if (names.count(ring2a) != 0) {
1767 ring2existing.insert(ring2a);
1768 }
1769 if (names.count(ring2b) != 0) {
1770 ring2existing.insert(ring2b);
1771 }
1772 if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
1773 ring1existing.size() != ring2existing.size()) {
1774 int pI; // sumo phase index
1775 if (ring1existing.size() < ring2existing.size()) {
1776 pI = names.find(*ring1existing.begin())->second;
1777 } else {
1778 pI = names.find(*ring2existing.begin())->second;
1779 }
1780 const auto& p = logic->getPhases()[pI];
1781 SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
1782 logic->setPhaseMaxDuration(pI, newMaxDur);
1783 }
1784}
1785
1786/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
@ DEFAULT
default cursor
#define DEBUGCOND(PED)
#define DEBUGCOND2(LANE)
#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:4379
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:3727
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:1287
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition NBEdge.cpp:2133
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition NBEdge.h:539
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition NBEdge.cpp:4008
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:2409
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:2094
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:2075
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 setPhaseNext(int phaseIndex, const std::vector< int > &next)
Modifies the next phase (used by netedit)
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
TrafficLightType getType() const
get the algorithm type (static etc..)
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