Eclipse SUMO - Simulation of Urban MObility
libsumo/TrafficLight.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2017-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // C++ TraCI client API implementation
22 /****************************************************************************/
23 #include <config.h>
24 
26 #include <microsim/MSLane.h>
27 #include <microsim/MSEdge.h>
28 #include <microsim/MSNet.h>
41 #include <libsumo/TraCIConstants.h>
42 #include "Helper.h"
43 #include "TrafficLight.h"
44 
45 //#define DEBUG_CONSTRAINT_DEADLOCK
46 
47 namespace libsumo {
48 // ===========================================================================
49 // static member initializations
50 // ===========================================================================
51 SubscriptionResults TrafficLight::mySubscriptionResults;
52 ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
53 
54 
55 // ===========================================================================
56 // static member definitions
57 // ===========================================================================
58 std::vector<std::string>
59 TrafficLight::getIDList() {
61 }
62 
63 
64 int
65 TrafficLight::getIDCount() {
66  return (int)getIDList().size();
67 }
68 
69 
70 std::string
71 TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
73 }
74 
75 
76 std::vector<TraCILogic>
77 TrafficLight::getAllProgramLogics(const std::string& tlsID) {
78  std::vector<TraCILogic> result;
79  const std::vector<MSTrafficLightLogic*> logics = Helper::getTLS(tlsID).getAllLogics();
80  for (MSTrafficLightLogic* logic : logics) {
81  TraCILogic l(logic->getProgramID(), (int)logic->getLogicType(), logic->getCurrentPhaseIndex());
82  l.subParameter = logic->getParametersMap();
83  for (const MSPhaseDefinition* const phase : logic->getPhases()) {
84  l.phases.emplace_back(new TraCIPhase(STEPS2TIME(phase->duration), phase->getState(),
85  STEPS2TIME(phase->minDuration), STEPS2TIME(phase->maxDuration),
86  phase->getNextPhases(), phase->getName()));
87  }
88  result.emplace_back(l);
89  }
90  return result;
91 }
92 
93 
94 std::vector<std::string>
95 TrafficLight::getControlledJunctions(const std::string& tlsID) {
96  std::set<std::string> junctionIDs;
98  for (const MSTrafficLightLogic::LinkVector& llinks : links) {
99  for (const MSLink* l : llinks) {
100  junctionIDs.insert(l->getJunction()->getID());
101  }
102  }
103  return std::vector<std::string>(junctionIDs.begin(), junctionIDs.end());
104 }
105 
106 
107 std::vector<std::string>
108 TrafficLight::getControlledLanes(const std::string& tlsID) {
109  std::vector<std::string> laneIDs;
111  for (const MSTrafficLightLogic::LaneVector& llanes : lanes) {
112  for (const MSLane* l : llanes) {
113  laneIDs.push_back(l->getID());
114  }
115  }
116  return laneIDs;
117 }
118 
119 
120 std::vector<std::vector<TraCILink> >
121 TrafficLight::getControlledLinks(const std::string& tlsID) {
122  std::vector<std::vector<TraCILink> > result;
125  for (int i = 0; i < (int)lanes.size(); ++i) {
126  std::vector<TraCILink> subList;
127  const MSTrafficLightLogic::LaneVector& llanes = lanes[i];
128  const MSTrafficLightLogic::LinkVector& llinks = links[i];
129  // number of links controlled by this signal (signal i)
130  for (int j = 0; j < (int)llanes.size(); ++j) {
131  MSLink* link = llinks[j];
132  // approached non-internal lane (if any)
133  const std::string to = link->getLane() != nullptr ? link->getLane()->getID() : "";
134  // approached "via", internal lane (if any)
135  const std::string via = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
136  subList.emplace_back(TraCILink(llanes[j]->getID(), via, to));
137  }
138  result.emplace_back(subList);
139  }
140  return result;
141 }
142 
143 
144 std::string
145 TrafficLight::getProgram(const std::string& tlsID) {
146  return Helper::getTLS(tlsID).getActive()->getProgramID();
147 }
148 
149 
150 int
151 TrafficLight::getPhase(const std::string& tlsID) {
152  return Helper::getTLS(tlsID).getActive()->getCurrentPhaseIndex();
153 }
154 
155 
156 std::string
157 TrafficLight::getPhaseName(const std::string& tlsID) {
158  return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getName();
159 }
160 
161 
162 double
163 TrafficLight::getPhaseDuration(const std::string& tlsID) {
164  return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
165 }
166 
167 
168 double
169 TrafficLight::getNextSwitch(const std::string& tlsID) {
170  return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
171 }
172 
173 int
174 TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
175  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
176  if (index < 0 || active->getPhaseNumber() <= index) {
177  throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
178  + toString(active->getPhaseNumber() - 1) + "].");
179  }
180  // find all crossings which have a green light in that phas
181  int result = 0;
182 
183  const std::string& state = active->getPhases()[index]->getState();
184  for (int i = 0; i < (int)state.size(); i++) {
185  for (MSLink* link : active->getLinksAt(i)) {
186  if (link->getLane()->getEdge().isCrossing()) {
187  // walking forwards across
188  for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
189  if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
190  result += 1;
191  }
192  }
193  // walking backwards across
194  MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
195  for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
196  if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
197  result += 1;
198  }
199  }
200  } else if (link->getLaneBefore()->getEdge().isCrossing()) {
201  // walking backwards across (in case both sides are separately controlled)
202  for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
203  if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
204  result += 1;
205  }
206  }
207  }
208  }
209  }
210  return result;
211 }
212 
213 std::vector<std::string>
214 TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
215  std::vector<std::string> result;
216  // for railsignals we cannot use the "online" program
217  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
218  if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
219  throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
220  + toString(active->getNumLinks() - 1) + "].");
221  }
222  for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
223  result.push_back(veh->getID());
224  }
225  return result;
226 }
227 
228 std::vector<std::string>
229 TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
230  std::vector<std::string> result;
231  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
232  if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
233  throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
234  + toString(active->getNumLinks() - 1) + "].");
235  }
236  for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
237  result.push_back(veh->getID());
238  }
239  return result;
240 }
241 
242 std::vector<std::string>
243 TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
244  std::vector<std::string> result;
245  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
246  if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
247  throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
248  + toString(active->getNumLinks() - 1) + "].");
249  }
250  for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
251  result.push_back(veh->getID());
252  }
253  return result;
254 }
255 
256 std::vector<TraCISignalConstraint>
257 TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
258  std::vector<TraCISignalConstraint> result;
259  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
260  MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
261  if (s == nullptr) {
262  throw TraCIException("'" + tlsID + "' is not a rail signal");
263  }
264  for (auto item : s->getConstraints()) {
265  if (tripId != "" && tripId != item.first) {
266  continue;
267  }
268  for (MSRailSignalConstraint* c : item.second) {
269  result.push_back(buildConstraint(tlsID, item.first, c, false));
270  }
271  }
272  for (auto item : s->getInsertionConstraints()) {
273  if (tripId != "" && tripId != item.first) {
274  continue;
275  }
276  for (MSRailSignalConstraint* c : item.second) {
277  result.push_back(buildConstraint(tlsID, item.first, c, true));
278  }
279  }
280  return result;
281 }
282 
283 std::vector<TraCISignalConstraint>
284 TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
285  // retrieve all constraints that have the given foeSignal (optionally filtered by foeId)
286  // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
287  std::vector<TraCISignalConstraint> result;
288  for (const std::string& tlsID : getIDList()) {
289  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
290  MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
291  if (s != nullptr) {
292  for (auto item : s->getConstraints()) {
293  for (MSRailSignalConstraint* cand : item.second) {
295  if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
296  && (foeId == "" || pc->myTripId == foeId)) {
297  result.push_back(buildConstraint(s->getID(), item.first, pc, false));
298  }
299  }
300  }
301  for (auto item : s->getInsertionConstraints()) {
302  for (MSRailSignalConstraint* cand : item.second) {
304  if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
305  && (foeId == "" || pc->myTripId == foeId)) {
306  result.push_back(buildConstraint(s->getID(), item.first, pc, true));
307  }
308  }
309  }
310  }
311  }
312  return result;
313 }
314 
315 std::vector<TraCISignalConstraint>
316 TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
317 #ifdef DEBUG_CONSTRAINT_DEADLOCK
318  std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
319 #endif
320  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
321  MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
322  MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
323  MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
324  if (s == nullptr) {
325  throw TraCIException("'" + tlsID + "' is not a rail signal");
326  }
327  if (s2 == nullptr) {
328  throw TraCIException("'" + foeSignal + "' is not a rail signal");
329  }
331  for (auto item : s->getConstraints()) {
332  if (tripId == item.first) {
333  for (MSRailSignalConstraint* cand : item.second) {
335  if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
336  c = pc;
337  break;
338  }
339  }
340  break;
341  }
342  }
343  if (c != nullptr) {
344  const int limit = c->myLimit;
345  s->removeConstraint(tripId, c);
346  s2->addConstraint(foeId, new MSRailSignalConstraint_Predecessor(s, tripId, limit));
347  return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
348  } else {
349  throw TraCIException("Rail signal '" + tlsID + "' does not have a contraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
350  }
351 }
352 
353 void
354 TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
355  // remove all constraints that have the given foeId
356  // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
357  for (const std::string& tlsCand : getIDList()) {
358  if (tlsID == "" || tlsCand == tlsID) {
359  MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
360  MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
361  if (s != nullptr) {
362  auto cands = s->getConstraints(); // make copy
363  for (auto item : cands) {
364  if (tripId == "" || item.first == tripId) {
365  for (MSRailSignalConstraint* cand : item.second) {
367  if (pc != nullptr
368  && (foeId == "" || pc->myTripId == foeId)
369  && (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
370  s->removeConstraint(item.first, cand);
371  }
372  }
373  }
374  }
375  }
376  }
377  }
378 }
379 
380 
381 std::vector<TraCISignalConstraint>
382 TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
383  std::vector<TraCISignalConstraint> result;
384  // find circular constraints (deadlock)
385  // foeId is now constrainted by tripId and assumed to follow tripId on the
386  // same track without possibility of overtaking
387  // we look for a third vehicle foeId2 where
388  // tripId waits for foeId2 and foeId2 waits on foeId
389  std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
390  std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
391  std::set<std::string> foeId2Cands1;
392  std::set<std::string> foeId2Cands2;
393  for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
394  for (auto item : s->getConstraints()) {
395  for (MSRailSignalConstraint* cand : item.second) {
397  if (pc != nullptr && !pc->cleared()) {
398  if (item.first == tripId) {
399  // tripId waits for foe2
400  // @could there by more than one constraint on tripId by this foe2?
401  constraintsOnTripId[pc->myTripId] = buildConstraint(s->getID(), item.first, pc, false);
402  foeId2Cands1.insert(pc->myTripId);
403  } else if (pc->myTripId == foeId) {
404  // foeId2 waits for foe
405  constrainedByFoeId[item.first] = buildConstraint(s->getID(), item.first, pc, false);
406  foeId2Cands2.insert(item.first);
407  }
408  }
409  }
410  }
411  }
412  if (foeId2Cands1.size() > 0) {
413  // foe2 might be constrained implicitly by foe due to following on the same track
414  // in this case foe must be on the route of foe2 between its current position and foeSignal
415 
416  // we have to check this first because it also affects foeInsertion
417  // constraints if the foe is already inserted but hasn't yet passed the
418  // signal (cleared == false).
419  SUMOVehicle* foe = getVehicleByTripId(foeId);
420  if (foe != nullptr) {
421  const MSEdge* foeEdge = foe->getEdge();
422  const double foePos = foe->getPositionOnLane();
423  for (const std::string& foeId2 : foeId2Cands1) {
424  // tripId waits for foeId2
425  SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
426  if (foe2 != nullptr) {
427  const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
428  const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
429  bool foeAhead = false;
430  for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
431  const MSEdge* e = foe2Route[i];
432  if (e == foeEdge &&
433  ((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
434  || (foe->hasDeparted() && !foe2->hasDeparted())
435  || (!foe->hasDeparted() && !foe2->hasDeparted() &&
436  (foe->getParameter().depart < foe2->getParameter().depart
437  || (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
438  )) {
439  foeAhead = true;
440 #ifdef DEBUG_CONSTRAINT_DEADLOCK
441  std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
442  std::cout << " foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
443  << " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
444  //<< " foePos=" << foePos << " foe2Pos=" << foe2->getPositionOnLane()
445  << " " << constraintsOnTripId[foeId2].getString() << "\n";
446 #endif
447  break;
448  }
449  if (e->getToJunction()->getID() == foeSignal
450  || e->getToJunction()->getID() == c.foeSignal) {
451  break;
452  }
453  }
454  if (foeAhead) {
455  // foe cannot wait for foe2 (since it's behind). Instead foe2 must wait for tripId
456  TraCISignalConstraint nc; // constraint after swap
457  nc.tripId = c.foeId;
458  nc.foeId = c.tripId;
459  nc.signalId = c.foeSignal;
460  nc.foeSignal = c.signalId;
461  nc.limit = c.limit;
462  nc.type = c.type;
463  nc.mustWait = true; // ???
464  result.push_back(nc);
465  // let foe wait for foe2
466  std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
467  result.insert(result.end(), result2.begin(), result2.end());
468 
469  // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
470  const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, c.signalId);
471  result.insert(result.end(), result4.begin(), result4.end());
472  return result;
473  }
474  }
475  }
476  }
477  }
478 
479  if (foeId2Cands2.size() > 0) {
480  // tripId might be constrained implicitly by foe2 due to following on the same track
481  // in this case foe2 must be on the route of tripId between its current position and tlsID
482  // if foe2 then waits for foe, deadlock occurs
483 
484  SUMOVehicle* ego = getVehicleByTripId(tripId);
485  if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
486  std::set<const MSEdge*> egoToSignal;
487  const double egoPos = ego->getPositionOnLane();
488  const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
489  for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
490  const MSEdge* e = egoRoute[i];
491  egoToSignal.insert(e);
492  if (e->getToJunction()->getID() == tlsID) {
493  break;
494  }
495  }
496 
497  for (const std::string& foeId2 : foeId2Cands2) {
498  // foeId2 waits for foe
499  SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
500  //std::cout << " foe2=" << foe2->getID() << " edge=" << foe2->getEdge()->getID() << " egoToSignal=" << toString(egoToSignal) << "\n";
501  if (foe2 != nullptr) {
502  if (egoToSignal.count(foe2->getEdge()) != 0
503  && (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
504  const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
505 #ifdef DEBUG_CONSTRAINT_DEADLOCK
506  std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
507  std::cout << " egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
508  << " " << c.getString() << "\n";
509 #endif
510  // foe is already waiting for tripId (ego) and should also wait for foeId2
511  TraCISignalConstraint nc; // constraint after swap
512  nc.tripId = c.foeId;
513  nc.foeId = c.tripId;
514  nc.signalId = c.foeSignal;
515  nc.foeSignal = c.signalId;
516  nc.limit = c.limit;
517  nc.type = c.type;
518  nc.mustWait = true; // ???
519  result.push_back(nc);
520  // let foe wait for foe2
521  std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
522  result.insert(result.end(), result2.begin(), result2.end());
523 
524  // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
525  const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(c.foeId, c.tripId, c.foeSignal, c.signalId);
526  result.insert(result.end(), result4.begin(), result4.end());
527  return result;
528  }
529  }
530  }
531  } else if (ego != nullptr) {
532  WRITE_WARNING("Cannot check for all deadlocks on swapConstraints because the route for vehicle '" + ego->getID() + "' is not computed yet");
533  }
534  }
535 
536  // find deadlock in explicit constraints
537  std::vector<std::string> foeIds2;
538  std::set_intersection(
539  foeId2Cands1.begin(), foeId2Cands1.end(),
540  foeId2Cands2.begin(), foeId2Cands2.end(),
541  std::back_inserter(foeIds2));
542 #ifdef DEBUG_CONSTRAINT_DEADLOCK
543  std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
544  for (const std::string& foeId2 : foeIds2) {
545  std::cout << " deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
546  }
547 #endif
548  if (foeIds2.size() > 0) {
549  const TraCISignalConstraint& c = constrainedByFoeId[foeIds2.front()];
550  TraCISignalConstraint nc; // constraint after swap
551  nc.tripId = c.foeId;
552  nc.foeId = c.tripId;
553  nc.signalId = c.foeSignal;
554  nc.foeSignal = c.signalId;
555  nc.limit = c.limit;
556  nc.type = c.type;
557  nc.mustWait = true; // ???
558  result.push_back(nc);
559  // let foe wait for foe2
560  const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
561  result.insert(result.end(), result2.begin(), result2.end());
562  if (foeIds2.size() > 1) {
563  // calling swapConstraints once may result in further swaps so we have to recheck for remaining deadlocks anew
564  const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, c.signalId);
565  result.insert(result.end(), result3.begin(), result3.end());
566  }
567  }
568  return result;
569 }
570 
571 
573 TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
575  for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
576  SUMOVehicle* veh = i->second;
577  if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
578  return veh;
579  }
580  }
581  return nullptr;
582 }
583 
584 
585 std::string
586 TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
588  if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
589  throw TraCIException("'" + tlsID + "' is not a NEMA controller");
590  }
591  return tll->getParameter(paramName, "");
592 }
593 
594 
596 
597 
598 void
599 TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
600  Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
601 }
602 
603 
604 void
605 TrafficLight::setPhase(const std::string& tlsID, const int index) {
606  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
607  if (index < 0 || active->getPhaseNumber() <= index) {
608  throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
609  + toString(active->getPhaseNumber() - 1) + "].");
610  }
612  const SUMOTime duration = active->getPhase(index).duration;
613  active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
614 }
615 
616 void
617 TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
618  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
619  const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
620 }
621 
622 
623 void
624 TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
625  try {
626  Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
627  } catch (ProcessError& e) {
628  throw TraCIException(e.what());
629  }
630 }
631 
632 
633 void
634 TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
635  MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
637  active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
638 }
639 
640 
641 void
642 TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
644  // make sure index and phaseNo are consistent
645  if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
646  throw TraCIException("set program: parameter index must be less than parameter phase number.");
647  }
648  std::vector<MSPhaseDefinition*> phases;
649  for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
650  MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
651  sumoPhase->minDuration = TIME2STEPS(phase->minDur);
652  sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
653  sumoPhase->nextPhases = phase->next;
654  phases.push_back(sumoPhase);
655  }
656  if (vars.getLogic(logic.programID) == nullptr) {
658  int step = logic.currentPhaseIndex;
659  const std::string basePath = "";
660  MSTrafficLightLogic* tlLogic = nullptr;
661  SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
662  switch ((TrafficLightType)logic.type) {
664  tlLogic = new MSActuatedTrafficLightLogic(tlc,
665  tlsID, logic.programID, 0,
666  phases, step, nextSwitch,
667  logic.subParameter, basePath);
668  break;
670  tlLogic = new NEMALogic(tlc,
671  tlsID, logic.programID, 0,
672  phases, step, nextSwitch,
673  logic.subParameter, basePath);
674  break;
676  tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
677  tlsID, logic.programID, 0,
678  phases, step, nextSwitch,
679  logic.subParameter, basePath);
680  break;
682  tlLogic = new MSSimpleTrafficLightLogic(tlc,
683  tlsID, logic.programID, 0, TrafficLightType::STATIC,
684  phases, step, nextSwitch,
685  logic.subParameter);
686  break;
687  default:
688  throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
689  }
690  vars.addLogic(logic.programID, tlLogic, true, true);
691  // XXX pass GUIDetectorBuilder when running with gui
693  tlLogic->init(db);
695  } else {
696  static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID))->setPhases(phases, logic.currentPhaseIndex);
697  }
698 }
699 
700 
701 void
702 TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
704  if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
705  throw TraCIException("'" + tlsID + "' is not a NEMA controller");
706  }
707  tll->setParameter(paramName, value);
708 }
709 
711 
712 void
713 TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
714  setParameter(tlsID, "NEMA.splits", toString(splits));
715 }
716 
717 void
718 TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
719  setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
720 }
721 
722 void
723 TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
724  setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
725 }
726 
727 void
728 TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
729  setParameter(tlsID, "NEMA.offset", toString(offset));
730 }
731 
732 
734 TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint, bool insertionConstraint) {
735  TraCISignalConstraint c;
736  c.tripId = tripId;
738  if (pc == nullptr) {
739  // unsupported constraint
740  c.type = -1;
741  } else {
742  c.signalId = tlsID;
743  c.foeId = pc->myTripId;
744  c.foeSignal = pc->myFoeSignal->getID();
745  c.limit = pc->myLimit;
746  c.type = insertionConstraint ? 1 : 0;
747  c.mustWait = !pc->cleared();
748  }
749  return c;
750 }
751 
752 
753 std::shared_ptr<VariableWrapper>
754 TrafficLight::makeWrapper() {
755  return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
756 }
757 
758 
759 bool
760 TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
761  switch (variable) {
762  case TRACI_ID_LIST:
763  return wrapper->wrapStringList(objID, variable, getIDList());
764  case ID_COUNT:
765  return wrapper->wrapInt(objID, variable, getIDCount());
767  return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
768  case TL_CONTROLLED_LANES:
769  return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
770  case TL_CURRENT_PHASE:
771  return wrapper->wrapInt(objID, variable, getPhase(objID));
772  case VAR_NAME:
773  return wrapper->wrapString(objID, variable, getPhaseName(objID));
774  case TL_CURRENT_PROGRAM:
775  return wrapper->wrapString(objID, variable, getProgram(objID));
776  case TL_PHASE_DURATION:
777  return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
778  case TL_NEXT_SWITCH:
779  return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
781  return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
783  paramData->readUnsignedByte();
784  return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
786  paramData->readUnsignedByte();
787  return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
788  default:
789  return false;
790  }
791 }
792 }
793 
794 
795 /****************************************************************************/
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
const int VEHPARS_FORCE_REROUTE
TrafficLightType
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
#define LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(CLASS, DOMAIN)
Definition: TraCIDefs.h:69
#define LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(CLASS)
Definition: TraCIDefs.h:115
An actuated (adaptive) traffic light logic.
An actuated traffic light logic based on time delay of approaching vehicles.
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::set< MSTransportable * > & getPersons() const
Returns this edge's persons set.
Definition: MSEdge.h:198
const MSJunction * getToJunction() const
Definition: MSEdge.h:401
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:641
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:674
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
MSTLLogicControl & getTLSControl()
Returns the tls logics control.
Definition: MSNet.h:449
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:376
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:318
virtual void createTLWrapper(MSTrafficLightLogic *)
creates a wrapper for the given logic (see GUINet)
Definition: MSNet.h:575
const std::string & getNextEdge() const
return the list of internal edges if this person is walking and the pedestrian model allows it
Definition: MSPerson.cpp:480
The definition of a single phase of a tls logic.
const std::string & getState() const
Returns the state within this phase.
SUMOTime maxDuration
The maximum duration of the phase.
SUMOTime minDuration
The minimum duration of the phase.
SUMOTime duration
The duration of the phase.
const std::string & getName() const
std::vector< int > nextPhases
The index of the phase that suceeds this one (or -1)
const MSRailSignal * myFoeSignal
store the foe signal (for TraCI access)
bool cleared() const
whether the constraint has been met
const std::string myTripId
id of the predecessor that must already have passed
const int myLimit
the number of passed vehicles within which tripId must have occured
A base class for constraints.
static MSRailSignalControl & getInstance()
A signal for rails.
Definition: MSRailSignal.h:46
void addConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for signal switching
const std::map< std::string, std::vector< MSRailSignalConstraint * > > & getInsertionConstraints() const
Definition: MSRailSignal.h:236
bool removeConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
remove contraint for signal switching
const std::map< std::string, std::vector< MSRailSignalConstraint * > > & getConstraints() const
Definition: MSRailSignal.h:232
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:120
A fixed traffic light logic.
Storage for all programs of a single tls.
void switchTo(MSTLLogicControl &tlc, const std::string &programID)
void setStateInstantiatingOnline(MSTLLogicControl &tlc, const std::string &state)
std::vector< MSTrafficLightLogic * > getAllLogics() const
MSTrafficLightLogic * getLogic(const std::string &programID) const
bool addLogic(const std::string &programID, MSTrafficLightLogic *logic, bool netWasLoaded, bool isNewDefault=true)
Adds a logic (program)
MSTrafficLightLogic * getActive() const
MSTrafficLightLogic * getDefault() const
return the default program (that last used program except TRACI_PROGRAM)
A class that stores and controls tls and switching of their programs.
std::vector< std::string > getAllTLIds() const
The parent class for traffic light logics.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
virtual const MSPhaseDefinition & getCurrentPhaseDef() const =0
Returns the definition of the current phase.
std::vector< LaneVector > LaneVectorVector
Definition of a list that holds lists of lanes that do have the same attribute.
virtual int getPhaseNumber() const =0
Returns the number of phases.
virtual int getCurrentPhaseIndex() const =0
Returns the current index within the program.
std::vector< MSLane * > LaneVector
Definition of the list of arrival lanes subjected to this tls.
virtual const MSPhaseDefinition & getPhase(int givenstep) const =0
Returns the definition of the phase from the given position within the plan.
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
virtual VehicleVector getPriorityVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and have priority over vehicles that wish ...
virtual void changeStepAndDuration(MSTLLogicControl &tlcontrol, SUMOTime simStep, int step, SUMOTime stepDuration)=0
Changes the current phase and her duration.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
virtual VehicleVector getBlockingVehicles(int linkIndex)
return vehicles that block the intersection/rail signal for vehicles that wish to pass the given link...
virtual VehicleVector getRivalVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and are in conflict with vehicles that wis...
TrafficLightType getLogicType() const
Returns the type of the logic.
int getNumLinks() const
return the number of controlled link indices
std::vector< LinkVector > LinkVectorVector
Definition of a list that holds lists of links that do have the same attribute.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
virtual const Phases & getPhases() const =0
Returns the phases of this tls program.
virtual void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
const std::string & getProgramID() const
Returns this tl-logic's id.
const MSEdge * getEdge() const
Returns the current edge.
const MSLane * getLane() const
Returns the current lane (may be nullptr)
The class responsible for building and deletion of vehicles.
std::map< std::string, SUMOVehicle * >::const_iterator constVehIt
Definition of the internal vehicles map iterator.
constVehIt loadedVehBegin() const
Returns the begin of the internal vehicle map.
constVehIt loadedVehEnd() const
Returns the end of the internal vehicle map.
A NEMA (adaptive) traffic light logic based on E2Detector.
Builds detectors for microsim.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual bool hasDeparted() const =0
Returns whether this vehicle has departed.
virtual NumericalID getNumericalID() const =0
return the numerical ID which is only for internal usage
virtual int getRoutePosition() const =0
return index of edge within route
bool wasSet(int what) const
Returns whether the given parameter was set.
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
C++ TraCI client API implementation.
Definition: TrafficLight.h:32
static MSTLLogicControl::TLSLogicVariants & getTLS(const std::string &id)
Definition: Helper.cpp:516
virtual std::string readString()
Definition: storage.cpp:180
virtual int readUnsignedByte()
Definition: storage.cpp:155
TRACI_CONST int VAR_NAME
TRACI_CONST int TRACI_ID_LIST
std::map< std::string, libsumo::SubscriptionResults > ContextSubscriptionResults
Definition: TraCIDefs.h:279
TRACI_CONST int TL_CONTROLLED_LANES
TRACI_CONST int TL_CONTROLLED_JUNCTIONS
std::map< std::string, libsumo::TraCIResults > SubscriptionResults
{object->{variable->value}}
Definition: TraCIDefs.h:278
TRACI_CONST int ID_COUNT
TRACI_CONST int VAR_PARAMETER
TRACI_CONST int TL_NEXT_SWITCH
TRACI_CONST int VAR_PARAMETER_WITH_KEY
TRACI_CONST int TL_PHASE_DURATION
TRACI_CONST int TL_CURRENT_PHASE
TRACI_CONST int TL_RED_YELLOW_GREEN_STATE
TRACI_CONST int TL_CURRENT_PROGRAM
std::string tripId
the tripId or vehicle id of the train that is constrained
Definition: TraCIDefs.h:594