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.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // A traffic light logics which must be computed (only nodes/edges are given)
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <vector>
26 #include <cassert>
27 #include <iterator>
29 #include "NBNode.h"
30 #include "NBOwnTLDef.h"
31 #include "NBTrafficLightLogic.h"
34 #include <utils/common/ToString.h>
37 #include <utils/options/Option.h>
38 
39 #define HEIGH_WEIGHT 2
40 #define LOW_WEIGHT .5;
41 
42 #define MIN_GREEN_TIME 5
43 
44 //#define DEBUG_STREAM_ORDERING
45 //#define DEBUG_PHASES
46 //#define DEBUG_CONTRELATION
47 #define DEBUGID "C"
48 #define DEBUGCOND (getID() == DEBUGID)
49 #define DEBUGCOND2(obj) (obj->getID() == DEBUGID)
50 //#define DEBUGEDGE(edge) (edge->getID() == "23209153#1" || edge->getID() == "319583927#0")
51 //#define DEBUGCOND (true)
52 #define DEBUGEDGE(edge) (true)
53 
54 // ===========================================================================
55 // static members
56 // ===========================================================================
57 const double NBOwnTLDef::MIN_SPEED_CROSSING_TIME(25 / 3.6);
58 
59 
60 // ===========================================================================
61 // member method definitions
62 // ===========================================================================
63 NBOwnTLDef::NBOwnTLDef(const std::string& id,
64  const std::vector<NBNode*>& junctions, SUMOTime offset,
65  TrafficLightType type) :
66  NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
67  myHaveSinglePhase(false),
68  myLayout(TrafficLightLayout::DEFAULT) {
69 }
70 
71 
72 NBOwnTLDef::NBOwnTLDef(const std::string& id, NBNode* junction, SUMOTime offset,
73  TrafficLightType type) :
74  NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
75  myHaveSinglePhase(false),
76  myLayout(TrafficLightLayout::DEFAULT) {
77 }
78 
79 
80 NBOwnTLDef::NBOwnTLDef(const std::string& id, SUMOTime offset,
81  TrafficLightType type) :
82  NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
83  myHaveSinglePhase(false),
84  myLayout(TrafficLightLayout::DEFAULT) {
85 }
86 
87 
89 
90 
91 int
92 NBOwnTLDef::getToPrio(const NBEdge* const e) {
93  return e->getJunctionPriority(e->getToNode());
94 }
95 
96 
97 double
99  switch (dir) {
103  return HEIGH_WEIGHT;
104  case LinkDirection::LEFT:
106  return LOW_WEIGHT;
107  default:
108  break;
109  }
110  return 0;
111 }
112 
113 double
115  double val = 0;
116  for (int e1l = 0; e1l < e1->getNumLanes(); e1l++) {
117  std::vector<NBEdge::Connection> approached1 = e1->getConnectionsFromLane(e1l);
118  for (int e2l = 0; e2l < e2->getNumLanes(); e2l++) {
119  std::vector<NBEdge::Connection> approached2 = e2->getConnectionsFromLane(e2l);
120  for (std::vector<NBEdge::Connection>::iterator e1c = approached1.begin(); e1c != approached1.end(); ++e1c) {
121  if (e1->getTurnDestination() == (*e1c).toEdge) {
122  continue;
123  }
124  for (std::vector<NBEdge::Connection>::iterator e2c = approached2.begin(); e2c != approached2.end(); ++e2c) {
125  if (e2->getTurnDestination() == (*e2c).toEdge) {
126  continue;
127  }
128  const double sign = (forbids(e1, (*e1c).toEdge, e2, (*e2c).toEdge, true)
129  || forbids(e2, (*e2c).toEdge, e1, (*e1c).toEdge, true)) ? -1 : 1;
130  double w1;
131  double w2;
132  const int prio1 = e1->getJunctionPriority(e1->getToNode());
133  const int prio2 = e2->getJunctionPriority(e2->getToNode());
134  if (prio1 == prio2) {
135  w1 = getDirectionalWeight(e1->getToNode()->getDirection(e1, (*e1c).toEdge));
136  w2 = getDirectionalWeight(e2->getToNode()->getDirection(e2, (*e2c).toEdge));
137  } else {
138  if (prio1 > prio2) {
139  w1 = HEIGH_WEIGHT;
140  w2 = LOW_WEIGHT;
141  } else {
142  w1 = LOW_WEIGHT;
143  w2 = HEIGH_WEIGHT;
144  }
145  if (sign == -1) {
146  // extra penalty if edges with different junction priority are in conflict
147  w1 *= 2;
148  w2 *= 2;
149  }
150  }
151  if (isRailway(e1->getPermissions()) != isRailway(e2->getPermissions())) {
152  w1 *= 0.1;
153  w2 *= 0.1;
154  }
155  if ((e1->getPermissions() & SVC_PASSENGER) == 0) {
156  w1 *= 0.1;
157  }
158  if ((e2->getPermissions() & SVC_PASSENGER) == 0) {
159  w2 *= 0.1;
160  }
161  val += sign * w1;
162  val += sign * w2;
163 #ifdef DEBUG_STREAM_ORDERING
164  if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
165  std::cout << " sign=" << sign << " w1=" << w1 << " w2=" << w2 << " val=" << val
166  << " c1=" << (*e1c).getDescription(e1)
167  << " c2=" << (*e2c).getDescription(e2)
168  << "\n";
169  }
170 #endif
171  }
172  }
173  }
174  }
175 #ifdef DEBUG_STREAM_ORDERING
176  if (DEBUGCOND && DEBUGEDGE(e2) && DEBUGEDGE(e1)) {
177  std::cout << " computeUnblockedWeightedStreamNumber e1=" << e1->getID() << " e2=" << e2->getID() << " val=" << val << "\n";
178  }
179 #endif
180  return val;
181 }
182 
183 
184 std::pair<NBEdge*, NBEdge*>
186  std::pair<NBEdge*, NBEdge*> bestPair(static_cast<NBEdge*>(nullptr), static_cast<NBEdge*>(nullptr));
187  double bestValue = -std::numeric_limits<double>::max();
188  for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
189  for (EdgeVector::const_iterator j = i + 1; j != edges.end(); ++j) {
190  const double value = computeUnblockedWeightedStreamNumber(*i, *j);
191  if (value > bestValue) {
192  bestValue = value;
193  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
194  } else if (value == bestValue) {
195  const double ca = GeomHelper::getMinAngleDiff((*i)->getAngleAtNode((*i)->getToNode()), (*j)->getAngleAtNode((*j)->getToNode()));
196  const double oa = GeomHelper::getMinAngleDiff(bestPair.first->getAngleAtNode(bestPair.first->getToNode()), bestPair.second->getAngleAtNode(bestPair.second->getToNode()));
197  if (fabs(oa - ca) < NUMERICAL_EPS) { // break ties by id
198  if (bestPair.first->getID() < (*i)->getID()) {
199  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
200  }
201  } else if (oa < ca) {
202  bestPair = std::pair<NBEdge*, NBEdge*>(*i, *j);
203  }
204  }
205  }
206  }
207  if (bestValue <= 0) {
208  // do not group edges
209  if (bestPair.first->getPriority() < bestPair.second->getPriority()) {
210  std::swap(bestPair.first, bestPair.second);
211  }
212  bestPair.second = nullptr;
213  }
214 #ifdef DEBUG_STREAM_ORDERING
215  if (DEBUGCOND) {
216  std::cout << " getBestCombination bestValue=" << bestValue << " best=" << Named::getIDSecure(bestPair.first) << ", " << Named::getIDSecure(bestPair.second) << "\n";
217  }
218 #endif
219  return bestPair;
220 }
221 
222 
223 std::pair<NBEdge*, NBEdge*>
225  if (incoming.size() == 1) {
226  // only one there - return the one
227  std::pair<NBEdge*, NBEdge*> ret(*incoming.begin(), static_cast<NBEdge*>(nullptr));
228  incoming.clear();
229  return ret;
230  }
231  // determine the best combination
232  // by priority, first
233  EdgeVector used;
234  std::sort(incoming.begin(), incoming.end(), edge_by_incoming_priority_sorter());
235  used.push_back(*incoming.begin()); // the first will definitely be used
236  // get the ones with the same priority
237  int prio = getToPrio(*used.begin());
238  for (EdgeVector::iterator i = incoming.begin() + 1; i != incoming.end() && prio == getToPrio(*i); ++i) {
239  used.push_back(*i);
240  }
241  // if there only lower priorised, use these, too
242  if (used.size() < 2) {
243  used = incoming;
244  }
245  std::pair<NBEdge*, NBEdge*> ret = getBestCombination(used);
246 #ifdef DEBUG_STREAM_ORDERING
247  if (DEBUGCOND) {
248  std::cout << "getBestPair tls=" << getID() << " incoming=" << toString(incoming) << " prio=" << prio << " used=" << toString(used) << " best=" << Named::getIDSecure(ret.first) << ", " << Named::getIDSecure(ret.second) << "\n";
249  }
250 #endif
251 
252  incoming.erase(find(incoming.begin(), incoming.end(), ret.first));
253  if (ret.second != nullptr) {
254  incoming.erase(find(incoming.begin(), incoming.end(), ret.second));
255  }
256  return ret;
257 }
258 
259 bool
261  for (const NBEdge::Connection& c : fromEdge->getConnections()) {
262  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, c.toEdge);
263  if (dir == LinkDirection::STRAIGHT) {
264  return true;
265  }
266  }
267  return false;
268 }
269 
271 NBOwnTLDef::myCompute(int brakingTimeSeconds) {
272  return computeLogicAndConts(brakingTimeSeconds);
273 }
274 
275 
277 NBOwnTLDef::computeLogicAndConts(int brakingTimeSeconds, bool onlyConts) {
278  if (myControlledNodes.size() == 1) {
279  // otherwise, use values from previous call to initNeedsContRelation
280  myNeedsContRelation.clear();
281  }
282  myRightOnRedConflicts.clear();
283  const bool isNEMA = myType == TrafficLightType::NEMA;
284  const SUMOTime brakingTime = TIME2STEPS(brakingTimeSeconds);
285  const SUMOTime leftTurnTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.left-green.time"));
288  const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
289  const SUMOTime latestEnd = UNSPECIFIED_DURATION;
290 
291  // things collect for NEMA phase building
292  std::vector<std::pair<NBEdge*, NBEdge*> > chosenList;
293  std::vector<std::string> straightStates;
294  std::vector<std::string> leftStates;
295 
296  // build complete lists first
297  const EdgeVector& incoming = getIncomingEdges();
298  EdgeVector fromEdges, toEdges;
299  std::vector<bool> isTurnaround;
300  std::vector<bool> hasTurnLane;
301  std::vector<int> fromLanes;
302  std::vector<int> toLanes;
303  std::vector<SUMOTime> crossingTime;
304  int totalNumLinks = 0;
305  for (NBEdge* const fromEdge : incoming) {
306  const int numLanes = fromEdge->getNumLanes();
307  const bool edgeHasStraight = hasStraightConnection(fromEdge);
308  for (int i2 = 0; i2 < numLanes; i2++) {
309  bool hasLeft = false;
310  bool hasPartLeft = false;
311  bool hasStraight = false;
312  bool hasRight = false;
313  bool hasTurnaround = false;
314  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
315  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
316  continue;
317  }
318  fromEdges.push_back(fromEdge);
319  fromLanes.push_back(i2);
320  toLanes.push_back(approached.toLane);
321  toEdges.push_back(approached.toEdge);
322  if (approached.vmax < NUMERICAL_EPS || (fromEdge->getPermissions() & SVC_PASSENGER) == 0
323  || (approached.toEdge->getPermissions() & SVC_PASSENGER) == 0) {
324  crossingTime.push_back(0);
325  } else {
326  crossingTime.push_back(TIME2STEPS((approached.length + approached.viaLength) / MAX2(approached.vmax, MIN_SPEED_CROSSING_TIME)));
327  }
328  // std::cout << fromEdge->getID() << " " << approached.toEdge->getID() << " " << (fromEdge->getPermissions() & SVC_PASSENGER) << " " << approached.length << " " << approached.viaLength << " " << approached.vmax << " " << crossingTime.back() << std::endl;
329  if (approached.toEdge != nullptr) {
330  isTurnaround.push_back(fromEdge->isTurningDirectionAt(approached.toEdge));
331  } else {
332  isTurnaround.push_back(true);
333  }
334  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, approached.toEdge);
335  if (dir == LinkDirection::STRAIGHT) {
336  hasStraight = true;
337  } else if (dir == LinkDirection::RIGHT || dir == LinkDirection::PARTRIGHT) {
338  hasRight = true;
339  } else if (dir == LinkDirection::LEFT) {
340  hasLeft = true;
341  } else if (dir == LinkDirection::PARTLEFT) {
342  hasPartLeft = true;
343  } else if (dir == LinkDirection::TURN) {
344  hasTurnaround = true;
345  }
346  totalNumLinks++;
347  }
348  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
349  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
350  continue;
351  }
352  hasTurnLane.push_back(
353  (hasLeft && !hasPartLeft && !hasStraight && !hasRight)
354  || (hasPartLeft && !hasLeft && !hasStraight && !hasRight)
355  || (hasPartLeft && hasLeft && edgeHasStraight && !hasRight)
356  || (!hasLeft && !hasPartLeft && !hasTurnaround && hasRight));
357  }
358  //std::cout << " from=" << fromEdge->getID() << "_" << i2 << " hasTurnLane=" << hasTurnLane.back() << " s=" << hasStraight << " l=" << hasLeft << " r=" << hasRight << " t=" << hasTurnaround << "\n";
359  }
360  }
361  // collect crossings
362  std::vector<NBNode::Crossing*> crossings;
363  for (NBNode* const node : myControlledNodes) {
364  const std::vector<NBNode::Crossing*>& c = node->getCrossings();
365  if (!onlyConts) {
366  // set tl indices for crossings
367  node->setCrossingTLIndices(getID(), totalNumLinks);
368  }
369  copy(c.begin(), c.end(), std::back_inserter(crossings));
370  totalNumLinks += (int)c.size();
371  }
372 
373  NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
374  EdgeVector toProc = getConnectedOuterEdges(incoming);
375  const SUMOTime greenTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.green.time"));
376  SUMOTime allRedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.allred.time"));
377  const double minorLeftSpeedThreshold = OptionsCont::getOptions().getFloat("tls.minor-left.max-speed");
378  const bool noMixed = OptionsCont::getOptions().getBool("tls.no-mixed");
379  // left-turn phases do not work well for joined tls, so we build incoming instead
381  // @note this prevents updating after loading plain-xml into netedit computing tls and then changing the default layout
383  }
384  const bool groupOpposites = (myLayout == TrafficLightLayout::OPPOSITES && (myControlledNodes.size() <= 2 || corridorLike()));
385 
386  // build all phases
387  std::vector<int> greenPhases; // indices of green phases
388  std::vector<bool> hadGreenMajor(totalNumLinks, false);
389  while (toProc.size() > 0) {
390  bool groupTram = false;
391  bool groupOther = false;
392  std::pair<NBEdge*, NBEdge*> chosen;
393  std::set<const NBEdge*> chosenSet;
394  if (groupOpposites) {
395  if (incoming.size() == 2) {
396  // if there are only 2 incoming edges we need to decide whether they are a crossing or a "continuation"
397  // @node: this heuristic could be extended to also check the number of outgoing edges
398  double angle = fabs(NBHelpers::relAngle(incoming[0]->getAngleAtNode(incoming[0]->getToNode()), incoming[1]->getAngleAtNode(incoming[1]->getToNode())));
399  // angle would be 180 for straight opposing incoming edges
400  if (angle < 135) {
401  chosen = std::pair<NBEdge*, NBEdge*>(toProc[0], static_cast<NBEdge*>(nullptr));
402  toProc.erase(toProc.begin());
403  } else {
404  chosen = getBestPair(toProc);
405  }
406  } else {
407  chosen = getBestPair(toProc);
408  if (chosen.second == nullptr && chosen.first->getPermissions() == SVC_TRAM) {
409  groupTram = true;
410  for (auto it = toProc.begin(); it != toProc.end();) {
411  if ((*it)->getPermissions() == SVC_TRAM) {
412  it = toProc.erase(it);
413  } else {
414  it++;
415  }
416  }
417  }
418  }
419  } else {
420  NBEdge* chosenEdge = toProc[0];
421  chosen = std::pair<NBEdge*, NBEdge*>(chosenEdge, static_cast<NBEdge*>(nullptr));
422  toProc.erase(toProc.begin());
423  SVCPermissions perms = chosenEdge->getPermissions();
424  if (perms == SVC_TRAM) {
425  groupTram = true;
426  } else if ((perms & ~(SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY)) == 0) {
427  groupOther = true;
428  }
429  // group all edges with the same permissions into a single phase (later)
430  if (groupTram || groupOther) {
431  for (auto it = toProc.begin(); it != toProc.end();) {
432  if ((*it)->getPermissions() == perms) {
433  it = toProc.erase(it);
434  } else {
435  it++;
436  }
437  }
438  }
439  }
440  int pos = 0;
441  std::string state(totalNumLinks, 'r');
442 #ifdef DEBUG_PHASES
443  if (DEBUGCOND) {
444  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";
445  }
446 #endif
447  chosenList.push_back(chosen);
448  chosenSet.insert(chosen.first);
449  if (chosen.second != nullptr) {
450  chosenSet.insert(chosen.second);
451  }
452  // find parallel bike edge for the chosen (passenger) edges
453  for (const NBEdge* e : chosenSet) {
454  if ((e->getPermissions() & SVC_PASSENGER) != 0) {
455  std::vector<NBEdge*> parallelBikeEdges;
456  for (NBEdge* cand : toProc) {
457  if ((cand->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE) {
458  double angle = fabs(NBHelpers::relAngle(e->getAngleAtNode(e->getToNode()), cand->getAngleAtNode(cand->getToNode())));
459  if (angle < 30) {
460  // roughly parallel
461  parallelBikeEdges.push_back(cand);
462  }
463  }
464  }
465  for (NBEdge* be : parallelBikeEdges) {
466 #ifdef DEBUG_PHASES
467  if (DEBUGCOND) {
468  std::cout << " chosen=" << e->getID() << " be=" << be->getID() << "\n";
469  }
470 #endif
471  chosenSet.insert(be);
472  toProc.erase(std::find(toProc.begin(), toProc.end(), be));
473  }
474  }
475  }
476  // plain straight movers
477  double maxSpeed = 0;
478  bool haveGreen = false;
479  for (const NBEdge* const fromEdge : incoming) {
480  const bool inChosen = chosenSet.count(fromEdge) != 0;
481  const int numLanes = fromEdge->getNumLanes();
482  for (int i2 = 0; i2 < numLanes; i2++) {
483  for (const NBEdge::Connection& approached : fromEdge->getConnectionsFromLane(i2)) {
484  if (!fromEdge->mayBeTLSControlled(i2, approached.toEdge, approached.toLane)) {
485  continue;
486  }
487  if (inChosen) {
488  state[pos] = 'G';
489  haveGreen = true;
490  maxSpeed = MAX2(maxSpeed, fromEdge->getSpeed());
491  } else {
492  state[pos] = 'r';
493  }
494  ++pos;
495  }
496  }
497  }
498  if (!haveGreen) {
499  continue;
500  }
501 
502 #ifdef DEBUG_PHASES
503  if (DEBUGCOND) {
504  std::cout << " state after plain straight movers " << state << "\n";
505  }
506 #endif
507  if (!isNEMA) {
508  // correct behaviour for those that are not in chosen, but may drive, though
509  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
510 #ifdef DEBUG_PHASES
511  if (DEBUGCOND) {
512  std::cout << " state after allowing compatible " << state << "\n";
513  }
514 #endif
515  if (groupTram) {
516  state = allowByVClass(state, fromEdges, toEdges, SVC_TRAM);
517  } else if (groupOther) {
518  state = allowByVClass(state, fromEdges, toEdges, SVC_PEDESTRIAN | SVC_BICYCLE | SVC_DELIVERY);
519  }
520 #ifdef DEBUG_PHASES
521  if (DEBUGCOND) {
522  std::cout << " state after grouping by vClass " << state << " (groupTram=" << groupTram << " groupOther=" << groupOther << ")\n";
523  }
524 #endif
525  if (groupOpposites || chosen.first->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED) {
526  state = allowUnrelated(state, fromEdges, toEdges, isTurnaround, crossings);
527  }
528 #ifdef DEBUG_PHASES
529  if (DEBUGCOND) {
530  std::cout << " state after finding allowUnrelated " << state << "\n";
531  }
532 #endif
533  }
534  // correct behaviour for those that have to wait (mainly left-mover)
535  bool haveForbiddenLeftMover = false;
536  std::vector<bool> rightTurnConflicts(pos, false);
537  std::vector<bool> mergeConflicts(pos, false);
538  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
539  for (int i1 = 0; i1 < pos; ++i1) {
540  if (state[i1] == 'G') {
541  hadGreenMajor[i1] = true;
542  }
543  }
544 #ifdef DEBUG_PHASES
545  if (DEBUGCOND) {
546  std::cout << " state after correcting left movers=" << state << "\n";
547  }
548 #endif
549 
550  std::vector<bool> leftGreen(pos, false);
551  // check whether at least one left-turn lane exist
552  bool foundLeftTurnLane = false;
553  for (int i1 = 0; i1 < pos; ++i1) {
554  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1] && hasTurnLane[i1]) {
555  foundLeftTurnLane = true;
556  }
557  }
558  const bool buildLeftGreenPhase = (haveForbiddenLeftMover && !myHaveSinglePhase && leftTurnTime > 0 && foundLeftTurnLane
559  && groupOpposites && !groupTram && !groupOther);
560 
561  // find indices for exclusive left green phase and apply option minor-left.max-speed
562  for (int i1 = 0; i1 < pos; ++i1) {
563  if (state[i1] == 'g' && !rightTurnConflicts[i1] && !mergeConflicts[i1]
564  // only activate turn-around together with a real left-turn
565  && (!isTurnaround[i1] || (i1 > 0 && leftGreen[i1 - 1]))) {
566  leftGreen[i1] = true;
567  if (fromEdges[i1]->getSpeed() > minorLeftSpeedThreshold) {
568  if (buildLeftGreenPhase) {
569  state[i1] = 'r';
570  //std::cout << " disabling minorLeft " << i1 << " (speed=" << fromEdges[i1]->getSpeed() << " thresh=" << minorLeftSpeedThreshold << ")\n";
571  } else if (!isTurnaround[i1]) {
572  WRITE_WARNINGF(TL("Minor green from edge '%' to edge '%' exceeds %m/s. Maybe a left-turn lane is missing."),
573  fromEdges[i1]->getID(), toEdges[i1]->getID(), minorLeftSpeedThreshold);
574  }
575  }
576  }
577  }
578 
579 #ifdef DEBUG_PHASES
580  if (DEBUGCOND) {
581  std::cout << getID() << " state=" << state << " buildLeft=" << buildLeftGreenPhase << " hFLM=" << haveForbiddenLeftMover << " turnLane=" << foundLeftTurnLane
582  << " \nrtC=" << toString(rightTurnConflicts)
583  << " \nmC=" << toString(mergeConflicts)
584  << " \nhTL=" << toString(hasTurnLane)
585  << " \nlGr=" << toString(leftGreen)
586  << "\n";
587  }
588 #endif
589  straightStates.push_back(state);
590 
591  const std::string vehicleState = state; // backup state before pedestrian modifications
592  greenPhases.push_back((int)logic->getPhases().size());
593 
594  // 5s at 50km/h, 10s at 80km/h, rounded to full seconds
595  const double minDurBySpeed = maxSpeed * 3.6 / 6 - 3.3;
596  SUMOTime minDur = MAX2(minMinDur, TIME2STEPS(floor(minDurBySpeed + 0.5)));
597  if (chosen.first->getPermissions() == SVC_TRAM && (chosen.second == nullptr || chosen.second->getPermissions() == SVC_TRAM)) {
598  // shorter minDuration for tram phase (only if the phase is
599  // exclusively for tram)
600  bool tramExclusive = true;
601  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
602  if (state[i1] == 'G') {
603  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
604  if (linkPerm != SVC_TRAM) {
605  tramExclusive = false;
606  break;
607  }
608  }
609  }
610  if (tramExclusive) {
611  // one tram per actuated phase
612  minDur = TIME2STEPS(1);
613  }
614  }
615 
616  state = addPedestrianPhases(logic, greenTime, minDur, maxDur, earliestEnd, latestEnd, state, crossings, fromEdges, toEdges);
617  // pedestrians have 'r' from here on
618  for (int i1 = pos; i1 < pos + (int)crossings.size(); ++i1) {
619  state[i1] = 'r';
620  }
621  if (brakingTime > 0) {
622  SUMOTime maxCross = 0;
623  // build yellow (straight)
624  for (int i1 = 0; i1 < pos; ++i1) {
625  if (state[i1] != 'G' && state[i1] != 'g') {
626  continue;
627  }
628  if ((vehicleState[i1] >= 'a' && vehicleState[i1] <= 'z')
629  && buildLeftGreenPhase
630  && !rightTurnConflicts[i1]
631  && !mergeConflicts[i1]
632  && leftGreen[i1]) {
633  continue;
634  }
635  state[i1] = 'y';
636  maxCross = MAX2(maxCross, crossingTime[i1]);
637  }
638  // add step
639  logic->addStep(brakingTime, state);
640  // add optional all-red state
641  if (!buildLeftGreenPhase) {
643  allRedTime = computeEscapeTime(state, fromEdges, toEdges);
644  }
645  buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
646  }
647  }
648 
649 
650  if (buildLeftGreenPhase) {
651  // build left green
652  for (int i1 = 0; i1 < pos; ++i1) {
653  if (state[i1] == 'Y' || state[i1] == 'y') {
654  state[i1] = 'r';
655  continue;
656  }
657  if (leftGreen[i1]) {
658  state[i1] = 'G';
659  }
660  }
661  leftStates.push_back(state);
662  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
663  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
664  bool buildMixedGreenPhase = false;
665  std::vector<bool> mixedGreen(pos, false);
666  const std::string oldState = state;
667  if (noMixed) {
668  state = correctMixed(state, fromEdges, fromLanes, buildMixedGreenPhase, mixedGreen);
669  }
670  if (state != oldState) {
671  for (int i1 = 0; i1 < pos; ++i1) {
672  if (mixedGreen[i1]) {
673  // patch previous yellow and allred phase
674  int yellowIndex = (int)logic->getPhases().size() - 1;
675  if (allRedTime > 0) {
676  logic->setPhaseState(yellowIndex--, i1, LINKSTATE_TL_RED);
677  }
678  if (brakingTime > 0) {
679  logic->setPhaseState(yellowIndex, i1, LINKSTATE_TL_YELLOW_MINOR);
680  }
681  }
682  }
683  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
684  }
685 
686  // add step
687  logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
688 
689  // build left yellow
690  if (brakingTime > 0) {
691  SUMOTime maxCross = 0;
692  for (int i1 = 0; i1 < pos; ++i1) {
693  if (state[i1] != 'G' && state[i1] != 'g') {
694  continue;
695  }
696  state[i1] = 'y';
697  maxCross = MAX2(maxCross, crossingTime[i1]);
698  }
699  // add step
700  logic->addStep(brakingTime, state);
701  // add optional all-red state
702  buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
703  }
704 
705  if (buildMixedGreenPhase) {
706  // build mixed green
707  // @todo if there is no left green phase we might want to build two
708  // mixed-green phases but then we should consider avoid a common
709  // opposite phase for this direction
710 
711  for (int i1 = 0; i1 < pos; ++i1) {
712  if (state[i1] == 'Y' || state[i1] == 'y') {
713  state[i1] = 'r';
714  continue;
715  }
716  if (mixedGreen[i1]) {
717  state[i1] = 'G';
718  }
719  }
720  state = allowCompatible(state, fromEdges, toEdges, fromLanes, toLanes);
721  state = correctConflicting(state, fromEdges, toEdges, isTurnaround, fromLanes, toLanes, hadGreenMajor, haveForbiddenLeftMover, rightTurnConflicts, mergeConflicts);
722 
723  // add step
724  logic->addStep(leftTurnTime, state, minDur, maxDur, earliestEnd, latestEnd);
725 
726  // build mixed yellow
727  if (brakingTime > 0) {
728  SUMOTime maxCross = 0;
729  for (int i1 = 0; i1 < pos; ++i1) {
730  if (state[i1] != 'G' && state[i1] != 'g') {
731  continue;
732  }
733  state[i1] = 'y';
734  maxCross = MAX2(maxCross, crossingTime[i1]);
735  }
736  // add step
737  logic->addStep(brakingTime, state);
738  // add optional all-red state
739  buildAllRedState(allRedTime + MAX2(0ll, maxCross - brakingTime - allRedTime), logic, state);
740  }
741  }
742 
743  } else if (isNEMA) {
744  std::string& s = straightStates.back();
745  std::string leftState = s;
746  for (int ii = 0; ii < pos; ++ii) {
747  if (s[ii] != 'r') {
748  NBEdge* fromEdge = fromEdges[ii];
749  NBEdge* toEdge = toEdges[ii];
750  LinkDirection dir = fromEdge->getToNode()->getDirection(fromEdge, toEdge);
751  if (hasTurnLane[ii] && (dir == LinkDirection::LEFT || dir == LinkDirection::TURN)) {
752  s[ii] = 'r';
753  leftState[ii] = 'G';
754  } else {
755  leftState[ii] = 'r';
756  }
757  }
758  }
759  leftStates.push_back(leftState);
760  }
761  // fix edges within joined traffic lights that did not get the green light yet
762  if (myEdgesWithin.size() > 0 && !isNEMA && toProc.size() == 0) {
763  addGreenWithin(logic, fromEdges, toProc);
764  }
765  }
766  // fix pedestrian crossings that did not get the green light yet
767  if (crossings.size() > 0) {
768  addPedestrianScramble(logic, totalNumLinks, TIME2STEPS(10), brakingTime, crossings, fromEdges, toEdges);
769  }
770  // add optional red phase if there were no foes
771  if (logic->getPhases().size() == 2 && brakingTime > 0
772  && OptionsCont::getOptions().getInt("tls.red.time") > 0) {
773  const SUMOTime redTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.red.time"));
774  logic->addStep(redTime, std::string(totalNumLinks, 'r'));
775  }
776  // fix states to account for custom crossing link indices
777  if (crossings.size() > 0 && !onlyConts) {
779  }
780 
782  // exiting the oneway section should always be possible
783  deactivateInsideEdges(logic, fromEdges);
784  }
785  if (isNEMA) {
786  NBTrafficLightLogic* nemaLogic = buildNemaPhases(fromEdges, toEdges, crossings, chosenList, straightStates, leftStates);
787  if (nemaLogic == nullptr) {
788  WRITE_WARNINGF(TL("Generating NEMA phases is not support for traffic light '%' with % incoming edges. Using tlType 'actuated' as fallback"), getID(), incoming.size());
791  } else {
792  delete logic;
793  logic = nemaLogic;
794  }
795  }
796 
797  SUMOTime totalDuration = logic->getDuration();
798 
799  if ((OptionsCont::getOptions().isDefault("tls.green.time") || !OptionsCont::getOptions().isDefault("tls.cycle.time")) && !isNEMA) {
800  const SUMOTime cycleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
801  // adapt to cycle time by changing the duration of the green phases
802  SUMOTime minGreenDuration = SUMOTime_MAX;
803  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
804  const SUMOTime dur = logic->getPhases()[*it].duration;
805  minGreenDuration = MIN2(minGreenDuration, dur);
806  }
807  const int patchSeconds = (int)(STEPS2TIME(cycleTime - totalDuration) / (double)greenPhases.size());
808  const int patchSecondsRest = (int)(STEPS2TIME(cycleTime - totalDuration)) - patchSeconds * (int)greenPhases.size();
809  //std::cout << "cT=" << cycleTime << " td=" << totalDuration << " pS=" << patchSeconds << " pSR=" << patchSecondsRest << "\n";
810  if (STEPS2TIME(minGreenDuration) + patchSeconds < MIN_GREEN_TIME
811  || STEPS2TIME(minGreenDuration) + patchSeconds + patchSecondsRest < MIN_GREEN_TIME
812  || greenPhases.size() == 0) {
813  if (getID() != DummyID) {
814  WRITE_WARNINGF(TL("The traffic light '%' cannot be adapted to a cycle time of %."), getID(), time2string(cycleTime));
815  }
816  // @todo use a multiple of cycleTime ?
817  } else {
818  for (std::vector<int>::const_iterator it = greenPhases.begin(); it != greenPhases.end(); ++it) {
819  logic->setPhaseDuration(*it, logic->getPhases()[*it].duration + TIME2STEPS(patchSeconds));
820  }
821  if (greenPhases.size() > 0) {
822  logic->setPhaseDuration(greenPhases.front(), logic->getPhases()[greenPhases.front()].duration + TIME2STEPS(patchSecondsRest));
823  }
824  totalDuration = logic->getDuration();
825  }
826  }
827 
828  // check for coherent signal sequence and remove yellow if preceded and followed by green
829  const std::vector<NBTrafficLightLogic::PhaseDefinition>& allPhases = logic->getPhases();
830  const int phaseCount = (int)allPhases.size();
831  const int stateSize = (int)logic->getNumLinks();
832  for (int i = 0; i < phaseCount; ++i) {
833  std::string currState = allPhases[i].state;
834  const int prevIndex = (i == 0) ? phaseCount - 1 : i - 1;
835  const std::string prevState = allPhases[prevIndex].state;
836  const std::string nextState = allPhases[(i + 1) % phaseCount].state;
837  bool updatedState = false;
838  for (int i1 = 0; i1 < stateSize; ++i1) {
839  if (currState[i1] == 'y' && (nextState[i1] == 'g' || nextState[i1] == 'G') && (prevState[i1] == 'g' || prevState[i1] == 'G')) {
840  LinkState ls = (nextState[i1] == prevState[i1]) ? (LinkState)prevState[i1] : (LinkState)'g';
841  logic->setPhaseState(i, i1, ls);
842  updatedState = true;
843  }
844  }
845  UNUSED_PARAMETER(updatedState); // disable warning
846 #ifdef DEBUG_PHASES
847  if (DEBUGCOND) {
848  if (updatedState) {
849  std::cout << getID() << " state of phase index " << i << " was patched due to yellow in between green\n";
850  }
851 
852  }
853 #endif
854  }
855 
856 
858  // this computation only makes sense for single nodes
860  if (totalDuration > 0) {
861  if (totalDuration > 3 * (greenTime + 2 * brakingTime + leftTurnTime) && !isNEMA) {
862  WRITE_WARNINGF(TL("The traffic light '%' has a high cycle time of %."), getID(), time2string(totalDuration));
863  }
864  logic->closeBuilding();
865  return logic;
866  } else {
867  delete logic;
868  return nullptr;
869  }
870 }
871 
872 
873 bool
874 NBOwnTLDef::hasCrossing(const NBEdge* from, const NBEdge* to, const std::vector<NBNode::Crossing*>& crossings) {
875  assert(to != 0);
876  for (auto c : crossings) {
877  const NBNode::Crossing& cross = *c;
878  // only check connections at this crossings node
879  if (to->getFromNode() == cross.node) {
880  for (EdgeVector::const_iterator it_e = cross.edges.begin(); it_e != cross.edges.end(); ++it_e) {
881  const NBEdge* edge = *it_e;
882  if (edge == from || edge == to) {
883  return true;
884  }
885  }
886  }
887  }
888  return false;
889 }
890 
891 
892 std::string
893 NBOwnTLDef::addPedestrianPhases(NBTrafficLightLogic* logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur,
894  const SUMOTime earliestEnd, const SUMOTime latestEnd,
895  std::string state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
896  // compute based on length of the crossing if not set by the user
897  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
898  // compute if not set by user: must be able to reach the middle of the second "Richtungsfahrbahn"
899  const SUMOTime minPedTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-min.time"));
900  const std::string orig = state;
901  state = patchStateForCrossings(state, crossings, fromEdges, toEdges);
902  if (orig == state) {
903  // add step
904  logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
905  } else {
906  const SUMOTime pedTime = greenTime - pedClearingTime;
907  if (pedTime >= minPedTime) {
908  // ensure clearing time for pedestrians
909  const int pedStates = (int)crossings.size();
910  logic->addStep(pedTime, state, minDur, maxDur, earliestEnd, latestEnd);
911 #ifdef DEBUG_PHASES
912  if (DEBUGCOND2(logic)) {
913  std::cout << " intermidate state for addPedestrianPhases " << state << "\n";
914  }
915 #endif
916  state = state.substr(0, state.size() - pedStates) + std::string(pedStates, 'r');
917  logic->addStep(pedClearingTime, state);
918  } else {
919  state = orig;
920  // not safe for pedestrians.
921  logic->addStep(greenTime, state, minDur, maxDur, earliestEnd, latestEnd);
922  }
923  }
924 #ifdef DEBUG_PHASES
925  if (DEBUGCOND2(logic)) {
926  std::cout << " state after addPedestrianPhases " << state << "\n";
927  }
928 #endif
929  return state;
930 }
931 
932 
933 std::string
934 NBOwnTLDef::patchStateForCrossings(const std::string& state, const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
935  std::string result = state;
936  const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
937  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
938  const int i1 = pos + ic;
939  const NBNode::Crossing& cross = *crossings[ic];
940  bool isForbidden = false;
941  for (int i2 = 0; i2 < pos && !isForbidden; ++i2) {
942  // only check connections at this crossings node
943  if (fromEdges[i2] != 0 && toEdges[i2] != 0 && fromEdges[i2]->getToNode() == cross.node) {
944  for (EdgeVector::const_iterator it = cross.edges.begin(); it != cross.edges.end(); ++it) {
945  const NBEdge* edge = *it;
946  const LinkDirection i2dir = cross.node->getDirection(fromEdges[i2], toEdges[i2]);
947  if (state[i2] != 'r' && state[i2] != 's' && (edge == fromEdges[i2] ||
948  (edge == toEdges[i2] && (i2dir == LinkDirection::STRAIGHT || i2dir == LinkDirection::PARTLEFT || i2dir == LinkDirection::PARTRIGHT)))) {
949  isForbidden = true;
950  break;
951  }
952  }
953  }
954  }
955  if (!isForbidden) {
956  result[i1] = 'G';
957  } else {
958  result[i1] = 'r';
959  }
960  }
961 
962  // correct behaviour for roads that are in conflict with a pedestrian crossing
963  for (int i1 = 0; i1 < pos; ++i1) {
964  if (result[i1] == 'G') {
965  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
966  const NBNode::Crossing& crossing = *crossings[ic];
967  if (fromEdges[i1] != 0 && toEdges[i1] != 0 && fromEdges[i1]->getToNode() == crossing.node) {
968  const int i2 = pos + ic;
969  if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
970  result[i1] = 'g';
971  break;
972  }
973  }
974  }
975  }
976  }
977  return result;
978 }
979 
980 
981 std::string
982 NBOwnTLDef::patchNEMAStateForCrossings(const std::string& state,
983  const std::vector<NBNode::Crossing*>& crossings,
984  const EdgeVector& fromEdges,
985  const EdgeVector& toEdges,
986  const NBEdge* greenEdge, NBEdge* otherChosen) {
987  std::string result = state;
988  const int pos = (int)(state.size() - crossings.size()); // number of controlled vehicle links
989  const EdgeVector& all = greenEdge->getToNode()->getEdges();
990  EdgeVector::const_iterator start = std::find(all.begin(), all.end(), greenEdge);
991 
992  // permit crossings over edges between the current green edge and it's straight continuation
993  const NBEdge* endEdge = nullptr;
994  for (int i = 0; i < (int)state.size(); i++) {
995  if (state[i] == 'G' && fromEdges[i] == greenEdge
996  && greenEdge->getToNode()->getDirection(greenEdge, toEdges[i]) == LinkDirection::STRAIGHT) {
997  // straight edge found
998  endEdge = toEdges[i];
999  break;
1000  }
1001  }
1002  if (endEdge == nullptr) {
1003  endEdge = otherChosen;
1004  }
1005  if (endEdge == nullptr) {
1006  // try to find the reverse edge of the green edge
1007  auto itCW = start;
1008  NBContHelper::nextCW(all, itCW);
1009  if ((*itCW)->getFromNode() == greenEdge->getToNode()) {
1010  endEdge = *itCW;
1011  }
1012  }
1013  if (endEdge == nullptr) {
1014  // at least prevent an infinite loop
1015  endEdge = greenEdge;
1016  }
1017  //std::cout << " patchNEMAStateForCrossings green=" << greenEdge->getID() << " other=" << Named::getIDSecure(otherChosen) << " end=" << Named::getIDSecure(end) << " all=" << toString(all) << "\n";
1018 
1019  EdgeVector::const_iterator end = std::find(all.begin(), all.end(), endEdge);
1020  auto it = start;
1021  NBContHelper::nextCCW(all, it);
1022  for (; it != end; NBContHelper::nextCCW(all, it)) {
1023  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
1024  const int i1 = pos + ic;
1025  const NBNode::Crossing& cross = *crossings[ic];
1026  for (const NBEdge* crossed : cross.edges) {
1027  //std::cout << " cand=" << (*it)->getID() << " crossed=" << crossed->getID() << "\n";
1028  if (crossed == *it) {
1029  result[i1] = 'G';
1030  break;
1031  }
1032  }
1033  }
1034  }
1035  // correct behaviour for roads that are in conflict with a pedestrian crossing
1036  for (int i1 = 0; i1 < pos; ++i1) {
1037  if (result[i1] == 'G') {
1038  for (int ic = 0; ic < (int)crossings.size(); ++ic) {
1039  const NBNode::Crossing& crossing = *crossings[ic];
1040  const int i2 = pos + ic;
1041  if (result[i2] == 'G' && crossing.node->mustBrakeForCrossing(fromEdges[i1], toEdges[i1], crossing)) {
1042  result[i1] = 'g';
1043  break;
1044  }
1045  }
1046  }
1047  }
1048  return result;
1049 }
1050 
1051 
1052 void
1054  myControlledLinks.clear();
1056 }
1057 
1058 
1059 void
1061  // set the information about the link's positions within the tl into the
1062  // edges the links are starting at, respectively
1063  for (NBConnectionVector::const_iterator j = myControlledLinks.begin(); j != myControlledLinks.end(); ++j) {
1064  const NBConnection& conn = *j;
1065  NBEdge* edge = conn.getFrom();
1066  edge->setControllingTLInformation(conn, getID());
1067  }
1068 }
1069 
1070 
1071 void
1072 NBOwnTLDef::remapRemoved(NBEdge* /*removed*/, const EdgeVector& /*incoming*/,
1073  const EdgeVector& /*outgoing*/) {}
1074 
1075 
1076 void
1077 NBOwnTLDef::replaceRemoved(NBEdge* /*removed*/, int /*removedLane*/,
1078  NBEdge* /*by*/, int /*byLane*/, bool /*incoming*/) {}
1079 
1080 
1081 void
1083  if (!myNeedsContRelationReady) {
1084  if (myControlledNodes.size() > 0) {
1085  // setParticipantsInformation resets myAmInTLS so we need to make a copy
1086  std::vector<bool> edgeInsideTLS;
1087  for (const NBEdge* e : myIncomingEdges) {
1088  edgeInsideTLS.push_back(e->isInsideTLS());
1089  }
1090  // we use a dummy node just to maintain const-correctness
1091  myNeedsContRelation.clear();
1092  for (NBNode* n : myControlledNodes) {
1095  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1096  delete tllDummy;
1097  myNeedsContRelation.insert(dummy.myNeedsContRelation.begin(), dummy.myNeedsContRelation.end());
1098  n->removeTrafficLight(&dummy);
1099  }
1100  if (myControlledNodes.size() > 1) {
1101  int i = 0;
1102  for (NBEdge* e : myIncomingEdges) {
1103  e->setInsideTLS(edgeInsideTLS[i]);
1104  i++;
1105  }
1106  }
1107 #ifdef DEBUG_CONTRELATION
1108  if (DEBUGCOND) {
1109  std::cout << " contRelations at " << getID() << " prog=" << getProgramID() << ":\n";
1110  for (const StreamPair& s : myNeedsContRelation) {
1111  std::cout << " " << s.from1->getID() << "->" << s.to1->getID() << " foe " << s.from2->getID() << "->" << s.to2->getID() << "\n";
1112  }
1113  }
1114 #endif
1115 
1116  }
1117  myNeedsContRelationReady = true;
1118  }
1119 }
1120 
1121 
1122 EdgeVector
1124  EdgeVector result = incoming;
1125  for (EdgeVector::iterator it = result.begin(); it != result.end();) {
1126  if ((*it)->getConnections().size() == 0 || (*it)->isInsideTLS()) {
1127  it = result.erase(it);
1128  } else {
1129  ++it;
1130  }
1131  }
1132  return result;
1133 }
1134 
1135 
1136 std::string
1137 NBOwnTLDef::allowCompatible(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1138  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1139  state = allowSingleEdge(state, fromEdges);
1140 #ifdef DEBUG_PHASES
1141  if (DEBUGCOND) {
1142  std::cout << " state after allowSingle " << state << "\n";
1143  }
1144 #endif
1145  if (myControlledNodes.size() > 1) {
1146  state = allowFollowers(state, fromEdges, toEdges);
1147 #ifdef DEBUG_PHASES
1148  if (DEBUGCOND) {
1149  std::cout << " state after allowFollowers " << state << "\n";
1150  }
1151 #endif
1152  state = allowPredecessors(state, fromEdges, toEdges, fromLanes, toLanes);
1153 #ifdef DEBUG_PHASES
1154  if (DEBUGCOND) {
1155  std::cout << " state after allowPredecessors " << state << "\n";
1156  }
1157 #endif
1158  }
1159  return state;
1160 }
1161 
1162 
1163 std::string
1164 NBOwnTLDef::allowSingleEdge(std::string state, const EdgeVector& fromEdges) {
1165  // if only one edge has green, ensure sure that all connections from that edge are green
1166  const int size = (int)fromEdges.size();
1167  NBEdge* greenEdge = nullptr;
1168  for (int i1 = 0; i1 < size; ++i1) {
1169  if (state[i1] == 'G') {
1170  if (greenEdge == nullptr) {
1171  greenEdge = fromEdges[i1];
1172  } else if (greenEdge != fromEdges[i1]) {
1173  return state;
1174  }
1175  }
1176  }
1177  if (greenEdge != nullptr) {
1178  for (int i1 = 0; i1 < size; ++i1) {
1179  if (fromEdges[i1] == greenEdge) {
1180  state[i1] = 'G';
1181  }
1182  }
1183  }
1184  return state;
1185 }
1186 
1187 
1188 std::string
1189 NBOwnTLDef::allowFollowers(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1190  // check continuation within joined traffic lights
1191  bool check = true;
1192  while (check) {
1193  check = false;
1194  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1195  if (state[i1] == 'G') {
1196  continue;
1197  }
1198  if (forbidden(state, i1, fromEdges, toEdges, true)) {
1199  continue;
1200  }
1201  bool followsChosen = false;
1202  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1203  if (state[i2] == 'G' && fromEdges[i1] == toEdges[i2]) {
1204  followsChosen = true;
1205  break;
1206  }
1207  }
1208  if (followsChosen) {
1209  state[i1] = 'G';
1210  check = true;
1211  }
1212  }
1213  }
1214  return state;
1215 }
1216 
1217 
1218 std::string
1219 NBOwnTLDef::allowPredecessors(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1220  const std::vector<int>& fromLanes, const std::vector<int>& toLanes) {
1221  // also allow predecessors of chosen edges if the lanes match and there is no conflict
1222  // (must be done after the followers are done because followers are less specific)
1223  bool check = true;
1224  while (check) {
1225  check = false;
1226  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1227  if (state[i1] == 'G') {
1228  continue;
1229  }
1230  if (forbidden(state, i1, fromEdges, toEdges, false)) {
1231  continue;
1232  }
1233  bool preceedsChosen = false;
1234  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1235  if (state[i2] == 'G' && fromEdges[i2] == toEdges[i1]
1236  && fromLanes[i2] == toLanes[i1]) {
1237  preceedsChosen = true;
1238  break;
1239  }
1240  }
1241  if (preceedsChosen) {
1242  state[i1] = 'G';
1243  check = true;
1244  }
1245  }
1246  }
1247  return state;
1248 }
1249 
1250 
1251 std::string
1252 NBOwnTLDef::allowUnrelated(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1253  const std::vector<bool>& isTurnaround,
1254  const std::vector<NBNode::Crossing*>& crossings) {
1255  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1256  if (state[i1] == 'G') {
1257  continue;
1258  }
1259  bool isForbidden = false;
1260  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1261  if (state[i2] == 'G' && !isTurnaround[i2] &&
1262  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) || forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1263  isForbidden = true;
1264  break;
1265  }
1266  }
1267  if (!isForbidden && !hasCrossing(fromEdges[i1], toEdges[i1], crossings)) {
1268  state[i1] = 'G';
1269  }
1270  }
1271  return state;
1272 }
1273 
1274 
1275 std::string
1276 NBOwnTLDef::allowByVClass(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges, SVCPermissions perm) {
1277  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1278  SVCPermissions linkPerm = (fromEdges[i1]->getPermissions() & toEdges[i1]->getPermissions());
1279  if ((linkPerm & ~perm) == 0) {
1280  state[i1] = 'G';
1281  }
1282  }
1283  return state;
1284 }
1285 
1286 
1287 bool
1288 NBOwnTLDef::forbidden(const std::string& state, int index, const EdgeVector& fromEdges, const EdgeVector& toEdges, bool allowCont) {
1289  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1290  if (state[i2] == 'G' && foes(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index])) {
1291  if (!allowCont || (
1292  !needsCont(fromEdges[i2], toEdges[i2], fromEdges[index], toEdges[index]) &&
1293  !needsCont(fromEdges[index], toEdges[index], fromEdges[i2], toEdges[i2]))) {
1294  return true;
1295  }
1296  }
1297  }
1298  return false;
1299 }
1300 
1301 
1302 std::string
1303 NBOwnTLDef::correctConflicting(std::string state, const EdgeVector& fromEdges, const EdgeVector& toEdges,
1304  const std::vector<bool>& isTurnaround,
1305  const std::vector<int>& fromLanes,
1306  const std::vector<int>& toLanes,
1307  const std::vector<bool>& hadGreenMajor,
1308  bool& haveForbiddenLeftMover,
1309  std::vector<bool>& rightTurnConflicts,
1310  std::vector<bool>& mergeConflicts) {
1311  const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
1312  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1313  if (state[i1] == 'G') {
1314  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1315  if ((state[i2] == 'G' || state[i2] == 'g')) {
1317  fromEdges[i1], toEdges[i1], fromLanes[i1], fromEdges[i2], toEdges[i2], fromLanes[i2])) {
1318  rightTurnConflicts[i1] = true;
1319  }
1320  if (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true, controlledWithin) || rightTurnConflicts[i1]) {
1321  state[i1] = 'g';
1322  if (myControlledNodes.size() == 1) {
1323  myNeedsContRelation.insert(StreamPair(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2]));
1324 #ifdef DEBUG_CONTRELATION
1325  if (DEBUGCOND) {
1326  std::cout << getID() << " p=" << getProgramID() << " contRel: " << fromEdges[i1]->getID() << "->" << toEdges[i1]->getID()
1327  << " foe " << fromEdges[i2]->getID() << "->" << toEdges[i2]->getID() << "\n";
1328  }
1329 #endif
1330  }
1331  if (!isTurnaround[i1] && !hadGreenMajor[i1] && !rightTurnConflicts[i1]) {
1332  haveForbiddenLeftMover = true;
1333  }
1334  } else if (fromEdges[i1] == fromEdges[i2]
1335  && fromLanes[i1] != fromLanes[i2]
1336  && toEdges[i1] == toEdges[i2]
1337  && toLanes[i1] == toLanes[i2]
1338  && fromEdges[i1]->getToNode()->mergeConflictYields(fromEdges[i1], fromLanes[i1], fromLanes[i2], toEdges[i1], toLanes[i1])) {
1339  mergeConflicts[i1] = true;
1340  state[i1] = 'g';
1341  }
1342  }
1343  }
1344  }
1345  if (state[i1] == 'r') {
1346  if (fromEdges[i1]->getToNode()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
1347  fromEdges[i1]->getToNode()->getDirection(fromEdges[i1], toEdges[i1]) == LinkDirection::RIGHT) {
1348  state[i1] = 's';
1349  // do not allow right-on-red when in conflict with exclusive left-turn phase
1350  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1351  if (state[i2] == 'G' && !isTurnaround[i2] &&
1352  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1353  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1354  const LinkDirection foeDir = fromEdges[i2]->getToNode()->getDirection(fromEdges[i2], toEdges[i2]);
1355  if (foeDir == LinkDirection::LEFT || foeDir == LinkDirection::PARTLEFT) {
1356  state[i1] = 'r';
1357  break;
1358  }
1359  }
1360  }
1361  if (state[i1] == 's') {
1362  // handle right-on-red conflicts
1363  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1364  if (state[i2] == 'G' && !isTurnaround[i2] &&
1365  (forbids(fromEdges[i2], toEdges[i2], fromEdges[i1], toEdges[i1], true) ||
1366  forbids(fromEdges[i1], toEdges[i1], fromEdges[i2], toEdges[i2], true))) {
1367  myRightOnRedConflicts.insert(std::make_pair(i1, i2));
1368  }
1369  }
1370  }
1371  }
1372  }
1373  }
1374  return state;
1375 }
1376 
1377 
1378 std::string
1379 NBOwnTLDef::correctMixed(std::string state, const EdgeVector& fromEdges,
1380  const std::vector<int>& fromLanes,
1381  bool& buildMixedGreenPhase, std::vector<bool>& mixedGreen) {
1382  for (int i1 = 0; i1 < (int)fromEdges.size(); ++i1) {
1383  if ((state[i1] == 'G' || state[i1] == 'g')) {
1384  for (int i2 = 0; i2 < (int)fromEdges.size(); ++i2) {
1385  if (i1 != i2 && fromEdges[i1] == fromEdges[i2] && fromLanes[i1] == fromLanes[i2]
1386  && state[i2] != 'G' && state[i2] != 'g') {
1387  state[i1] = state[i2];
1388  //std::cout << " mixedGreen i1=" << i1 << " i2=" << i2 << "\n";
1389  mixedGreen[i1] = true;
1390  if (fromEdges[i1]->getNumLanesThatAllow(SVC_PASSENGER) > 1) {
1391  buildMixedGreenPhase = true;
1392  }
1393  }
1394  }
1395  }
1396  }
1397  return state;
1398 }
1399 
1400 
1401 void
1403  std::vector<bool> foundGreen(fromEdges.size(), false);
1404  for (const auto& phase : logic->getPhases()) {
1405  const std::string state = phase.state;
1406  for (int j = 0; j < (int)fromEdges.size(); j++) {
1407  LinkState ls = (LinkState)state[j];
1409  foundGreen[j] = true;
1410  }
1411  }
1412  }
1413  for (int j = 0; j < (int)foundGreen.size(); j++) {
1414  if (!foundGreen[j]) {
1415  NBEdge* e = fromEdges[j];
1416  if (std::find(toProc.begin(), toProc.end(), e) == toProc.end()) {
1417  toProc.push_back(e);
1418  }
1419  }
1420  }
1421 }
1422 
1423 
1424 void
1425 NBOwnTLDef::addPedestrianScramble(NBTrafficLightLogic* logic, int totalNumLinks, SUMOTime /* greenTime */, SUMOTime brakingTime,
1426  const std::vector<NBNode::Crossing*>& crossings, const EdgeVector& fromEdges, const EdgeVector& toEdges) {
1427  const int vehLinks = totalNumLinks - (int)crossings.size();
1428  std::vector<bool> foundGreen(crossings.size(), false);
1429  const std::vector<NBTrafficLightLogic::PhaseDefinition>& phases = logic->getPhases();
1430  for (int i = 0; i < (int)phases.size(); i++) {
1431  const std::string state = phases[i].state;
1432  for (int j = 0; j < (int)crossings.size(); j++) {
1433  LinkState ls = (LinkState)state[vehLinks + j];
1435  foundGreen[j] = true;
1436  }
1437  }
1438  }
1439 #ifdef DEBUG_PHASES
1440  if (DEBUGCOND2(logic)) {
1441  std::cout << " foundCrossingGreen=" << toString(foundGreen) << "\n";
1442  }
1443 #endif
1444  for (int j = 0; j < (int)foundGreen.size(); j++) {
1445  if (!foundGreen[j]) {
1446  // add a phase where all pedestrians may walk, (preceded by a yellow phase and followed by a clearing phase)
1447  if (phases.size() > 0) {
1448  bool needYellowPhase = false;
1449  std::string state = phases.back().state;
1450  for (int i1 = 0; i1 < vehLinks; ++i1) {
1451  if (state[i1] == 'G' || state[i1] == 'g') {
1452  state[i1] = 'y';
1453  needYellowPhase = true;
1454  }
1455  }
1456  // add yellow step
1457  if (needYellowPhase && brakingTime > 0) {
1458  logic->addStep(brakingTime, state);
1459  }
1460  }
1461  const SUMOTime pedClearingTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.crossing-clearance.time"));
1462  const SUMOTime scrambleTime = TIME2STEPS(OptionsCont::getOptions().getInt("tls.scramble.time"));
1463  addPedestrianPhases(logic, scrambleTime + pedClearingTime, UNSPECIFIED_DURATION,
1464  UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, UNSPECIFIED_DURATION, std::string(totalNumLinks, 'r'), crossings, fromEdges, toEdges);
1465  break;
1466  }
1467  }
1468 }
1469 
1470 
1471 void
1472 NBOwnTLDef::buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic* logic, const std::string& state) {
1473  if (allRedTime > 0) {
1474  // build all-red phase
1475  std::string allRedState = state;
1476  for (int i = 0; i < (int)state.size(); i++) {
1477  if (allRedState[i] == 'Y' || allRedState[i] == 'y') {
1478  allRedState[i] = 'r';
1479  }
1480  }
1481  logic->addStep(TIME2STEPS(ceil(STEPS2TIME(allRedTime))), allRedState);
1482  }
1483 }
1484 
1485 
1486 void
1488  int minCustomIndex = -1;
1489  int maxCustomIndex = -1;
1490  // collect crossings
1491  for (std::vector<NBNode*>::const_iterator i = myControlledNodes.begin(); i != myControlledNodes.end(); i++) {
1492  const std::vector<NBNode::Crossing*>& c = (*i)->getCrossings();
1493  for (auto crossing : c) {
1494  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex);
1495  minCustomIndex = MIN2(minCustomIndex, crossing->customTLIndex2);
1496  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex);
1497  maxCustomIndex = MAX2(maxCustomIndex, crossing->customTLIndex2);
1498  }
1499  }
1500  // custom crossing linkIndex could lead to longer states. ensure that every index has a state
1501  if (maxCustomIndex >= logic->getNumLinks()) {
1502  logic->setStateLength(maxCustomIndex + 1);
1503  }
1504  // XXX shorter state vectors are possible as well
1505  // XXX if the indices are shuffled the guessed crossing states should be shuffled correspondingly
1506  // XXX initialize the backward index to the same state as the forward index
1507 }
1508 
1509 void
1511  // assume that yellow states last at most one phase
1512  const int n = logic->getNumLinks();
1513  const int p = (int)logic->getPhases().size();
1514  for (int i1 = 0; i1 < n; ++i1) {
1515  LinkState prev = (LinkState)logic->getPhases().back().state[i1];
1516  for (int i2 = 0; i2 < p; ++i2) {
1517  LinkState cur = (LinkState)logic->getPhases()[i2].state[i1];
1518  LinkState next = (LinkState)logic->getPhases()[(i2 + 1) % p].state[i1];
1519  if (cur == LINKSTATE_TL_YELLOW_MINOR
1520  && (prev == LINKSTATE_TL_GREEN_MAJOR || prev == LINKSTATE_TL_YELLOW_MINOR)
1521  && next == LINKSTATE_TL_GREEN_MAJOR) {
1522  logic->setPhaseState(i2, i1, prev);
1523  }
1524  prev = cur;
1525  }
1526  }
1527 }
1528 
1529 
1530 void
1532  const int n = logic->getNumLinks();
1533  std::vector<bool> alwaysGreen(n, true);
1534  for (int i1 = 0; i1 < n; ++i1) {
1535  for (const auto& phase : logic->getPhases()) {
1536  if (phase.state[i1] != 'G') {
1537  alwaysGreen[i1] = false;
1538  break;
1539  }
1540  }
1541  }
1542  const int p = (int)logic->getPhases().size();
1543  for (int i1 = 0; i1 < n; ++i1) {
1544  if (alwaysGreen[i1]) {
1545  for (int i2 = 0; i2 < p; ++i2) {
1546  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1547  }
1548  }
1549  }
1550 }
1551 
1552 
1553 void
1555  const int n = logic->getNumLinks();
1556  const int p = (int)logic->getPhases().size();
1557  for (int i1 = 0; i1 < n; ++i1) {
1558  if (fromEdges[i1]->isInsideTLS()) {
1559  for (int i2 = 0; i2 < p; ++i2) {
1560  logic->setPhaseState(i2, i1, LINKSTATE_TL_OFF_NOSIGNAL);
1561  }
1562  }
1563  }
1564 }
1565 
1566 
1567 SUMOTime
1568 NBOwnTLDef::computeEscapeTime(const std::string& state, const EdgeVector& fromEdges, const EdgeVector& toEdges) const {
1569  const int n = (int)state.size();
1570  double maxTime = 0;
1571  for (int i1 = 0; i1 < n; ++i1) {
1572  if (state[i1] == 'y' && !fromEdges[i1]->isInsideTLS()) {
1573  for (int i2 = 0; i2 < n; ++i2) {
1574  if (fromEdges[i2]->isInsideTLS()) {
1575  double gapSpeed = (toEdges[i1]->getSpeed() + fromEdges[i2]->getSpeed()) / 2;
1576  double time = fromEdges[i1]->getGeometry().back().distanceTo2D(fromEdges[i2]->getGeometry().back()) / gapSpeed;
1577  maxTime = MAX2(maxTime, time);
1578  }
1579  }
1580  }
1581  }
1582  // give some slack
1583  return TIME2STEPS(floor(maxTime * 1.2 + 5));
1584 }
1585 
1586 
1587 int
1591  if (logic != nullptr) {
1592  return logic->getNumLinks() - 1;
1593  } else {
1594  return -1;
1595  }
1596 }
1597 
1598 
1599 bool
1601  if (getID() == DummyID) {
1602  // avoid infinite recursion
1603  return true;
1604  }
1605  assert(myControlledNodes.size() >= 2);
1608  NBTrafficLightLogic* tllDummy = dummy.computeLogicAndConts(0, true);
1609  int greenPhases = 0;
1610  for (const auto& phase : tllDummy->getPhases()) {
1611  if (phase.state.find_first_of("gG") != std::string::npos) {
1612  greenPhases++;
1613  }
1614  }
1615  delete tllDummy;
1616  for (const auto& controlledNode : myControlledNodes) {
1617  controlledNode->removeTrafficLight(&dummy);
1618  }
1619  return greenPhases <= 2;
1620 }
1621 
1622 
1625  const EdgeVector& fromEdges,
1626  const EdgeVector& toEdges,
1627  const std::vector<NBNode::Crossing*>& crossings,
1628  const std::vector<std::pair<NBEdge*, NBEdge*> >& chosenList,
1629  const std::vector<std::string>& straightStates,
1630  const std::vector<std::string>& leftStates) {
1631  if (chosenList.size() != 2) {
1632  return nullptr;
1633  }
1634  const SUMOTime dur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.cycle.time"));
1635  const SUMOTime vehExt = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.vehExt"));
1636  const SUMOTime yellow = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.yellow"));
1637  const SUMOTime red = TIME2STEPS(OptionsCont::getOptions().getInt("tls.nema.red"));
1638  const SUMOTime minMinDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.min-dur"));
1639  const SUMOTime maxDur = TIME2STEPS(OptionsCont::getOptions().getInt("tls.max-dur"));
1640  const SUMOTime earliestEnd = UNSPECIFIED_DURATION;
1641  const SUMOTime latestEnd = UNSPECIFIED_DURATION;
1642 
1643  const int totalNumLinks = (int)straightStates[0].size();
1644  NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), totalNumLinks, myOffset, myType);
1645  std::vector<int> ring1({1, 2, 3, 4});
1646  std::vector<int> ring2({5, 6, 7, 8});
1647  std::vector<int> barrier1({4, 8});
1648  std::vector<int> barrier2({2, 6});
1649  int phaseNameLeft = 1;
1650  for (int i = 0; i < (int)chosenList.size(); i++) {
1651  NBEdge* e1 = chosenList[i].first;
1652  assert(e1 != nullptr);
1653  NBEdge* e2 = chosenList[i].second;
1654  if (i < (int)leftStates.size()) {
1655  std::string left1 = filterState(leftStates[i], fromEdges, e1);
1656  if (left1 != "") {
1657  logic->addStep(dur, left1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft));
1658  }
1659  }
1660  if (e2 != nullptr) {
1661  std::string straight2 = filterState(straightStates[i], fromEdges, e2);
1662  straight2 = patchNEMAStateForCrossings(straight2, crossings, fromEdges, toEdges, e2, e1);
1663 
1664  logic->addStep(dur, straight2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 1));
1665  if (i < (int)leftStates.size()) {
1666  std::string left2 = filterState(leftStates[i], fromEdges, e2);
1667  if (left2 != "") {
1668  logic->addStep(dur, left2, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 4));
1669  }
1670  }
1671 
1672  }
1673  std::string straight1 = filterState(straightStates[i], fromEdges, e1);
1674  if (straight1 == "") {
1675  delete logic;
1676  return nullptr;
1677  }
1678  straight1 = patchNEMAStateForCrossings(straight1, crossings, fromEdges, toEdges, e1, e2);
1679  logic->addStep(dur, straight1, minMinDur, maxDur, earliestEnd, latestEnd, vehExt, yellow, red, toString(phaseNameLeft + 5));
1680  phaseNameLeft += 2;
1681  }
1682  std::map<int, int> names; // nema phase name -> sumo phase index
1683  for (int i = 0; i < (int)logic->getPhases().size(); i++) {
1684  names[StringUtils::toInt(logic->getPhases()[i].name)] = i;
1685  }
1686 
1687  filterMissingNames(ring1, names, false);
1688  filterMissingNames(ring2, names, false);
1689  filterMissingNames(barrier1, names, true, 8);
1690  filterMissingNames(barrier2, names, true, 6);
1691  if (ring1[0] == 0 && ring1[1] == 0) {
1692  ring1[1] = 6;
1693  }
1694  if (ring1[2] == 0 && ring1[3] == 0) {
1695  ring1[3] = 8;
1696  }
1697  fixDurationSum(logic, names, ring1[0], ring1[1], ring2[0], ring2[1]);
1698  fixDurationSum(logic, names, ring1[2], ring1[3], ring2[2], ring2[3]);
1699 
1700  logic->setParameter("ring1", joinToString(ring1, ","));
1701  logic->setParameter("ring2", joinToString(ring2, ","));
1702  logic->setParameter("barrierPhases", joinToString(barrier1, ","));
1703  logic->setParameter("barrier2Phases", joinToString(barrier2, ","));
1704  return logic;
1705 }
1706 
1707 
1708 std::string
1709 NBOwnTLDef::filterState(std::string state, const EdgeVector& fromEdges, const NBEdge* e) {
1710  bool haveGreen = false;
1711  for (int j = 0; j < (int)fromEdges.size(); j++) {
1712  if (fromEdges[j] != e) {
1713  state[j] = 'r';
1714  } else if (state[j] != 'r') {
1715  haveGreen = true;
1716  }
1717  }
1718  if (haveGreen) {
1719  return state;
1720  } else {
1721  return "";
1722  }
1723 }
1724 
1725 void
1726 NBOwnTLDef::filterMissingNames(std::vector<int>& vec, const std::map<int, int>& names, bool isBarrier, int barrierDefault) {
1727  for (int i = 0; i < (int)vec.size(); i++) {
1728  if (names.count(vec[i]) == 0) {
1729  if (isBarrier) {
1730  if (names.count(vec[i] - 1) > 0) {
1731  vec[i] = vec[i] - 1;
1732  } else {
1733  vec[i] = barrierDefault;
1734  }
1735  } else {
1736  vec[i] = 0;
1737  }
1738  }
1739  }
1740 }
1741 
1742 void
1743 NBOwnTLDef::fixDurationSum(NBTrafficLightLogic* logic, const std::map<int, int>& names, int ring1a, int ring1b, int ring2a, int ring2b) {
1744  std::set<int> ring1existing;
1745  std::set<int> ring2existing;
1746  if (names.count(ring1a) != 0) {
1747  ring1existing.insert(ring1a);
1748  }
1749  if (names.count(ring1b) != 0) {
1750  ring1existing.insert(ring1b);
1751  }
1752  if (names.count(ring2a) != 0) {
1753  ring2existing.insert(ring2a);
1754  }
1755  if (names.count(ring2b) != 0) {
1756  ring2existing.insert(ring2b);
1757  }
1758  if (ring1existing.size() > 0 && ring2existing.size() > 0 &&
1759  ring1existing.size() != ring2existing.size()) {
1760  int pI; // sumo phase index
1761  if (ring1existing.size() < ring2existing.size()) {
1762  pI = names.find(*ring1existing.begin())->second;
1763  } else {
1764  pI = names.find(*ring2existing.begin())->second;
1765  }
1766  const auto& p = logic->getPhases()[pI];
1767  SUMOTime newMaxDur = 2 * p.maxDur + p.yellow + p.red;
1768  logic->setPhaseMaxDuration(pI, newMaxDur);
1769  }
1770 }
1771 
1772 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
@ DEFAULT
default cursor
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define TL(string)
Definition: MsgHandler.h:315
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
#define DEBUGCOND
Definition: NBOwnTLDef.cpp:48
#define MIN_GREEN_TIME
Definition: NBOwnTLDef.cpp:42
#define HEIGH_WEIGHT
Definition: NBOwnTLDef.cpp:39
#define DEBUGEDGE(edge)
Definition: NBOwnTLDef.cpp:52
#define DEBUGCOND2(obj)
Definition: NBOwnTLDef.cpp:49
#define LOW_WEIGHT
Definition: NBOwnTLDef.cpp:40
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition: SUMOTime.h:55
#define SUMOTime_MAX
Definition: SUMOTime.h:34
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
bool isForbidden(SVCPermissions permissions)
Returns whether an edge with the given permission is a forbidden edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_TRAM
vehicle is a light rail
@ SVC_PEDESTRIAN
pedestrian
TrafficLightType
TrafficLightLayout
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_YELLOW_MINOR
The link has yellow light, has to brake anyway.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
@ LINKSTATE_TL_OFF_NOSIGNAL
The link is controlled by a tls which is off, not blinking, may pass.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:172
NBEdge * getFrom() const
returns the from-edge (start of the connection)
static void nextCCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
The representation of a single edge during network building.
Definition: NBEdge.h:92
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4308
const std::string & getID() const
Definition: NBEdge.h:1522
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:542
bool setControllingTLInformation(const NBConnection &c, const std::string &tlID)
Returns if the link could be set as to be controlled.
Definition: NBEdge.cpp:3656
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:516
std::vector< Connection > getConnectionsFromLane(int lane, const NBEdge *to=nullptr, int toLane=-1) const
Returns connections from a given lane.
Definition: NBEdge.cpp:1252
int getJunctionPriority(const NBNode *const node) const
Returns the junction priority (normalised for the node currently build)
Definition: NBEdge.cpp:2084
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3937
const std::vector< Connection > & getConnections() const
Returns the connections.
Definition: NBEdge.h:1035
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:535
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition: NBHelpers.cpp:45
A definition of a pedestrian crossing.
Definition: NBNode.h:135
const NBNode * node
The parent node of this crossing.
Definition: NBNode.h:140
EdgeVector edges
The edges being crossed.
Definition: NBNode.h:142
Represents a single node (junction) during network building.
Definition: NBNode.h:66
LinkDirection getDirection(const NBEdge *const incoming, const NBEdge *const outgoing, bool leftHand=false) const
Returns the representation of the described stream's direction.
Definition: NBNode.cpp:2349
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:2034
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:2015
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:278
Sorts edges by their priority within the node they end at.
Definition: NBOwnTLDef.h:321
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
void fixSuperfluousYellow(NBTrafficLightLogic *logic) const
avoid yellow signal between successive green (major) phases
std::string correctConflicting(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< int > &fromLanes, const std::vector< int > &toLanes, const std::vector< bool > &hadGreenMajor, bool &haveForbiddenLeftMover, std::vector< bool > &rightTurnConflicts, std::vector< bool > &mergeConflicts)
change 'G' to 'g' for conflicting connections
NBTrafficLightLogic * buildNemaPhases(const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< NBNode::Crossing * > &crossings, const std::vector< std::pair< NBEdge *, NBEdge * > > &chosenList, const std::vector< std::string > &straightStates, const std::vector< std::string > &leftStates)
void checkCustomCrossingIndices(NBTrafficLightLogic *logic) const
fix states in regard to custom crossing indices
static std::string patchStateForCrossings(const std::string &state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
compute phase state in regard to pedestrian crossings
Definition: NBOwnTLDef.cpp:934
std::string allowByVClass(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, SVCPermissions perm)
int getMaxIndex()
Returns the maximum index controlled by this traffic light.
bool myHaveSinglePhase
Whether left-mover should not have an additional phase.
Definition: NBOwnTLDef.h:338
bool corridorLike() const
test whether a joined tls with layout 'opposites' would be built without dedicated left-turn phase
SUMOTime computeEscapeTime(const std::string &state, const EdgeVector &fromEdges, const EdgeVector &toEdges) const
compute time to clear all vehicles from within an alternateOneWay layout
void replaceRemoved(NBEdge *removed, int removedLane, NBEdge *by, int byLane, bool incoming)
Replaces a removed edge/lane.
std::pair< NBEdge *, NBEdge * > getBestPair(EdgeVector &incoming)
Returns the combination of two edges from the given which has most unblocked streams.
Definition: NBOwnTLDef.cpp:224
~NBOwnTLDef()
Destructor.
Definition: NBOwnTLDef.cpp:88
void collectLinks()
Collects the links participating in this traffic light.
void deactivateAlwaysGreen(NBTrafficLightLogic *logic) const
switch of signal for links that are always green
static void addGreenWithin(NBTrafficLightLogic *logic, const EdgeVector &fromEdges, EdgeVector &toProc)
ensure inner edges all get the green light eventually
NBTrafficLightLogic * computeLogicAndConts(int brakingTimeSeconds, bool onlyConts=false)
helper function for myCompute
Definition: NBOwnTLDef.cpp:277
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:874
std::string allowPredecessors(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
void deactivateInsideEdges(NBTrafficLightLogic *logic, const EdgeVector &fromEdges) const
switch of signal for links that are inside a joined tls
double computeUnblockedWeightedStreamNumber(const NBEdge *const e1, const NBEdge *const e2)
Returns how many streams outgoing from the edges can pass the junction without being blocked.
Definition: NBOwnTLDef.cpp:114
void remapRemoved(NBEdge *removed, const EdgeVector &incoming, const EdgeVector &outgoing)
Replaces occurrences of the removed edge in incoming/outgoing edges of all definitions.
int getToPrio(const NBEdge *const e)
Returns this edge's priority at the node it ends at.
Definition: NBOwnTLDef.cpp:92
std::string allowCompatible(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< int > &fromLanes, const std::vector< int > &toLanes)
allow connections that are compatible with the chosen edges
std::string correctMixed(std::string state, const EdgeVector &fromEdges, const std::vector< int > &fromLanes, bool &buildMixedGreenPhase, std::vector< bool > &mixedGreen)
prevent green and red from the same lane
void fixDurationSum(NBTrafficLightLogic *logic, const std::map< int, int > &names, int ring1a, int ring1b, int ring2a, int ring2b)
ensure that phase max durations before each barrier have the same sum in both rings
NBTrafficLightLogic * myCompute(int brakingTimeSeconds)
Computes the traffic light logic finally in dependence to the type.
Definition: NBOwnTLDef.cpp:271
static std::string patchNEMAStateForCrossings(const std::string &state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges, const NBEdge *greenEdge, NBEdge *otherChosen)
Definition: NBOwnTLDef.cpp:982
std::string filterState(std::string state, const EdgeVector &fromEdges, const NBEdge *e)
mask out all greens that do not originate at the given edge
std::string allowFollowers(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges)
void buildAllRedState(SUMOTime allRedTime, NBTrafficLightLogic *logic, const std::string &state)
double getDirectionalWeight(LinkDirection dir)
Returns the weight of a stream given its direction.
Definition: NBOwnTLDef.cpp:98
std::string allowSingleEdge(std::string state, const EdgeVector &fromEdges)
bool hasStraightConnection(const NBEdge *fromEdge)
check whether there is a straight connection from this edge
Definition: NBOwnTLDef.cpp:260
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:185
void initNeedsContRelation() const
static void addPedestrianScramble(NBTrafficLightLogic *logic, int totalNumLinks, SUMOTime greenTime, SUMOTime yellowTime, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add an additional pedestrian phase if there are crossings that did not get green yet
NBOwnTLDef(const std::string &id, const std::vector< NBNode * > &junctions, SUMOTime offset, TrafficLightType type)
Constructor.
Definition: NBOwnTLDef.cpp:63
static EdgeVector getConnectedOuterEdges(const EdgeVector &incoming)
get edges that have connections
TrafficLightLayout myLayout
the layout for generated signal plans
Definition: NBOwnTLDef.h:341
bool forbidden(const std::string &state, int index, const EdgeVector &fromEdges, const EdgeVector &toEdges, bool allowCont)
whether the given index is forbidden by a green link in the current state
static std::string addPedestrianPhases(NBTrafficLightLogic *logic, const SUMOTime greenTime, const SUMOTime minDur, const SUMOTime maxDur, const SUMOTime earliestEnd, const SUMOTime latestEnd, std::string state, const std::vector< NBNode::Crossing * > &crossings, const EdgeVector &fromEdges, const EdgeVector &toEdges)
add 1 or 2 phases depending on the presence of pedestrian crossings
Definition: NBOwnTLDef.cpp:893
std::string allowUnrelated(std::string state, const EdgeVector &fromEdges, const EdgeVector &toEdges, const std::vector< bool > &isTurnaround, const std::vector< NBNode::Crossing * > &crossings)
void filterMissingNames(std::vector< int > &vec, const std::map< int, int > &names, bool isBarrier, int barrierDefault=0)
keep only valid NEMA phase names (for params)
void setTLControllingInformation() const
Informs edges about being controlled by a tls.
static const double MIN_SPEED_CROSSING_TIME
minimum speed for computing time to cross intersection
Definition: NBOwnTLDef.h:152
The base class for traffic light logic definitions.
const std::string & getProgramID() const
Returns the ProgramID.
const EdgeVector & getIncomingEdges() const
Returns the list of incoming edges (must be build first)
bool needsCont(const NBEdge *fromE, const NBEdge *toE, const NBEdge *otherFromE, const NBEdge *otherToE) const
std::vector< NBNode * > myControlledNodes
The container with participating nodes.
TrafficLightType getType() const
get the algorithm type (static etc..)
EdgeVector myIncomingEdges
The list of incoming edges.
NBTrafficLightLogic * compute(const OptionsCont &oc)
Computes the traffic light logic.
RightOnRedConflicts myRightOnRedConflicts
TrafficLightType myType
The algorithm type for the traffic light.
EdgeVector myEdgesWithin
The list of edges within the area controlled by the tls.
static const std::string DummyID
id for temporary definitions
bool forbids(const NBEdge *const possProhibitorFrom, const NBEdge *const possProhibitorTo, const NBEdge *const possProhibitedFrom, const NBEdge *const possProhibitedTo, bool regardNonSignalisedLowerPriority, bool sameNodeOnly=false) const
Returns the information whether "prohibited" flow must let "prohibitor" flow pass.
NBConnectionVector myControlledLinks
The list of controlled links.
virtual void setType(TrafficLightType type)
set the algorithm type (static etc..)
virtual void setParticipantsInformation()
Builds the list of participating nodes/edges/links.
void collectAllLinks(NBConnectionVector &into)
helper method for use in NBOwnTLDef and NBLoadedSUMOTLDef
SUMOTime myOffset
The offset in the program.
static const SUMOTime UNSPECIFIED_DURATION
bool foes(const NBEdge *const from1, const NBEdge *const to1, const NBEdge *const from2, const NBEdge *const to2) const
Returns the information whether the given flows cross.
A SUMO-compliant built logic for a traffic light.
SUMOTime getDuration() const
Returns the duration of the complete cycle.
void closeBuilding(bool checkVarDurations=true)
closes the building process
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)
void setPhaseMaxDuration(int phaseIndex, SUMOTime duration)
Modifies the max duration for an existing phase (used by netedit)
int getNumLinks()
Returns the number of participating links.
void setType(TrafficLightType type)
set the algorithm type (static etc..)
void setStateLength(int numLinks, LinkState fill=LINKSTATE_TL_RED)
void addStep(const SUMOTime duration, const std::string &state, const std::vector< int > &next=std::vector< int >(), const std::string &name="", const int index=-1)
Adds a phase to the logic (static)
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
static StringBijection< TrafficLightLayout > TrafficLightLayouts
traffic light layouts
T get(const std::string &str) const
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
A structure which describes a connection between edges or lanes.
Definition: NBEdge.h:201
data structure for caching needsCont information