Eclipse SUMO - Simulation of Urban MObility
MSActuatedTrafficLightLogic.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 /****************************************************************************/
22 // An actuated (adaptive) traffic light logic
23 /****************************************************************************/
24 #include <config.h>
25 
26 #include <cassert>
27 #include <utility>
28 #include <vector>
29 #include <bitset>
34 #include <microsim/MSGlobals.h>
35 #include <microsim/MSNet.h>
36 #include <microsim/MSLane.h>
37 #include <microsim/MSEdge.h>
41 
42 //#define DEBUG_DETECTORS
43 //#define DEBUG_PHASE_SELECTION
44 #define DEBUG_COND (getID()=="C")
45 
46 // ===========================================================================
47 // static members
48 // ===========================================================================
49 const std::vector<std::string> MSActuatedTrafficLightLogic::OPERATOR_PRECEDENCE({
50  "**", "^", "*", "/", "+", "-", "%",
51  "=", "==", "!=", "<", ">", "<=", ">=",
52  "and", "&&", "or", "||",
53 });
54 
55 // ===========================================================================
56 // parameter defaults definitions
57 // ===========================================================================
58 #define DEFAULT_MAX_GAP "3.0"
59 #define DEFAULT_PASSING_TIME "1.9"
60 #define DEFAULT_DETECTOR_GAP "2.0"
61 #define DEFAULT_INACTIVE_THRESHOLD "180"
62 #define DEFAULT_CURRENT_PRIORITY 10
63 
64 #define DEFAULT_LENGTH_WITH_GAP 7.5
65 #define DEFAULT_BIKE_LENGTH_WITH_GAP (getDefaultVehicleLength(SVC_BICYCLE) + 0.5)
66 
67 #define NO_DETECTOR "NO_DETECTOR"
68 #define DEFAULT_CONDITION "DEFAULT"
69 
70 // ===========================================================================
71 // method definitions
72 // ===========================================================================
74  const std::string& id, const std::string& programID,
75  const SUMOTime offset,
76  const Phases& phases,
77  int step, SUMOTime delay,
78  const Parameterised::Map& parameter,
79  const std::string& basePath,
80  const ConditionMap& conditions,
81  const AssignmentMap& assignments,
82  const FunctionMap& functions) :
83  MSSimpleTrafficLightLogic(tlcontrol, id, programID, offset, TrafficLightType::ACTUATED, phases, step, delay, parameter),
84  myHasMultiTarget(false),
85  myLastTrySwitchTime(0),
86  myConditions(conditions),
87  myAssignments(assignments),
88  myFunctions(functions),
89  myTraCISwitch(false),
90  myDetectorPrefix(id + "_" + programID + "_") {
92  myJamThreshold = StringUtils::toDouble(getParameter("jam-threshold", OptionsCont::getOptions().getValueString("tls.actuated.jam-threshold")));
96  myShowDetectors = StringUtils::toBool(getParameter("show-detectors", toString(OptionsCont::getOptions().getBool("tls.actuated.show-detectors"))));
97  myBuildAllDetectors = StringUtils::toBool(getParameter("build-all-detectors", "false"));
98  myFile = FileHelpers::checkForRelativity(getParameter("file", "NUL"), basePath);
100  myVehicleTypes = getParameter("vTypes", "");
101 
102  if (hasParameter("hide-conditions")) {
103  std::vector<std::string> hidden = StringTokenizer(getParameter("hide-conditions", "")).getVector();
104  std::set<std::string> hiddenSet(hidden.begin(), hidden.end());
105  for (auto item : myConditions) {
106  if (hiddenSet.count(item.first) == 0) {
107  myListedConditions.insert(item.first);
108  }
109  }
110  } else {
111  const bool showAll = getParameter("show-conditions", "") == "";
112  std::vector<std::string> shown = StringTokenizer(getParameter("show-conditions", "")).getVector();
113  std::set<std::string> shownSet(shown.begin(), shown.end());
114  for (auto item : myConditions) {
115  if (showAll || shownSet.count(item.first) != 0) {
116  myListedConditions.insert(item.first);
117  }
118  }
119  }
120  if (hasParameter("extra-detectors")) {
121  const std::string extraIDs = getParameter("extra-detectors", "");
122  for (std::string customID : StringTokenizer(extraIDs).getVector()) {
123  try {
124  myExtraLoops.push_back(retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(customID, extraIDs, true));
125  } catch (ProcessError&) {
126  myExtraE2.push_back(retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(customID, extraIDs, true));
127  }
128  }
129  }
130  myStack.push_back(std::map<std::string, double>());
131 }
132 
133 
135 
136 void
141  if (myLanes.size() == 0) {
142  // must be an older network
143  WRITE_WARNINGF(TL("Traffic light '%' does not control any links"), getID());
144  }
145  bool warn = true; // warn only once
146  const int numLinks = (int)myLinks.size();
147 
148  // Detector position should be computed based on road speed. If the position
149  // is quite far away and the minDur is short this may cause the following
150  // problems:
151  //
152  // 1) high flow failure:
153  // In a standing queue, no vehicle touches the detector.
154  // By the time the queue advances, the detector gap has been exceeded and the phase terminates prematurely
155  //
156  // 2) low flow failure
157  // The standing queue is fully between stop line and detector and there are no further vehicles.
158  // The minDur is too short to let all vehicles pass
159  //
160  // Problem 2) is not so critical because there is less potential for
161  // jamming in a low-flow situation. In contrast, problem 1) should be
162  // avoided as it has big jamming potential. We compute an upper bound for the
163  // detector distance to avoid it
164 
165 
166  // change values for setting the loops and lanestate-detectors, here
167  //SUMOTime inductLoopInterval = 1; //
168  // build the induct loops
169  std::map<const MSLane*, MSInductLoop*> laneInductLoopMap;
170  std::map<MSInductLoop*, int> inductLoopInfoMap; // retrieve junction entry lane in case loops are placed further upstream (and other properties)
171  int detEdgeIndex = -1;
172  int detLaneIndex = 0;
173  const double detDefaultLength = StringUtils::toDouble(getParameter("detector-length",
174  OptionsCont::getOptions().getValueString("tls.actuated.detector-length")));
175  MSEdge* prevDetEdge = nullptr;
176  for (LaneVector& lanes : myLanes) {
177  for (MSLane* lane : lanes) {
178  const std::string customID = getParameter(lane->getID());
179  if (noVehicles(lane->getPermissions()) && customID == "") {
180  // do not build detectors on green verges or sidewalks
181  continue;
182  }
183  if (laneInductLoopMap.find(lane) != laneInductLoopMap.end()) {
184  // only build one detector per lane
185  continue;
186  }
187  const SUMOTime minDur = getMinimumMinDuration(lane);
188  if (minDur == std::numeric_limits<SUMOTime>::max() && customID == "" && !myBuildAllDetectors) {
189  // only build detector if this lane is relevant for an actuated phase
190  continue;
191  }
192  double length = lane->getLength();
193  double ilpos;
194  double inductLoopPosition;
195  MSInductLoop* loop = nullptr;
196  if (&lane->getEdge() != prevDetEdge) {
197  detEdgeIndex++;
198  detLaneIndex = 0;
199  prevDetEdge = &lane->getEdge();
200  } else {
201  detLaneIndex++;
202  }
203  const bool isBikeLane = (lane->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE;
204  const double defaultLength = isBikeLane ? DEFAULT_BIKE_LENGTH_WITH_GAP : DEFAULT_LENGTH_WITH_GAP;
205  if (customID == "") {
206  const double speed = isBikeLane ? DEFAULT_BICYCLE_SPEED : lane->getSpeedLimit();
207  inductLoopPosition = MIN2(
208  myDetectorGap * speed,
209  (STEPS2TIME(minDur) / myPassingTime + 0.5) * defaultLength);
210 
211  // check whether the lane is long enough
212  ilpos = length - inductLoopPosition;
213  MSLane* placementLane = lane;
214  while (ilpos < 0 && placementLane->getIncomingLanes().size() == 1
215  && placementLane->getIncomingLanes().front().viaLink->getCorrespondingEntryLink()->getTLLogic() == nullptr) {
216  placementLane = placementLane->getLogicalPredecessorLane();
217  ilpos += placementLane->getLength();
218  }
219  if (ilpos < 0) {
220  ilpos = 0;
221  }
222  // Build the induct loop and set it into the container
223  const double detLength = getDouble("detector-length:" + lane->getID(), detDefaultLength);
224  std::string id = myDetectorPrefix + "D" + toString(detEdgeIndex) + "." + toString(detLaneIndex);
225  loop = static_cast<MSInductLoop*>(nb.createInductLoop(id, placementLane, ilpos, detLength, "", myVehicleTypes, "", (int)PersonMode::NONE, myShowDetectors));
227  } else if (customID == NO_DETECTOR) {
228  continue;
229  } else {
231  if (loop == nullptr) {
232  throw ProcessError(TLF("Unknown inductionLoop '%' given as custom detector for actuated tlLogic '%', program '%.", customID, getID(), getProgramID()));
233  }
234  ilpos = loop->getPosition();
235  inductLoopPosition = length - ilpos;
236  }
237  const double maxGap = getDouble("max-gap:" + lane->getID(), myMaxGap);
238  const double jamThreshold = getDouble("jam-threshold:" + lane->getID(), myJamThreshold);
239  laneInductLoopMap[lane] = loop;
240  inductLoopInfoMap[loop] = (int)myInductLoops.size();
241  myInductLoops.push_back(InductLoopInfo(loop, lane, (int)myPhases.size(), maxGap, jamThreshold));
242 
243  if (warn && floor(floor(inductLoopPosition / defaultLength) * myPassingTime) > STEPS2TIME(minDur)) {
244  // warn if the minGap is insufficient to clear vehicles between stop line and detector
245  WRITE_WARNINGF(TL("At actuated tlLogic '%', minDur % is too short for a detector gap of %m."), getID(), time2string(minDur), toString(inductLoopPosition));
246  warn = false;
247  }
248  }
249  }
250  // assign loops to phase index (myInductLoopsForPhase)
251  // check1: loops may not be used for a phase if there are other connections from the same lane that may not drive in that phase
252  // greenMinor is ambiguous as vehicles may not be able to drive
253  // Under the following condition we allow actuation from minor link:
254  // check1a : the minor link is minor in all phases
255  // check1b : there is another major link from the same lane in the current phase
256  // check1e : the conflict is only with bikes/pedestrians (i.e. for a right turn, also left turn with no oncoming traffic)
257  // check1f : the conflict is only with a link from the same edge
258  // (Under these conditions we assume that the minor link is unimportant and traffic is mostly for the major link)
259  //
260  // check1c: when the edge has only one lane, we treat greenMinor as green as there would be no actuation otherwise
261  // check1d: for turnarounds 1b is sufficient and we do not require 1a
262  //
263  // check2: if there are two loops on subsequent lanes (joined tls) and the second one has a red link, the first loop may not be used
264  //
265  // if a jamThreshold is specificed for the loop, all checks are ignored
266 
267  // also assign loops to link index for validation:
268  // check if all links from actuated phases (minDur != maxDur) have an inductionloop in at least one phase
269  const SVCPermissions motorized = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
270  std::map<int, std::set<MSInductLoop*> > linkToLoops;
271  std::set<int> actuatedLinks;
272 
273  std::vector<bool> neverMajor(numLinks, true);
274  for (const MSPhaseDefinition* phase : myPhases) {
275  const std::string& state = phase->getState();
276  for (int i = 0; i < numLinks; i++) {
277  if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
278  neverMajor[i] = false;
279  }
280  }
281  }
282  std::vector<bool> oneLane(numLinks, false);
283  std::vector<bool> turnaround(numLinks, true);
284  for (int i = 0; i < numLinks; i++) {
285  for (MSLane* lane : getLanesAt(i)) {
286  // only count motorized vehicle lanes
287  int numMotorized = 0;
288  for (MSLane* l : lane->getEdge().getLanes()) {
289  if ((l->getPermissions() & motorized) != 0) {
290  numMotorized++;
291  }
292  }
293  if (numMotorized == 1) {
294  oneLane[i] = true;
295  break;
296  }
297  }
298  for (MSLink* link : getLinksAt(i)) {
299  if (!link->isTurnaround()) {
300  turnaround[i] = false;
301  break;
302  }
303  }
304  }
305 
306 
307  for (const MSPhaseDefinition* phase : myPhases) {
308  const int phaseIndex = (int)myInductLoopsForPhase.size();
309  std::set<MSInductLoop*> loops;
310  if (phase->isActuated()) {
311  const std::string& state = phase->getState();
312  // collect indices of all green links for the phase
313  std::set<int> greenLinks;
314  // green links that could jam
315  std::set<int> greenLinksPermissive;
316  // collect green links for each induction loops (in this phase)
317  std::map<MSInductLoop*, std::set<int> > loopLinks;
318 
319  for (int i = 0; i < numLinks; i++) {
320  if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
321  greenLinks.insert(i);
322  actuatedLinks.insert(i);
323  } else if (state[i] == LINKSTATE_TL_GREEN_MINOR) {
324  if (((neverMajor[i] || turnaround[i]) // check1a, 1d
325  && hasMajor(state, getLanesAt(i))) // check1b
326  || oneLane[i] // check1c
327  || weakConflict(i, state)) { // check1e, check1f
328  greenLinks.insert(i);
329  if (!turnaround[i]) {
330  actuatedLinks.insert(i);
331  }
332  } else {
333  greenLinksPermissive.insert(i);
334  }
335  }
336 #ifdef DEBUG_DETECTORS
337  if (DEBUG_COND) {
338  std::cout << " phase=" << phaseIndex << " i=" << i << " state=" << state[i] << " green=" << greenLinks.count(i) << " oneLane=" << oneLane[i]
339  << " turn=" << turnaround[i] << " loopLanes=";
340  for (MSLane* lane : getLanesAt(i)) {
341  if (laneInductLoopMap.count(lane) != 0) {
342  std::cout << lane->getID() << " ";
343  }
344  }
345  std::cout << "\n";
346  }
347 #endif
348  for (MSLane* lane : getLanesAt(i)) {
349  if (laneInductLoopMap.count(lane) != 0) {
350  loopLinks[laneInductLoopMap[lane]].insert(i);
351  }
352  }
353  }
354  for (auto& item : loopLinks) {
355  MSInductLoop* loop = item.first;
356  const InductLoopInfo& info = myInductLoops[inductLoopInfoMap[loop]];
357  const MSLane* loopLane = info.lane;
358  bool usable = true;
359  bool foundUsable = false;
360  // check1
361  for (int j : item.second) {
362  if (greenLinks.count(j) == 0 && (info.jamThreshold <= 0 || greenLinksPermissive.count(j) == 0)) {
363  usable = false;
364 #ifdef DEBUG_DETECTORS
365  if (DEBUG_COND) {
366  std::cout << " phase=" << phaseIndex << " check1: loopLane=" << loopLane->getID() << " notGreen=" << j << " oneLane[j]=" << oneLane[j] << "\n";
367  }
368 #endif
369  } else {
370  foundUsable = true;
371  }
372  }
373  if (!usable && foundUsable && info.jamThreshold > 0) {
374  // permit green even when the same lane has green and red links (if we have jamDetection)
375  usable = true;
376  }
377  // check2 (skip if we have jam detection)
378  if (usable && info.jamThreshold <= 0) {
379  for (MSLink* link : loopLane->getLinkCont()) {
380  if (link->isTurnaround()) {
381  continue;
382  }
383  const MSLane* next = link->getLane();
384  if (laneInductLoopMap.count(next) != 0) {
385  MSInductLoop* nextLoop = laneInductLoopMap[next];
386  for (int j : loopLinks[nextLoop]) {
387  if (greenLinks.count(j) == 0) {
388  usable = false;
389 #ifdef DEBUG_DETECTORS
390  if (DEBUG_COND) std::cout << " phase=" << phaseIndex << " check2: loopLane=" << loopLane->getID()
391  << " nextLane=" << next->getID() << " nextLink=" << j << " nextState=" << state[j] << "\n";
392 #endif
393  break;
394  }
395  }
396  }
397  }
398  }
399 
400  if (usable) {
401  loops.insert(item.first);
402 #ifdef DEBUG_DETECTORS
403  if (DEBUG_COND) {
404  std::cout << " phase=" << phaseIndex << " usableLoops=" << item.first->getID() << " links=" << joinToString(item.second, " ") << "\n";
405  }
406 #endif
407  for (int j : item.second) {
408  linkToLoops[j].insert(item.first);
409  }
410  }
411  }
412  if (loops.size() == 0) {
413  WRITE_WARNINGF(TL("At actuated tlLogic '%', actuated phase % has no controlling detector."), getID(), toString(phaseIndex));
414  }
415  }
416 #ifdef DEBUG_DETECTORS
417  if (DEBUG_COND) {
418  std::cout << " phase=" << phaseIndex << " loops=" << joinNamedToString(loops, " ") << "\n";
419  }
420  if (DEBUG_COND) {
421  std::cout << " linkToLoops:\n";
422  for (auto item : linkToLoops) {
423  std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
424  }
425  }
426 #endif
427  std::vector<InductLoopInfo*> loopInfos;
428  myInductLoopsForPhase.push_back(loopInfos);
429  for (MSInductLoop* loop : loops) {
430  for (InductLoopInfo& loopInfo : myInductLoops) {
431  if (loopInfo.loop == loop) {
432  myInductLoopsForPhase.back().push_back(&loopInfo);
433  loopInfo.servedPhase[phaseIndex] = true;
434  }
435  }
436  }
437  }
438 #ifdef DEBUG_DETECTORS
439  if (DEBUG_COND) {
440  std::cout << "final linkToLoops:\n";
441  for (auto item : linkToLoops) {
442  std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
443  }
444  }
445 #endif
446  std::vector<int> warnLinks;
447  for (int i : actuatedLinks) {
448  if (linkToLoops[i].size() == 0 && myLinks[i].size() > 0
449  && (myLinks[i].front()->getLaneBefore()->getPermissions() & motorized) != 0) {
450  if (getParameter(myLinks[i].front()->getLaneBefore()->getID()) != NO_DETECTOR) {
451  warnLinks.push_back(i);
452  }
453  }
454  }
455  if (warnLinks.size() > 0) {
456  WRITE_WARNINGF(TL("At actuated tlLogic '%', linkIndex % has no controlling detector."), getID(), joinToString(warnLinks, ","));
457  }
458  // parse maximum green times for each link (optional)
459  for (const auto& kv : getParametersMap()) {
460  if (StringUtils::startsWith(kv.first, "linkMaxDur:")) {
461  int link = StringUtils::toInt(kv.first.substr(11));
462  if (link < 0 || link >= myNumLinks) {
463  WRITE_ERRORF(TL("Invalid link '%' given as linkMaxDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
464  continue;
465  }
466  if (myLinkMaxGreenTimes.empty()) {
467  myLinkMaxGreenTimes = std::vector<SUMOTime>(myNumLinks, std::numeric_limits<SUMOTime>::max());
468  }
469  myLinkMaxGreenTimes[link] = string2time(kv.second);
470  } else if (StringUtils::startsWith(kv.first, "linkMinDur:")) {
471  int link = StringUtils::toInt(kv.first.substr(11));
472  if (link < 0 || link >= myNumLinks) {
473  WRITE_ERRORF(TL("Invalid link '%' given as linkMinDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
474  continue;
475  }
476  if (myLinkMinGreenTimes.empty()) {
477  myLinkMinGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
478  }
479  myLinkMinGreenTimes[link] = string2time(kv.second);
480  }
481  }
482  if (myLinkMaxGreenTimes.size() > 0 || myLinkMinGreenTimes.size() > 0 || mySwitchingRules.size() > 0) {
483  myLinkGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
484  myLinkRedTimes = std::vector<SUMOTime>(myNumLinks, 0);
485  }
486  //std::cout << SIMTIME << " linkMaxGreenTimes=" << toString(myLinkMaxGreenTimes) << "\n";
487 }
488 
489 
490 bool
491 MSActuatedTrafficLightLogic::weakConflict(int tlIndex, const std::string& state) const {
492  for (MSLink* link : getLinksAt(tlIndex)) {
493  int linkIndex = link->getIndex();
494  const MSJunction* junction = link->getJunction();
495  for (int i = 0; i < (int)myLinks.size(); i++) {
496  if (i == tlIndex) {
497  continue;
498  }
499  if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
500  for (MSLink* foe : getLinksAt(i)) {
501  // junction logic is based on junction link index rather than tl index
502  int foeIndex = foe->getIndex();
503  const MSJunction* junction2 = foe->getJunction();
504  if (junction == junction2) {
505  const MSJunctionLogic* logic = junction->getLogic();
506  //std::cout << " greenLink=" << i << " isFoe=" << logic->getFoesFor(linkIndex).test(foeIndex) << "\n";
507  if (logic->getFoesFor(linkIndex).test(foeIndex)
508  && (foe->getPermissions() & ~SVC_VULNERABLE) != 0 // check1e
509  && &foe->getLaneBefore()->getEdge() != &link->getLaneBefore()->getEdge()) { // check1f
510  //std::cout << " strongConflict " << tlIndex << " in phase " << state << " with link " << foe->getTLIndex() << "\n";
511  return false;
512  }
513  }
514  }
515 
516  }
517  }
518  }
519  //std::cout << " weakConflict " << tlIndex << " in phase " << state << "\n";
520  return true;
521 }
522 
523 
524 SUMOTime
526  step = step < 0 ? myStep : step;
527  const MSPhaseDefinition* p = myPhases[step];
529  ? p->minDuration
530  : TIME2STEPS(evalExpression(myConditions.find("minDur:" + toString(step))->second));
531 }
532 
533 SUMOTime
535  step = step < 0 ? myStep : step;
536  const MSPhaseDefinition* p = myPhases[step];
538  ? p->maxDuration
539  : TIME2STEPS(evalExpression(myConditions.find("maxDur:" + toString(step))->second));
540 }
541 
542 SUMOTime
544  step = step < 0 ? myStep : step;
545  const MSPhaseDefinition* p = myPhases[step];
547  ? p->earliestEnd
548  : TIME2STEPS(evalExpression(myConditions.find("earliestEnd:" + toString(step))->second));
549 }
550 
551 SUMOTime
553  step = step < 0 ? myStep : step;
554  const MSPhaseDefinition* p = myPhases[step];
556  ? p->latestEnd
557  : TIME2STEPS(evalExpression(myConditions.find("latestEnd:" + toString(step))->second));
558 }
559 
560 
561 void
564  for (int i = 0; i < (int)myPhases.size(); i++) {
565  MSPhaseDefinition* phase = myPhases[i];
566  const std::string errorSuffix = "' for overriding attribute in phase " + toString(i) + " of tlLogic '" + getID() + "' in program '" + getProgramID() + "'.";
567  if (phase->minDuration == ovrd) {
568  const std::string cond = "minDur:" + toString(i);
569  if (myConditions.count(cond) == 0) {
570  throw ProcessError("Missing condition '" + cond + errorSuffix);
571  }
572  }
573  if (phase->maxDuration == ovrd) {
574  const std::string cond = "maxDur:" + toString(i);
575  if (myConditions.count(cond) == 0) {
576  throw ProcessError("Missing condition '" + cond + errorSuffix);
577  }
578  }
579  if (phase->earliestEnd == ovrd) {
580  const std::string cond = "earliestEnd:" + toString(i);
581  if (myConditions.count(cond) == 0) {
582  throw ProcessError("Missing condition '" + cond + errorSuffix);
583  }
584  }
585  if (phase->latestEnd == ovrd) {
586  const std::string cond = "latestEnd:" + toString(i);
587  if (myConditions.count(cond) == 0) {
588  throw ProcessError("Missing condition '" + cond + errorSuffix);
589  }
590  }
591  }
592 }
593 
594 
595 void
597  for (int i = 0; i < (int)myPhases.size(); i++) {
598  SwitchingRules sr;
599  MSPhaseDefinition* phase = myPhases[i];
600  std::vector<int> nextPhases = phase->nextPhases;
601  if (nextPhases.size() == 0) {
602  nextPhases.push_back((i + 1) % (int)myPhases.size());
603  } else if (nextPhases.size() > 1) {
604  myHasMultiTarget = true;
605  }
606  for (int next : nextPhases) {
607  if (next >= 0 && next < (int)myPhases.size()) {
608  const MSPhaseDefinition* nextPhase = myPhases[next];
609  if (nextPhase->earlyTarget != "" || nextPhase->finalTarget != "") {
610  sr.enabled = true;
611  // simplifies later code
612  phase->nextPhases = nextPhases;
613  }
614  }
615  }
616  mySwitchingRules.push_back(sr);
617  }
618 }
619 
620 
621 SUMOTime
623  SUMOTime result = std::numeric_limits<SUMOTime>::max();
624  for (int pI = 0; pI < (int)myPhases.size(); pI++) {
625  const MSPhaseDefinition* phase = myPhases[pI];
626  const std::string& state = phase->getState();
627  for (int i = 0; i < (int)state.size(); i++) {
628  if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
629  for (MSLane* cand : getLanesAt(i)) {
630  if (lane == cand) {
631  if (phase->isActuated()) {
632  result = MIN2(result, getMinDur(pI));
633  }
634  }
635  }
636  }
637  }
638  }
639  return result;
640 }
641 
642 bool
643 MSActuatedTrafficLightLogic::hasMajor(const std::string& state, const LaneVector& lanes) const {
644  for (int i = 0; i < (int)state.size(); i++) {
645  if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
646  for (MSLane* cand : getLanesAt(i)) {
647  for (MSLane* lane : lanes) {
648  if (lane == cand) {
649  return true;
650  }
651  }
652  }
653  }
654  }
655  return false;
656 }
657 
658 
659 // ------------ Switching and setting current rows
660 void
663  for (InductLoopInfo& loopInfo : myInductLoops) {
664  loopInfo.loop->setVisible(myShowDetectors);
665  }
666 }
667 
668 
669 void
672  for (InductLoopInfo& loopInfo : myInductLoops) {
673  loopInfo.loop->setVisible(false);
674  }
675 }
676 
677 void
679  SUMOTime simStep, int step, SUMOTime stepDuration) {
680  // do not change timing if the phase changes
681  if (step >= 0 && step != myStep) {
682  myStep = step;
684  setTrafficLightSignals(simStep);
685  tlcontrol.get(getID()).executeOnSwitchActions();
686  } else if (step < 0) {
687  // TraCI requested new timing
689  mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
691  mySwitchCommand, stepDuration + simStep);
692  myTraCISwitch = true;
693  }
694 }
695 
696 
697 void
699  const SUMOTime lastSwitch = t - spentDuration;
700  myStep = step;
701  myPhases[myStep]->myLastSwitch = lastSwitch;
702  const SUMOTime nextSwitch = t + getPhase(step).minDuration - spentDuration;
704  mySwitchCommand = new SwitchCommand(tlcontrol, this, nextSwitch);
706  setTrafficLightSignals(lastSwitch);
707  tlcontrol.get(getID()).executeOnSwitchActions();
708 }
709 
710 
711 SUMOTime
713  // checks if the actual phase should be continued
714  // @note any vehicles which arrived during the previous phases which are now waiting between the detector and the stop line are not
715  // considere here. RiLSA recommends to set minDuration in a way that lets all vehicles pass the detector
718 
719  if (myLinkGreenTimes.size() > 0) {
720  // constraints exist, record green time durations for each link
721  const std::string& state = getCurrentPhaseDef().getState();
722  SUMOTime lastDuration = SIMSTEP - myLastTrySwitchTime;
723  for (int i = 0; i < myNumLinks; i++) {
724  if (state[i] == 'G' || state[i] == 'g') {
725  myLinkGreenTimes[i] += lastDuration;
726  } else {
727  myLinkGreenTimes[i] = 0;
728  }
729  if (state[i] == 'r' || state[i] == 'u') {
730  myLinkRedTimes[i] += lastDuration;
731  } else {
732  myLinkRedTimes[i] = 0;
733  }
734  }
735  }
736  myLastTrySwitchTime = now;
737  // decide the next phase
738  const bool multiTarget = myPhases[myStep]->nextPhases.size() > 1 && myPhases[myStep]->nextPhases.front() >= 0;
739  const int origStep = myStep;
740  int nextStep = myStep;
741  SUMOTime actDuration = now - myPhases[myStep]->myLastSwitch;
742 
743  if (mySwitchingRules[myStep].enabled) {
744  const bool mustSwitch = MIN2(getMaxDur() - actDuration, getLatest()) <= 0;
745  nextStep = decideNextPhaseCustom(mustSwitch);
746  } else {
747  // default algorithm
748  const double detectionGap = gapControl();
749 #ifdef DEBUG_PHASE_SELECTION
750  if (DEBUG_COND) {
751  std::cout << SIMTIME << " p=" << myStep
752  << " trySwitch dGap=" << (detectionGap == std::numeric_limits<double>::max() ? "inf" : toString(detectionGap))
753  << " multi=" << multiTarget << "\n";
754  }
755 #endif
756  if (detectionGap < std::numeric_limits<double>::max() && !multiTarget && !myTraCISwitch) {
757  return duration(detectionGap);
758  }
759  if (multiTarget) {
760  nextStep = decideNextPhase();
761  } else {
762  if (myPhases[myStep]->nextPhases.size() == 1 && myPhases[myStep]->nextPhases.front() >= 0) {
763  nextStep = myPhases[myStep]->nextPhases.front();
764  } else {
765  nextStep = (myStep + 1) % (int)myPhases.size();
766  }
767  }
768  }
769 
770  myTraCISwitch = false;
771  if (myLinkMinGreenTimes.size() > 0) {
772  SUMOTime linkMinDur = getLinkMinDuration(getTarget(nextStep));
773  if (linkMinDur > 0) {
774  // for multiTarget, the current phase must be extended but if another
775  // targer is chosen, earlier switching than linkMinDur is possible
776  return multiTarget ? TIME2STEPS(1) : linkMinDur;
777  }
778  }
779  myStep = nextStep;
780  assert(myStep <= (int)myPhases.size());
781  assert(myStep >= 0);
782  //stores the time the phase started
783  const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
784  if (myStep != origStep) {
785  myPhases[origStep]->myLastEnd = now;
786  myPhases[myStep]->myLastSwitch = now;
787  actDuration = 0;
788  }
789  // activate coloring
790  if ((myShowDetectors || myHasMultiTarget) && getCurrentPhaseDef().isGreenPhase()) {
791  for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
792  //std::cout << SIMTIME << " p=" << myStep << " loopinfo=" << loopInfo->loop->getID() << " set lastGreen=" << STEPS2TIME(now) << "\n";
793  if (loopInfo->isJammed()) {
794  loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
795  } else {
796  loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
797  }
798  loopInfo->lastGreenTime = now;
799  }
800  }
801  // set the next event
802 #ifdef DEBUG_PHASE_SELECTION
803  if (DEBUG_COND) {
804  std::cout << SIMTIME << " tl=" << getID() << " p=" << myStep
805  << " nextTryMinDur=" << STEPS2TIME(getMinDur() - actDuration)
806  << " nextTryEarliest=" << STEPS2TIME(getEarliest(prevStart)) << "\n";
807  }
808 #endif
809  SUMOTime minRetry = myStep != origStep ? 0 : TIME2STEPS(1);
810  return MAX3(minRetry, getMinDur() - actDuration, getEarliest(prevStart));
811 }
812 
813 
814 // ------------ "actuated" algorithm methods
815 SUMOTime
816 MSActuatedTrafficLightLogic::duration(const double detectionGap) const {
817  assert(getCurrentPhaseDef().isGreenPhase());
818  assert((int)myPhases.size() > myStep);
819  const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
820  // ensure that minimum duration is kept
821  SUMOTime newDuration = getMinDur() - actDuration;
822  // try to let the last detected vehicle pass the intersection (duration must be positive)
823  newDuration = MAX3(newDuration, TIME2STEPS(myDetectorGap - detectionGap), SUMOTime(1));
824  // cut the decimal places to ensure that phases always have integer duration
825  if (newDuration % 1000 != 0) {
826  const SUMOTime totalDur = newDuration + actDuration;
827  newDuration = (totalDur / 1000 + 1) * 1000 - actDuration;
828  }
829  // ensure that the maximum duration is not exceeded
830  newDuration = MIN3(newDuration, getMaxDur() - actDuration, getLatest());
831  return newDuration;
832 }
833 
834 
835 double
837  //intergreen times should not be lengthend
838  assert((int)myPhases.size() > myStep);
839  double result = std::numeric_limits<double>::max();
841  return result;
842  }
843  // switch off active colors
844  if (myShowDetectors) {
845  for (InductLoopInfo& loopInfo : myInductLoops) {
846  if (loopInfo.lastGreenTime < loopInfo.loop->getLastDetectionTime()) {
847  loopInfo.loop->setSpecialColor(&RGBColor::RED);
848  } else {
849  loopInfo.loop->setSpecialColor(nullptr);
850  }
851  }
852  }
853  if (!getCurrentPhaseDef().isGreenPhase()) {
854  return result; // end current phase
855  }
856 
857  // Checks, if the maxDuration is kept. No phase should last longer than maxDuration.
858  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
859  if (actDuration >= getCurrentPhaseDef().maxDuration || maxLinkDurationReached() || getLatest() == 0) {
860 #ifdef DEBUG_PHASE_SELECTION
861  if (DEBUG_COND) {
862  std::cout << SIMTIME << " actDuration=" << STEPS2TIME(actDuration) << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
863  << " maxLinkDurationReached=" << maxLinkDurationReached() << " latest=" << STEPS2TIME(getLatest()) << "\n";
864  }
865 #endif
866  return result; // end current phase
867  }
868 
869  // now the gapcontrol starts
870  for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
871  MSInductLoop* loop = loopInfo->loop;
872  if (loopInfo->isJammed()) {
873  loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
874  } else {
875  loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
876  }
877  const double actualGap = loop->getTimeSinceLastDetection();
878  if (actualGap < loopInfo->maxGap && !loopInfo->isJammed()) {
879  result = MIN2(result, actualGap);
880  }
881  }
882  return result;
883 }
884 
885 int
887  const auto& cands = myPhases[myStep]->nextPhases;
888  // decide by priority
889  // first target is the default when there is no traffic
890  // @note: to keep the current phase, even when there is no traffic, it must be added to 'next' explicitly
891  int result = cands.front();
892  int maxPrio = 0;
893  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
894  const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && !maxLinkDurationReached() && getLatest() > 0;
895  if (canExtend) {
896  // consider keeping the current phase until maxDur is reached
897  // (only when there is still traffic in that phase)
898  int currentPrio = getPhasePriority(myStep);
899 #ifdef DEBUG_PHASE_SELECTION
900  std::cout << SIMTIME << " p=" << myStep << " loops=" << myInductLoopsForPhase[myStep].size() << " currentPrio=" << currentPrio << "\n";
901 #endif
902  if (currentPrio > maxPrio) {
903  result = myStep;
904  maxPrio = currentPrio;
905  }
906  }
907  for (int step : cands) {
908  int target = getTarget(step);
909  int prio = getPhasePriority(target);
910 #ifdef DEBUG_PHASE_SELECTION
911  if (DEBUG_COND) {
912  std::cout << SIMTIME << " p=" << myStep << " step=" << step << " target=" << target << " loops=" << myInductLoopsForPhase[target].size() << " prio=" << prio << "\n";
913  }
914 #endif
915  if (prio > maxPrio && canExtendLinkGreen(target)) {
916  maxPrio = prio;
917  result = step;
918  }
919  }
920  // prevent starvation in phases that are not direct targets
921  for (const InductLoopInfo& loopInfo : myInductLoops) {
922  int prio = getDetectorPriority(loopInfo);
923  if (prio > maxPrio) {
924  result = cands.front();
925  if (result == myStep) {
926  WRITE_WARNING("At actuated tlLogic '" + getID()
927  + "', starvation at e1Detector '" + loopInfo.loop->getID()
928  + "' which cannot be reached from the default phase " + toString(myStep) + ".");
929  }
930  // use default phase to reach other phases
931 #ifdef DEBUG_PHASE_SELECTION
932  if (DEBUG_COND) {
933  std::cout << SIMTIME << " p=" << myStep << " loop=" << loopInfo.loop->getID() << " prio=" << prio << " next=" << result << "\n";
934  }
935 #endif
936  break;
937  }
938  }
939  return result;
940 }
941 
942 
943 int
945  int origStep = step;
946  // if step is a transition, find the upcoming green phase
947  while (!myPhases[step]->isGreenPhase()) {
948  if (myPhases[step]->nextPhases.size() > 0 && myPhases[step]->nextPhases.front() >= 0) {
949  if (myPhases[step]->nextPhases.size() > 1) {
950  WRITE_WARNINGF(TL("At actuated tlLogic '%', transition phase % should not have multiple next phases"), getID(), toString(step));
951  }
952  step = myPhases[step]->nextPhases.front();
953  } else {
954  step = (step + 1) % (int)myPhases.size();
955  }
956  if (step == origStep) {
957  WRITE_WARNING("At actuated tlLogic '" + getID() + "', infinite transition loop from phase " + toString(origStep));
958  return 0;
959  }
960  }
961  return step;
962 }
963 
964 int
966  MSInductLoop* loop = loopInfo.loop;
967  const double actualGap = loop->getTimeSinceLastDetection();
968  if ((actualGap < loopInfo.maxGap && !loopInfo.isJammed())
969  || loopInfo.lastGreenTime < loop->getLastDetectionTime()) {
970  SUMOTime inactiveTime = MSNet::getInstance()->getCurrentTimeStep() - loopInfo.lastGreenTime;
971  // @note. Inactive time could also be tracked regardless of current activity (to increase robustness in case of detection failure
972  if (inactiveTime > myInactiveThreshold) {
973 #ifdef DEBUG_PHASE_SELECTION
974  if (DEBUG_COND) {
975  std::cout << " loop=" << loop->getID() << " gap=" << loop->getTimeSinceLastDetection() << " lastGreen=" << STEPS2TIME(loopInfo.lastGreenTime)
976  << " lastDetection=" << STEPS2TIME(loop->getLastDetectionTime()) << " inactive=" << STEPS2TIME(inactiveTime) << "\n";
977  }
978 #endif
979  return (int)STEPS2TIME(inactiveTime);
980  } else {
981  // give bonus to detectors that are currently served (if that phase can stil be extended)
982  if (loopInfo.servedPhase[myStep]) {
983  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
984  const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && getLatest() > 0;
985 #ifdef DEBUG_PHASE_SELECTION
986  if (DEBUG_COND) {
987  std::cout << " loop=" << loop->getID()
988  << " actDuration=" << STEPS2TIME(actDuration)
989  << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
990  << " getLatest=" << STEPS2TIME(getLatest())
991  << " canExtend=" << canExtend
992  << "\n";
993  }
994 #endif
995  if (canExtend) {
997  } else {
998  return 0;
999  }
1000  }
1001  return 1;
1002  }
1003  }
1004  return 0;
1005 }
1006 
1007 int
1009  int result = 0;
1010  for (const InductLoopInfo* loopInfo : myInductLoopsForPhase[step]) {
1011  result += getDetectorPriority(*loopInfo);
1012  }
1013  return result;
1014 }
1015 
1016 
1017 void
1019  myShowDetectors = show;
1020  for (InductLoopInfo& loopInfo : myInductLoops) {
1021  loopInfo.loop->setVisible(myShowDetectors);
1022  }
1023 }
1024 
1025 
1026 bool
1028  if (myLinkMaxGreenTimes.empty()) {
1029  return false;
1030  }
1031  for (int i = 0; i < myNumLinks; i++) {
1032  if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i]) {
1033  //std::cout << SIMTIME << " maxLinkDurationReached i=" << i << "\n";
1034  return true;
1035  }
1036  }
1037  return false;
1038 }
1039 
1040 bool
1042  if (myLinkMaxGreenTimes.empty()) {
1043  return true;
1044  }
1045  const std::string& targetState = myPhases[target]->getState();
1046  for (int i = 0; i < myNumLinks; i++) {
1047  if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i] && (
1048  targetState[i] == 'G' || targetState[i] == 'g')) {
1049  //std::cout << SIMTIME << " cannotExtendLinkGreen target=" << target << " i=" << i << "\n";
1050  return false;
1051  }
1052  }
1053  return true;
1054 }
1055 
1056 SUMOTime
1058  SUMOTime result = 0;
1059  if (target != myStep && myLinkMinGreenTimes.size() > 0) {
1060  const std::string& state = myPhases[myStep]->getState();
1061  const std::string& targetState = myPhases[target]->getState();
1062  for (int i = 0; i < myNumLinks; i++) {
1064  && (state[i] == 'G' || state[i] == 'g')
1065  && !(targetState[i] == 'G' || targetState[i] == 'g')) {
1066  result = MAX2(result, myLinkMinGreenTimes[i] - myLinkGreenTimes[i]);
1067  //std::cout << SIMTIME << " getLinkMinDuration myStep=" << myStep << " target=" << target << " i=" << i
1068  // << " greenTime=" << STEPS2TIME(myLinkGreenTimes[i]) << " min=" << STEPS2TIME(myLinkMinGreenTimes[i]) << " result=" << STEPS2TIME(result) << "\n";
1069  }
1070  }
1071  }
1072  return result;
1073 }
1074 
1075 int
1077  for (int next : getCurrentPhaseDef().nextPhases) {
1078  const MSPhaseDefinition* phase = myPhases[next];
1079  const std::string& condition = mustSwitch ? phase->finalTarget : phase->earlyTarget;
1080  //std::cout << SIMTIME << " mustSwitch=" << mustSwitch << " condition=" << condition << "\n";
1081  if (condition != "") {
1082  // backward compatibility if a user redefined DEFAULT_CONDITION
1083  if (condition == DEFAULT_CONDITION && myConditions.count(DEFAULT_CONDITION) == 0) {
1084  if (gapControl() == std::numeric_limits<double>::max()) {
1085  return next;
1086  }
1087  } else if (evalExpression(condition)) {
1088  return next;
1089  }
1090  }
1091  }
1092  return mustSwitch ? getCurrentPhaseDef().nextPhases.back() : myStep;
1093 }
1094 
1095 
1096 double
1097 MSActuatedTrafficLightLogic::evalExpression(const std::string& condition) const {
1098  const size_t bracketOpen = condition.find('(');
1099  if (bracketOpen != std::string::npos) {
1100  // find matching closing bracket
1101  size_t bracketClose = std::string::npos;
1102  int open = 1;
1103  for (size_t i = bracketOpen + 1; i < condition.size(); i++) {
1104  if (condition[i] == '(') {
1105  open++;
1106  } else if (condition[i] == ')') {
1107  open--;
1108  if (open == 0) {
1109  bracketClose = i;
1110  break;
1111  }
1112  }
1113  }
1114  if (bracketClose == std::string::npos) {
1115  throw ProcessError(TLF("Unmatched parentheses in condition %'", condition));
1116  }
1117  std::string cond2 = condition;
1118  const std::string inBracket = condition.substr(bracketOpen + 1, bracketClose - bracketOpen - 1);
1119  double bracketVal = evalExpression(inBracket);
1120  cond2.replace(bracketOpen, bracketClose - bracketOpen + 1, toString(bracketVal));
1121  try {
1122  return evalExpression(cond2);
1123  } catch (ProcessError& e) {
1124  throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1125  }
1126  }
1127  std::vector<std::string> tokens = StringTokenizer(condition).getVector();
1128  //std::cout << SIMTIME << " tokens(" << tokens.size() << ")=" << toString(tokens) << "\n";
1129  if (tokens.size() == 0) {
1130  throw ProcessError(TLF("Invalid empty condition '%'", condition));
1131  } else if (tokens.size() == 1) {
1132  try {
1133  return evalAtomicExpression(tokens[0]);
1134  } catch (ProcessError& e) {
1135  throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1136  }
1137  } else if (tokens.size() == 2) {
1138  if (tokens[0] == "not") {
1139  try {
1140  return evalAtomicExpression(tokens[1]) == 0. ? 1. : 0.;
1141  } catch (ProcessError& e) {
1142  throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1143  }
1144  } else {
1145  throw ProcessError(TLF("Unsupported condition '%'", condition));
1146  }
1147  } else if (tokens.size() == 3) {
1148  // infix expression
1149  const double a = evalAtomicExpression(tokens[0]);
1150  const double b = evalAtomicExpression(tokens[2]);
1151  const std::string& o = tokens[1];
1152  //std::cout << SIMTIME << " o=" << o << " a=" << a << " b=" << b << "\n";
1153  try {
1154  return evalTernaryExpression(a, o, b, condition);
1155  } catch (ProcessError& e) {
1156  throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1157  }
1158  } else {
1159  const int iEnd = (int)tokens.size() - 1;
1160  for (const std::string& o : OPERATOR_PRECEDENCE) {
1161  for (int i = 1; i < iEnd; i++) {
1162  if (tokens[i] == o) {
1163  try {
1164  const double val = evalTernaryExpression(
1165  evalAtomicExpression(tokens[i - 1]), o,
1166  evalAtomicExpression(tokens[i + 1]), condition);
1167  std::vector<std::string> newTokens(tokens.begin(), tokens.begin() + (i - 1));
1168  newTokens.push_back(toString(val));
1169  newTokens.insert(newTokens.end(), tokens.begin() + (i + 2), tokens.end());
1170  return evalExpression(toString(newTokens));
1171  } catch (ProcessError& e) {
1172  throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1173  }
1174  }
1175  }
1176  }
1177  throw ProcessError("Parsing expressions with " + toString(tokens.size()) + " elements ('" + condition + "') is not supported");
1178  }
1179  return true;
1180 }
1181 
1182 double
1183 MSActuatedTrafficLightLogic::evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const {
1184  if (o == "=" || o == "==") {
1185  return (double)(a == b);
1186  } else if (o == "<") {
1187  return (double)(a < b);
1188  } else if (o == ">") {
1189  return (double)(a > b);
1190  } else if (o == "<=") {
1191  return (double)(a <= b);
1192  } else if (o == ">=") {
1193  return (double)(a >= b);
1194  } else if (o == "!=") {
1195  return (double)(a != b);
1196  } else if (o == "or" || o == "||") {
1197  return (double)(a || b);
1198  } else if (o == "and" || o == "&&") {
1199  return (double)(a && b);
1200  } else if (o == "+") {
1201  return a + b;
1202  } else if (o == "-") {
1203  return a - b;
1204  } else if (o == "*") {
1205  return a * b;
1206  } else if (o == "/") {
1207  if (b == 0) {
1208  WRITE_ERRORF(TL("Division by 0 in condition '%'"), condition);
1209  return 0;
1210  }
1211  return a / b;
1212  } else if (o == "%") {
1213  return fmod(a, b);
1214  } else if (o == "**" || o == "^") {
1215  return pow(a, b);
1216  } else {
1217  throw ProcessError("Unsupported operator '" + o + "' in condition '" + condition + "'");
1218  }
1219 }
1220 
1221 double
1222 MSActuatedTrafficLightLogic::evalCustomFunction(const std::string& fun, const std::string& arg) const {
1223  std::vector<std::string> args = StringTokenizer(arg, ",").getVector();
1224  const Function& f = myFunctions.find(fun)->second;
1225  if ((int)args.size() != f.nArgs) {
1226  throw ProcessError("Function '" + fun + "' requires " + toString(f.nArgs) + " arguments but " + toString(args.size()) + " were given");
1227  }
1228  std::vector<double> args2;
1229  for (auto a : args) {
1230  args2.push_back(evalExpression(a));
1231  }
1232  myStack.push_back(myStack.back());
1233  myStack.back()["$0"] = 0;
1234  for (int i = 0; i < (int)args2.size(); i++) {
1235  myStack.back()["$" + toString(i + 1)] = args2[i];
1236  }
1237  try {
1238  ConditionMap empty;
1240  } catch (ProcessError& e) {
1241  throw ProcessError("Error when evaluating function '" + fun + "' with args '" + joinToString(args2, ",") + "' (" + e.what() + ")");
1242  }
1243  double result = myStack.back()["$0"];
1244  myStack.pop_back();
1245  return result;
1246 }
1247 
1248 
1249 void
1250 MSActuatedTrafficLightLogic::executeAssignments(const AssignmentMap& assignments, ConditionMap& conditions, const ConditionMap& forbidden) const {
1251  for (const auto& assignment : assignments) {
1252  if (evalExpression(std::get<1>(assignment))) {
1253  const std::string& id = std::get<0>(assignment);
1254  const double val = evalExpression(std::get<2>(assignment));
1255  ConditionMap::iterator it = conditions.find(id);
1256  if (it != conditions.end()) {
1257  it->second = toString(val);
1258  } else if (forbidden.find(id) != forbidden.end()) {
1259  throw ProcessError(TLF("Modifying global condition '%' is forbidden", id));
1260  } else {
1261  myStack.back()[id] = val;
1262  }
1263  }
1264  }
1265 }
1266 
1267 
1268 double
1270  if (expr.size() == 0) {
1271  throw ProcessError(TL("Invalid empty expression"));
1272  } else if (expr[0] == '!') {
1273  return evalAtomicExpression(expr.substr(1)) == 0. ? 1. : 0.;
1274  } else if (expr[0] == '-') {
1275  return -evalAtomicExpression(expr.substr(1));
1276  } else {
1277  // check for 'operator:'
1278  const size_t pos = expr.find(':');
1279  if (pos == std::string::npos) {
1280  auto it = myConditions.find(expr);
1281  if (it != myConditions.end()) {
1282  // symbol lookup
1283  return evalExpression(it->second);
1284  } else {
1285  // look at stack
1286  auto it2 = myStack.back().find(expr);
1287  if (it2 != myStack.back().end()) {
1288  return it2->second;
1289  }
1290  // must be a number
1291  return StringUtils::toDouble(expr);
1292  }
1293  } else {
1294  const std::string fun = expr.substr(0, pos);
1295  const std::string arg = expr.substr(pos + 1);
1296  if (fun == "z") {
1297  return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection();
1298  } else if (fun == "a") {
1299  try {
1300  return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection() == 0;
1301  } catch (ProcessError&) {
1302  return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentVehicleNumber();
1303  }
1304  } else if (fun == "g" || fun == "r") {
1305  try {
1306  int linkIndex = StringUtils::toInt(arg);
1307  if (linkIndex >= 0 && linkIndex < myNumLinks) {
1308  const std::vector<SUMOTime>& times = fun == "g" ? myLinkGreenTimes : myLinkRedTimes;
1309  if (times.empty()) {
1310  return 0;
1311  }
1312  if (myLastTrySwitchTime < SIMSTEP) {
1313  // times are only updated at the start of a phase where
1314  // switching is possible (i.e. not during minDur).
1315  // If somebody is looking at those values in the tracker
1316  // this would be confusing
1317  const LinkState ls = getCurrentPhaseDef().getSignalState(linkIndex);
1318  if ((fun == "g" && (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR))
1319  || (fun == "r" && (ls == LINKSTATE_TL_RED || ls == LINKSTATE_TL_REDYELLOW))) {
1320  const SUMOTime currentGreen = SIMSTEP - myLastTrySwitchTime;
1321  return STEPS2TIME(times[linkIndex] + currentGreen);
1322  } else {
1323  return 0;
1324  }
1325  } else {
1326  return STEPS2TIME(times[linkIndex]);
1327  }
1328  }
1329  } catch (NumberFormatException&) { }
1330  throw ProcessError("Invalid link index '" + arg + "' in expression '" + expr + "'");
1331  } else if (fun == "c") {
1332  return STEPS2TIME(getTimeInCycle());
1333  } else {
1334  if (myFunctions.find(fun) == myFunctions.end()) {
1335  throw ProcessError("Unsupported function '" + fun + "' in expression '" + expr + "'");
1336  }
1337  return evalCustomFunction(fun, arg);
1338  }
1339  }
1340  }
1341 }
1342 
1343 
1344 std::map<std::string, double>
1346  std::map<std::string, double> result;
1347  for (auto li : myInductLoops) {
1348  result[li.loop->getID()] = li.loop->getOccupancy() > 0 ? 1 : 0;
1349  }
1350  for (auto loop : myExtraLoops) {
1351  result[loop->getID()] = loop->getOccupancy() > 0 ? 1 : 0;
1352  }
1353  for (auto loop : myExtraE2) {
1354  result[loop->getID()] = loop->getCurrentVehicleNumber();
1355  }
1356  return result;
1357 }
1358 
1359 double
1360 MSActuatedTrafficLightLogic::getDetectorState(const std::string laneID) const {
1361  double result = 0.0;
1362  for (auto li : myInductLoops) {
1363  if (li.lane->getID() == laneID) {
1364  result = li.loop->getOccupancy() > 0 ? 1 : 0;
1365  break;
1366  }
1367  }
1368  return result;
1369 }
1370 
1371 std::map<std::string, double>
1373  std::map<std::string, double> result;
1374  for (auto item : myConditions) {
1375  if (myListedConditions.count(item.first) != 0) {
1376  try {
1377  result[item.first] = evalExpression(item.second);
1378  } catch (ProcessError& e) {
1379  WRITE_ERRORF(TL("Error when retrieving conditions '%' for tlLogic '%' (%)"), item.first, getID(), e.what());
1380  }
1381  }
1382  }
1383  return result;
1384 }
1385 
1386 const std::string
1387 MSActuatedTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
1388  if (StringUtils::startsWith(key, "condition.")) {
1389  const std::string cond = key.substr(10);
1390  auto it = myConditions.find(cond);
1391  if (it != myConditions.end()) {
1392  return toString(evalExpression(it->second));
1393  } else {
1394  throw InvalidArgument("Unknown condition '" + cond + "' for actuated traffic light '" + getID() + "'");
1395  }
1396  } else {
1397  return MSSimpleTrafficLightLogic::getParameter(key, defaultValue);
1398  }
1399 }
1400 
1401 void
1402 MSActuatedTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
1403  // some pre-defined parameters can be updated at runtime
1404  if (key == "detector-gap" || key == "passing-time" || key == "file" || key == "freq" || key == "vTypes"
1405  || key == "build-all-detectors"
1406  || StringUtils::startsWith(key, "linkMaxDur")
1407  || StringUtils::startsWith(key, "linkMinDur")) {
1408  throw InvalidArgument(key + " cannot be changed dynamically for actuated traffic light '" + getID() + "'");
1409  } else if (key == "max-gap") {
1411  // overwrite custom values
1412  for (InductLoopInfo& loopInfo : myInductLoops) {
1413  loopInfo.maxGap = myMaxGap;
1414  }
1415  Parameterised::setParameter(key, value);
1416  } else if (StringUtils::startsWith(key, "max-gap:")) {
1417  const std::string laneID = key.substr(8);
1418  for (InductLoopInfo& loopInfo : myInductLoops) {
1419  if (loopInfo.lane->getID() == laneID) {
1420  loopInfo.maxGap = StringUtils::toDouble(value);
1421  Parameterised::setParameter(key, value);
1422  return;
1423  }
1424  }
1425  throw InvalidArgument("Invalid lane '" + laneID + "' in key '" + key + "' for actuated traffic light '" + getID() + "'");
1426  } else if (key == "jam-threshold") {
1428  // overwrite custom values
1429  for (InductLoopInfo& loopInfo : myInductLoops) {
1430  loopInfo.jamThreshold = myJamThreshold;
1431  }
1432  Parameterised::setParameter(key, value);
1433  } else if (StringUtils::startsWith(key, "jam-threshold:")) {
1434  const std::string laneID = key.substr(14);
1435  for (InductLoopInfo& loopInfo : myInductLoops) {
1436  if (loopInfo.lane->getID() == laneID) {
1437  loopInfo.jamThreshold = StringUtils::toDouble(value);
1438  Parameterised::setParameter(key, value);
1439  return;
1440  }
1441  }
1442  throw InvalidArgument("Invalid lane '" + laneID + "' in key '" + key + "' for actuated traffic light '" + getID() + "'");
1443  } else if (key == "show-detectors") {
1445  Parameterised::setParameter(key, value);
1446  for (InductLoopInfo& loopInfo : myInductLoops) {
1447  loopInfo.loop->setVisible(myShowDetectors);
1448  }
1449  } else if (key == "inactive-threshold") {
1451  Parameterised::setParameter(key, value);
1452  } else {
1454  }
1455 }
1456 
1457 
1458 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#define DEFAULT_DETECTOR_GAP
#define DEFAULT_MAX_GAP
#define DEFAULT_PASSING_TIME
#define DEFAULT_BIKE_LENGTH_WITH_GAP
#define DEFAULT_LENGTH_WITH_GAP
#define NO_DETECTOR
#define DEBUG_COND
#define DEFAULT_INACTIVE_THRESHOLD
#define DEFAULT_CONDITION
#define DEFAULT_CURRENT_PRIORITY
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_ERRORF(...)
Definition: MsgHandler.h:305
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:46
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 SIMSTEP
Definition: SUMOTime.h:61
#define SIMTIME
Definition: SUMOTime.h:62
#define TIME2STEPS(x)
Definition: SUMOTime.h:57
bool noVehicles(SVCPermissions permissions)
Returns whether an edge with the given permissions forbids vehicles.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const double DEFAULT_BICYCLE_SPEED
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_VULNERABLE
@ SVC_PEDESTRIAN
pedestrian
TrafficLightType
@ SUMO_TAG_INDUCTION_LOOP
alternative tag for e1 detector
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_REDYELLOW
The link has red light (must brake) but indicates upcoming green.
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
T MIN3(T a, T b, T c)
Definition: StdDefs.h:89
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
T MAX3(T a, T b, T c)
Definition: StdDefs.h:96
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition: ToString.h:317
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 std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessable from the current working directory.
double myDetectorGap
The detector distance in seconds.
FunctionMap myFunctions
The loaded functions.
double myJamThreshold
The minimum continuous occupancy time to mark a detector as jammed.
bool myBuildAllDetectors
Whether all detectors shall be built.
double myMaxGap
The maximum gap to check in seconds.
const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
try to get the value of the given parameter (including prefixed parameters)
std::vector< SwitchingRules > mySwitchingRules
std::vector< std::map< std::string, double > > myStack
The function call stack;.
double evalAtomicExpression(const std::string &expr) const
evaluate atomic expression
int getTarget(int step)
get the green phase following step
SUMOTime trySwitch() override
Switches to the next phase.
SUMOTime myLastTrySwitchTime
last time trySwitch was called
int getDetectorPriority(const InductLoopInfo &loopInfo) const
SUMOTime myFreq
The frequency for aggregating detector output.
SUMOTime getMinimumMinDuration(MSLane *lane) const
get the minimum min duration for all stretchable phases that affect the given lane
std::vector< const MSInductLoop * > myExtraLoops
extra loops for output/tracking
bool myShowDetectors
Whether the detectors shall be shown in the GUI.
std::vector< SUMOTime > myLinkMaxGreenTimes
maximum consecutive time that the given link may remain green
MSActuatedTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const SUMOTime offset, const MSSimpleTrafficLightLogic::Phases &phases, int step, SUMOTime delay, const Parameterised::Map &parameter, const std::string &basePath, const ConditionMap &conditions=ConditionMap(), const AssignmentMap &assignments=AssignmentMap(), const FunctionMap &functions=FunctionMap())
Constructor.
void loadState(MSTLLogicControl &tlcontrol, SUMOTime t, int step, SUMOTime spentDuration) override
restores the tls state
SUMOTime getMaxDur(int step=-1) const override
AssignmentMap myAssignments
The condition assignments.
std::string myVehicleTypes
Whether detector output separates by vType.
double gapControl()
Return the minimum detection gap of all detectors if the current phase should be extended and double:...
std::vector< std::tuple< std::string, std::string, std::string > > AssignmentMap
std::set< std::string > myListedConditions
the conditions which shall be listed in GUITLLogicPhasesTrackerWindow
double evalExpression(const std::string &condition) const
evaluate custom switching condition
std::vector< SUMOTime > myLinkMinGreenTimes
minimum consecutive time that the given link must remain green
void changeStepAndDuration(MSTLLogicControl &tlcontrol, SUMOTime simStep, int step, SUMOTime stepDuration) override
Changes the current phase and her duration.
bool weakConflict(int linkIndex, const std::string &state) const
whether a given link has only weak mode foes that are green in the given state
static const std::vector< std::string > OPERATOR_PRECEDENCE
bool myHasMultiTarget
Whether any of the phases has multiple targets.
double myPassingTime
The passing time used in seconds.
SUMOTime getLinkMinDuration(int target) const
the minimum duratin for keeping the current phase due to linkMinDur constraints
SUMOTime getMinDur(int step=-1) const override
bool canExtendLinkGreen(int target)
whether the target phase is acceptable in light of linkMaxDur constraints
InductLoopMap myInductLoopsForPhase
A map from phase to induction loops to be used for gap control.
int decideNextPhaseCustom(bool mustSwitch)
select among candidate phases based on detector states and custom switching rules
double evalTernaryExpression(double a, const std::string &o, double b, const std::string &condition) const
evaluate atomic expression
void executeAssignments(const AssignmentMap &assignments, ConditionMap &conditions, const ConditionMap &forbidden=ConditionMap()) const
execute assignemnts of the logic or a custom function
bool myTraCISwitch
whether the next switch time was requested via TraCI
int getPhasePriority(int step) const
count the number of active detectors for the given step
SUMOTime duration(const double detectionGap) const
Returns the minimum duration of the current phase.
void activateProgram() override
called when switching programs
std::vector< InductLoopInfo > myInductLoops
bool maxLinkDurationReached()
whether the current phase cannot be continued due to linkMaxDur constraints
double evalCustomFunction(const std::string &fun, const std::string &arg) const
evaluate function expression
void initAttributeOverride()
initialize custom switching rules
std::map< std::string, double > getConditions() const override
return all named conditions defined for this traffic light
bool hasMajor(const std::string &state, const LaneVector &lanes) const
return whether there is a major link from the given lane in the given phase
std::vector< const MSE2Collector * > myExtraE2
SUMOTime getEarliestEnd(int step=-1) const override
std::map< std::string, Function > FunctionMap
std::map< std::string, double > getDetectorStates() const override
retrieve all detectors used by this program
double getDetectorState(const std::string laneID) const override
retrieve a specific detector used by this program
void setParameter(const std::string &key, const std::string &value) override
Sets a parameter and updates internal constants.
std::vector< SUMOTime > myLinkGreenTimes
consecutive time that the given link index has been green
SUMOTime getLatestEnd(int step=-1) const override
std::string myFile
The output file for generated detectors.
ConditionMap myConditions
The custom switching conditions.
void init(NLDetectorBuilder &nb) override
Initialises the tls with information about incoming lanes.
int decideNextPhase()
select among candidate phases based on detector states
SUMOTime myInactiveThreshold
The time threshold to avoid starved phases.
const NamedObjectCont< MSDetectorFileOutput * > & getTypedDetectors(SumoXMLTag type) const
Returns the list of detectors of the given type.
void add(SumoXMLTag type, MSDetectorFileOutput *d, const std::string &device, SUMOTime interval, SUMOTime begin=-1)
Adds a detector/output combination into the containers.
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:103
An unextended detector measuring at a fixed position on a fixed lane.
Definition: MSInductLoop.h:63
double getPosition() const
Returns the position of the detector on the lane.
Definition: MSInductLoop.h:100
virtual void setSpecialColor(const RGBColor *)
allows for special color in the gui version
Definition: MSInductLoop.h:327
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
SUMOTime getLastDetectionTime() const
return last time a vehicle was on the detector
The base class for an intersection.
Definition: MSJunction.h:58
virtual const MSJunctionLogic * getLogic() const
Definition: MSJunction.h:141
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:716
double getLength() const
Returns the lane's length.
Definition: MSLane.h:598
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:942
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:3116
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:756
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:184
MSDetectorControl & getDetectorControl()
Returns the detector control.
Definition: MSNet.h:441
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:471
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.
LinkState getSignalState(int pos) const
Returns the state of the tls signal at the given position.
bool isActuated() const
static const SUMOTime OVERRIDE_DURATION
SUMOTime latestEnd
The maximum time within the cycle for switching (for coordinated actuation)
SUMOTime minDuration
The minimum duration of the phase.
std::vector< int > nextPhases
The index of the phase that suceeds this one (or -1)
std::string finalTarget
The condition expression for switching into this phase when the active phase must end.
std::string earlyTarget
The condition expression for an early switch into this phase.
SUMOTime earliestEnd
The minimum time within the cycle for switching (for coordinated actuation)
A fixed traffic light logic.
SUMOTime getLatest() const
the maximum duration for keeping the current phase when considering 'latestEnd'
Phases myPhases
The list of phases this logic uses.
const MSPhaseDefinition & getPhase(int givenstep) const override
Returns the definition of the phase from the given position within the plan.
SUMOTime getEarliest(SUMOTime prevStart) const
the minimum duration for keeping the current phase when considering 'earliestEnd'
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
gets a parameter
virtual void setParameter(const std::string &key, const std::string &value) override
Sets a parameter and updates internal constants.
const MSPhaseDefinition & getCurrentPhaseDef() const override
Returns the definition of the current phase.
A class that stores and controls tls and switching of their programs.
TLSLogicVariants & get(const std::string &id) const
Returns the variants of a named tls.
Class realising the switch between the traffic light phases.
void deschedule(MSTrafficLightLogic *tlLogic)
Marks this swicth as invalid (if the phase duration has changed, f.e.)
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
std::vector< MSLane * > LaneVector
Definition of the list of arrival lanes subjected to this tls.
virtual void deactivateProgram()
SUMOTime getTimeInCycle() const
return time within the current cycle
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
SwitchCommand * mySwitchCommand
The current switch command.
int myNumLinks
number of controlled links
virtual void activateProgram()
called when switching programs
const LaneVector & getLanesAt(int i) const
Returns the list of lanes that are controlled by the signals at the given position.
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
LinkVectorVector myLinks
The list of LinkVectors; each vector contains the links that belong to the same link index.
virtual void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
const std::string & getProgramID() const
Returns this tl-logic's id.
Builds detectors for microsim.
virtual MSDetectorFileOutput * createInductLoop(const std::string &id, MSLane *lane, double pos, double length, const std::string name, const std::string &vTypes, const std::string &nextEdges, int detectPersons, bool show)
Creates an instance of an e1 detector using the given values.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
T get(const std::string &id) const
Retrieves an item.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
std::map< std::string, std::string > Map
parameters map
Definition: Parameterised.h:45
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
static const RGBColor ORANGE
Definition: RGBColor.h:191
static const RGBColor GREEN
Definition: RGBColor.h:186
static const RGBColor RED
named colors
Definition: RGBColor.h:185
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter