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