Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2013-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 MSDevice_Bluelight.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @author Jakob Erdmann
18 : /// @author Laura Bieker
19 : /// @date 01.06.2017
20 : ///
21 : // A device for emergency vehicle. The behaviour of other traffic participants will be triggered with this device.
22 : // For example building a rescue lane.
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <utils/common/StringUtils.h>
27 : #include <utils/common/StringTokenizer.h>
28 : #include <utils/options/OptionsCont.h>
29 : #include <utils/iodevices/OutputDevice.h>
30 : #include <utils/vehicle/SUMOVehicle.h>
31 : #include <microsim/MSNet.h>
32 : #include <microsim/MSLane.h>
33 : #include <microsim/MSEdge.h>
34 : #include <microsim/MSLink.h>
35 : #include <microsim/MSVehicle.h>
36 : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
37 : #include <microsim/MSVehicleControl.h>
38 : #include <microsim/MSVehicleType.h>
39 : #include "MSDevice_Tripinfo.h"
40 : #include "MSDevice_Bluelight.h"
41 :
42 : //#define DEBUG_BLUELIGHT
43 : //#define DEBUG_BLUELIGHT_RESCUELANE
44 :
45 : #define INFLUENCED_BY "rescueLane"
46 :
47 : // ===========================================================================
48 : // method definitions
49 : // ===========================================================================
50 : // ---------------------------------------------------------------------------
51 : // static initialisation methods
52 : // ---------------------------------------------------------------------------
53 : void
54 43644 : MSDevice_Bluelight::insertOptions(OptionsCont& oc) {
55 43644 : oc.addOptionSubTopic("Bluelight Device");
56 87288 : insertDefaultAssignmentOptions("bluelight", "Bluelight Device", oc);
57 :
58 43644 : oc.doRegister("device.bluelight.reactiondist", new Option_Float(25.0));
59 87288 : oc.addDescription("device.bluelight.reactiondist", "Bluelight Device", TL("Set the distance at which other drivers react to the blue light and siren sound"));
60 43644 : oc.doRegister("device.bluelight.mingapfactor", new Option_Float(1.));
61 87288 : oc.addDescription("device.bluelight.mingapfactor", "Bluelight Device", TL("Reduce the minGap for reacting vehicles by the given factor"));
62 43644 : }
63 :
64 :
65 : void
66 5104369 : MSDevice_Bluelight::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
67 5104369 : OptionsCont& oc = OptionsCont::getOptions();
68 10208738 : if (equippedByDefaultAssignmentOptions(oc, "bluelight", v, false)) {
69 180 : if (MSGlobals::gUseMesoSim) {
70 0 : WRITE_WARNINGF(TL("bluelight device is not compatible with mesosim (ignored for vehicle '%')"), v.getID());
71 : } else {
72 360 : MSDevice_Bluelight* device = new MSDevice_Bluelight(v, "bluelight_" + v.getID(),
73 : v.getFloatParam("device.bluelight.reactiondist"),
74 540 : v.getFloatParam("device.bluelight.mingapfactor"));
75 180 : into.push_back(device);
76 : }
77 : }
78 5104369 : }
79 :
80 :
81 : // ---------------------------------------------------------------------------
82 : // MSDevice_Bluelight-methods
83 : // ---------------------------------------------------------------------------
84 180 : MSDevice_Bluelight::MSDevice_Bluelight(SUMOVehicle& holder, const std::string& id,
85 180 : const double reactionDist, const double minGapFactor) :
86 : MSVehicleDevice(holder, id),
87 180 : myReactionDist(reactionDist),
88 180 : myMinGapFactor(minGapFactor) {
89 : #ifdef DEBUG_BLUELIGHT
90 : std::cout << SIMTIME << " initialized device '" << id << "' with myReactionDist=" << myReactionDist << "\n";
91 : #endif
92 180 : }
93 :
94 :
95 360 : MSDevice_Bluelight::~MSDevice_Bluelight() {
96 360 : }
97 :
98 :
99 : bool
100 57668 : MSDevice_Bluelight::notifyMove(SUMOTrafficObject& veh, double /* oldPos */,
101 : double /* newPos */, double newSpeed) {
102 : #ifdef DEBUG_BLUELIGHT
103 : std::cout << SIMTIME << " device '" << getID() << "' notifyMove: newSpeed=" << newSpeed << "\n";
104 : #else
105 : UNUSED_PARAMETER(newSpeed);
106 : #endif
107 : //violate red lights this only need to be done once so shift it todo
108 57668 : MSVehicle& ego = dynamic_cast<MSVehicle&>(veh);
109 57668 : MSVehicle::Influencer& redLight = ego.getInfluencer();
110 57668 : const double vMax = ego.getLane()->getVehicleMaxSpeed(&ego);
111 57668 : redLight.setSpeedMode(7);
112 57668 : if (ego.getSpeed() < 0.5 * vMax) {
113 : // advance as far as possible (assume vehicles will keep moving out of the way)
114 50244 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
115 50244 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD), "0");
116 : try {
117 50244 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_MINGAP_LAT), "0");
118 276 : } catch (InvalidArgument&) {
119 : // not supported by the current laneChangeModel
120 276 : }
121 : } else {
122 : // restore defaults
123 97638 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
124 32546 : ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
125 97638 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD),
126 32546 : ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, "5"));
127 : try {
128 97638 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_MINGAP_LAT),
129 62719 : toString(ego.getVehicleType().getMinGapLat()));
130 2373 : } catch (InvalidArgument&) {
131 : // not supported by the current laneChangeModel
132 2373 : }
133 : }
134 : // build a rescue lane for all vehicles on the route of the emergency vehicle within the range of the siren
135 57668 : MSVehicleType* vt = MSNet::getInstance()->getVehicleControl().getVType(veh.getVehicleType().getID());
136 57668 : vt->setPreferredLateralAlignment(LatAlignmentDefinition::ARBITRARY);
137 57668 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
138 : // use edges on the way of the emergency vehicle
139 : std::vector<const MSEdge*> upcomingEdges;
140 : std::set<MSVehicle*, ComparatorIdLess> upcomingVehicles;
141 : std::set<std::string> lastStepInfluencedVehicles = myInfluencedVehicles;
142 : std::vector<MSLink*> upcomingLinks;
143 57668 : double affectedJunctionDist = ego.getPositionOnLane() + myReactionDist;
144 161680 : for (const MSLane* const l : ego.getUpcomingLanesUntil(myReactionDist)) {
145 104012 : upcomingEdges.push_back(&l->getEdge());
146 :
147 104012 : affectedJunctionDist -= l->getLength();
148 104012 : if (affectedJunctionDist > 0 && l->isInternal()) {
149 26520 : upcomingLinks.push_back(l->getIncomingLanes()[0].viaLink);
150 : }
151 57668 : }
152 :
153 161680 : for (const MSEdge* const e : upcomingEdges) {
154 : //inform all vehicles on upcomingEdges
155 578197 : for (const SUMOVehicle* v : e->getVehicles()) {
156 474185 : upcomingVehicles.insert(dynamic_cast<MSVehicle*>(const_cast<SUMOVehicle*>(v)));
157 : if (lastStepInfluencedVehicles.count(v->getID()) > 0) {
158 : lastStepInfluencedVehicles.erase(v->getID());
159 : }
160 104012 : }
161 : }
162 : // reset all vehicles that were in myInfluencedVehicles in the previous step but not in the current step todo refactor
163 58909 : for (std::string vehID : lastStepInfluencedVehicles) {
164 : myInfluencedVehicles.erase(vehID);
165 : Parameterised::Map::iterator it = myInfluencedTypes.find(vehID);
166 1241 : MSVehicle* veh2 = dynamic_cast<MSVehicle*>(vc.getVehicle(vehID));
167 1193 : if (veh2 != nullptr && it != myInfluencedTypes.end()) {
168 : // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
169 1193 : resetVehicle(veh2, it->second);
170 : }
171 : }
172 :
173 531853 : for (MSVehicle* veh2 : upcomingVehicles) {
174 : assert(veh2 != nullptr);
175 474185 : if (veh2->getLane() == nullptr) {
176 0 : continue;
177 : }
178 474185 : if (std::find(upcomingEdges.begin(), upcomingEdges.end(), &veh2->getLane()->getEdge()) != upcomingEdges.end()) {
179 474179 : if (veh2->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
180 : // emergency vehicles should not react
181 265061 : continue;
182 : }
183 209118 : const int numLanes = (int)veh2->getLane()->getEdge().getNumLanes();
184 : // make sure that vehicles are still building the rescue lane as they might have moved to a new edge or changed lanes
185 : if (myInfluencedVehicles.count(veh2->getID()) > 0) {
186 : // Vehicle gets a new Vehicletype to change the alignment and the lanechange options
187 91328 : MSVehicleType& t = veh2->getSingularType();
188 : // Setting the lateral alignment to build a rescue lane
189 91328 : LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
190 91328 : if (veh2->getLane()->getIndex() == numLanes - 1) {
191 37626 : align = LatAlignmentDefinition::LEFT;
192 : }
193 91328 : t.setPreferredLateralAlignment(align);
194 : #ifdef DEBUG_BLUELIGHT_RESCUELANE
195 : std::cout << "Refresh alignment for vehicle: " << veh2->getID()
196 : << " laneIndex=" << veh2->getLane()->getIndex() << " numLanes=" << numLanes
197 : << " alignment=" << toString(align) << "\n";
198 : #endif
199 : }
200 :
201 209118 : double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
202 : //emergency vehicle has to slow down when entering the rescue lane
203 229992 : if (distanceDelta <= 10 && veh.getID() != veh2->getID() && myInfluencedVehicles.count(veh2->getID()) > 0 && veh2->getSpeed() < 1) {
204 : // set ev speed to 20 km/h 0 5.56 m/s
205 : std::vector<std::pair<SUMOTime, double> > speedTimeLine;
206 19589 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh.getSpeed()));
207 19589 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(2), 5.56));
208 19589 : redLight.setSpeedTimeLine(speedTimeLine);
209 19589 : }
210 :
211 : // the perception of the sound of the siren should be around 25 meters
212 : // todo only vehicles in front of the emergency vehicle should react
213 209118 : if (distanceDelta <= myReactionDist && veh.getID() != veh2->getID() && myInfluencedVehicles.count(veh2->getID()) == 0) {
214 : // only a percentage of vehicles should react to the emergency vehicle to make the behaviour more realistic
215 14633 : double reaction = RandHelper::rand();
216 14633 : MSVehicle::Influencer& lanechange = veh2->getInfluencer();
217 :
218 : //other vehicle should not use the rescue lane so they should not make any lane changes
219 14633 : lanechange.setLaneChangeMode(1605);//todo change lane back
220 : // the vehicles should react according to the distance to the emergency vehicle taken from real world data
221 : double reactionProb = (
222 14633 : distanceDelta < myHolder.getFloatParam("device.bluelight.near-dist", false, 12.5)
223 29266 : ? myHolder.getFloatParam("device.bluelight.reaction-prob-near", false, 0.577)
224 28415 : : myHolder.getFloatParam("device.bluelight.reaction-prob-far", false, 0.189));
225 : // todo works only for one second steps
226 : //std::cout << SIMTIME << " veh2=" << veh2->getID() << " distanceDelta=" << distanceDelta << " reaction=" << reaction << " reactionProb=" << reactionProb << "\n";
227 14633 : if (veh2->isActionStep(SIMSTEP) && reaction < reactionProb * veh2->getActionStepLengthSecs()) {
228 : myInfluencedVehicles.insert(veh2->getID());
229 1241 : myInfluencedTypes.insert(std::make_pair(veh2->getID(), veh2->getVehicleType().getID()));
230 1241 : if (myMinGapFactor != 1.) {
231 : // TODO this is a permanent change to the vtype!
232 16 : MSNet::getInstance()->getVehicleControl().getVType(veh2->getVehicleType().getID())->getCarFollowModel().setCollisionMinGapFactor(myMinGapFactor);
233 : }
234 :
235 : // Vehicle gets a new Vehicletype to change the alignment and the lanechange options
236 1241 : MSVehicleType& t = veh2->getSingularType();
237 : // Setting the lateral alignment to build a rescue lane
238 1241 : LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
239 1241 : if (veh2->getLane()->getIndex() == numLanes - 1) {
240 573 : align = LatAlignmentDefinition::LEFT;
241 : }
242 1241 : t.setPreferredLateralAlignment(align);
243 1241 : t.setMinGap(t.getMinGap() * myMinGapFactor);
244 1241 : const_cast<SUMOVTypeParameter&>(t.getParameter()).jmParameter[SUMO_ATTR_JM_STOPLINE_GAP] = toString(myMinGapFactor);
245 : // disable strategic lane-changing
246 : #ifdef DEBUG_BLUELIGHT_RESCUELANE
247 : std::cout << SIMTIME << " device=" << getID() << " formingRescueLane=" << veh2->getID()
248 : << " laneIndex=" << veh2->getLane()->getIndex() << " numLanes=" << numLanes
249 : << " alignment=" << toString(align) << "\n";
250 : #endif
251 2482 : std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
252 1241 : if (std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID()) == influencedBy.end()) {
253 1241 : influencedBy.push_back(myHolder.getID());
254 2482 : const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
255 : }
256 2482 : veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
257 1241 : }
258 : }
259 :
260 : } else { //if vehicle is passed all vehicles which had to react should get their state back after they leave the communication range
261 : if (myInfluencedVehicles.count(veh2->getID()) > 0) {
262 3 : double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
263 3 : if (distanceDelta > myReactionDist && veh.getID() != veh2->getID()) {
264 : myInfluencedVehicles.erase(veh2->getID());
265 : Parameterised::Map::iterator it = myInfluencedTypes.find(veh2->getID());
266 0 : if (it != myInfluencedTypes.end()) {
267 : // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
268 0 : resetVehicle(veh2, it->second);
269 : }
270 : }
271 : }
272 : }
273 : }
274 : // make upcoming junction foes slow down
275 84188 : for (MSLink* link : upcomingLinks) {
276 26520 : auto avi = link->getApproaching(&ego);
277 : MSLink::BlockingFoes blockingFoes;
278 26520 : link->opened(avi.arrivalTime, avi.arrivalSpeed, avi.arrivalSpeed, ego.getLength(),
279 26520 : 0, ego.getCarFollowModel().getMaxDecel(), ego.getWaitingTime(), ego.getLateralPositionOnLane(), &blockingFoes, true, &ego);
280 26520 : const SUMOTime timeToArrival = avi.arrivalTime - SIMSTEP;
281 34639 : for (const SUMOTrafficObject* foe : blockingFoes) {
282 8119 : if (!foe->isVehicle()) {
283 0 : continue;
284 : }
285 8119 : const double dist = ego.getPosition().distanceTo2D(foe->getPosition());
286 8119 : if (dist < myReactionDist) {
287 3277 : MSVehicle* microFoe = dynamic_cast<MSVehicle*>(const_cast<SUMOTrafficObject*>(foe));
288 3277 : if (microFoe->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
289 : // emergency vehicles should not react
290 0 : continue;
291 : }
292 3277 : const double timeToBrake = foe->getSpeed() / 4.5;
293 3277 : if (timeToArrival < TIME2STEPS(timeToBrake + 1)) {
294 : ;
295 : std::vector<std::pair<SUMOTime, double> > speedTimeLine;
296 2459 : speedTimeLine.push_back(std::make_pair(SIMSTEP, foe->getSpeed()));
297 2459 : speedTimeLine.push_back(std::make_pair(avi.arrivalTime, 0));
298 2459 : microFoe->getInfluencer().setSpeedTimeLine(speedTimeLine);
299 : //std::cout << SIMTIME << " foe=" << foe->getID() << " dist=" << dist << " timeToBrake= " << timeToBrake << " ttA=" << STEPS2TIME(timeToArrival) << "\n";
300 2459 : }
301 : }
302 : }
303 26520 : }
304 :
305 : // ego is at the end of its current lane and cannot continue
306 57668 : const double distToEnd = ego.getLane()->getLength() - ego.getPositionOnLane();
307 : //std::cout << SIMTIME << " " << getID() << " lane=" << ego.getLane()->getID() << " pos=" << ego.getPositionOnLane() << " distToEnd=" << distToEnd << " conts=" << toString(ego.getBestLanesContinuation()) << " furtherEdges=" << upcomingEdges.size() << "\n";
308 90554 : if (ego.getBestLanesContinuation().size() == 1 && distToEnd <= POSITION_EPS
309 : // route continues
310 57862 : && upcomingEdges.size() > 1) {
311 22 : const MSEdge* currentEdge = &ego.getLane()->getEdge();
312 : // move onto the intersection as if there was a connection from the current lane
313 22 : const MSEdge* next = currentEdge->getInternalFollowingEdge(upcomingEdges[1], ego.getVClass());
314 22 : if (next == nullptr) {
315 0 : next = upcomingEdges[1];
316 : }
317 : // pick the lane that causes the minimizes lateral jump
318 22 : const std::vector<MSLane*>* allowed = next->allowedLanes(ego.getVClass());
319 22 : MSLane* nextLane = next->getLanes().front();
320 : double bestJump = std::numeric_limits<double>::max();
321 : double newPosLat = 0;
322 22 : if (allowed != nullptr) {
323 44 : for (MSLane* nextCand : *allowed) {
324 44 : for (auto ili : nextCand->getIncomingLanes()) {
325 22 : if (&ili.lane->getEdge() == currentEdge) {
326 22 : double jump = fabs(ego.getLatOffset(ili.lane) + ego.getLateralPositionOnLane());
327 22 : if (jump < bestJump) {
328 : //std::cout << SIMTIME << " nextCand=" << nextCand->getID() << " from=" << ili.lane->getID() << " jump=" << jump << "\n";
329 : bestJump = jump;
330 : nextLane = nextCand;
331 : // stay within newLane
332 22 : const double maxVehOffset = MAX2(0.0, nextLane->getWidth() - ego.getVehicleType().getWidth()) * 0.5;
333 22 : newPosLat = ego.getLatOffset(ili.lane) + ego.getLateralPositionOnLane();
334 22 : newPosLat = MAX2(-maxVehOffset, newPosLat);
335 : newPosLat = MIN2(maxVehOffset, newPosLat);
336 : }
337 : }
338 : }
339 : }
340 : }
341 22 : ego.leaveLane(NOTIFICATION_JUNCTION, nextLane);
342 22 : ego.getLaneChangeModel().cleanupShadowLane();
343 22 : ego.getLaneChangeModel().cleanupTargetLane();
344 22 : ego.setTentativeLaneAndPosition(nextLane, 0, newPosLat); // update position
345 22 : ego.enterLaneAtMove(nextLane);
346 : // sublane model must adapt state to the new lane
347 22 : ego.getLaneChangeModel().prepareStep();
348 : }
349 57668 : return true; // keep the device
350 115336 : }
351 :
352 :
353 : void
354 1193 : MSDevice_Bluelight::resetVehicle(MSVehicle* veh2, const std::string& targetTypeID) {
355 1193 : MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(targetTypeID);
356 : //targetType is nullptr if the vehicle type has already changed to its old vehicleType
357 1193 : if (targetType != nullptr) {
358 : #ifdef DEBUG_BLUELIGHT_RESCUELANE
359 : std::cout << SIMTIME << " device=" << getID() << " reset " << veh2->getID() << "\n";
360 : #endif
361 :
362 2386 : std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
363 1193 : auto it = std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID());
364 1193 : if (it != influencedBy.end()) {
365 : influencedBy.erase(it);
366 2386 : const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
367 : }
368 1193 : if (influencedBy.size() == 0) {
369 894 : veh2->replaceVehicleType(targetType);
370 2682 : veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
371 1788 : targetType->getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
372 : }
373 1193 : }
374 1193 : }
375 :
376 :
377 :
378 : bool
379 917 : MSDevice_Bluelight::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
380 : UNUSED_PARAMETER(veh);
381 : #ifdef DEBUG_BLUELIGHT
382 : std::cout << SIMTIME << " device '" << getID() << "' notifyEnter: reason=" << toString(reason) << " enteredLane=" << Named::getIDSecure(enteredLane) << "\n";
383 : #else
384 : UNUSED_PARAMETER(reason);
385 : UNUSED_PARAMETER(enteredLane);
386 : #endif
387 917 : return true; // keep the device
388 : }
389 :
390 :
391 : bool
392 917 : MSDevice_Bluelight::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
393 : UNUSED_PARAMETER(veh);
394 : #ifdef DEBUG_BLUELIGHT
395 : std::cout << SIMTIME << " device '" << getID() << "' notifyLeave: reason=" << toString(reason) << " approachedLane=" << Named::getIDSecure(enteredLane) << "\n";
396 : #else
397 : UNUSED_PARAMETER(reason);
398 : UNUSED_PARAMETER(enteredLane);
399 : #endif
400 917 : return true; // keep the device
401 : }
402 :
403 :
404 : void
405 180 : MSDevice_Bluelight::generateOutput(OutputDevice* tripinfoOut) const {
406 180 : if (tripinfoOut != nullptr) {
407 144 : tripinfoOut->openTag("bluelight");
408 288 : tripinfoOut->closeTag();
409 : }
410 180 : }
411 :
412 : std::string
413 0 : MSDevice_Bluelight::getParameter(const std::string& key) const {
414 0 : if (key == "reactiondist") {
415 0 : return toString(myReactionDist);
416 : }
417 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
418 : }
419 :
420 :
421 : void
422 0 : MSDevice_Bluelight::setParameter(const std::string& key, const std::string& value) {
423 : double doubleValue;
424 : try {
425 0 : doubleValue = StringUtils::toDouble(value);
426 0 : } catch (NumberFormatException&) {
427 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
428 0 : }
429 0 : if (key == "reactiondist") {
430 0 : myReactionDist = doubleValue;
431 : } else {
432 0 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
433 : }
434 0 : }
435 :
436 :
437 : /****************************************************************************/
|