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