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-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
18 // A traffic light logics which must be computed (only nodes/edges are given)
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <vector>
28 #include <cassert>
29 #include <iterator>
31 #include "NBNode.h"
32 #include "NBOwnTLDef.h"
33 #include "NBTrafficLightLogic.h"
36 #include <utils/common/ToString.h>
38 #include <utils/options/Option.h>
39 
40 #define MIN_GREEN_TIME 5
41 
42 //#define DEBUG_STREAM_ORDERING
43 #define DEBUGCOND true
44 
45 // ===========================================================================
46 // member method definitions
47 // ===========================================================================
48 NBOwnTLDef::NBOwnTLDef(const std::string& id,
49  const std::vector<NBNode*>& junctions, SUMOTime offset,
50  TrafficLightType type) :
51  NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
52  myHaveSinglePhase(false) {
53 }
54 
55 
56 NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
57  TrafficLightType type) :
58  NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
59  myHaveSinglePhase(false) {
60 }
61 
62 
63 NBOwnTLDef::NBOwnTLDef(const std::string& id, SUMOTime offset,
64  TrafficLightType type) :
65  NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
66  myHaveSinglePhase(false) {
67 }
68 
69 
71 
72 
73 int
74 NBOwnTLDef::getToPrio(const NBEdge* const e) {
75  return e->getJunctionPriority(e->getToNode());
76 }
77 
78 
79 double
81  switch (dir) {
82  case LINKDIR_STRAIGHT:
83  case LINKDIR_PARTLEFT:
84  case LINKDIR_PARTRIGHT:
85  return 2.;
86  case LINKDIR_LEFT:
87  case LINKDIR_RIGHT:
88  return .5;
89  default:
90  break;
91  }
92  return 0;
93 }
94 
95 double
97  double val = 0;
98  for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
99  std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
100  for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
101  std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
102  for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
103  if (e1->getTurnDestination() == (*e1c).toEdge) {
104  continue;
105  }
106  for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
107  if (e2->getTurnDestination() == (*e2c).toEdge) {
108  continue;
109  }
110  if (!forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)) {
111  val += getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
112  val += getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
113  }
114  }
115  }
116  }
117  }
118  return val;
119 }
120 
121 
122 std::pair<NBEdge*, NBEdge*>
124  std::pair<NBEdge*, NBEdge*> bestPair(static_cast<NBEdge*>(nullptr), static_cast<NBEdge*>(nullptr));
125  double bestValue = -1;
126  for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
127  for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
128  const double value = computeUnblockedWeightedStreamNumber(*i, *j);
129  if (value > bestValue) {
130  bestValue = value;
131  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
132  } else if (value == bestValue) {
133  const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
134  const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
135  if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
136  if (bestPair.first->getID() < (*i)->getID()) {
137  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
138  }
139  } else if (oa < ca) {
140  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
141  }
142  }
143  }
144  }
145  return bestPair;
146 }
147 
148 
149 std::pair<NBEdge*, NBEdge*>
151  if (incoming.size() == 1) {
152  // only one there - return the one
153  std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(), static_cast<NBEdge*>(nullptr));
154  incoming.clear();
155  return ret;
156  }
157  // determine the best combination
158  // by priority, first
159  EdgeVector used;
160  std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
161  used.push_back(*incoming.begin()); // the first will definitely be used
162  // get the ones with the same priority
163  int prio = getToPrio(*used.begin());
164  for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
165  used.push_back(*i);
166  }
167  // if there only lower priorised, use these, too
168  if (used.size() < 2) {
169  used = incoming;
170  }
171  std::pair<NBEdge*, NBEdge*> ret = getBestCombination(used);
172 #ifdef DEBUG_STREAM_ORDERING
173  if (DEBUGCOND) {
174  std::cout << "getBestPair tls=" << getID() << " incoming=" << toString(incoming) << " prio=" << prio << " used=" << toString(used) << " best=" << Named::getIDSecure(ret.first) << ", " << Named::getIDSecure(ret.second) << "\n";
175  }
176 #endif
177 
178  incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
179  incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
180  return ret;
181 }
182 
184 NBOwnTLDef::myCompute(int brakingTimeSeconds) {
185  return computeLogicAndConts(brakingTimeSeconds);
186 }
187 
189 NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
190  myNeedsContRelation.clear();
191  myRightOnRedConflicts.clear();
192  const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
193  const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
194  const SUMOTime minDur = myType == TLTYPE_STATIC ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
195  const SUMOTime maxDur = myType == TLTYPE_STATIC ? UNSPECIFIED_DURATION : TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
196 
197  // build complete lists first
198  const EdgeVector& incoming = getIncomingEdges();
199  EdgeVector fromEdges, toEdges;
200  std::vector<bool> isTurnaround;
201  std::vector<bool> hasTurnLane;
202  std::vector<int> fromLanes;
203  int noLanesAll = 0;
204  int noLinksAll = 0;
205  for (int i1 = 0; i1 < (int)incoming.size(); i1++) {
206  int noLanes = incoming[i1]->getNumLanes();
207  noLanesAll += noLanes;
208  for (int i2 = 0; i2 < noLanes; i2++) {
209  NBEdge* fromEdge = incoming[i1];
210  std::vector<NBEdge::Connection> approached = fromEdge->getConnectionsFromLane(i2);
211  noLinksAll += (int) approached.size();
212  bool hasStraight = false;
213  for (int i3 = 0; i3 < (int)approached.size(); i3++) {
214  if (!fromEdge->mayBeTLSControlled(i2, approached[i3].toEdge, approached[i3].toLane)) {
215  --noLinksAll;
216  continue;
217  }
218  assert(i3 < (int)approached.size());
219  NBEdge* toEdge = approached[i3].toEdge;
220  fromEdges.push_back(fromEdge);
221  fromLanes.push_back((int)i2);
222  toEdges.push_back(toEdge);
223  if (toEdge != nullptr) {
224  isTurnaround.push_back(fromEdge->isTurningDirectionAt(toEdge));
225  } else {
226  isTurnaround.push_back(true);
227  }
228  if (fromEdge->getToNode()->getDirection(fromEdge, toEdge) == LINKDIR_STRAIGHT) {
229  hasStraight = true;
230  }
231  }
232  for (int i3 = 0; i3 < (int)approached.size(); i3++) {
233  hasTurnLane.push_back(!hasStraight);
234  }
235  }
236  }
237  // collect crossings
238  std::vector<NBNode::Crossing*> crossings;
239  for (std::vector<NBNode*>::iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
240  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
241  if (!onlyConts) {
242  // set tl indices for crossings
243  (*i)->setCrossingTLIndices(getID(), noLinksAll);
244  }
245  copy(c.begin(), c.end(), std::back_inserter(crossings));
246  noLinksAll += (int)c.size();
247  }
248 
249  NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), noLinksAll, myOffset, myType);
250  EdgeVector toProc = getConnectedOuterEdges(incoming);
251  const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
252  const SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
253  const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
254  const double groupOpposites = OptionsCont::getOptions().getString("tls.layout") == "opposites";
255  // build all phases
256  std::vector<int> greenPhases; // indices of green phases
257  std::vector<bool> hadGreenMajor(noLinksAll, false);
258  while (toProc.size() > 0) {
259  std::pair<NBEdge*, NBEdge*> chosen;
260  if (groupOpposites) {
261  if (incoming.size() == 2) {
262  // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
263  // @node: this heuristic could be extended to also check the number of outgoing edges
264  double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
265  // angle would be 180 for straight opposing incoming edges
266  if (angle < 135) {
267  chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
268  toProc.erase(toProc.begin());
269  } else {
270  chosen = getBestPair(toProc);
271  }
272  } else {
273  chosen = getBestPair(toProc);
274  }
275  } else {
276  chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
277  toProc.erase(toProc.begin());
278  }
279  int pos = 0;
280  std::string state((int) noLinksAll, 'r');
281  //std::cout << " computing " << getID() << " prog=" << getProgramID() << " cho1=" << Named::getIDSecure(chosen.first) << " cho2=" << Named::getIDSecure(chosen.second) << " toProc=" << toString(toProc) << "\n";
282  // plain straight movers
283  for (int i1 = 0; i1 < (int) incoming.size(); ++i1) {
284  NBEdge* fromEdge = incoming[i1];
285  const bool inChosen = fromEdge == chosen.first || fromEdge == chosen.second; //chosen.find(fromEdge)!=chosen.end();
286  const int numLanes = fromEdge->getNumLanes();
287  for (int i2 = 0; i2 < numLanes; i2++) {
288  std::vector<NBEdge::Connection> approached = fromEdge->getConnectionsFromLane(i2);
289  for (int i3 = 0; i3 < (int)approached.size(); ++i3) {
290  if (!fromEdge->mayBeTLSControlled(i2, approached[i3].toEdge, approached[i3].toLane)) {
291  continue;
292  }
293  if (inChosen) {
294  state[pos] = 'G';
295  } else {
296  state[pos] = 'r';
297  }
298  ++pos;
299  }
300  }
301  }
302  //std::cout << " state after plain straight movers=" << state << "\n";
303  // correct behaviour for those that are not in chosen, but may drive, though
304  state = allowFollowersOfChosen(state, fromEdges, toEdges);
305  if (groupOpposites || chosen.first->getToNode()->getType() == NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED) {
306  for (int i1 = 0; i1 < pos; ++i1) {
307  if (state[i1] == 'G') {
308  continue;
309  }
310  bool isForbidden = false;
311  for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
312  if (state[i2] == 'G' && !isTurnaround[i2] &&
313  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
314  isForbidden = true;
315  }
316  }
317  if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
318  state[i1] = 'G';
319  }
320  }
321  }
322  //std::cout << " state after finding additional 'G's=" << state << "\n";
323  // correct behaviour for those that have to wait (mainly left-mover)
324  bool haveForbiddenLeftMover = false;
325  std::vector<bool> rightTurnConflicts(pos, false);
326  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts);
327  for (int i1 = 0; i1 < pos; ++i1) {
328  if (state[i1] == 'G') {
329  hadGreenMajor[i1] = true;
330  }
331  }
332  //std::cout << " state after correcting left movers=" << state << "\n";
333 
334  std::vector<bool> leftGreen(pos, false);
335  // check whether at least one left-turn lane exist
336  bool foundLeftTurnLane = false;
337  for (int i1 = 0; i1 < pos; ++i1) {
338  if (state[i1] == 'g' && !rightTurnConflicts[i1] && hasTurnLane[i1]) {
339  foundLeftTurnLane = true;
340  }
341  }
342  const bool buildLeftGreenPhase = haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane;
343 
344  // find indices for exclusive left green phase and apply option minor-left.max-speed
345  for (int i1 = 0; i1 < pos; ++i1) {
346  if (state[i1] == 'g' && !rightTurnConflicts[i1]) {
347  leftGreen[i1] = true;
348  if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
349  if (buildLeftGreenPhase) {
350  state[i1] = 'r';
351  } else if (!isTurnaround[i1]) {
352  WRITE_WARNING("Minor green from edge '" + fromEdges[i1]->getID() + "' to edge '" + toEdges[i1]->getID() + "' exceeds "
353  + toString(minorLeftSpeedThreshold) + "m/s. Maybe a left-turn lane is missing.");
354  }
355  }
356  }
357  }
358 
359  const std::string vehicleState = state; // backup state before pedestrian modifications
360  greenPhases.push_back((int)logic->getPhases().size());
361  state = addPedestrianPhases(logic, greenTime, minDur, maxDur, state, crossings, fromEdges, toEdges);
362  // pedestrians have 'r' from here on
363  for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
364  state[i1] = 'r';
365  }
366  if (brakingTime > 0) {
367  // build yellow (straight)
368  for (int i1 = 0; i1 < pos; ++i1) {
369  if (state[i1] != 'G' && state[i1] != 'g') {
370  continue;
371  }
372  if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z') && buildLeftGreenPhase && !rightTurnConflicts[i1]) {
373  continue;
374  }
375  state[i1] = 'y';
376  }
377  // add step
378  logic->addStep(brakingTime, state);
379  // add optional all-red state
380  buildAllRedState(allRedTime, logic, state);
381  }
382 
383 
384  if (buildLeftGreenPhase) {
385  // build left green
386  for (int i1 = 0; i1 < pos; ++i1) {
387  if (state[i1] == 'Y' || state[i1] == 'y') {
388  state[i1] = 'r';
389  continue;
390  }
391  if (state[i1] == 'g' || leftGreen[i1]) {
392  state[i1] = 'G';
393  }
394  }
395  state = allowFollowersOfChosen(state, fromEdges, toEdges);
396  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts);
397 
398  // add step
399  logic->addStep(leftTurnTime, state, minDur, maxDur);
400 
401  // build left yellow
402  if (brakingTime > 0) {
403  for (int i1 = 0; i1 < pos; ++i1) {
404  if (state[i1] != 'G' && state[i1] != 'g') {
405  continue;
406  }
407  state[i1] = 'y';
408  }
409  // add step
410  logic->addStep(brakingTime, state);
411  // add optional all-red state
412  buildAllRedState(allRedTime, logic, state);
413  }
414  }
415  }
416  // fix pedestrian crossings that did not get the green light yet
417  if (crossings.size() > 0) {
418  addPedestrianScramble(logic, noLinksAll, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
419  }
420  // add optional red phase if there where no foes
421  if (logic->getPhases().size() == 2 && brakingTime > 0
422  && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
423  const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
424  logic->addStep(redTime, std::string(noLinksAll, 'r'));
425  }
426  // fix states to account for custom crossing link indices
427  if (crossings.size() > 0 && !onlyConts) {
429  }
430 
431  SUMOTime totalDuration = logic->getDuration();
432  if (OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) {
433  const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
434  // adapt to cycle time by changing the duration of the green phases
435  SUMOTime greenPhaseTime = 0;
436  SUMOTime minGreenDuration = SUMOTime_MAX;
437  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
438  const SUMOTime dur = logic->getPhases()[*it].duration;
439  greenPhaseTime += dur;
440  minGreenDuration = MIN2(minGreenDuration, dur);
441  }
442  const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / greenPhases.size());
443  const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
444  //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
445  if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
446  || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
447  || greenPhases.size() == 0) {
448  if (getID() != DummyID) {
449  WRITE_WARNING("The traffic light '" + getID() + "' cannot be adapted to a cycle time of " + time2string(cycleTime) + ".");
450  }
451  // @todo use a multiple of cycleTime ?
452  } else {
453  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
454  logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
455  }
456  if (greenPhases.size() > 0) {
457  logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
458  }
459  totalDuration = logic->getDuration();
460  }
461  }
462 
464  // this computation only makes sense for single nodes
466  if (totalDuration > 0) {
467  if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime)) {
468  WRITE_WARNING("The traffic light '" + getID() + "' has a high cycle time of " + time2string(totalDuration) + ".");
469  }
470  logic->closeBuilding();
471  return logic;
472  } else {
473  delete logic;
474  return nullptr;
475  }
476 }
477 
478 
479 bool
480 NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
481  assert(to != 0);
482  for (auto c : crossings) {
483  const NBNode::Crossing& cross = *c;
484  // only check connections at this crossings node
485  if (to->getFromNode() == cross.node) {
486  for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
487  const NBEdge* edge = *it_e;
488  if (edge == from || edge == to) {
489  return true;
490  }
491  }
492  }
493  }
494  return false;
495 }
496 
497 
498 std::string
500  SUMOTime minDur, SUMOTime maxDur,
501  std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
502  // compute based on length of the crossing if not set by the user
503  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
504  // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
505  const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
506  const std::string orig = state;
507  state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
508  if (orig == state) {
509  // add step
510  logic->addStep(greenTime, state, minDur, maxDur);
511  } else {
512  const SUMOTime pedTime = greenTime - pedClearingTime;
513  if (pedTime >= minPedTime) {
514  // ensure clearing time for pedestrians
515  const int pedStates = (int)crossings.size();
516  logic->addStep(pedTime, state, minDur, maxDur);
517  state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
518  logic->addStep(pedClearingTime, state);
519  } else {
520  state = orig;
521  // not safe for pedestrians.
522  logic->addStep(greenTime, state, minDur, maxDur);
523  }
524  }
525  return state;
526 }
527 
528 
529 std::string
530 NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
531  std::string result = state;
532  const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
533  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
534  const int i1 = pos + ic;
535  const NBNode::Crossing& cross = *crossings[ic];
536  bool isForbidden = false;
537  for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
538  // only check connections at this crossings node
539  if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
540  for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
541  const NBEdge* edge = *it;
542  const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
543  if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
544  (edge == toEdges[i2] && (i2dir == LINKDIR_STRAIGHT || i2dir == LINKDIR_PARTLEFT || i2dir == LINKDIR_PARTRIGHT)))) {
545  isForbidden = true;
546  break;
547  }
548  }
549  }
550  }
551  if (!isForbidden) {
552  result[i1] = 'G';
553  } else {
554  result[i1] = 'r';
555  }
556  }
557 
558  // correct behaviour for roads that are in conflict with a pedestrian crossing
559  for (int i1 = 0; i1 < pos; ++i1) {
560  if (result[i1] == 'G') {
561  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
562  const NBNode::Crossing& crossing = *crossings[ic];
563  if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
564  const int i2 = pos + ic;
565  if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
566  result[i1] = 'g';
567  break;
568  }
569  }
570  }
571  }
572  }
573  return result;
574 }
575 
576 
577 void
579  collectAllLinks();
580 }
581 
582 
583 void
585  // set the information about the link's positions within the tl into the
586  // edges the links are starting at, respectively
587  for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
588  const NBConnection& conn = *j;
589  NBEdge* edge = conn.getFrom();
590  edge->setControllingTLInformation(conn, getID());
591  }
592 }
593 
594 
595 void
596 NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
597  const EdgeVector& /*outgoing*/) {}
598 
599 
600 void
601 NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
602  NBEdge* /*by*/, int /*byLane*/) {}
603 
604 
605 void
608  if (myControlledNodes.size() > 0) {
609  // we use a dummy node just to maintain const-correctness
610  myNeedsContRelation.clear();
613  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
614  delete tllDummy;
616  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
617  (*i)->removeTrafficLight(&dummy);
618  }
619  }
621  }
622 }
623 
624 
627  EdgeVector result = incoming;
628  for (EdgeVector::iterator it = result.begin(); it != result.end();) {
629  if ((*it)->getConnections().size() == 0 || (*it)->isInternal()) {
630  it = result.erase(it);
631  } else {
632  ++it;
633  }
634  }
635  return result;
636 }
637 
638 
639 std::string
640 NBOwnTLDef::allowFollowersOfChosen(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
641  bool check = true;
642  while (check) {
643  check = false;
644  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
645  if (state[i1] == 'G') {
646  continue;
647  }
648  bool followsChosen = false;
649  for (int i2 = 0; i2 < (int)fromEdges.size() && !followsChosen; ++i2) {
650  if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
651  followsChosen = true;
652  }
653  }
654  if (followsChosen) {
655  state[i1] = 'G';
656  check = true;
657  }
658  }
659  }
660  return state;
661 }
662 
663 
664 std::string
665 NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
666  const std::vector<bool>& isTurnaround,
667  const std::vector<int>& fromLanes,
668  const std::vector<bool>& hadGreenMajor,
669  bool& haveForbiddenLeftMover,
670  std::vector<bool>& rightTurnConflicts) {
671  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
672  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
673  if (state[i1] == 'G') {
674  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
675  if ((state[i2] == 'G' || state[i2] == 'g')) {
677  fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
678  rightTurnConflicts[i1] = true;
679  }
680  if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
681  state[i1] = 'g';
682  myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
683  if (!isTurnaround[i1] && !hadGreenMajor[i1]) {
684  haveForbiddenLeftMover = true;
685  }
686  }
687  }
688  }
689  }
690  if (state[i1] == 'r') {
691  if (fromEdges[i1]->getToNode()->getType() == NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED &&
692  fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LINKDIR_RIGHT) {
693  state[i1] = 's';
694  // do not allow right-on-red when in conflict with exclusive left-turn phase
695  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
696  if (state[i2] == 'G' && !isTurnaround[i2] &&
697  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
698  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
699  const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
700  if (foeDir == LINKDIR_LEFT || foeDir == LINKDIR_PARTLEFT) {
701  state[i1] = 'r';
702  break;
703  }
704  }
705  }
706  if (state[i1] == 's') {
707  // handle right-on-red conflicts
708  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
709  if (state[i2] == 'G' && !isTurnaround[i2] &&
710  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
711  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
712  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
713  }
714  }
715  }
716  }
717  }
718  }
719  return state;
720 }
721 
722 
723 void
724 NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int noLinksAll, SUMOTime /* greenTime */, SUMOTime brakingTime,
725  const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
726  const int vehLinks = noLinksAll - (int)crossings.size();
727  std::vector<bool> foundGreen(crossings.size(), false);
728  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
729  for (int i = 0; i < (int)phases.size(); ++i) {
730  const std::string state = phases[i].state;
731  for (int j = 0; j < (int)crossings.size(); ++j) {
732  LinkState ls = (LinkState)state[vehLinks + j];
734  foundGreen[j] = true;
735  }
736  }
737  }
738  for (int j = 0; j < (int)foundGreen.size(); ++j) {
739  if (!foundGreen[j]) {
740 
741  // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
742  if (phases.size() > 0) {
743  bool needYellowPhase = false;
744  std::string state = phases.back().state;
745  for (int i1 = 0; i1 < vehLinks; ++i1) {
746  if (state[i1] == 'G' || state[i1] == 'g') {
747  state[i1] = 'y';
748  needYellowPhase = true;
749  }
750  }
751  // add yellow step
752  if (needYellowPhase && brakingTime > 0) {
753  logic->addStep(brakingTime, state);
754  }
755  }
756  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
757  const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
758  addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(noLinksAll, 'r'), crossings, fromEdges, toEdges);
759  break;
760  }
761  }
762 }
763 
764 
765 void
766 NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
767  if (allRedTime > 0) {
768  // build all-red phase
769  std::string allRedState = state;
770  for (int i1 = 0; i1 < (int)state.size(); ++i1) {
771  if (allRedState[i1] == 'Y' || allRedState[i1] == 'y') {
772  allRedState[i1] = 'r';
773  }
774  }
775  logic->addStep(allRedTime, allRedState);
776  }
777 }
778 
779 void
781  int minCustomIndex = -1;
782  int maxCustomIndex = -1;
783  // collect crossings
784  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
785  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
786  for (auto crossing : c) {
787  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
788  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
789  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
790  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
791  }
792  }
793  // custom crossing linkIndex could lead to longer states. ensure that every index has a state
794  if (maxCustomIndex >= logic->getNumLinks()) {
795  logic->setStateLength(maxCustomIndex + 1);
796  }
797  // XXX shorter state vectors are possible as well
798  // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
799  // XXX initialize the backward index to the same state as the forward index
800 }
801 
802 
803 int
807  if (logic != nullptr) {
808  return logic->getNumLinks() - 1;
809  } else {
810  return -1;
811  }
812 }
813 /****************************************************************************/
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition: NBHelpers.cpp:47
bool mayBeTLSControlled(int fromLane, NBEdge *toEdge, int toLane) const
return true if certain connection must be controlled by TLS
Definition: NBEdge.cpp:2737
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:161
#define MIN_GREEN_TIME
Definition: NBOwnTLDef.cpp:40
The link is a partial left direction.
The link has green light, may pass.
virtual void setParticipantsInformation()
Builds the list of participating nodes/edges/links.
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:2748
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
Definition: NBOwnTLDef.cpp:584
TrafficLightType myType
The algorithm type for the traffic light.
long long int SUMOTime
Definition: SUMOTime.h:36
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
void collectAllLinks()
helper method for use in NBOwnTLDef and NBLoadedSUMOTLDef
static const std::string DummyID
id for temporary definitions
int getNumLinks()
Returns the number of participating links.
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:480
RightOnRedConflicts myRightOnRedConflicts
A SUMO-compliant built logic for a traffic light.
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:1781
The link has green light, has to brake.
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< bool > &hadGreenMajor, bool &haveForbiddenLeftMover, std::vector< bool > &rightTurnConflicts)
change &#39;G&#39; to &#39;g&#39; for conflicting connections
Definition: NBOwnTLDef.cpp:665
The representation of a single edge during network building.
Definition: NBEdge.h:65
std::string allowFollowersOfChosen(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
allow connections that follow on of the chosen edges
Definition: NBOwnTLDef.cpp:640
TrafficLightType getType() const
get the algorithm type (static etc..)
const std::vector< PhaseDefinition > & getPhases() const
Returns the phases.
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
NBTrafficLightLogic * compute(OptionsCont &oc)
Computes the traffic light logic.
The base class for traffic light logic definitions.
T MAX2(T a, T b)
Definition: StdDefs.h:76
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3013
static const SUMOTime UNSPECIFIED_DURATION
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:71
NBEdge * getFrom() const
returns the from-edge (start of the connection)
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const std::string & getID() const
Returns the id.
Definition: Named.h:78
#define TIME2STEPS(x)
Definition: SUMOTime.h:60
static EdgeVector getConnectedOuterEdges(const EdgeVector &incoming)
get edges that have connections
Definition: NBOwnTLDef.cpp:626
SUMOTime myOffset
The offset in the program.
The link is a (hard) left direction.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:241
std::pair< NBEdge *, NBEdge * > getBestPair(EdgeVector &incoming)
Returns the combination of two edges from the given which has most unblocked streams.
Definition: NBOwnTLDef.cpp:150
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
static bool rightTurnConflict(const NBEdge *from, const NBEdge *to, int fromLane, const NBEdge *prohibitorFrom, const NBEdge *prohibitorTo, int prohibitorFromLane, bool lefthand=false)
return whether the given laneToLane connection is a right turn which must yield to a bicycle crossing...
Definition: NBNode.cpp:1554
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)...
The link is a straight direction.
std::vector< Connection > getConnectionsFromLane(int lane) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1117
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 ...
Definition: NBOwnTLDef.cpp:724
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:420
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane)
Replaces a removed edge/lane.
Definition: NBOwnTLDef.cpp:601
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:96
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:123
bool myHaveSinglePhase
Whether left-mover should not have an additional phase.
Definition: NBOwnTLDef.h:261
void checkCustomCrossingIndices(NBTrafficLightLogic *logic) const
fix states in regard to custom crossing indices
Definition: NBOwnTLDef.cpp:780
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
#define STEPS2TIME(x)
Definition: SUMOTime.h:58
~NBOwnTLDef()
Destructor.
Definition: NBOwnTLDef.cpp:70
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic, in MSLink and GNEInternalLane.
#define DEBUGCOND
Definition: NBOwnTLDef.cpp:43
NBOwnTLDef(const std::string &id, const std::vector< NBNode *> &junctions, SUMOTime offset, TrafficLightType type)
Constructor.
Definition: NBOwnTLDef.cpp:48
T MIN2(T a, T b)
Definition: StdDefs.h:70
The link is a (hard) right direction.
static const std::string DefaultProgramID
const std::string & getProgramID() const
Returns the ProgramID.
The link is a partial right direction.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
void buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic *logic, const std::string &state)
Definition: NBOwnTLDef.cpp:766
int getMaxIndex()
Returns the maximum index controlled by this traffic light.
Definition: NBOwnTLDef.cpp:804
SUMOTime getDuration() const
Returns the duration of the complete cycle.
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream&#39;s direction.
Definition: NBNode.cpp:1764
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
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:530
void closeBuilding(bool checkVarDurations=true)
closes the building process
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
Definition: NBOwnTLDef.cpp:184
#define SUMOTime_MAX
Definition: SUMOTime.h:37
NBTrafficLightLogic * computeLogicAndConts(int brakingTimeSeconds, bool onlyConts=false)
helper function for myCompute
Definition: NBOwnTLDef.cpp:189
void collectLinks()
Collects the links participating in this traffic light.
Definition: NBOwnTLDef.cpp:578
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:499
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.
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:34
const NBNode * node
The parent node of this crossing.
Definition: NBNode.h:129
void setPhaseDuration(int phaseIndex, SUMOTime duration)
Modifies the duration for an existing phase (used by NETEDIT)
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:2684
double getDirectionalWeight(LinkDirection dir)
Returns the weight of a stream given its direction.
Definition: NBOwnTLDef.cpp:80
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:131
Represents a single node (junction) during network building.
Definition: NBNode.h:68
A definition of a pedestrian crossing.
Definition: NBNode.h:125
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:1548
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
#define NUMERICAL_EPS
Definition: config.h:148
data structure for caching needsCont information
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:434
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:47
void addStep(SUMOTime duration, const std::string &state, int index=-1)
Adds a phase to the logic.
void initNeedsContRelation() const
Definition: NBOwnTLDef.cpp:606
Sorts edges by their priority within the node they end at.
Definition: NBOwnTLDef.h:244
NBConnectionVector myControlledLinks
The list of controlled links.
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:441
int getToPrio(const NBEdge *const e)
Returns this edge&#39;s priority at the node it ends at.
Definition: NBOwnTLDef.cpp:74
TrafficLightType
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:596