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-2020 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 
236 NBOwnTLDef::myCompute(int brakingTimeSeconds) {
237  return computeLogicAndConts(brakingTimeSeconds);
238 }
239 
241 NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
242  myNeedsContRelation.clear();
243  myRightOnRedConflicts.clear();
244  const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
245  const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
246  const SUMOTime minMinDur = myType == TrafficLightType::STATIC ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
248 
249  // build complete lists first
250  const EdgeVector& incoming = getIncomingEdges();
251  EdgeVector fromEdges, toEdges;
252  std::vector<bool> isTurnaround;
253  std::vector<bool> hasTurnLane;
254  std::vector<int> fromLanes;
255  std::vector<int> toLanes;
256  int noLinksAll = 0;
257  for (NBEdge* const fromEdge : incoming) {
258  const int numLanes = fromEdge->getNumLanes();
259  for (int i2 = 0; i2 < numLanes; i2++) {
260  bool hasLeft = false;
261  bool hasStraight = false;
262  bool hasRight = false;
263  bool hasTurnaround = false;
264  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
265  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
266  continue;
267  }
268  fromEdges.push_back(fromEdge);
269  fromLanes.push_back(i2);
270  toLanes.push_back(approached.toLane);
271  toEdges.push_back(approached.toEdge);
272  if (approached.toEdge != nullptr) {
273  isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
274  } else {
275  isTurnaround.push_back(true);
276  }
277  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
278  if (dir == LinkDirection::STRAIGHT) {
279  hasStraight = true;
280  } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
281  hasRight = true;
282  } else if (dir == LinkDirection::LEFT || dir == LinkDirection::PARTLEFT) {
283  hasLeft = true;
284  } else if (dir == LinkDirection::TURN) {
285  hasTurnaround = true;
286  }
287  noLinksAll++;
288  }
289  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
290  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
291  continue;
292  }
293  hasTurnLane.push_back(
294  (hasLeft && !hasStraight && !hasRight)
295  || (!hasLeft && !hasTurnaround && hasRight));
296  }
297  //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
298  }
299  }
300  // collect crossings
301  std::vector<NBNode::Crossing*> crossings;
302  for (NBNode* const node : myControlledNodes) {
303  const std::vector<NBNode::Crossing*>& c = node->getCrossings();
304  if (!onlyConts) {
305  // set tl indices for crossings
306  node->setCrossingTLIndices(getID(), noLinksAll);
307  }
308  copy(c.begin(), c.end(), std::back_inserter(crossings));
309  noLinksAll += (int)c.size();
310  }
311 
312  NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), noLinksAll, myOffset, myType);
313  EdgeVector toProc = getConnectedOuterEdges(incoming);
314  const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
315  SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
316  const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
317  // left-turn phases do not work well for joined tls, so we build incoming instead
319  // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
321  }
322  const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
323 
324  // build all phases
325  std::vector<int> greenPhases; // indices of green phases
326  std::vector<bool> hadGreenMajor(noLinksAll, false);
327  while (toProc.size() > 0) {
328  bool groupTram = false;
329  bool groupOther = false;
330  std::pair<NBEdge*, NBEdge*> chosen;
331  if (groupOpposites) {
332  if (incoming.size() == 2) {
333  // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
334  // @node: this heuristic could be extended to also check the number of outgoing edges
335  double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
336  // angle would be 180 for straight opposing incoming edges
337  if (angle < 135) {
338  chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
339  toProc.erase(toProc.begin());
340  } else {
341  chosen = getBestPair(toProc);
342  }
343  } else {
344  chosen = getBestPair(toProc);
345  if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
346  groupTram = true;
347  for (auto it = toProc.begin(); it != toProc.end();) {
348  if ((*it)->getPermissions() == SVC_TRAM) {
349  it = toProc.erase(it);
350  } else {
351  it++;
352  }
353  }
354  }
355  }
356  } else {
357  NBEdge* chosenEdge = toProc[0];
358  chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
359  toProc.erase(toProc.begin());
360  SVCPermissions perms = chosenEdge->getPermissions();
361  if (perms == SVC_TRAM) {
362  groupTram = true;
363  } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
364  groupOther = true;
365  }
366  // group all edges with the same permissions into a single phase (later)
367  if (groupTram || groupOther) {
368  for (auto it = toProc.begin(); it != toProc.end();) {
369  if ((*it)->getPermissions() == perms) {
370  it = toProc.erase(it);
371  } else {
372  it++;
373  }
374  }
375  }
376  }
377  int pos = 0;
378  std::string state((int) noLinksAll, 'r');
379 #ifdef DEBUG_PHASES
380  if (DEBUGCOND) {
381  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";
382  }
383 #endif
384  // plain straight movers
385  double maxSpeed = 0;
386  bool haveGreen = false;
387  for (const NBEdge* const fromEdge : incoming) {
388  const bool inChosen = fromEdge == chosen.first || fromEdge == chosen.second; //chosen.find(fromEdge)!=chosen.end();
389  const int numLanes = fromEdge->getNumLanes();
390  for (int i2 = 0; i2 < numLanes; i2++) {
391  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
392  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
393  continue;
394  }
395  if (inChosen) {
396  state[pos] = 'G';
397  haveGreen = true;
398  maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
399  } else {
400  state[pos] = 'r';
401  }
402  ++pos;
403  }
404  }
405  }
406  if (!haveGreen) {
407  continue;
408  }
409 
410 #ifdef DEBUG_PHASES
411  if (DEBUGCOND) {
412  std::cout << " state after plain straight movers " << state << "\n";
413  }
414 #endif
415  // correct behaviour for those that are not in chosen, but may drive, though
416  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
417  if (groupTram) {
418  state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
419  } else if (groupOther) {
420  state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
421  }
422 #ifdef DEBUG_PHASES
423  if (DEBUGCOND) {
424  std::cout << " state after grouping by vClass " << state << "\n";
425  }
426 #endif
427  if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
428  state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
429  }
430 #ifdef DEBUG_PHASES
431  if (DEBUGCOND) {
432  std::cout << " state after finding allowUnrelated " << state << "\n";
433  }
434 #endif
435  // correct behaviour for those that have to wait (mainly left-mover)
436  bool haveForbiddenLeftMover = false;
437  std::vector<bool> rightTurnConflicts(pos, false);
438  std::vector<bool> mergeConflicts(pos, false);
439  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
440  for (int i1 = 0; i1 < pos; ++i1) {
441  if (state[i1] == 'G') {
442  hadGreenMajor[i1] = true;
443  }
444  }
445 #ifdef DEBUG_PHASES
446  if (DEBUGCOND) {
447  std::cout << " state after correcting left movers=" << state << "\n";
448  }
449 #endif
450 
451  std::vector<bool> leftGreen(pos, false);
452  // check whether at least one left-turn lane exist
453  bool foundLeftTurnLane = false;
454  for (int i1 = 0; i1 < pos; ++i1) {
455  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
456  foundLeftTurnLane = true;
457  }
458  }
459  const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
460  && groupOpposites && !groupTram && !groupOther);
461 
462  // find indices for exclusive left green phase and apply option minor-left.max-speed
463  for (int i1 = 0; i1 < pos; ++i1) {
464  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
465  // only activate turn-around together with a real left-turn
466  && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
467  leftGreen[i1] = true;
468  if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
469  if (buildLeftGreenPhase) {
470  state[i1] = 'r';
471  //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
472  } else if (!isTurnaround[i1]) {
473  WRITE_WARNINGF("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing.",
474  fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
475  }
476  }
477  }
478  }
479 
480 #ifdef DEBUG_PHASES
481  if (DEBUGCOND) {
482  std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
483  << " \nrtC=" << toString(rightTurnConflicts)
484  << " \nmC=" << toString(mergeConflicts)
485  << " \nhTL=" << toString(hasTurnLane)
486  << " \nlGr=" << toString(leftGreen)
487  << "\n";
488  }
489 #endif
490 
491  const std::string vehicleState = state; // backup state before pedestrian modifications
492  greenPhases.push_back((int)logic->getPhases().size());
493 
494  // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
495  const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
496  SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
497  if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
498  // shorter minDuration for tram phase (only if the phase is
499  // exclusively for tram)
500  bool tramExclusive = true;
501  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
502  if (state[i1] == 'G') {
503  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
504  if (linkPerm != SVC_TRAM) {
505  tramExclusive = false;
506  break;
507  }
508  }
509  }
510  if (tramExclusive) {
511  // one tram per actuated phase
512  minDur = TIME2STEPS(1);
513  }
514  }
515 
516  state = addPedestrianPhases(logic, greenTime, minDur, maxDur, state, crossings, fromEdges, toEdges);
517  // pedestrians have 'r' from here on
518  for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
519  state[i1] = 'r';
520  }
521  if (brakingTime > 0) {
522  // build yellow (straight)
523  for (int i1 = 0; i1 < pos; ++i1) {
524  if (state[i1] != 'G' && state[i1] != 'g') {
525  continue;
526  }
527  if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
528  && buildLeftGreenPhase
529  && !rightTurnConflicts[i1]
530  && !mergeConflicts[i1]
531  && leftGreen[i1]) {
532  continue;
533  }
534  state[i1] = 'y';
535  }
536  // add step
537  logic->addStep(brakingTime, state);
538  // add optional all-red state
540  allRedTime = computeEscapeTime(state, fromEdges, toEdges);
541  }
542  buildAllRedState(allRedTime, logic, state);
543  }
544 
545 
546  if (buildLeftGreenPhase) {
547  // build left green
548  for (int i1 = 0; i1 < pos; ++i1) {
549  if (state[i1] == 'Y' || state[i1] == 'y') {
550  state[i1] = 'r';
551  continue;
552  }
553  if (leftGreen[i1]) {
554  state[i1] = 'G';
555  }
556  }
557  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
558  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
559 
560  // add step
561  logic->addStep(leftTurnTime, state, minDur, maxDur);
562 
563  // build left yellow
564  if (brakingTime > 0) {
565  for (int i1 = 0; i1 < pos; ++i1) {
566  if (state[i1] != 'G' && state[i1] != 'g') {
567  continue;
568  }
569  state[i1] = 'y';
570  }
571  // add step
572  logic->addStep(brakingTime, state);
573  // add optional all-red state
574  buildAllRedState(allRedTime, logic, state);
575  }
576  }
577  }
578  // fix pedestrian crossings that did not get the green light yet
579  if (crossings.size() > 0) {
580  addPedestrianScramble(logic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
581  }
582  // add optional red phase if there where no foes
583  if (logic->getPhases().size() == 2 && brakingTime > 0
584  && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
585  const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
586  logic->addStep(redTime, std::string(noLinksAll, 'r'));
587  }
588  // fix states to account for custom crossing link indices
589  if (crossings.size() > 0 && !onlyConts) {
591  }
592 
594  // exiting the oneway section should always be possible
595  deactivateInsideEdges(logic, fromEdges);
596  }
597 
598  SUMOTime totalDuration = logic->getDuration();
599  if (OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) {
600  const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
601  // adapt to cycle time by changing the duration of the green phases
602  SUMOTime greenPhaseTime = 0;
603  SUMOTime minGreenDuration = SUMOTime_MAX;
604  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
605  const SUMOTime dur = logic->getPhases()[*it].duration;
606  greenPhaseTime += dur;
607  minGreenDuration = MIN2(minGreenDuration, dur);
608  }
609  const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / greenPhases.size());
610  const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
611  //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
612  if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
613  || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
614  || greenPhases.size() == 0) {
615  if (getID() != DummyID) {
616  WRITE_WARNINGF("The traffic light '%' cannot be adapted to a cycle time of %.", getID(), time2string(cycleTime));
617  }
618  // @todo use a multiple of cycleTime ?
619  } else {
620  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
621  logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
622  }
623  if (greenPhases.size() > 0) {
624  logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
625  }
626  totalDuration = logic->getDuration();
627  }
628  }
629 
631  // this computation only makes sense for single nodes
633  if (totalDuration > 0) {
634  if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime)) {
635  WRITE_WARNINGF("The traffic light '%' has a high cycle time of %.", getID(), time2string(totalDuration));
636  }
637  logic->closeBuilding();
638  return logic;
639  } else {
640  delete logic;
641  return nullptr;
642  }
643 }
644 
645 
646 bool
647 NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
648  assert(to != 0);
649  for (auto c : crossings) {
650  const NBNode::Crossing& cross = *c;
651  // only check connections at this crossings node
652  if (to->getFromNode() == cross.node) {
653  for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
654  const NBEdge* edge = *it_e;
655  if (edge == from || edge == to) {
656  return true;
657  }
658  }
659  }
660  }
661  return false;
662 }
663 
664 
665 std::string
667  SUMOTime minDur, SUMOTime maxDur,
668  std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
669  // compute based on length of the crossing if not set by the user
670  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
671  // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
672  const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
673  const std::string orig = state;
674  state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
675  if (orig == state) {
676  // add step
677  logic->addStep(greenTime, state, minDur, maxDur);
678  } else {
679  const SUMOTime pedTime = greenTime - pedClearingTime;
680  if (pedTime >= minPedTime) {
681  // ensure clearing time for pedestrians
682  const int pedStates = (int)crossings.size();
683  logic->addStep(pedTime, state, minDur, maxDur);
684  state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
685  logic->addStep(pedClearingTime, state);
686  } else {
687  state = orig;
688  // not safe for pedestrians.
689  logic->addStep(greenTime, state, minDur, maxDur);
690  }
691  }
692  return state;
693 }
694 
695 
696 std::string
697 NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
698  std::string result = state;
699  const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
700  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
701  const int i1 = pos + ic;
702  const NBNode::Crossing& cross = *crossings[ic];
703  bool isForbidden = false;
704  for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
705  // only check connections at this crossings node
706  if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
707  for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
708  const NBEdge* edge = *it;
709  const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
710  if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
711  (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
712  isForbidden = true;
713  break;
714  }
715  }
716  }
717  }
718  if (!isForbidden) {
719  result[i1] = 'G';
720  } else {
721  result[i1] = 'r';
722  }
723  }
724 
725  // correct behaviour for roads that are in conflict with a pedestrian crossing
726  for (int i1 = 0; i1 < pos; ++i1) {
727  if (result[i1] == 'G') {
728  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
729  const NBNode::Crossing& crossing = *crossings[ic];
730  if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
731  const int i2 = pos + ic;
732  if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
733  result[i1] = 'g';
734  break;
735  }
736  }
737  }
738  }
739  }
740  return result;
741 }
742 
743 
744 void
746  myControlledLinks.clear();
748 }
749 
750 
751 void
753  // set the information about the link's positions within the tl into the
754  // edges the links are starting at, respectively
755  for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
756  const NBConnection& conn = *j;
757  NBEdge* edge = conn.getFrom();
758  edge->setControllingTLInformation(conn, getID());
759  }
760 }
761 
762 
763 void
764 NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
765  const EdgeVector& /*outgoing*/) {}
766 
767 
768 void
769 NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
770  NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
771 
772 
773 void
776  if (myControlledNodes.size() > 0) {
777  // we use a dummy node just to maintain const-correctness
778  myNeedsContRelation.clear();
781  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
782  delete tllDummy;
784  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
785  (*i)->removeTrafficLight(&dummy);
786  }
787  }
789  }
790 }
791 
792 
795  EdgeVector result = incoming;
796  for (EdgeVector::iterator it = result.begin(); it != result.end();) {
797  if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
798  it = result.erase(it);
799  } else {
800  ++it;
801  }
802  }
803  return result;
804 }
805 
806 
807 std::string
808 NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
809  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
810  state = allowSingleEdge(state, fromEdges);
811  state = allowFollowers(state, fromEdges, toEdges);
812  state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
813  return state;
814 }
815 
816 
817 std::string
818 NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
819  // if only one edge has green, ensure sure that all connections from that edge are green
820  const int size = (int)fromEdges.size();
821  NBEdge* greenEdge = nullptr;
822  for (int i1 = 0; i1 < size; ++i1) {
823  if (state[i1] == 'G') {
824  if (greenEdge == nullptr) {
825  greenEdge = fromEdges[i1];
826  } else if (greenEdge != fromEdges[i1]) {
827  return state;
828  }
829  }
830  }
831  if (greenEdge != nullptr) {
832  for (int i1 = 0; i1 < size; ++i1) {
833  if (fromEdges[i1] == greenEdge) {
834  state[i1] = 'G';
835  }
836  }
837  }
838  return state;
839 }
840 
841 
842 std::string
843 NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
844  // check continuation within joined traffic lights
845  bool check = true;
846  while (check) {
847  check = false;
848  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
849  if (state[i1] == 'G') {
850  continue;
851  }
852  //if (forbidden(state, i1, fromEdges, toEdges)) {
853  // continue;
854  //}
855  bool followsChosen = false;
856  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
857  if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
858  followsChosen = true;
859  break;
860  }
861  }
862  if (followsChosen) {
863  state[i1] = 'G';
864  check = true;
865  }
866  }
867  }
868  return state;
869 }
870 
871 
872 std::string
873 NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
874  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
875  // also allow predecessors of chosen edges if the lanes match and there is no conflict
876  // (must be done after the followers are done because followers are less specific)
877  bool check = true;
878  while (check) {
879  check = false;
880  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
881  if (state[i1] == 'G') {
882  continue;
883  }
884  if (forbidden(state, i1, fromEdges, toEdges)) {
885  continue;
886  }
887  bool preceedsChosen = false;
888  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
889  if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
890  && fromLanes[i2] == toLanes[i1]) {
891  preceedsChosen = true;
892  break;
893  }
894  }
895  if (preceedsChosen) {
896  state[i1] = 'G';
897  check = true;
898  }
899  }
900  }
901  return state;
902 }
903 
904 
905 std::string
906 NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
907  const std::vector<bool>& isTurnaround,
908  const std::vector<NBNode::Crossing*>& crossings) {
909  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
910  if (state[i1] == 'G') {
911  continue;
912  }
913  bool isForbidden = false;
914  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
915  if (state[i2] == 'G' && !isTurnaround[i2] &&
916  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
917  isForbidden = true;
918  break;
919  }
920  }
921  if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
922  state[i1] = 'G';
923  }
924  }
925  return state;
926 }
927 
928 
929 std::string
930 NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
931  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
932  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
933  if ((linkPerm & ~perm) == 0) {
934  state[i1] = 'G';
935  }
936  }
937  return state;
938 }
939 
940 
941 bool
942 NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
943  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
944  if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
945  return true;
946  }
947  }
948  return false;
949 }
950 
951 
952 std::string
953 NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
954  const std::vector<bool>& isTurnaround,
955  const std::vector<int>& fromLanes,
956  const std::vector<int>& toLanes,
957  const std::vector<bool>& hadGreenMajor,
958  bool& haveForbiddenLeftMover,
959  std::vector<bool>& rightTurnConflicts,
960  std::vector<bool>& mergeConflicts) {
961  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
962  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
963  if (state[i1] == 'G') {
964  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
965  if ((state[i2] == 'G' || state[i2] == 'g')) {
967  fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
968  rightTurnConflicts[i1] = true;
969  }
970  if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
971  state[i1] = 'g';
972  myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
973  if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
974  haveForbiddenLeftMover = true;
975  }
976  } else if (fromEdges[i1] == fromEdges[i2]
977  && fromLanes[i1] != fromLanes[i2]
978  && toEdges[i1] == toEdges[i2]
979  && toLanes[i1] == toLanes[i2]
980  && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
981  mergeConflicts[i1] = true;
982  state[i1] = 'g';
983  }
984  }
985  }
986  }
987  if (state[i1] == 'r') {
988  if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
989  fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
990  state[i1] = 's';
991  // do not allow right-on-red when in conflict with exclusive left-turn phase
992  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
993  if (state[i2] == 'G' && !isTurnaround[i2] &&
994  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
995  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
996  const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
997  if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
998  state[i1] = 'r';
999  break;
1000  }
1001  }
1002  }
1003  if (state[i1] == 's') {
1004  // handle right-on-red conflicts
1005  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1006  if (state[i2] == 'G' && !isTurnaround[i2] &&
1007  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1008  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1009  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
1010  }
1011  }
1012  }
1013  }
1014  }
1015  }
1016  return state;
1017 }
1018 
1019 
1020 void
1021 NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int noLinksAll, SUMOTime /* greenTime */, SUMOTime brakingTime,
1022  const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1023  const int vehLinks = noLinksAll - (int)crossings.size();
1024  std::vector<bool> foundGreen(crossings.size(), false);
1025  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
1026  for (int i = 0; i < (int)phases.size(); ++i) {
1027  const std::string state = phases[i].state;
1028  for (int j = 0; j < (int)crossings.size(); ++j) {
1029  LinkState ls = (LinkState)state[vehLinks + j];
1031  foundGreen[j] = true;
1032  }
1033  }
1034  }
1035  for (int j = 0; j < (int)foundGreen.size(); ++j) {
1036  if (!foundGreen[j]) {
1037 
1038  // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
1039  if (phases.size() > 0) {
1040  bool needYellowPhase = false;
1041  std::string state = phases.back().state;
1042  for (int i1 = 0; i1 < vehLinks; ++i1) {
1043  if (state[i1] == 'G' || state[i1] == 'g') {
1044  state[i1] = 'y';
1045  needYellowPhase = true;
1046  }
1047  }
1048  // add yellow step
1049  if (needYellowPhase && brakingTime > 0) {
1050  logic->addStep(brakingTime, state);
1051  }
1052  }
1053  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
1054  const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
1055  addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(noLinksAll, 'r'), crossings, fromEdges, toEdges);
1056  break;
1057  }
1058  }
1059 }
1060 
1061 
1062 void
1063 NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
1064  if (allRedTime > 0) {
1065  // build all-red phase
1066  std::string allRedState = state;
1067  for (int i1 = 0; i1 < (int)state.size(); ++i1) {
1068  if (allRedState[i1] == 'Y' || allRedState[i1] == 'y') {
1069  allRedState[i1] = 'r';
1070  }
1071  }
1072  logic->addStep(allRedTime, allRedState);
1073  }
1074 }
1075 
1076 void
1078  int minCustomIndex = -1;
1079  int maxCustomIndex = -1;
1080  // collect crossings
1081  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1082  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1083  for (auto crossing : c) {
1084  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
1085  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
1086  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
1087  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
1088  }
1089  }
1090  // custom crossing linkIndex could lead to longer states. ensure that every index has a state
1091  if (maxCustomIndex >= logic->getNumLinks()) {
1092  logic->setStateLength(maxCustomIndex + 1);
1093  }
1094  // XXX shorter state vectors are possible as well
1095  // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
1096  // XXX initialize the backward index to the same state as the forward index
1097 }
1098 
1099 void
1101  // assume that yellow states last at most one phase
1102  const int n = logic->getNumLinks();
1103  const int p = (int)logic->getPhases().size();
1104  for (int i1 = 0; i1 < n; ++i1) {
1105  LinkState prev = (LinkState)logic->getPhases().back().state[i1];
1106  for (int i2 = 0; i2 < p; ++i2) {
1107  LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
1108  LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
1109  if (cur == LINKSTATE_TL_YELLOW_MINOR
1110  && (prev == LINKSTATE_TL_GREEN_MAJOR || prev == LINKSTATE_TL_YELLOW_MINOR)
1111  && next == LINKSTATE_TL_GREEN_MAJOR) {
1112  logic->setPhaseState(i2, i1, prev);
1113  }
1114  prev = cur;
1115  }
1116  }
1117 }
1118 
1119 
1120 void
1122  const int n = logic->getNumLinks();
1123  std::vector<bool> alwaysGreen(n, true);
1124  for (int i1 = 0; i1 < n; ++i1) {
1125  for (const auto& phase : logic->getPhases()) {
1126  if (phase.state[i1] != 'G') {
1127  alwaysGreen[i1] = false;
1128  break;
1129  }
1130  }
1131  }
1132  const int p = (int)logic->getPhases().size();
1133  for (int i1 = 0; i1 < n; ++i1) {
1134  if (alwaysGreen[i1]) {
1135  for (int i2 = 0; i2 < p; ++i2) {
1136  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1137  }
1138  }
1139  }
1140 }
1141 
1142 
1143 void
1145  const int n = logic->getNumLinks();
1146  const int p = (int)logic->getPhases().size();
1147  for (int i1 = 0; i1 < n; ++i1) {
1148  if (fromEdges[i1]->isInsideTLS()) {
1149  for (int i2 = 0; i2 < p; ++i2) {
1150  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1151  }
1152  }
1153  }
1154 }
1155 
1156 
1157 SUMOTime
1158 NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
1159  const int n = (int)state.size();
1160  double maxTime = 0;
1161  for (int i1 = 0; i1 < n; ++i1) {
1162  if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
1163  for (int i2 = 0; i2 < n; ++i2) {
1164  if (fromEdges[i2]->isInsideTLS()) {
1165  double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1166  double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1167  maxTime = MAX2(maxTime, time);
1168  }
1169  }
1170  }
1171  }
1172  // give some slack
1173  return TIME2STEPS(floor(maxTime * 1.2 + 5));
1174 }
1175 
1176 
1177 int
1181  if (logic != nullptr) {
1182  return logic->getNumLinks() - 1;
1183  } else {
1184  return -1;
1185  }
1186 }
1187 
1188 
1189 bool
1191  if (getID() == DummyID) {
1192  // avoid infinite recursion
1193  return true;
1194  }
1195  assert(myControlledNodes.size() >= 2);
1198  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1199  int greenPhases = 0;
1200  for (const auto& phase : tllDummy->getPhases()) {
1201  if (phase.state.find_first_of("gG") != std::string::npos) {
1202  greenPhases++;
1203  }
1204  }
1205  delete tllDummy;
1206  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1207  (*i)->removeTrafficLight(&dummy);
1208  }
1209  return greenPhases <= 2;
1210 }
1211 
1212 
1213 /****************************************************************************/
#define DEBUGCOND(PEDID)
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:277
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
#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:32
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
@ 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
@ DEFAULT
No information given; use default.
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_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:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
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:3655
const std::string & getID() const
Definition: NBEdge.h:1423
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:516
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3070
std::vector< Connection > getConnectionsFromLane(int lane, NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1152
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:490
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1920
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3336
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:509
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:2078
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:1819
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:1813
Sorts edges by their priority within the node they end at.
Definition: NBOwnTLDef.h:287
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
Definition: NBOwnTLDef.cpp:942
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
Definition: NBOwnTLDef.cpp:953
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:697
std::string allowByVClass(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, SVCPermissions perm)
Definition: NBOwnTLDef.cpp:930
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:304
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:769
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:745
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:241
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:647
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:873
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:764
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:808
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
Definition: NBOwnTLDef.cpp:236
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:666
std::string allowFollowers(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
Definition: NBOwnTLDef.cpp:843
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:818
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:774
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:794
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:307
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:906
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
Definition: NBOwnTLDef.cpp:752
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:66
const std::string & getID() const
Returns the id.
Definition: Named.h:73
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:188
data structure for caching needsCont information