Eclipse SUMO - Simulation of Urban MObility
NBOwnTLDef.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2022 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"
34 #include <utils/common/ToString.h>
36 #include <utils/options/Option.h>
37 
38 #define HEIGH_WEIGHT 2
39 #define LOW_WEIGHT .5;
40 
41 #define MIN_GREEN_TIME 5
42 
43 //#define DEBUG_STREAM_ORDERING
44 //#define DEBUG_PHASES
45 //#define DEBUGCOND (getID() == "cluster_251050941_280598736_280598739_28902891_3142549227_3142550438")
46 //#define DEBUGEDGE(edge) (edge->getID() == "23209153#1" || edge->getID() == "319583927#0")
47 //#define DEBUGCOND (true)
48 //#define DEBUGEDGE(edge) (true)
49 
50 // ===========================================================================
51 // member method definitions
52 // ===========================================================================
53 NBOwnTLDef::NBOwnTLDef(const std::string& id,
54  const std::vector<NBNode*>& junctions, SUMOTime offset,
55  TrafficLightType type) :
56  NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
57  myHaveSinglePhase(false),
58  myLayout(TrafficLightLayout::DEFAULT) {
59 }
60 
61 
62 NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
63  TrafficLightType type) :
64  NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
65  myHaveSinglePhase(false),
66  myLayout(TrafficLightLayout::DEFAULT) {
67 }
68 
69 
70 NBOwnTLDef::NBOwnTLDef(const std::string& id, SUMOTime offset,
71  TrafficLightType type) :
72  NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
73  myHaveSinglePhase(false),
74  myLayout(TrafficLightLayout::DEFAULT) {
75 }
76 
77 
79 
80 
81 int
82 NBOwnTLDef::getToPrio(const NBEdge* const e) {
83  return e->getJunctionPriority(e->getToNode());
84 }
85 
86 
87 double
89  switch (dir) {
93  return HEIGH_WEIGHT;
96  return LOW_WEIGHT;
97  default:
98  break;
99  }
100  return 0;
101 }
102 
103 double
105  double val = 0;
106  for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
107  std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
108  for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
109  std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
110  for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
111  if (e1->getTurnDestination() == (*e1c).toEdge) {
112  continue;
113  }
114  for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
115  if (e2->getTurnDestination() == (*e2c).toEdge) {
116  continue;
117  }
118  const double sign = (forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)
119  || forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge, true)) ? -1 : 1;
120  double w1;
121  double w2;
122  if (e1->getJunctionPriority(e1->getToNode()) == e2->getJunctionPriority(e2->getToNode())) {
123  w1 = getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
124  w2 = getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
125  } else {
126  if (e1->getJunctionPriority(e1->getToNode()) > e2->getJunctionPriority(e2->getToNode())) {
127  w1 = HEIGH_WEIGHT;
128  w2 = LOW_WEIGHT;
129  } else {
130  w1 = LOW_WEIGHT;
131  w2 = HEIGH_WEIGHT;
132  }
133  if (sign == -1) {
134  // extra penalty if edges with different junction priority are in conflict
135  w1 *= 2;
136  w2 *= 2;
137  }
138  }
139  val += sign * w1;
140  val += sign * w2;
141 #ifdef DEBUG_STREAM_ORDERING
142  if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
143  std::cout << " sign=" << sign << " w1=" << w1 << " w2=" << w2 << " val=" << val
144  << " c1=" << (*e1c).getDescription(e1)
145  << " c2=" << (*e2c).getDescription(e2)
146  << "\n";
147  }
148 #endif
149  }
150  }
151  }
152  }
153 #ifdef DEBUG_STREAM_ORDERING
154  if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
155  std::cout << " computeUnblockedWeightedStreamNumber e1=" << e1->getID() << " e2=" << e2->getID() << " val=" << val << "\n";
156  }
157 #endif
158  return val;
159 }
160 
161 
162 std::pair<NBEdge*, NBEdge*>
164  std::pair<NBEdge*, NBEdge*> bestPair(static_cast<NBEdge*>(nullptr), static_cast<NBEdge*>(nullptr));
165  double bestValue = -std::numeric_limits<double>::max();
166  for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
167  for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
168  const double value = computeUnblockedWeightedStreamNumber(*i, *j);
169  if (value > bestValue) {
170  bestValue = value;
171  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
172  } else if (value == bestValue) {
173  const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
174  const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
175  if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
176  if (bestPair.first->getID() < (*i)->getID()) {
177  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
178  }
179  } else if (oa < ca) {
180  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
181  }
182  }
183  }
184  }
185  if (bestValue <= 0) {
186  // do not group edges
187  bestPair.second = nullptr;
188 
189  }
190 #ifdef DEBUG_STREAM_ORDERING
191  if (DEBUGCOND) {
192  std::cout << " getBestCombination bestValue=" << bestValue << " best=" << Named::getIDSecure(bestPair.first) << ", " << Named::getIDSecure(bestPair.second) << "\n";
193  }
194 #endif
195  return bestPair;
196 }
197 
198 
199 std::pair<NBEdge*, NBEdge*>
201  if (incoming.size() == 1) {
202  // only one there - return the one
203  std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(), static_cast<NBEdge*>(nullptr));
204  incoming.clear();
205  return ret;
206  }
207  // determine the best combination
208  // by priority, first
209  EdgeVector used;
210  std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
211  used.push_back(*incoming.begin()); // the first will definitely be used
212  // get the ones with the same priority
213  int prio = getToPrio(*used.begin());
214  for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
215  used.push_back(*i);
216  }
217  // if there only lower priorised, use these, too
218  if (used.size() < 2) {
219  used = incoming;
220  }
221  std::pair<NBEdge*, NBEdge*> ret = getBestCombination(used);
222 #ifdef DEBUG_STREAM_ORDERING
223  if (DEBUGCOND) {
224  std::cout << "getBestPair tls=" << getID() << " incoming=" << toString(incoming) << " prio=" << prio << " used=" << toString(used) << " best=" << Named::getIDSecure(ret.first) << ", " << Named::getIDSecure(ret.second) << "\n";
225  }
226 #endif
227 
228  incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
229  if (ret.second != nullptr) {
230  incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
231  }
232  return ret;
233 }
234 
235 bool
237  for (const NBEdge::Connection& c : fromEdge->getConnections()) {
238  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, c.toEdge);
239  if (dir == LinkDirection::STRAIGHT) {
240  return true;
241  }
242  }
243  return false;
244 }
245 
247 NBOwnTLDef::myCompute(int brakingTimeSeconds) {
248  return computeLogicAndConts(brakingTimeSeconds);
249 }
250 
252 NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
253  myNeedsContRelation.clear();
254  myRightOnRedConflicts.clear();
255  const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
256  const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
257  const SUMOTime minMinDur = myType == TrafficLightType::STATIC ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
259 
260  // build complete lists first
261  const EdgeVector& incoming = getIncomingEdges();
262  EdgeVector fromEdges, toEdges;
263  std::vector<bool> isTurnaround;
264  std::vector<bool> hasTurnLane;
265  std::vector<int> fromLanes;
266  std::vector<int> toLanes;
267  int noLinksAll = 0;
268  for (NBEdge* const fromEdge : incoming) {
269  const int numLanes = fromEdge->getNumLanes();
270  const bool edgeHasStraight = hasStraightConnection(fromEdge);
271  for (int i2 = 0; i2 < numLanes; i2++) {
272  bool hasLeft = false;
273  bool hasPartLeft = false;
274  bool hasStraight = false;
275  bool hasRight = false;
276  bool hasTurnaround = false;
277  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
278  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
279  continue;
280  }
281  fromEdges.push_back(fromEdge);
282  fromLanes.push_back(i2);
283  toLanes.push_back(approached.toLane);
284  toEdges.push_back(approached.toEdge);
285  if (approached.toEdge != nullptr) {
286  isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
287  } else {
288  isTurnaround.push_back(true);
289  }
290  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
291  if (dir == LinkDirection::STRAIGHT) {
292  hasStraight = true;
293  } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
294  hasRight = true;
295  } else if (dir == LinkDirection::LEFT) {
296  hasLeft = true;
297  } else if (dir == LinkDirection::PARTLEFT) {
298  hasPartLeft = true;
299  } else if (dir == LinkDirection::TURN) {
300  hasTurnaround = true;
301  }
302  noLinksAll++;
303  }
304  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
305  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
306  continue;
307  }
308  hasTurnLane.push_back(
309  (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
310  || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
311  || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
312  || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
313  }
314  //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
315  }
316  }
317  // collect crossings
318  std::vector<NBNode::Crossing*> crossings;
319  for (NBNode* const node : myControlledNodes) {
320  const std::vector<NBNode::Crossing*>& c = node->getCrossings();
321  if (!onlyConts) {
322  // set tl indices for crossings
323  node->setCrossingTLIndices(getID(), noLinksAll);
324  }
325  copy(c.begin(), c.end(), std::back_inserter(crossings));
326  noLinksAll += (int)c.size();
327  }
328 
329  NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), noLinksAll, myOffset, myType);
330  EdgeVector toProc = getConnectedOuterEdges(incoming);
331  const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
332  SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
333  const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
334  const bool noMixed = OptionsCont::getOptions().getBool("tls.no-mixed");
335  // left-turn phases do not work well for joined tls, so we build incoming instead
337  // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
339  }
340  const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
341 
342  // build all phases
343  std::vector<int> greenPhases; // indices of green phases
344  std::vector<bool> hadGreenMajor(noLinksAll, false);
345  while (toProc.size() > 0) {
346  bool groupTram = false;
347  bool groupOther = false;
348  std::pair<NBEdge*, NBEdge*> chosen;
349  if (groupOpposites) {
350  if (incoming.size() == 2) {
351  // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
352  // @node: this heuristic could be extended to also check the number of outgoing edges
353  double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
354  // angle would be 180 for straight opposing incoming edges
355  if (angle < 135) {
356  chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
357  toProc.erase(toProc.begin());
358  } else {
359  chosen = getBestPair(toProc);
360  }
361  } else {
362  chosen = getBestPair(toProc);
363  if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
364  groupTram = true;
365  for (auto it = toProc.begin(); it != toProc.end();) {
366  if ((*it)->getPermissions() == SVC_TRAM) {
367  it = toProc.erase(it);
368  } else {
369  it++;
370  }
371  }
372  }
373  }
374  } else {
375  NBEdge* chosenEdge = toProc[0];
376  chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
377  toProc.erase(toProc.begin());
378  SVCPermissions perms = chosenEdge->getPermissions();
379  if (perms == SVC_TRAM) {
380  groupTram = true;
381  } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
382  groupOther = true;
383  }
384  // group all edges with the same permissions into a single phase (later)
385  if (groupTram || groupOther) {
386  for (auto it = toProc.begin(); it != toProc.end();) {
387  if ((*it)->getPermissions() == perms) {
388  it = toProc.erase(it);
389  } else {
390  it++;
391  }
392  }
393  }
394  }
395  int pos = 0;
396  std::string state((int) noLinksAll, 'r');
397 #ifdef DEBUG_PHASES
398  if (DEBUGCOND) {
399  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";
400  }
401 #endif
402  // plain straight movers
403  double maxSpeed = 0;
404  bool haveGreen = false;
405  for (const NBEdge* const fromEdge : incoming) {
406  const bool inChosen = fromEdge == chosen.first || fromEdge == chosen.second; //chosen.find(fromEdge)!=chosen.end();
407  const int numLanes = fromEdge->getNumLanes();
408  for (int i2 = 0; i2 < numLanes; i2++) {
409  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
410  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
411  continue;
412  }
413  if (inChosen) {
414  state[pos] = 'G';
415  haveGreen = true;
416  maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
417  } else {
418  state[pos] = 'r';
419  }
420  ++pos;
421  }
422  }
423  }
424  if (!haveGreen) {
425  continue;
426  }
427 
428 #ifdef DEBUG_PHASES
429  if (DEBUGCOND) {
430  std::cout << " state after plain straight movers " << state << "\n";
431  }
432 #endif
433  // correct behaviour for those that are not in chosen, but may drive, though
434  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
435  if (groupTram) {
436  state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
437  } else if (groupOther) {
438  state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
439  }
440 #ifdef DEBUG_PHASES
441  if (DEBUGCOND) {
442  std::cout << " state after grouping by vClass " << state << "\n";
443  }
444 #endif
445  if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
446  state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
447  }
448 #ifdef DEBUG_PHASES
449  if (DEBUGCOND) {
450  std::cout << " state after finding allowUnrelated " << state << "\n";
451  }
452 #endif
453  // correct behaviour for those that have to wait (mainly left-mover)
454  bool haveForbiddenLeftMover = false;
455  std::vector<bool> rightTurnConflicts(pos, false);
456  std::vector<bool> mergeConflicts(pos, false);
457  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
458  for (int i1 = 0; i1 < pos; ++i1) {
459  if (state[i1] == 'G') {
460  hadGreenMajor[i1] = true;
461  }
462  }
463 #ifdef DEBUG_PHASES
464  if (DEBUGCOND) {
465  std::cout << " state after correcting left movers=" << state << "\n";
466  }
467 #endif
468 
469  std::vector<bool> leftGreen(pos, false);
470  // check whether at least one left-turn lane exist
471  bool foundLeftTurnLane = false;
472  for (int i1 = 0; i1 < pos; ++i1) {
473  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
474  foundLeftTurnLane = true;
475  }
476  }
477  const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
478  && groupOpposites && !groupTram && !groupOther);
479 
480  // find indices for exclusive left green phase and apply option minor-left.max-speed
481  for (int i1 = 0; i1 < pos; ++i1) {
482  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
483  // only activate turn-around together with a real left-turn
484  && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
485  leftGreen[i1] = true;
486  if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
487  if (buildLeftGreenPhase) {
488  state[i1] = 'r';
489  //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
490  } else if (!isTurnaround[i1]) {
491  WRITE_WARNINGF("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing.",
492  fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
493  }
494  }
495  }
496  }
497 
498 #ifdef DEBUG_PHASES
499  if (DEBUGCOND) {
500  std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
501  << " \nrtC=" << toString(rightTurnConflicts)
502  << " \nmC=" << toString(mergeConflicts)
503  << " \nhTL=" << toString(hasTurnLane)
504  << " \nlGr=" << toString(leftGreen)
505  << "\n";
506  }
507 #endif
508 
509  const std::string vehicleState = state; // backup state before pedestrian modifications
510  greenPhases.push_back((int)logic->getPhases().size());
511 
512  // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
513  const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
514  SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
515  if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
516  // shorter minDuration for tram phase (only if the phase is
517  // exclusively for tram)
518  bool tramExclusive = true;
519  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
520  if (state[i1] == 'G') {
521  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
522  if (linkPerm != SVC_TRAM) {
523  tramExclusive = false;
524  break;
525  }
526  }
527  }
528  if (tramExclusive) {
529  // one tram per actuated phase
530  minDur = TIME2STEPS(1);
531  }
532  }
533 
534  state = addPedestrianPhases(logic, greenTime, minDur, maxDur, state, crossings, fromEdges, toEdges);
535  // pedestrians have 'r' from here on
536  for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
537  state[i1] = 'r';
538  }
539  if (brakingTime > 0) {
540  // build yellow (straight)
541  for (int i1 = 0; i1 < pos; ++i1) {
542  if (state[i1] != 'G' && state[i1] != 'g') {
543  continue;
544  }
545  if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
546  && buildLeftGreenPhase
547  && !rightTurnConflicts[i1]
548  && !mergeConflicts[i1]
549  && leftGreen[i1]) {
550  continue;
551  }
552  state[i1] = 'y';
553  }
554  // add step
555  logic->addStep(brakingTime, state);
556  // add optional all-red state
558  allRedTime = computeEscapeTime(state, fromEdges, toEdges);
559  }
560  buildAllRedState(allRedTime, logic, state);
561  }
562 
563 
564  if (buildLeftGreenPhase) {
565  // build left green
566  for (int i1 = 0; i1 < pos; ++i1) {
567  if (state[i1] == 'Y' || state[i1] == 'y') {
568  state[i1] = 'r';
569  continue;
570  }
571  if (leftGreen[i1]) {
572  state[i1] = 'G';
573  }
574  }
575  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
576  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
577  bool buildMixedGreenPhase = false;
578  std::vector<bool> mixedGreen(pos, false);
579  const std::string oldState = state;
580  if (noMixed) {
581  state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
582  }
583  if (state != oldState) {
584  for (int i1 = 0; i1 < pos; ++i1) {
585  if (mixedGreen[i1]) {
586  // patch previous yellow and allred phase
587  int yellowIndex = (int)logic->getPhases().size() - 1;
588  if (allRedTime > 0) {
589  logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
590  }
591  if (brakingTime > 0) {
592  logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
593  }
594  }
595  }
596  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
597  }
598 
599  // add step
600  logic->addStep(leftTurnTime, state, minDur, maxDur);
601 
602  // build left yellow
603  if (brakingTime > 0) {
604  for (int i1 = 0; i1 < pos; ++i1) {
605  if (state[i1] != 'G' && state[i1] != 'g') {
606  continue;
607  }
608  state[i1] = 'y';
609  }
610  // add step
611  logic->addStep(brakingTime, state);
612  // add optional all-red state
613  buildAllRedState(allRedTime, logic, state);
614  }
615 
616  if (buildMixedGreenPhase) {
617  // build mixed green
618  // @todo if there is no left green phase we might want to build two
619  // mixed-green phases but then we should consider avoid a common
620  // opposite phase for this direction
621 
622  for (int i1 = 0; i1 < pos; ++i1) {
623  if (state[i1] == 'Y' || state[i1] == 'y') {
624  state[i1] = 'r';
625  continue;
626  }
627  if (mixedGreen[i1]) {
628  state[i1] = 'G';
629  }
630  }
631  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
632  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
633 
634  // add step
635  logic->addStep(leftTurnTime, state, minDur, maxDur);
636 
637  // build mixed yellow
638  if (brakingTime > 0) {
639  for (int i1 = 0; i1 < pos; ++i1) {
640  if (state[i1] != 'G' && state[i1] != 'g') {
641  continue;
642  }
643  state[i1] = 'y';
644  }
645  // add step
646  logic->addStep(brakingTime, state);
647  // add optional all-red state
648  buildAllRedState(allRedTime, logic, state);
649  }
650 
651  }
652 
653  }
654  }
655  // fix pedestrian crossings that did not get the green light yet
656  if (crossings.size() > 0) {
657  addPedestrianScramble(logic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
658  }
659  // add optional red phase if there where no foes
660  if (logic->getPhases().size() == 2 && brakingTime > 0
661  && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
662  const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
663  logic->addStep(redTime, std::string(noLinksAll, 'r'));
664  }
665  // fix states to account for custom crossing link indices
666  if (crossings.size() > 0 && !onlyConts) {
668  }
669 
671  // exiting the oneway section should always be possible
672  deactivateInsideEdges(logic, fromEdges);
673  }
674 
675  SUMOTime totalDuration = logic->getDuration();
676  if (OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) {
677  const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
678  // adapt to cycle time by changing the duration of the green phases
679  SUMOTime greenPhaseTime = 0;
680  SUMOTime minGreenDuration = SUMOTime_MAX;
681  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
682  const SUMOTime dur = logic->getPhases()[*it].duration;
683  greenPhaseTime += dur;
684  minGreenDuration = MIN2(minGreenDuration, dur);
685  }
686  const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / greenPhases.size());
687  const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
688  //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
689  if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
690  || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
691  || greenPhases.size() == 0) {
692  if (getID() != DummyID) {
693  WRITE_WARNINGF("The traffic light '%' cannot be adapted to a cycle time of %.", getID(), time2string(cycleTime));
694  }
695  // @todo use a multiple of cycleTime ?
696  } else {
697  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
698  logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
699  }
700  if (greenPhases.size() > 0) {
701  logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
702  }
703  totalDuration = logic->getDuration();
704  }
705  }
706 
708  // this computation only makes sense for single nodes
710  if (totalDuration > 0) {
711  if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime)) {
712  WRITE_WARNINGF("The traffic light '%' has a high cycle time of %.", getID(), time2string(totalDuration));
713  }
714  logic->closeBuilding();
715  return logic;
716  } else {
717  delete logic;
718  return nullptr;
719  }
720 }
721 
722 
723 bool
724 NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
725  assert(to != 0);
726  for (auto c : crossings) {
727  const NBNode::Crossing& cross = *c;
728  // only check connections at this crossings node
729  if (to->getFromNode() == cross.node) {
730  for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
731  const NBEdge* edge = *it_e;
732  if (edge == from || edge == to) {
733  return true;
734  }
735  }
736  }
737  }
738  return false;
739 }
740 
741 
742 std::string
744  SUMOTime minDur, SUMOTime maxDur,
745  std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
746  // compute based on length of the crossing if not set by the user
747  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
748  // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
749  const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
750  const std::string orig = state;
751  state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
752  if (orig == state) {
753  // add step
754  logic->addStep(greenTime, state, minDur, maxDur);
755  } else {
756  const SUMOTime pedTime = greenTime - pedClearingTime;
757  if (pedTime >= minPedTime) {
758  // ensure clearing time for pedestrians
759  const int pedStates = (int)crossings.size();
760  logic->addStep(pedTime, state, minDur, maxDur);
761  state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
762  logic->addStep(pedClearingTime, state);
763  } else {
764  state = orig;
765  // not safe for pedestrians.
766  logic->addStep(greenTime, state, minDur, maxDur);
767  }
768  }
769  return state;
770 }
771 
772 
773 std::string
774 NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
775  std::string result = state;
776  const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
777  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
778  const int i1 = pos + ic;
779  const NBNode::Crossing& cross = *crossings[ic];
780  bool isForbidden = false;
781  for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
782  // only check connections at this crossings node
783  if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
784  for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
785  const NBEdge* edge = *it;
786  const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
787  if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
788  (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
789  isForbidden = true;
790  break;
791  }
792  }
793  }
794  }
795  if (!isForbidden) {
796  result[i1] = 'G';
797  } else {
798  result[i1] = 'r';
799  }
800  }
801 
802  // correct behaviour for roads that are in conflict with a pedestrian crossing
803  for (int i1 = 0; i1 < pos; ++i1) {
804  if (result[i1] == 'G') {
805  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
806  const NBNode::Crossing& crossing = *crossings[ic];
807  if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
808  const int i2 = pos + ic;
809  if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
810  result[i1] = 'g';
811  break;
812  }
813  }
814  }
815  }
816  }
817  return result;
818 }
819 
820 
821 void
823  myControlledLinks.clear();
825 }
826 
827 
828 void
830  // set the information about the link's positions within the tl into the
831  // edges the links are starting at, respectively
832  for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
833  const NBConnection& conn = *j;
834  NBEdge* edge = conn.getFrom();
835  edge->setControllingTLInformation(conn, getID());
836  }
837 }
838 
839 
840 void
841 NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
842  const EdgeVector& /*outgoing*/) {}
843 
844 
845 void
846 NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
847  NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
848 
849 
850 void
853  if (myControlledNodes.size() > 0) {
854  // we use a dummy node just to maintain const-correctness
855  myNeedsContRelation.clear();
858  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
859  delete tllDummy;
861  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
862  (*i)->removeTrafficLight(&dummy);
863  }
864  }
866  }
867 }
868 
869 
872  EdgeVector result = incoming;
873  for (EdgeVector::iterator it = result.begin(); it != result.end();) {
874  if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
875  it = result.erase(it);
876  } else {
877  ++it;
878  }
879  }
880  return result;
881 }
882 
883 
884 std::string
885 NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
886  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
887  state = allowSingleEdge(state, fromEdges);
888  state = allowFollowers(state, fromEdges, toEdges);
889  state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
890  return state;
891 }
892 
893 
894 std::string
895 NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
896  // if only one edge has green, ensure sure that all connections from that edge are green
897  const int size = (int)fromEdges.size();
898  NBEdge* greenEdge = nullptr;
899  for (int i1 = 0; i1 < size; ++i1) {
900  if (state[i1] == 'G') {
901  if (greenEdge == nullptr) {
902  greenEdge = fromEdges[i1];
903  } else if (greenEdge != fromEdges[i1]) {
904  return state;
905  }
906  }
907  }
908  if (greenEdge != nullptr) {
909  for (int i1 = 0; i1 < size; ++i1) {
910  if (fromEdges[i1] == greenEdge) {
911  state[i1] = 'G';
912  }
913  }
914  }
915  return state;
916 }
917 
918 
919 std::string
920 NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
921  // check continuation within joined traffic lights
922  bool check = true;
923  while (check) {
924  check = false;
925  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
926  if (state[i1] == 'G') {
927  continue;
928  }
929  //if (forbidden(state, i1, fromEdges, toEdges)) {
930  // continue;
931  //}
932  bool followsChosen = false;
933  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
934  if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
935  followsChosen = true;
936  break;
937  }
938  }
939  if (followsChosen) {
940  state[i1] = 'G';
941  check = true;
942  }
943  }
944  }
945  return state;
946 }
947 
948 
949 std::string
950 NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
951  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
952  // also allow predecessors of chosen edges if the lanes match and there is no conflict
953  // (must be done after the followers are done because followers are less specific)
954  bool check = true;
955  while (check) {
956  check = false;
957  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
958  if (state[i1] == 'G') {
959  continue;
960  }
961  if (forbidden(state, i1, fromEdges, toEdges)) {
962  continue;
963  }
964  bool preceedsChosen = false;
965  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
966  if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
967  && fromLanes[i2] == toLanes[i1]) {
968  preceedsChosen = true;
969  break;
970  }
971  }
972  if (preceedsChosen) {
973  state[i1] = 'G';
974  check = true;
975  }
976  }
977  }
978  return state;
979 }
980 
981 
982 std::string
983 NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
984  const std::vector<bool>& isTurnaround,
985  const std::vector<NBNode::Crossing*>& crossings) {
986  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
987  if (state[i1] == 'G') {
988  continue;
989  }
990  bool isForbidden = false;
991  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
992  if (state[i2] == 'G' && !isTurnaround[i2] &&
993  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
994  isForbidden = true;
995  break;
996  }
997  }
998  if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
999  state[i1] = 'G';
1000  }
1001  }
1002  return state;
1003 }
1004 
1005 
1006 std::string
1007 NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
1008  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1009  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
1010  if ((linkPerm & ~perm) == 0) {
1011  state[i1] = 'G';
1012  }
1013  }
1014  return state;
1015 }
1016 
1017 
1018 bool
1019 NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1020  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1021  if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
1022  return true;
1023  }
1024  }
1025  return false;
1026 }
1027 
1028 
1029 std::string
1030 NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1031  const std::vector<bool>& isTurnaround,
1032  const std::vector<int>& fromLanes,
1033  const std::vector<int>& toLanes,
1034  const std::vector<bool>& hadGreenMajor,
1035  bool& haveForbiddenLeftMover,
1036  std::vector<bool>& rightTurnConflicts,
1037  std::vector<bool>& mergeConflicts) {
1038  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
1039  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1040  if (state[i1] == 'G') {
1041  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1042  if ((state[i2] == 'G' || state[i2] == 'g')) {
1044  fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
1045  rightTurnConflicts[i1] = true;
1046  }
1047  if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
1048  state[i1] = 'g';
1049  myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
1050  if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
1051  haveForbiddenLeftMover = true;
1052  }
1053  } else if (fromEdges[i1] == fromEdges[i2]
1054  && fromLanes[i1] != fromLanes[i2]
1055  && toEdges[i1] == toEdges[i2]
1056  && toLanes[i1] == toLanes[i2]
1057  && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
1058  mergeConflicts[i1] = true;
1059  state[i1] = 'g';
1060  }
1061  }
1062  }
1063  }
1064  if (state[i1] == 'r') {
1065  if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
1066  fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
1067  state[i1] = 's';
1068  // do not allow right-on-red when in conflict with exclusive left-turn phase
1069  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1070  if (state[i2] == 'G' && !isTurnaround[i2] &&
1071  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1072  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1073  const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
1074  if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
1075  state[i1] = 'r';
1076  break;
1077  }
1078  }
1079  }
1080  if (state[i1] == 's') {
1081  // handle right-on-red conflicts
1082  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1083  if (state[i2] == 'G' && !isTurnaround[i2] &&
1084  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1085  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1086  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
1087  }
1088  }
1089  }
1090  }
1091  }
1092  }
1093  return state;
1094 }
1095 
1096 
1097 std::string
1098 NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
1099  const std::vector<int>& fromLanes,
1100  bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
1101  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1102  if ((state[i1] == 'G' || state[i1] == 'g')) {
1103  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1104  if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
1105  && state[i2] != 'G' && state[i2] != 'g') {
1106  state[i1] = state[i2];
1107  //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
1108  mixedGreen[i1] = true;
1109  if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
1110  buildMixedGreenPhase = true;
1111  }
1112  }
1113  }
1114  }
1115  }
1116  return state;
1117 }
1118 
1119 
1120 void
1121 NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int noLinksAll, SUMOTime /* greenTime */, SUMOTime brakingTime,
1122  const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1123  const int vehLinks = noLinksAll - (int)crossings.size();
1124  std::vector<bool> foundGreen(crossings.size(), false);
1125  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
1126  for (int i = 0; i < (int)phases.size(); ++i) {
1127  const std::string state = phases[i].state;
1128  for (int j = 0; j < (int)crossings.size(); ++j) {
1129  LinkState ls = (LinkState)state[vehLinks + j];
1131  foundGreen[j] = true;
1132  }
1133  }
1134  }
1135  for (int j = 0; j < (int)foundGreen.size(); ++j) {
1136  if (!foundGreen[j]) {
1137 
1138  // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
1139  if (phases.size() > 0) {
1140  bool needYellowPhase = false;
1141  std::string state = phases.back().state;
1142  for (int i1 = 0; i1 < vehLinks; ++i1) {
1143  if (state[i1] == 'G' || state[i1] == 'g') {
1144  state[i1] = 'y';
1145  needYellowPhase = true;
1146  }
1147  }
1148  // add yellow step
1149  if (needYellowPhase && brakingTime > 0) {
1150  logic->addStep(brakingTime, state);
1151  }
1152  }
1153  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
1154  const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
1155  addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(noLinksAll, 'r'), crossings, fromEdges, toEdges);
1156  break;
1157  }
1158  }
1159 }
1160 
1161 
1162 void
1163 NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
1164  if (allRedTime > 0) {
1165  // build all-red phase
1166  std::string allRedState = state;
1167  for (int i1 = 0; i1 < (int)state.size(); ++i1) {
1168  if (allRedState[i1] == 'Y' || allRedState[i1] == 'y') {
1169  allRedState[i1] = 'r';
1170  }
1171  }
1172  logic->addStep(allRedTime, allRedState);
1173  }
1174 }
1175 
1176 void
1178  int minCustomIndex = -1;
1179  int maxCustomIndex = -1;
1180  // collect crossings
1181  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1182  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1183  for (auto crossing : c) {
1184  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
1185  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
1186  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
1187  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
1188  }
1189  }
1190  // custom crossing linkIndex could lead to longer states. ensure that every index has a state
1191  if (maxCustomIndex >= logic->getNumLinks()) {
1192  logic->setStateLength(maxCustomIndex + 1);
1193  }
1194  // XXX shorter state vectors are possible as well
1195  // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
1196  // XXX initialize the backward index to the same state as the forward index
1197 }
1198 
1199 void
1201  // assume that yellow states last at most one phase
1202  const int n = logic->getNumLinks();
1203  const int p = (int)logic->getPhases().size();
1204  for (int i1 = 0; i1 < n; ++i1) {
1205  LinkState prev = (LinkState)logic->getPhases().back().state[i1];
1206  for (int i2 = 0; i2 < p; ++i2) {
1207  LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
1208  LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
1209  if (cur == LINKSTATE_TL_YELLOW_MINOR
1210  && (prev == LINKSTATE_TL_GREEN_MAJOR || prev == LINKSTATE_TL_YELLOW_MINOR)
1211  && next == LINKSTATE_TL_GREEN_MAJOR) {
1212  logic->setPhaseState(i2, i1, prev);
1213  }
1214  prev = cur;
1215  }
1216  }
1217 }
1218 
1219 
1220 void
1222  const int n = logic->getNumLinks();
1223  std::vector<bool> alwaysGreen(n, true);
1224  for (int i1 = 0; i1 < n; ++i1) {
1225  for (const auto& phase : logic->getPhases()) {
1226  if (phase.state[i1] != 'G') {
1227  alwaysGreen[i1] = false;
1228  break;
1229  }
1230  }
1231  }
1232  const int p = (int)logic->getPhases().size();
1233  for (int i1 = 0; i1 < n; ++i1) {
1234  if (alwaysGreen[i1]) {
1235  for (int i2 = 0; i2 < p; ++i2) {
1236  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1237  }
1238  }
1239  }
1240 }
1241 
1242 
1243 void
1245  const int n = logic->getNumLinks();
1246  const int p = (int)logic->getPhases().size();
1247  for (int i1 = 0; i1 < n; ++i1) {
1248  if (fromEdges[i1]->isInsideTLS()) {
1249  for (int i2 = 0; i2 < p; ++i2) {
1250  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1251  }
1252  }
1253  }
1254 }
1255 
1256 
1257 SUMOTime
1258 NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
1259  const int n = (int)state.size();
1260  double maxTime = 0;
1261  for (int i1 = 0; i1 < n; ++i1) {
1262  if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
1263  for (int i2 = 0; i2 < n; ++i2) {
1264  if (fromEdges[i2]->isInsideTLS()) {
1265  double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1266  double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1267  maxTime = MAX2(maxTime, time);
1268  }
1269  }
1270  }
1271  }
1272  // give some slack
1273  return TIME2STEPS(floor(maxTime * 1.2 + 5));
1274 }
1275 
1276 
1277 int
1281  if (logic != nullptr) {
1282  return logic->getNumLinks() - 1;
1283  } else {
1284  return -1;
1285  }
1286 }
1287 
1288 
1289 bool
1291  if (getID() == DummyID) {
1292  // avoid infinite recursion
1293  return true;
1294  }
1295  assert(myControlledNodes.size() >= 2);
1298  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1299  int greenPhases = 0;
1300  for (const auto& phase : tllDummy->getPhases()) {
1301  if (phase.state.find_first_of("gG") != std::string::npos) {
1302  greenPhases++;
1303  }
1304  }
1305  delete tllDummy;
1306  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1307  (*i)->removeTrafficLight(&dummy);
1308  }
1309  return greenPhases <= 2;
1310 }
1311 
1312 
1313 /****************************************************************************/
@ DEFAULT
default cursor
#define DEBUGCOND(PEDID)
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
#define MIN_GREEN_TIME
Definition: NBOwnTLDef.cpp:41
#define HEIGH_WEIGHT
Definition: NBOwnTLDef.cpp:38
#define LOW_WEIGHT
Definition: NBOwnTLDef.cpp:39
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define SUMOTime_MAX
Definition: SUMOTime.h:33
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightType
TrafficLightLayout
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_YELLOW_MINOR
The link has yellow light, has to brake anyway.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
@ LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
T MIN2(T a, T b)
Definition: StdDefs.h:74
T MAX2(T a, T b)
Definition: StdDefs.h:80
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:173
NBEdge * getFrom() const
returns the from-edge (start of the connection)
The representation of a single edge during network building.
Definition: NBEdge.h:91
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4022
const std::string & getID() const
Definition: NBEdge.h:1465
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:541
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3420
std::vector< Connection > getConnectionsFromLane(int lane, NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1206
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:515
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:2027
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3684
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:1006
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:534
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:129
const NBNode * node
The parent node of this crossing.
Definition: NBNode.h:134
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:136
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:2221
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:1925
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:1906
Sorts edges by their priority within the node they end at.
Definition: NBOwnTLDef.h:295
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
bool forbidden(const std::string &state, int index, const EdgeVector &fromEdges, const EdgeVector &toEdges)
whether the given index is forbidden by a green link in the current state
void fixSuperfluousYellow(NBTrafficLightLogic *logic) const
avoid yellow signal between successive green (major) phases
std::string correctConflicting(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< int > &fromLanes, const std::vector< int > &toLanes, const std::vector< bool > &hadGreenMajor, bool &haveForbiddenLeftMover, std::vector< bool > &rightTurnConflicts, std::vector< bool > &mergeConflicts)
change 'G' to 'g' for conflicting connections
void checkCustomCrossingIndices(NBTrafficLightLogic *logic) const
fix states in regard to custom crossing indices
static std::string patchStateForCrossings(const std::string &state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
compute phase state in regard to pedestrian crossings
Definition: NBOwnTLDef.cpp:774
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:312
bool corridorLike() const
test whether a joined tls with layout 'opposites' would be built without dedicated left-turn phase
SUMOTime computeEscapeTime(const std::string &state, const EdgeVector &fromEdges, const EdgeVector &toEdges) const
compute time to clear all vehicles from within an alternateOneWay layout
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces a removed edge/lane.
Definition: NBOwnTLDef.cpp:846
std::pair< NBEdge *, NBEdge * > getBestPair(EdgeVector &incoming)
Returns the combination of two edges from the given which has most unblocked streams.
Definition: NBOwnTLDef.cpp:200
~NBOwnTLDef()
Destructor.
Definition: NBOwnTLDef.cpp:78
void collectLinks()
Collects the links participating in this traffic light.
Definition: NBOwnTLDef.cpp:822
void deactivateAlwaysGreen(NBTrafficLightLogic *logic) const
switch of signal for links that are always green
NBTrafficLightLogic * computeLogicAndConts(int brakingTimeSeconds, bool onlyConts=false)
helper function for myCompute
Definition: NBOwnTLDef.cpp:252
static bool hasCrossing(const NBEdge *from, const NBEdge *to, const std::vector< NBNode::Crossing * > &crossings)
compute whether the given connection is crossed by pedestrians
Definition: NBOwnTLDef.cpp:724
std::string allowPredecessors(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
Definition: NBOwnTLDef.cpp:950
void deactivateInsideEdges(NBTrafficLightLogic *logic, const EdgeVector &fromEdges) const
switch of signal for links that are inside a joined tls
double computeUnblockedWeightedStreamNumber(const NBEdge *const e1, const NBEdge *const e2)
Returns how many streams outgoing from the edges can pass the junction without being blocked.
Definition: NBOwnTLDef.cpp:104
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurences of the removed edge in incoming/outgoing edges of all definitions.
Definition: NBOwnTLDef.cpp:841
int getToPrio(const NBEdge *const e)
Returns this edge's priority at the node it ends at.
Definition: NBOwnTLDef.cpp:82
std::string allowCompatible(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
allow connections that are compatible with the chosen edges
Definition: NBOwnTLDef.cpp:885
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
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
Definition: NBOwnTLDef.cpp:247
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, SUMOTime greenTime, SUMOTime minDur, SUMOTime maxDur, std::string state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add 1 or 2 phases depending on the presence of pedestrian crossings
Definition: NBOwnTLDef.cpp:743
std::string allowFollowers(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
Definition: NBOwnTLDef.cpp:920
void buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic *logic, const std::string &state)
double getDirectionalWeight(LinkDirection dir)
Returns the weight of a stream given its direction.
Definition: NBOwnTLDef.cpp:88
std::string allowSingleEdge(std::string state, const EdgeVector &fromEdges)
Definition: NBOwnTLDef.cpp:895
bool hasStraightConnection(const NBEdge *fromEdge)
check whether there is a straight connection from this edge
Definition: NBOwnTLDef.cpp:236
std::pair< NBEdge *, NBEdge * > getBestCombination(const EdgeVector &edges)
Returns the combination of two edges from the given which has most unblocked streams.
Definition: NBOwnTLDef.cpp:163
void initNeedsContRelation() const
Definition: NBOwnTLDef.cpp:851
NBOwnTLDef(const std::string &id, const std::vector< NBNode * > &junctions, SUMOTime offset, TrafficLightType type)
Constructor.
Definition: NBOwnTLDef.cpp:53
static EdgeVector getConnectedOuterEdges(const EdgeVector &incoming)
get edges that have connections
Definition: NBOwnTLDef.cpp:871
static void addPedestrianScramble(NBTrafficLightLogic *logic, int noLinksAll, 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
TrafficLightLayout myLayout
the layout for generated signal plans
Definition: NBOwnTLDef.h:315
std::string allowUnrelated(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< NBNode::Crossing * > &crossings)
Definition: NBOwnTLDef.cpp:983
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
Definition: NBOwnTLDef.cpp:829
The base class for traffic light logic definitions.
const std::string & getProgramID() const
Returns the ProgramID.
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
RightOnRedConflicts myRightOnRedConflicts
TrafficLightType myType
The algorithm type for the traffic light.
static const std::string DummyID
id for temporary definitions
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority, bool sameNodeOnly=false) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
NBTrafficLightLogic * compute(OptionsCont &oc)
Computes the traffic light logic.
NBConnectionVector myControlledLinks
The list of controlled links.
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
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
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)
int getNumLinks()
Returns the number of participating links.
void addStep(SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", int index=-1)
Adds a phase to the logic.
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
static StringBijection< TrafficLightLayout > TrafficLightLayouts
traffic light layouts
T get(const std::string &str) const
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:197
data structure for caching needsCont information