Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2017-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 : /****************************************************************************/
14 : /// @file TrafficLight.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Mario Krumnow
17 : /// @author Jakob Erdmann
18 : /// @author Michael Behrisch
19 : /// @date 30.05.2012
20 : ///
21 : // C++ TraCI client API implementation
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <utils/common/StringUtils.h>
26 : #include <microsim/MSLane.h>
27 : #include <microsim/MSEdge.h>
28 : #include <microsim/MSNet.h>
29 : #include <microsim/MSVehicleControl.h>
30 : #include <microsim/MSStop.h>
31 : #include <microsim/transportables/MSTransportable.h>
32 : #include <microsim/transportables/MSPerson.h>
33 : #include <microsim/traffic_lights/MSTLLogicControl.h>
34 : #include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
35 : #include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>
36 : #include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
37 : #include "microsim/traffic_lights/NEMAController.h"
38 : #include <microsim/traffic_lights/MSRailSignal.h>
39 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
40 : #include <microsim/traffic_lights/MSRailSignalControl.h>
41 : #include <netload/NLDetectorBuilder.h>
42 : #include <libsumo/TraCIConstants.h>
43 : #include "Helper.h"
44 : #include "TrafficLight.h"
45 :
46 : //#define DEBUG_CONSTRAINT_DEADLOCK
47 :
48 : namespace libsumo {
49 : // ===========================================================================
50 : // static member initializations
51 : // ===========================================================================
52 : SubscriptionResults TrafficLight::mySubscriptionResults;
53 : ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
54 :
55 : // ===========================================================================
56 : // static member definitions
57 : // ===========================================================================
58 : std::vector<std::string>
59 596 : TrafficLight::getIDList() {
60 596 : return MSNet::getInstance()->getTLSControl().getAllTLIds();
61 : }
62 :
63 :
64 : int
65 23 : TrafficLight::getIDCount() {
66 23 : return (int)getIDList().size();
67 : }
68 :
69 :
70 : std::string
71 132 : TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
72 132 : return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getState();
73 : }
74 :
75 :
76 : std::vector<TraCILogic>
77 105 : TrafficLight::getAllProgramLogics(const std::string& tlsID) {
78 : std::vector<TraCILogic> result;
79 105 : const std::vector<MSTrafficLightLogic*> logics = Helper::getTLS(tlsID).getAllLogics();
80 293 : for (MSTrafficLightLogic* logic : logics) {
81 188 : TraCILogic l(logic->getProgramID(), (int)logic->getLogicType(), logic->getCurrentPhaseIndex());
82 188 : l.subParameter = logic->getParametersMap();
83 1415 : for (const MSPhaseDefinition* const phase : logic->getPhases()) {
84 1227 : l.phases.emplace_back(new TraCIPhase(STEPS2TIME(phase->duration), phase->getState(),
85 1227 : STEPS2TIME(phase->minDuration), STEPS2TIME(phase->maxDuration),
86 1227 : phase->getNextPhases(), phase->getName()));
87 : }
88 188 : result.emplace_back(l);
89 188 : }
90 105 : return result;
91 0 : }
92 :
93 :
94 : std::vector<std::string>
95 6 : TrafficLight::getControlledJunctions(const std::string& tlsID) {
96 : std::set<std::string> junctionIDs;
97 6 : const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
98 66 : for (const MSTrafficLightLogic::LinkVector& llinks : links) {
99 120 : for (const MSLink* l : llinks) {
100 : junctionIDs.insert(l->getJunction()->getID());
101 : }
102 : }
103 6 : return std::vector<std::string>(junctionIDs.begin(), junctionIDs.end());
104 : }
105 :
106 :
107 : std::vector<std::string>
108 53 : TrafficLight::getControlledLanes(const std::string& tlsID) {
109 : std::vector<std::string> laneIDs;
110 53 : const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
111 932 : for (const MSTrafficLightLogic::LaneVector& llanes : lanes) {
112 1758 : for (const MSLane* l : llanes) {
113 879 : laneIDs.push_back(l->getID());
114 : }
115 : }
116 53 : return laneIDs;
117 0 : }
118 :
119 :
120 : std::vector<std::vector<TraCILink> >
121 53 : TrafficLight::getControlledLinks(const std::string& tlsID) {
122 : std::vector<std::vector<TraCILink> > result;
123 53 : const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
124 53 : const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
125 932 : for (int i = 0; i < (int)lanes.size(); ++i) {
126 : std::vector<TraCILink> subList;
127 879 : const MSTrafficLightLogic::LaneVector& llanes = lanes[i];
128 : const MSTrafficLightLogic::LinkVector& llinks = links[i];
129 : // number of links controlled by this signal (signal i)
130 1758 : for (int j = 0; j < (int)llanes.size(); ++j) {
131 879 : MSLink* link = llinks[j];
132 : // approached non-internal lane (if any)
133 1758 : const std::string to = link->getLane() != nullptr ? link->getLane()->getID() : "";
134 : // approached "via", internal lane (if any)
135 1166 : const std::string via = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
136 879 : subList.emplace_back(TraCILink(llanes[j]->getID(), via, to));
137 : }
138 879 : result.emplace_back(subList);
139 879 : }
140 53 : return result;
141 0 : }
142 :
143 :
144 : std::string
145 90 : TrafficLight::getProgram(const std::string& tlsID) {
146 90 : return Helper::getTLS(tlsID).getActive()->getProgramID();
147 : }
148 :
149 :
150 : int
151 85097 : TrafficLight::getPhase(const std::string& tlsID) {
152 85097 : return Helper::getTLS(tlsID).getActive()->getCurrentPhaseIndex();
153 : }
154 :
155 :
156 : std::string
157 52639 : TrafficLight::getPhaseName(const std::string& tlsID) {
158 52639 : return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getName();
159 : }
160 :
161 :
162 : double
163 63 : TrafficLight::getPhaseDuration(const std::string& tlsID) {
164 63 : return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
165 : }
166 :
167 :
168 : double
169 1309 : TrafficLight::getNextSwitch(const std::string& tlsID) {
170 1309 : return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
171 : }
172 :
173 :
174 : double
175 30 : TrafficLight::getSpentDuration(const std::string& tlsID) {
176 30 : return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getSpentDuration());
177 : }
178 :
179 : int
180 148 : TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
181 148 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
182 148 : if (index < 0 || active->getPhaseNumber() <= index) {
183 0 : throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
184 0 : + toString(active->getPhaseNumber() - 1) + "].");
185 : }
186 : // find all crossings which have a green light in that phas
187 : int result = 0;
188 :
189 148 : const std::string& state = active->getPhases()[index]->getState();
190 1084 : for (int i = 0; i < (int)state.size(); i++) {
191 1872 : for (MSLink* link : active->getLinksAt(i)) {
192 936 : if (link->getLane()->getEdge().isCrossing()) {
193 : // walking forwards across
194 254 : for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
195 92 : if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
196 88 : result += 1;
197 : }
198 : }
199 : // walking backwards across
200 162 : MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
201 240 : for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
202 78 : if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
203 76 : result += 1;
204 : }
205 : }
206 774 : } else if (link->getLaneBefore()->getEdge().isCrossing()) {
207 : // walking backwards across (in case both sides are separately controlled)
208 10 : for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
209 0 : if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
210 0 : result += 1;
211 : }
212 : }
213 : }
214 : }
215 : }
216 148 : return result;
217 : }
218 :
219 : std::vector<std::string>
220 7560 : TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
221 : std::vector<std::string> result;
222 : // for railsignals we cannot use the "online" program
223 7560 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
224 7560 : if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
225 0 : throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
226 0 : + toString(active->getNumLinks() - 1) + "].");
227 : }
228 9662 : for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
229 2102 : result.push_back(veh->getID());
230 : }
231 7560 : return result;
232 0 : }
233 :
234 : std::vector<std::string>
235 7548 : TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
236 : std::vector<std::string> result;
237 7548 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
238 7548 : if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
239 0 : throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
240 0 : + toString(active->getNumLinks() - 1) + "].");
241 : }
242 7928 : for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
243 380 : result.push_back(veh->getID());
244 : }
245 7548 : return result;
246 0 : }
247 :
248 : std::vector<std::string>
249 7548 : TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
250 : std::vector<std::string> result;
251 7548 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
252 7548 : if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
253 0 : throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
254 0 : + toString(active->getNumLinks() - 1) + "].");
255 : }
256 7708 : for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
257 160 : result.push_back(veh->getID());
258 : }
259 7548 : return result;
260 0 : }
261 :
262 : std::vector<TraCISignalConstraint>
263 1470 : TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
264 : std::vector<TraCISignalConstraint> result;
265 1470 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
266 1470 : MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
267 1470 : if (s == nullptr) {
268 0 : throw TraCIException("'" + tlsID + "' is not a rail signal");
269 : }
270 2633 : for (auto item : s->getConstraints()) {
271 1163 : if (tripId != "" && tripId != item.first) {
272 : continue;
273 : }
274 2333 : for (MSRailSignalConstraint* c : item.second) {
275 2352 : result.push_back(buildConstraint(tlsID, item.first, c));
276 : }
277 1163 : }
278 1470 : return result;
279 0 : }
280 :
281 : std::vector<TraCISignalConstraint>
282 12 : TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
283 : // retrieve all constraints that have the given foeSignal (optionally filtered by foeId)
284 : // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
285 : std::vector<TraCISignalConstraint> result;
286 36 : for (const std::string& tlsID : getIDList()) {
287 24 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
288 24 : MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
289 24 : if (s != nullptr) {
290 42 : for (auto item : s->getConstraints()) {
291 60 : for (MSRailSignalConstraint* cand : item.second) {
292 42 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
293 42 : if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
294 84 : && (foeId == "" || pc->myTripId == foeId)) {
295 84 : result.push_back(buildConstraint(s->getID(), item.first, pc));
296 : }
297 : }
298 18 : }
299 : }
300 12 : }
301 12 : return result;
302 0 : }
303 :
304 :
305 : void
306 6 : TrafficLight::addConstraint(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId, const int type, const int limit) {
307 6 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
308 6 : MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
309 6 : MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
310 6 : MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
311 6 : if (s == nullptr) {
312 0 : throw TraCIException("'" + tlsID + "' is not a rail signal");
313 : }
314 6 : if (s2 == nullptr) {
315 0 : throw TraCIException("'" + foeSignal + "' is not a rail signal");
316 : }
317 6 : MSRailSignalConstraint* c = new MSRailSignalConstraint_Predecessor((MSRailSignalConstraint::ConstraintType)type, s2, foeId, limit, true);
318 6 : s->addConstraint(tripId, c);
319 6 : }
320 :
321 :
322 : std::vector<TraCISignalConstraint>
323 247 : TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
324 : #ifdef DEBUG_CONSTRAINT_DEADLOCK
325 : std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
326 : #endif
327 247 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
328 247 : MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
329 247 : MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
330 247 : MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
331 247 : if (s == nullptr) {
332 0 : throw TraCIException("'" + tlsID + "' is not a rail signal");
333 : }
334 247 : if (s2 == nullptr) {
335 0 : throw TraCIException("'" + foeSignal + "' is not a rail signal");
336 : }
337 : MSRailSignalConstraint_Predecessor* c = nullptr;
338 271 : for (auto item : s->getConstraints()) {
339 271 : if (tripId == item.first) {
340 264 : for (MSRailSignalConstraint* cand : item.second) {
341 264 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
342 264 : if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
343 : c = pc;
344 : break;
345 : }
346 : }
347 : break;
348 : }
349 271 : }
350 247 : if (c != nullptr) {
351 247 : const int limit = c->myLimit;
352 : // the two constraints are complementary so we actually remove rather than deactivate to avoid redundant conflict information
353 : MSRailSignalConstraint::ConstraintType type = c->getSwappedType();
354 247 : MSRailSignalConstraint* swapped = new MSRailSignalConstraint_Predecessor(type, s, tripId, limit, true);
355 247 : swapped->updateParameters(c->getParametersMap());
356 247 : swapParameters(swapped);
357 247 : s->removeConstraint(tripId, c);
358 247 : s2->addConstraint(foeId, swapped);
359 247 : return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
360 : } else {
361 0 : throw TraCIException("Rail signal '" + tlsID + "' does not have a constraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
362 : }
363 : }
364 :
365 :
366 : std::vector<std::pair<std::string, std::string> >
367 362 : TrafficLight::getSwapParams(int constraintType) {
368 : std::vector<std::pair<std::string, std::string> > result({
369 : {"vehID", "foeID"},
370 : {"line", "foeLine"},
371 1448 : {"arrival", "foeArrival"}});
372 :
373 362 : if (constraintType == MSRailSignalConstraint::ConstraintType::BIDI_PREDECESSOR) {
374 : std::vector<std::pair<std::string, std::string> > special({
375 : {"busStop", "busStop2"},
376 : {"priorStop", "priorStop2"},
377 90 : {"stopArrival", "foeStopArrival"}});
378 18 : result.insert(result.end(), special.begin(), special.end());
379 18 : }
380 362 : return result;
381 0 : }
382 :
383 :
384 : void
385 247 : TrafficLight::swapParameters(MSRailSignalConstraint* c) {
386 : // swap parameters that were assigned by generateRailSignalConstraints.py
387 1024 : for (auto keys : getSwapParams(c->getType())) {
388 777 : swapParameters(c, keys.first, keys.second);
389 1024 : }
390 247 : }
391 :
392 : void
393 777 : TrafficLight::swapParameters(MSRailSignalConstraint* c, const std::string& key1, const std::string& key2) {
394 777 : const std::string value1 = c->getParameter(key1);
395 1554 : const std::string value2 = c->getParameter(key2);
396 777 : if (value1 != "") {
397 84 : c->setParameter(key2, value1);
398 : } else {
399 693 : c->unsetParameter(key2);
400 : }
401 777 : if (value2 != "") {
402 84 : c->setParameter(key1, value2);
403 : } else {
404 693 : c->unsetParameter(key1);
405 : }
406 777 : }
407 :
408 : void
409 115 : TrafficLight::swapParameters(TraCISignalConstraint& c) {
410 : // swap parameters that were assigned by generateRailSignalConstraints.py
411 478 : for (auto keys : getSwapParams(c.type)) {
412 363 : swapParameters(c, keys.first, keys.second);
413 478 : }
414 115 : }
415 :
416 : void
417 363 : TrafficLight::swapParameters(TraCISignalConstraint& c, const std::string& key1, const std::string& key2) {
418 : auto it1 = c.param.find(key1);
419 : auto it2 = c.param.find(key2);
420 363 : const std::string value1 = it1 != c.param.end() ? it1->second : "";
421 405 : const std::string value2 = it2 != c.param.end() ? it2->second : "";
422 363 : if (value1 != "") {
423 42 : c.param[key2] = value1;
424 : } else {
425 : c.param.erase(key2);
426 : }
427 363 : if (value2 != "") {
428 42 : c.param[key1] = value2;
429 : } else {
430 : c.param.erase(key1);
431 : }
432 363 : }
433 :
434 :
435 : void
436 30 : TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
437 : // remove all constraints that have the given foeId
438 : // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
439 150 : for (const std::string& tlsCand : getIDList()) {
440 120 : if (tlsID == "" || tlsCand == tlsID) {
441 102 : MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
442 102 : MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
443 102 : if (s != nullptr) {
444 180 : for (auto item : s->getConstraints()) {
445 78 : if (tripId == "" || item.first == tripId) {
446 144 : for (MSRailSignalConstraint* cand : item.second) {
447 72 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
448 : if (pc != nullptr
449 72 : && (foeId == "" || pc->myTripId == foeId)
450 138 : && (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
451 54 : cand->setActive(false);
452 : }
453 : }
454 : }
455 78 : }
456 : }
457 : }
458 30 : }
459 30 : }
460 :
461 :
462 : void
463 5 : TrafficLight::updateConstraints(const std::string& vehID, std::string tripId) {
464 : // Removes all constraints that can no longer be met because the route of
465 : // vehID does not pass the signal involved in the constraint with the given tripId.
466 : // This includes constraints on tripId as well as constraints where tripId is the foeId.
467 :
468 5 : MSBaseVehicle* veh = Helper::getVehicle(vehID);
469 10 : std::string curTripId = veh->getParameter().getParameter("tripId", veh->getID());
470 5 : tripId = tripId == "" ? curTripId : tripId;
471 :
472 : // find signals and tripId along the route of veh
473 : std::map<const MSRailSignal*, std::set<std::string> > onRoute;
474 5 : const ConstMSEdgeVector& route = veh->getRoute().getEdges();
475 5 : auto routeIt = veh->getCurrentRouteEdge();
476 20 : for (const MSStop& stop : veh->getStops()) {
477 40 : for (auto it = routeIt; it < stop.edge; it++) {
478 25 : const MSEdge* edge = *it;
479 25 : if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
480 15 : if (it + 1 != route.end()) {
481 15 : const MSEdge* next = *(it + 1);
482 15 : const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
483 15 : if (link != nullptr && link->getTLLogic() != nullptr) {
484 10 : const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
485 10 : onRoute[s].insert(curTripId);
486 : }
487 : }
488 : }
489 : }
490 15 : if (stop.pars.tripId != "") {
491 : curTripId = stop.pars.tripId;
492 : }
493 15 : routeIt = stop.edge;
494 : }
495 10 : for (auto it = routeIt; it < route.end(); it++) {
496 5 : const MSEdge* edge = *it;
497 5 : if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
498 0 : if (it + 1 != route.end()) {
499 0 : const MSEdge* next = *(it + 1);
500 0 : const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
501 0 : if (link != nullptr && link->getTLLogic() != nullptr) {
502 0 : const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
503 0 : onRoute[s].insert(curTripId);
504 : }
505 : }
506 : }
507 : }
508 : //for (auto item : onRoute) {
509 : // std::cout << " s=" << item.first->getID() << " @" << item.first << " ids=" << toString(item.second) << "\n";
510 : //}
511 :
512 : // check relevance for all active contraints
513 35 : for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
514 :
515 : // record outdated constraints on and by the vehicle
516 : std::vector<MSRailSignalConstraint*> onVeh;
517 : std::vector<std::pair<std::string, MSRailSignalConstraint*> > byVeh;
518 :
519 50 : for (auto item : s->getConstraints()) {
520 40 : for (MSRailSignalConstraint* cand : item.second) {
521 20 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
522 20 : if (pc != nullptr && !pc->cleared() && pc->isActive()) {
523 20 : if (item.first == tripId) {
524 10 : if (onRoute[s].count(tripId) == 0) {
525 : // constraint on our veh no longer relevant
526 5 : onVeh.push_back(cand);
527 : }
528 10 : } else if (pc->myTripId == tripId) {
529 10 : if (onRoute[pc->myFoeSignal].count(tripId) == 0) {
530 : // constraint by our veh no longer relevant
531 5 : byVeh.push_back(std::make_pair(item.first, cand));
532 : }
533 : }
534 : }
535 : }
536 20 : }
537 35 : for (MSRailSignalConstraint* c : onVeh) {
538 5 : s->removeConstraint(tripId, c);
539 : }
540 35 : for (auto item : byVeh) {
541 5 : s->removeConstraint(item.first, item.second);
542 : }
543 30 : }
544 5 : }
545 :
546 :
547 : std::vector<TraCISignalConstraint>
548 292 : TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
549 : std::vector<TraCISignalConstraint> result;
550 : // find circular constraints (deadlock)
551 : // foeId is now constrainted by tripId and assumed to follow tripId on the
552 : // same track without possibility of overtaking
553 : // we look for a third vehicle foeId2 where
554 : // tripId waits for foeId2 and foeId2 waits on foeId
555 : std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
556 : std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
557 : std::set<std::string> foeId2Cands1;
558 : std::set<std::string> foeId2Cands2;
559 1634 : for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
560 2632 : for (auto item : s->getConstraints()) {
561 2333 : for (MSRailSignalConstraint* cand : item.second) {
562 1043 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
563 1043 : if (pc != nullptr && !pc->cleared() && pc->isActive()) {
564 1028 : if (item.first == tripId) {
565 : // tripId waits for foe2
566 : // @could there by more than one constraint on tripId by this foe2?
567 176 : libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
568 176 : constraintsOnTripId[pc->myTripId] = tsc;
569 : foeId2Cands1.insert(pc->myTripId);
570 352 : for (std::string& futureFoe2Id : getFutureTripIds(pc->myTripId)) {
571 : foeId2Cands1.insert(futureFoe2Id);
572 : //tsc.foeId = futureFoe2Id; // if we do this, the constraint to swap will not be found
573 0 : constraintsOnTripId[futureFoe2Id] = tsc;
574 176 : }
575 1028 : } else if (pc->myTripId == foeId) {
576 : // foeId2 waits for foe
577 149 : libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
578 149 : constrainedByFoeId[item.first] = tsc;
579 : foeId2Cands2.insert(item.first);
580 304 : for (std::string& futureTripId : getFutureTripIds(item.first)) {
581 : foeId2Cands2.insert(futureTripId);
582 : //tsc.tripId = futureTripId; // if we do this, the constraint to swap will not be found
583 6 : constrainedByFoeId[futureTripId] = tsc;
584 149 : }
585 149 : }
586 : }
587 : }
588 1290 : }
589 : }
590 : #ifdef DEBUG_CONSTRAINT_DEADLOCK
591 : std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << " tlsID=" << tlsID << "\n";
592 : std::cout << " foeId2Cands1=" << toString(foeId2Cands1) << "\n";
593 : std::cout << " foeId2Cands2=" << toString(foeId2Cands2) << "\n";
594 : #endif
595 292 : if (foeId2Cands1.size() > 0) {
596 : // foe2 might be constrained implicitly by foe due to following on the same track
597 : // in this case foe must be on the route of foe2 between its current position and foeSignal
598 :
599 : // we have to check this first because it also affects foeInsertion
600 : // constraints if the foe is already inserted but hasn't yet passed the
601 : // signal (cleared == false).
602 146 : SUMOVehicle* foe = getVehicleByTripId(foeId);
603 146 : if (foe != nullptr) {
604 130 : const MSEdge* foeEdge = foe->getEdge();
605 130 : const double foePos = foe->getPositionOnLane();
606 242 : for (const std::string& foeId2 : foeId2Cands1) {
607 : // tripId waits for foeId2
608 145 : SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
609 145 : if (foe2 != nullptr) {
610 139 : const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
611 139 : const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
612 : bool foeAhead = false;
613 253 : for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
614 208 : const MSEdge* e = foe2Route[i];
615 246 : if (e == foeEdge &&
616 64 : ((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
617 26 : || (foe->hasDeparted() && !foe2->hasDeparted())
618 26 : || (!foe->hasDeparted() && !foe2->hasDeparted() &&
619 26 : (foe->getParameter().depart < foe2->getParameter().depart
620 16 : || (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
621 : )) {
622 : foeAhead = true;
623 : #ifdef DEBUG_CONSTRAINT_DEADLOCK
624 : std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
625 : std::cout << " foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
626 : << " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
627 : //<< " foePos=" << foePos << " foe2Pos=" << foe2->getPositionOnLane()
628 : << " " << constraintsOnTripId[foeId2].getString() << "\n";
629 : #endif
630 : break;
631 : }
632 175 : if (e->getToJunction()->getID() == foeSignal
633 175 : || e->getToJunction()->getID() == c.foeSignal) {
634 : break;
635 : }
636 : }
637 139 : if (foeAhead) {
638 : // foe cannot wait for foe2 (since it's behind). Instead foe2 must wait for tripId
639 : TraCISignalConstraint nc; // constraint after swap
640 33 : nc.tripId = c.foeId;
641 33 : nc.foeId = c.tripId;
642 33 : nc.signalId = c.foeSignal;
643 33 : nc.foeSignal = c.signalId;
644 33 : nc.limit = c.limit;
645 33 : nc.type = c.type;
646 33 : nc.mustWait = true; // ???
647 33 : nc.active = true;
648 : nc.param = c.param;
649 33 : swapParameters(nc);
650 33 : result.push_back(nc);
651 : // let foe wait for foe2
652 33 : std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
653 33 : result.insert(result.end(), result2.begin(), result2.end());
654 :
655 : // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
656 33 : const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
657 33 : result.insert(result.end(), result4.begin(), result4.end());
658 : return result;
659 33 : }
660 : }
661 : }
662 : }
663 : }
664 :
665 259 : if (foeId2Cands2.size() > 0) {
666 : // tripId might be constrained implicitly by foe2 due to following on the same track
667 : // in this case foe2 must be on the route of tripId between its current position and tlsID
668 : // if foe2 then waits for foe, deadlock occurs
669 :
670 119 : SUMOVehicle* ego = getVehicleByTripId(tripId);
671 119 : if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
672 : std::set<const MSEdge*> egoToSignal;
673 18 : const double egoPos = ego->getPositionOnLane();
674 18 : const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
675 30 : for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
676 30 : const MSEdge* e = egoRoute[i];
677 : egoToSignal.insert(e);
678 30 : if (e->getToJunction()->getID() == tlsID) {
679 : break;
680 : }
681 : }
682 :
683 30 : for (const std::string& foeId2 : foeId2Cands2) {
684 : // foeId2 waits for foe
685 18 : SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
686 : //std::cout << " foe2=" << foe2->getID() << " edge=" << foe2->getEdge()->getID() << " egoToSignal=" << toString(egoToSignal) << "\n";
687 18 : if (foe2 != nullptr) {
688 18 : if (egoToSignal.count(foe2->getEdge()) != 0
689 11 : && (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
690 6 : const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
691 : #ifdef DEBUG_CONSTRAINT_DEADLOCK
692 : std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
693 : std::cout << " egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
694 : << " " << c.getString() << "\n";
695 : #endif
696 : // foe is already waiting for tripId (ego) and should also wait for foeId2
697 : TraCISignalConstraint nc; // constraint after swap
698 6 : nc.tripId = c.foeId;
699 6 : nc.foeId = c.tripId;
700 6 : nc.signalId = c.foeSignal;
701 6 : nc.foeSignal = c.signalId;
702 6 : nc.limit = c.limit;
703 6 : nc.type = c.type;
704 6 : nc.mustWait = true; // ???
705 6 : nc.active = true;
706 : nc.param = c.param;
707 6 : swapParameters(nc);
708 6 : result.push_back(nc);
709 : // let foe wait for foe2
710 6 : std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
711 6 : result.insert(result.end(), result2.begin(), result2.end());
712 :
713 : // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
714 6 : const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
715 6 : result.insert(result.end(), result4.begin(), result4.end());
716 : return result;
717 6 : }
718 : }
719 : }
720 101 : } else if (ego != nullptr) {
721 261 : WRITE_WARNINGF(TL("Cannot check for all deadlocks on swapConstraints because the route for vehicle '%' is not computed yet"), ego->getID());
722 : }
723 : }
724 :
725 : // find deadlock in explicit constraints
726 : std::vector<std::string> foeIds2;
727 253 : std::set_intersection(
728 : foeId2Cands1.begin(), foeId2Cands1.end(),
729 : foeId2Cands2.begin(), foeId2Cands2.end(),
730 : std::back_inserter(foeIds2));
731 : #ifdef DEBUG_CONSTRAINT_DEADLOCK
732 : std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
733 : for (const std::string& foeId2 : foeIds2) {
734 : std::cout << " deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
735 : }
736 : #endif
737 253 : if (foeIds2.size() > 0) {
738 76 : TraCISignalConstraint c = constrainedByFoeId[foeIds2.front()];
739 76 : if (c.type == MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR) {
740 : // avoid swapping insertion constraint
741 12 : c = constraintsOnTripId[foeIds2.front()];
742 : }
743 : TraCISignalConstraint nc; // constraint after swap
744 : nc.tripId = c.foeId;
745 : nc.foeId = c.tripId;
746 : nc.signalId = c.foeSignal;
747 : nc.foeSignal = c.signalId;
748 76 : nc.limit = c.limit;
749 76 : nc.type = c.type;
750 76 : nc.mustWait = true; // ???
751 76 : nc.active = true;
752 : nc.param = c.param;
753 76 : swapParameters(nc);
754 76 : result.push_back(nc);
755 : // let foe wait for foe2
756 76 : const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
757 76 : result.insert(result.end(), result2.begin(), result2.end());
758 76 : if (foeIds2.size() > 1) {
759 : // calling swapConstraints once may result in further swaps so we have to recheck for remaining deadlocks anew
760 6 : const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
761 6 : result.insert(result.end(), result3.begin(), result3.end());
762 6 : }
763 76 : }
764 : return result;
765 253 : }
766 :
767 :
768 : SUMOVehicle*
769 428 : TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
770 428 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
771 890 : for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
772 854 : SUMOVehicle* veh = i->second;
773 854 : if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
774 : return veh;
775 : }
776 : }
777 : return nullptr;
778 : }
779 :
780 :
781 : std::vector<std::string>
782 325 : TrafficLight::getFutureTripIds(const std::string vehID) {
783 : std::vector<std::string> result;
784 325 : MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(vehID));
785 281 : if (veh) {
786 562 : std::string tripId = veh->getParameter().getParameter("tripId");
787 281 : if (tripId != "") {
788 0 : result.push_back(tripId);
789 : }
790 299 : for (const MSStop& stop : veh->getStops()) {
791 18 : if (stop.pars.tripId != "") {
792 6 : result.push_back(stop.pars.tripId);
793 : }
794 : }
795 : }
796 325 : return result;
797 0 : }
798 :
799 :
800 : std::string
801 5997 : TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
802 5997 : MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
803 11994 : if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
804 2 : throw TraCIException("'" + tlsID + "' is not a NEMA controller");
805 : }
806 11992 : return tll->getParameter(paramName, "");
807 : }
808 :
809 :
810 56 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(TrafficLight)
811 :
812 :
813 : void
814 46 : TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
815 46 : Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
816 46 : }
817 :
818 :
819 : void
820 3280 : TrafficLight::setPhase(const std::string& tlsID, const int index) {
821 3280 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
822 3279 : if (index < 0 || active->getPhaseNumber() <= index) {
823 4 : throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
824 8 : + toString(active->getPhaseNumber() - 1) + "].");
825 : }
826 3277 : const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
827 3277 : const SUMOTime duration = active->getPhase(index).duration;
828 3277 : active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
829 3277 : }
830 :
831 : void
832 17 : TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
833 17 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
834 17 : const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
835 17 : }
836 :
837 :
838 : void
839 34 : TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
840 : try {
841 34 : Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
842 1 : } catch (ProcessError& e) {
843 2 : throw TraCIException(e.what());
844 1 : }
845 33 : }
846 :
847 :
848 : void
849 41 : TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
850 41 : MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
851 41 : const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
852 41 : active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
853 41 : }
854 :
855 :
856 : void
857 59 : TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
858 59 : MSTLLogicControl::TLSLogicVariants& vars = Helper::getTLS(tlsID);
859 : // make sure index and phaseNo are consistent
860 59 : if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
861 2 : throw TraCIException("set program: parameter index must be less than parameter phase number.");
862 : }
863 : std::vector<MSPhaseDefinition*> phases;
864 295 : for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
865 237 : MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
866 237 : sumoPhase->minDuration = TIME2STEPS(phase->minDur);
867 237 : sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
868 237 : sumoPhase->nextPhases = phase->next;
869 237 : phases.push_back(sumoPhase);
870 : }
871 58 : if (vars.getLogic(logic.programID) == nullptr) {
872 34 : MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
873 34 : int step = logic.currentPhaseIndex;
874 34 : const std::string basePath = "";
875 : MSTrafficLightLogic* tlLogic = nullptr;
876 34 : SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
877 34 : switch ((TrafficLightType)logic.type) {
878 8 : case TrafficLightType::ACTUATED:
879 8 : tlLogic = new MSActuatedTrafficLightLogic(tlc,
880 : tlsID, logic.programID, 0,
881 : phases, step, nextSwitch,
882 8 : logic.subParameter, basePath);
883 8 : break;
884 0 : case TrafficLightType::NEMA:
885 : tlLogic = new NEMALogic(tlc,
886 : tlsID, logic.programID, 0,
887 : phases, step, nextSwitch,
888 0 : logic.subParameter, basePath);
889 : break;
890 2 : case TrafficLightType::DELAYBASED:
891 : tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
892 : tlsID, logic.programID, 0,
893 : phases, step, nextSwitch,
894 2 : logic.subParameter, basePath);
895 : break;
896 24 : case TrafficLightType::STATIC:
897 : tlLogic = new MSSimpleTrafficLightLogic(tlc,
898 : tlsID, logic.programID, 0, TrafficLightType::STATIC,
899 : phases, step, nextSwitch,
900 24 : logic.subParameter);
901 : break;
902 0 : default:
903 0 : throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
904 : }
905 : try {
906 34 : if (!vars.addLogic(logic.programID, tlLogic, true, true)) {
907 0 : throw TraCIException("Could not add traffic light logic '" + logic.programID + "'");
908 : }
909 0 : } catch (const ProcessError& e) {
910 0 : throw TraCIException(e.what());
911 0 : }
912 : // XXX pass GUIDetectorBuilder when running with gui
913 68 : NLDetectorBuilder db(*MSNet::getInstance());
914 34 : tlLogic->init(db);
915 34 : MSNet::getInstance()->createTLWrapper(tlLogic);
916 : } else {
917 24 : MSSimpleTrafficLightLogic* tlLogic = static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID));
918 24 : tlLogic->setPhases(phases, logic.currentPhaseIndex);
919 24 : tlLogic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
920 24 : vars.executeOnSwitchActions();
921 : }
922 58 : }
923 :
924 :
925 : void
926 160 : TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
927 160 : MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
928 320 : if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
929 8 : throw TraCIException("'" + tlsID + "' is not a NEMA controller");
930 : }
931 156 : tll->setParameter(paramName, value);
932 156 : }
933 :
934 192 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(TrafficLight, TL)
935 :
936 : void
937 0 : TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
938 0 : setParameter(tlsID, "NEMA.splits", toString(splits));
939 0 : }
940 :
941 : void
942 2 : TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
943 4 : setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
944 2 : }
945 :
946 : void
947 0 : TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
948 0 : setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
949 0 : }
950 :
951 : void
952 0 : TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
953 0 : setParameter(tlsID, "NEMA.offset", toString(offset));
954 0 : }
955 :
956 :
957 : libsumo::TraCISignalConstraint
958 1543 : TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint) {
959 : TraCISignalConstraint c;
960 1543 : c.tripId = tripId;
961 1543 : MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(constraint);
962 1543 : if (pc == nullptr) {
963 : // unsupported constraint
964 0 : c.type = -1;
965 : } else {
966 1543 : c.signalId = tlsID;
967 1543 : c.foeId = pc->myTripId;
968 1543 : c.foeSignal = pc->myFoeSignal->getID();
969 1543 : c.limit = pc->myLimit;
970 1543 : c.type = pc->getType();
971 1543 : c.mustWait = !pc->cleared() && pc->isActive();
972 1543 : c.active = pc->isActive();
973 1543 : c.param = constraint->getParametersMap();
974 : }
975 1543 : return c;
976 0 : }
977 :
978 :
979 : std::shared_ptr<VariableWrapper>
980 267 : TrafficLight::makeWrapper() {
981 267 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
982 : }
983 :
984 :
985 : bool
986 126501 : TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
987 126501 : switch (variable) {
988 367 : case TRACI_ID_LIST:
989 367 : return wrapper->wrapStringList(objID, variable, getIDList());
990 17 : case ID_COUNT:
991 17 : return wrapper->wrapInt(objID, variable, getIDCount());
992 89 : case TL_RED_YELLOW_GREEN_STATE:
993 176 : return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
994 35 : case TL_CONTROLLED_LANES:
995 35 : return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
996 66667 : case TL_CURRENT_PHASE:
997 66667 : return wrapper->wrapInt(objID, variable, getPhase(objID));
998 35109 : case VAR_NAME:
999 70218 : return wrapper->wrapString(objID, variable, getPhaseName(objID));
1000 62 : case TL_CURRENT_PROGRAM:
1001 124 : return wrapper->wrapString(objID, variable, getProgram(objID));
1002 43 : case TL_PHASE_DURATION:
1003 43 : return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
1004 889 : case TL_NEXT_SWITCH:
1005 889 : return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
1006 20 : case TL_SPENT_DURATION:
1007 20 : return wrapper->wrapDouble(objID, variable, getSpentDuration(objID));
1008 4 : case TL_CONTROLLED_JUNCTIONS:
1009 4 : return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
1010 3889 : case libsumo::VAR_PARAMETER:
1011 3889 : paramData->readUnsignedByte();
1012 7777 : return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
1013 24 : case libsumo::VAR_PARAMETER_WITH_KEY:
1014 24 : paramData->readUnsignedByte();
1015 24 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
1016 : default:
1017 : return false;
1018 : }
1019 : }
1020 : }
1021 :
1022 :
1023 : /****************************************************************************/
|