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