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 36320 : MSDevice_Bluelight::insertOptions(OptionsCont& oc) {
55 36320 : oc.addOptionSubTopic("Bluelight Device");
56 72640 : insertDefaultAssignmentOptions("bluelight", "Bluelight Device", oc);
57 :
58 36320 : oc.doRegister("device.bluelight.reactiondist", new Option_Float(25.0));
59 108960 : oc.addDescription("device.bluelight.reactiondist", "Bluelight Device", TL("Set the distance at which other drivers react to the blue light and siren sound"));
60 36320 : oc.doRegister("device.bluelight.mingapfactor", new Option_Float(1.));
61 108960 : oc.addDescription("device.bluelight.mingapfactor", "Bluelight Device", TL("Reduce the minGap for reacting vehicles by the given factor"));
62 36320 : }
63 :
64 :
65 : void
66 4658938 : MSDevice_Bluelight::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
67 4658938 : OptionsCont& oc = OptionsCont::getOptions();
68 9317876 : if (equippedByDefaultAssignmentOptions(oc, "bluelight", v, false)) {
69 184 : if (MSGlobals::gUseMesoSim) {
70 0 : WRITE_WARNINGF(TL("bluelight device is not compatible with mesosim (ignored for vehicle '%')"), v.getID());
71 : } else {
72 184 : MSDevice_Bluelight* device = new MSDevice_Bluelight(v, "bluelight_" + v.getID(),
73 552 : getFloatParam(v, oc, "bluelight.reactiondist", oc.getFloat("device.bluelight.reactiondist")),
74 552 : getFloatParam(v, oc, "bluelight.mingapfactor", oc.getFloat("device.bluelight.mingapfactor")));
75 184 : into.push_back(device);
76 : }
77 : }
78 4658938 : }
79 :
80 :
81 : // ---------------------------------------------------------------------------
82 : // MSDevice_Bluelight-methods
83 : // ---------------------------------------------------------------------------
84 184 : MSDevice_Bluelight::MSDevice_Bluelight(SUMOVehicle& holder, const std::string& id,
85 184 : const double reactionDist, const double minGapFactor) :
86 : MSVehicleDevice(holder, id),
87 184 : myReactionDist(reactionDist),
88 184 : myMinGapFactor(minGapFactor) {
89 : #ifdef DEBUG_BLUELIGHT
90 : std::cout << SIMTIME << " initialized device '" << id << "' with myReactionDist=" << myReactionDist << "\n";
91 : #endif
92 184 : }
93 :
94 :
95 368 : MSDevice_Bluelight::~MSDevice_Bluelight() {
96 368 : }
97 :
98 :
99 : bool
100 58705 : 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 58705 : MSVehicle& ego = dynamic_cast<MSVehicle&>(veh);
109 58705 : MSVehicle::Influencer& redLight = ego.getInfluencer();
110 58705 : const double vMax = ego.getLane()->getVehicleMaxSpeed(&ego);
111 58705 : redLight.setSpeedMode(7);
112 58705 : if (ego.getSpeed() < 0.5 * vMax) {
113 : // advance as far as possible (assume vehicles will keep moving out of the way)
114 50958 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
115 50958 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD), "0");
116 : try {
117 50958 : 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 99678 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
124 66452 : ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
125 99678 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD),
126 66452 : ego.getVehicleType().getParameter().getLCParamString(SUMO_ATTR_LCA_SPEEDGAIN_LOOKAHEAD, "5"));
127 : try {
128 99678 : ego.getLaneChangeModel().setParameter(toString(SUMO_ATTR_MINGAP_LAT),
129 64079 : 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 58705 : MSVehicleType* vt = MSNet::getInstance()->getVehicleControl().getVType(veh.getVehicleType().getID());
136 58705 : vt->setPreferredLateralAlignment(LatAlignmentDefinition::ARBITRARY);
137 58705 : 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 58705 : double affectedJunctionDist = ego.getPositionOnLane() + myReactionDist;
144 164211 : for (const MSLane* const l : ego.getUpcomingLanesUntil(myReactionDist)) {
145 105506 : upcomingEdges.push_back(&l->getEdge());
146 :
147 105506 : affectedJunctionDist -= l->getLength();
148 105506 : if (affectedJunctionDist > 0 && l->isInternal()) {
149 26817 : upcomingLinks.push_back(l->getIncomingLanes()[0].viaLink);
150 : }
151 : }
152 :
153 164211 : for (const MSEdge* const e : upcomingEdges) {
154 : //inform all vehicles on upcomingEdges
155 592043 : for (const SUMOVehicle* v : e->getVehicles()) {
156 486537 : upcomingVehicles.insert(dynamic_cast<MSVehicle*>(const_cast<SUMOVehicle*>(v)));
157 : if (lastStepInfluencedVehicles.count(v->getID()) > 0) {
158 : lastStepInfluencedVehicles.erase(v->getID());
159 : }
160 : }
161 : }
162 : // reset all vehicles that were in myInfluencedVehicles in the previous step but not in the current step todo refactor
163 60000 : for (std::string vehID : lastStepInfluencedVehicles) {
164 : myInfluencedVehicles.erase(vehID);
165 : Parameterised::Map::iterator it = myInfluencedTypes.find(vehID);
166 1295 : MSVehicle* veh2 = dynamic_cast<MSVehicle*>(vc.getVehicle(vehID));
167 1243 : if (veh2 != nullptr && it != myInfluencedTypes.end()) {
168 : // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
169 1243 : resetVehicle(veh2, it->second);
170 : }
171 : }
172 :
173 545242 : for (MSVehicle* veh2 : upcomingVehicles) {
174 : assert(veh2 != nullptr);
175 486537 : if (veh2->getLane() == nullptr) {
176 0 : continue;
177 : }
178 486537 : if (std::find(upcomingEdges.begin(), upcomingEdges.end(), &veh2->getLane()->getEdge()) != upcomingEdges.end()) {
179 486535 : if (veh2->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
180 : // emergency vehicles should not react
181 266787 : continue;
182 : }
183 219748 : 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 94684 : MSVehicleType& t = veh2->getSingularType();
188 : // Setting the lateral alignment to build a rescue lane
189 94684 : LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
190 94684 : if (veh2->getLane()->getIndex() == numLanes - 1) {
191 38728 : align = LatAlignmentDefinition::LEFT;
192 : }
193 94684 : 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 219748 : double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
202 : //emergency vehicle has to slow down when entering the rescue lane
203 240957 : 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 19812 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep(), veh.getSpeed()));
207 19812 : speedTimeLine.push_back(std::make_pair(MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(2), 5.56));
208 19812 : redLight.setSpeedTimeLine(speedTimeLine);
209 : }
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 219748 : 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 15249 : double reaction = RandHelper::rand();
216 15249 : MSVehicle::Influencer& lanechange = veh2->getInfluencer();
217 :
218 : //other vehicle should not use the rescue lane so they should not make any lane changes
219 15249 : 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 15249 : distanceDelta < getFloatParam(myHolder, OptionsCont::getOptions(), "bluelight.near-dist", 12.5, false)
223 30498 : ? getFloatParam(myHolder, OptionsCont::getOptions(), "bluelight.reaction-prob-near", 0.577, false)
224 29618 : : getFloatParam(myHolder, OptionsCont::getOptions(), "bluelight.reaction-prob-far", 0.189, false));
225 : // todo works only for one second steps
226 : //std::cout << SIMTIME << " veh2=" << veh2->getID() << " distanceDelta=" << distanceDelta << " reaction=" << reaction << " reactionProb=" << reactionProb << "\n";
227 15249 : if (veh2->isActionStep(SIMSTEP) && reaction < reactionProb * veh2->getActionStepLengthSecs()) {
228 : myInfluencedVehicles.insert(veh2->getID());
229 2590 : myInfluencedTypes.insert(std::make_pair(veh2->getID(), veh2->getVehicleType().getID()));
230 1295 : 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 1295 : MSVehicleType& t = veh2->getSingularType();
237 : // Setting the lateral alignment to build a rescue lane
238 1295 : LatAlignmentDefinition align = LatAlignmentDefinition::RIGHT;
239 1295 : if (veh2->getLane()->getIndex() == numLanes - 1) {
240 603 : align = LatAlignmentDefinition::LEFT;
241 : }
242 1295 : t.setPreferredLateralAlignment(align);
243 1295 : t.setMinGap(t.getMinGap() * myMinGapFactor);
244 1295 : 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 2718 : std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
252 1295 : if (std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID()) == influencedBy.end()) {
253 1295 : influencedBy.push_back(myHolder.getID());
254 2851 : const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
255 : }
256 2590 : veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM), "-1");
257 1295 : }
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 2 : double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
263 2 : 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 85522 : for (MSLink* link : upcomingLinks) {
276 26817 : auto avi = link->getApproaching(&ego);
277 : MSLink::BlockingFoes blockingFoes;
278 26817 : link->opened(avi.arrivalTime, avi.arrivalSpeed, avi.arrivalSpeed, ego.getLength(),
279 26817 : 0, ego.getCarFollowModel().getMaxDecel(), ego.getWaitingTime(), ego.getLateralPositionOnLane(), &blockingFoes, true, &ego);
280 26817 : const SUMOTime timeToArrival = avi.arrivalTime - SIMSTEP;
281 35855 : for (const SUMOVehicle* foe : blockingFoes) {
282 9038 : const double dist = ego.getPosition().distanceTo2D(foe->getPosition());
283 9038 : if (dist < myReactionDist) {
284 3563 : MSVehicle* microFoe = dynamic_cast<MSVehicle*>(const_cast<SUMOVehicle*>(foe));
285 3563 : if (microFoe->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
286 : // emergency vehicles should not react
287 0 : continue;
288 : }
289 3563 : const double timeToBrake = foe->getSpeed() / 4.5;
290 3563 : if (timeToArrival < TIME2STEPS(timeToBrake + 1)) {
291 : ;
292 : std::vector<std::pair<SUMOTime, double> > speedTimeLine;
293 2635 : speedTimeLine.push_back(std::make_pair(SIMSTEP, foe->getSpeed()));
294 0 : speedTimeLine.push_back(std::make_pair(avi.arrivalTime, 0));
295 2635 : microFoe->getInfluencer().setSpeedTimeLine(speedTimeLine);
296 : //std::cout << SIMTIME << " foe=" << foe->getID() << " dist=" << dist << " timeToBrake= " << timeToBrake << " ttA=" << STEPS2TIME(timeToArrival) << "\n";
297 : }
298 : }
299 : }
300 : }
301 :
302 : // ego is at the end of its current lane and cannot continue
303 58705 : const double distToEnd = ego.getLane()->getLength() - ego.getPositionOnLane();
304 : //std::cout << SIMTIME << " " << getID() << " lane=" << ego.getLane()->getID() << " pos=" << ego.getPositionOnLane() << " distToEnd=" << distToEnd << " conts=" << toString(ego.getBestLanesContinuation()) << " furtherEdges=" << upcomingEdges.size() << "\n";
305 92173 : if (ego.getBestLanesContinuation().size() == 1 && distToEnd <= POSITION_EPS
306 : // route continues
307 58904 : && upcomingEdges.size() > 1) {
308 23 : const MSEdge* currentEdge = &ego.getLane()->getEdge();
309 : // move onto the intersection as if there was a connection from the current lane
310 23 : const MSEdge* next = currentEdge->getInternalFollowingEdge(upcomingEdges[1], ego.getVClass());
311 23 : if (next == nullptr) {
312 0 : next = upcomingEdges[1];
313 : }
314 : // pick the lane that causes the minimizes lateral jump
315 23 : const std::vector<MSLane*>* allowed = next->allowedLanes(ego.getVClass());
316 23 : MSLane* nextLane = next->getLanes().front();
317 : double bestJump = std::numeric_limits<double>::max();
318 : double newPosLat = 0;
319 23 : if (allowed != nullptr) {
320 46 : for (MSLane* nextCand : *allowed) {
321 46 : for (auto ili : nextCand->getIncomingLanes()) {
322 23 : if (&ili.lane->getEdge() == currentEdge) {
323 23 : double jump = fabs(ego.getLatOffset(ili.lane) + ego.getLateralPositionOnLane());
324 23 : if (jump < bestJump) {
325 : //std::cout << SIMTIME << " nextCand=" << nextCand->getID() << " from=" << ili.lane->getID() << " jump=" << jump << "\n";
326 : bestJump = jump;
327 : nextLane = nextCand;
328 : // stay within newLane
329 23 : const double maxVehOffset = MAX2(0.0, nextLane->getWidth() - ego.getVehicleType().getWidth()) * 0.5;
330 23 : newPosLat = ego.getLatOffset(ili.lane) + ego.getLateralPositionOnLane();
331 23 : newPosLat = MAX2(-maxVehOffset, newPosLat);
332 : newPosLat = MIN2(maxVehOffset, newPosLat);
333 : }
334 : }
335 : }
336 : }
337 : }
338 23 : ego.leaveLane(NOTIFICATION_JUNCTION, nextLane);
339 23 : ego.getLaneChangeModel().cleanupShadowLane();
340 23 : ego.getLaneChangeModel().cleanupTargetLane();
341 23 : ego.setTentativeLaneAndPosition(nextLane, 0, newPosLat); // update position
342 23 : ego.enterLaneAtMove(nextLane);
343 : // sublane model must adapt state to the new lane
344 23 : ego.getLaneChangeModel().prepareStep();
345 : }
346 58705 : return true; // keep the device
347 : }
348 :
349 :
350 : void
351 1243 : MSDevice_Bluelight::resetVehicle(MSVehicle* veh2, const std::string& targetTypeID) {
352 1243 : MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(targetTypeID);
353 : //targetType is nullptr if the vehicle type has already changed to its old vehicleType
354 1243 : if (targetType != nullptr) {
355 : #ifdef DEBUG_BLUELIGHT_RESCUELANE
356 : std::cout << SIMTIME << " device=" << getID() << " reset " << veh2->getID() << "\n";
357 : #endif
358 :
359 2737 : std::vector<std::string> influencedBy = StringTokenizer(veh2->getParameter().getParameter(INFLUENCED_BY, "")).getVector();
360 1243 : auto it = std::find(influencedBy.begin(), influencedBy.end(), myHolder.getID());
361 1243 : if (it != influencedBy.end()) {
362 : influencedBy.erase(it);
363 2614 : const_cast<SUMOVehicleParameter&>(veh2->getParameter()).setParameter(INFLUENCED_BY, toString(influencedBy));
364 : }
365 1243 : if (influencedBy.size() == 0) {
366 938 : veh2->replaceVehicleType(targetType);
367 2814 : veh2->getLaneChangeModel().setParameter(toString(SUMO_ATTR_LCA_STRATEGIC_PARAM),
368 1876 : targetType->getParameter().getLCParamString(SUMO_ATTR_LCA_STRATEGIC_PARAM, "1"));
369 : }
370 1243 : }
371 1243 : }
372 :
373 :
374 :
375 : bool
376 933 : MSDevice_Bluelight::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
377 : UNUSED_PARAMETER(veh);
378 : #ifdef DEBUG_BLUELIGHT
379 : std::cout << SIMTIME << " device '" << getID() << "' notifyEnter: reason=" << toString(reason) << " enteredLane=" << Named::getIDSecure(enteredLane) << "\n";
380 : #else
381 : UNUSED_PARAMETER(reason);
382 : UNUSED_PARAMETER(enteredLane);
383 : #endif
384 933 : return true; // keep the device
385 : }
386 :
387 :
388 : bool
389 933 : MSDevice_Bluelight::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
390 : UNUSED_PARAMETER(veh);
391 : #ifdef DEBUG_BLUELIGHT
392 : std::cout << SIMTIME << " device '" << getID() << "' notifyLeave: reason=" << toString(reason) << " approachedLane=" << Named::getIDSecure(enteredLane) << "\n";
393 : #else
394 : UNUSED_PARAMETER(reason);
395 : UNUSED_PARAMETER(enteredLane);
396 : #endif
397 933 : return true; // keep the device
398 : }
399 :
400 :
401 : void
402 184 : MSDevice_Bluelight::generateOutput(OutputDevice* tripinfoOut) const {
403 184 : if (tripinfoOut != nullptr) {
404 148 : tripinfoOut->openTag("bluelight");
405 296 : tripinfoOut->closeTag();
406 : }
407 184 : }
408 :
409 : std::string
410 0 : MSDevice_Bluelight::getParameter(const std::string& key) const {
411 0 : if (key == "reactiondist") {
412 0 : return toString(myReactionDist);
413 : }
414 0 : throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
415 : }
416 :
417 :
418 : void
419 0 : MSDevice_Bluelight::setParameter(const std::string& key, const std::string& value) {
420 : double doubleValue;
421 : try {
422 0 : doubleValue = StringUtils::toDouble(value);
423 0 : } catch (NumberFormatException&) {
424 0 : throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
425 0 : }
426 0 : if (key == "reactiondist") {
427 0 : myReactionDist = doubleValue;
428 : } else {
429 0 : throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
430 : }
431 0 : }
432 :
433 :
434 : /****************************************************************************/
|