1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2013-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    MSDevice_Bluelight.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Michael Behrisch
13 /// @author  Jakob Erdmann
14 /// @author  Laura Bieker
15 /// @date    01.06.2017
16 /// @version $Id$
17 ///
18 // A device for emergency vehicle. The behaviour of other traffic participants will be triggered with this device.
19 // For example building a rescue lane.
20 /****************************************************************************/
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26 
27 #include <utils/common/StringUtils.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/MSVehicle.h>
35 #include "MSDevice_Tripinfo.h"
36 #include "MSDevice_Bluelight.h"
37 #include <microsim/MSVehicleControl.h>
38 #include <microsim/MSVehicleType.h>
39 
40 //#define DEBUG_BLUELIGHT
41 
42 // ===========================================================================
43 // method definitions
44 // ===========================================================================
45 // ---------------------------------------------------------------------------
46 // static initialisation methods
47 // ---------------------------------------------------------------------------
48 void
insertOptions(OptionsCont & oc)49 MSDevice_Bluelight::insertOptions(OptionsCont& oc) {
50     oc.addOptionSubTopic("Bluelight Device");
51     insertDefaultAssignmentOptions("bluelight", "Bluelight Device", oc);
52 
53     oc.doRegister("device.bluelight.parameter", new Option_Float(0.0));
54     oc.addDescription("device.bluelight.parameter", "Bluelight Device", "An exemplary parameter which can be used by all instances of the example device");
55 
56 }
57 
58 
59 void
buildVehicleDevices(SUMOVehicle & v,std::vector<MSVehicleDevice * > & into)60 MSDevice_Bluelight::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
61     OptionsCont& oc = OptionsCont::getOptions();
62     if (equippedByDefaultAssignmentOptions(oc, "bluelight", v, false)) {
63         // build the device
64         // get custom vehicle parameter
65         double customParameter2 = -1;
66         if (v.getParameter().knowsParameter("bluelight")) {
67             try {
68                 customParameter2 = StringUtils::toDouble(v.getParameter().getParameter("bluelight", "-1"));
69             } catch (...) {
70                 WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("bluelight", "-1") + "'for vehicle parameter 'example'");
71             }
72 
73         } else {
74 #ifdef DEBUG_BLUELIGHT
75             std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'bluelight'. Using default of " << customParameter2 << "\n";
76 #endif
77         }
78         // get custom vType parameter
79         double customParameter3 = -1;
80         if (v.getVehicleType().getParameter().knowsParameter("bluelight")) {
81             try {
82                 customParameter3 = StringUtils::toDouble(v.getVehicleType().getParameter().getParameter("bluelight", "-1"));
83             } catch (...) {
84                 WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("bluelight", "-1") + "'for vType parameter 'bluelight'");
85             }
86 
87         } else {
88 #ifdef DEBUG_BLUELIGHT
89             std::cout << "vehicle '" << v.getID() << "' does not supply vType parameter 'bluelight'. Using default of " << customParameter3 << "\n";
90 #endif
91         }
92         MSDevice_Bluelight* device = new MSDevice_Bluelight(v, "bluelight_" + v.getID(),
93                 oc.getFloat("device.bluelight.parameter"),
94                 customParameter2,
95                 customParameter3);
96         into.push_back(device);
97     }
98 }
99 
100 
101 // ---------------------------------------------------------------------------
102 // MSDevice_Bluelight-methods
103 // ---------------------------------------------------------------------------
MSDevice_Bluelight(SUMOVehicle & holder,const std::string & id,double customValue1,double customValue2,double customValue3)104 MSDevice_Bluelight::MSDevice_Bluelight(SUMOVehicle& holder, const std::string& id,
105                                        double customValue1, double customValue2, double customValue3) :
106     MSVehicleDevice(holder, id),
107     myCustomValue1(customValue1),
108     myCustomValue2(customValue2),
109     myCustomValue3(customValue3) {
110 #ifdef DEBUG_BLUELIGHT
111     std::cout << "initialized device '" << id << "' with myCustomValue1=" << myCustomValue1 << ", myCustomValue2=" << myCustomValue2 << ", myCustomValue3=" << myCustomValue3 << "\n";
112 #endif
113 }
114 
115 
~MSDevice_Bluelight()116 MSDevice_Bluelight::~MSDevice_Bluelight() {
117 }
118 
119 
120 bool
notifyMove(SUMOTrafficObject & veh,double,double,double newSpeed)121 MSDevice_Bluelight::notifyMove(SUMOTrafficObject& veh, double /* oldPos */,
122                                double /* newPos */, double newSpeed) {
123 #ifdef DEBUG_BLUELIGHT
124     std::cout << "device '" << getID() << "' notifyMove: newSpeed=" << newSpeed << "\n";
125 #else
126     UNUSED_PARAMETER(newSpeed);
127 #endif
128     // check whether another device is present on the vehicle:
129     /*MSDevice_Tripinfo* otherDevice = static_cast<MSDevice_Tripinfo*>(veh.getDevice(typeid(MSDevice_Tripinfo)));
130     if (otherDevice != 0) {
131         std::cout << "  veh '" << veh.getID() << " has device '" << otherDevice->getID() << "'\n";
132     }*/
133     //violate red lights  this only need to be done once so shift it todo
134     MSVehicle::Influencer& redLight = static_cast<MSVehicle&>(veh).getInfluencer();
135     redLight.setSpeedMode(7);
136     // build a rescue lane for all vehicles on the route of the emergency vehicle within the range of the siren
137     MSVehicleType* vt = MSNet::getInstance()->getVehicleControl().getVType(veh.getVehicleType().getID());
138     vt->setPreferredLateralAlignment(LATALIGN_ARBITRARY);
139     MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
140     std::string currentEdgeID = veh.getEdge()->getID();
141     for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
142         SUMOVehicle* veh2 = it->second;
143         //Vehicle only from edge should react
144         if (currentEdgeID == veh2->getEdge()->getID()) {
145             if (veh2->getDevice(typeid(MSDevice_Bluelight)) != nullptr) {
146                 // emergency vehicles should not react
147                 continue;
148             }
149             double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
150             // the perception of the sound of the siren should be around 25 meters
151             // todo only vehicles in front of the emergency vehicle should react
152             if (distanceDelta <= 25 && veh.getID() != veh2->getID() && influencedVehicles.count(veh2->getID()) == 0) {
153                 influencedVehicles.insert(static_cast<std::string>(veh2->getID()));
154                 influencedTypes.insert(std::make_pair(static_cast<std::string>(veh2->getID()), veh2->getVehicleType().getID()));
155                 //Vehicle gets a new Vehicletype to change the alignment and the lanechange options
156                 MSVehicleType& t = static_cast<MSVehicle*>(veh2)->getSingularType();
157                 MSVehicle::Influencer& lanechange = static_cast<MSVehicle*>(veh2)->getInfluencer();
158 
159                 //other vehicle should not use the rescue lane so they should not make any lane changes
160                 lanechange.setLaneChangeMode(1605);
161                 const int numLanes = (int)veh2->getEdge()->getLanes().size();
162                 //Setting the lateral alignment to build a rescue lane
163                 if (veh2->getLane()->getIndex() == numLanes - 1) {
164                     t.setPreferredLateralAlignment(LATALIGN_LEFT);
165                     // the alignement is changet to left for the vehicle std::cout << "New alignment to left for vehicle: " << veh2->getID() << " " << veh2->getVehicleType().getPreferredLateralAlignment() << "\n";
166                 } else {
167                     t.setPreferredLateralAlignment(LATALIGN_RIGHT);
168                     // the alignement is changet to right for the vehicle std::cout << "New alignment to right for vehicle: " << veh2->getID() << " " << veh2->getVehicleType().getPreferredLateralAlignment() << "\n";
169                 }
170 
171             }
172 
173         } else { //if vehicle is passed all vehicles which had to react should get their state back after they leave the communication range
174             if (influencedVehicles.count(veh2->getID()) > 0) {
175                 double distanceDelta = veh.getPosition().distanceTo(veh2->getPosition());
176                 if (distanceDelta > 25 && veh.getID() != veh2->getID()) {
177                     influencedVehicles.erase(veh2->getID());
178                     std::map<std::string, std::string>::iterator it = influencedTypes.find(veh2->getID());
179                     if (it != influencedTypes.end()) {
180                         // The vehicle gets back its old VehicleType after the emergency vehicle have passed them
181                         MSVehicleType* targetType = MSNet::getInstance()->getVehicleControl().getVType(it->second);
182                         //targetType is nullptr if the vehicle type has already changed to its old vehicleType
183                         if (targetType != nullptr) {
184                             static_cast<MSVehicle*>(veh2)->replaceVehicleType(targetType);
185                         }
186                     }
187                 }
188             }
189         }
190     }
191     return true; // keep the device
192 }
193 
194 
195 bool
notifyEnter(SUMOTrafficObject & veh,MSMoveReminder::Notification reason,const MSLane *)196 MSDevice_Bluelight::notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
197 #ifdef DEBUG_BLUELIGHT
198     std::cout << "device '" << getID() << "' notifyEnter: reason=" << reason << " currentEdge=" << veh.getEdge()->getID() << "\n";
199 #else
200     UNUSED_PARAMETER(veh);
201     UNUSED_PARAMETER(reason);
202 #endif
203     return true; // keep the device
204 }
205 
206 
207 bool
notifyLeave(SUMOTrafficObject & veh,double,MSMoveReminder::Notification reason,const MSLane *)208 MSDevice_Bluelight::notifyLeave(SUMOTrafficObject& veh, double /*lastPos*/, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
209 #ifdef DEBUG_BLUELIGHT
210     std::cout << "device '" << getID() << "' notifyLeave: reason=" << reason << " currentEdge=" << veh.getEdge()->getID() << "\n";
211 #else
212     UNUSED_PARAMETER(veh);
213     UNUSED_PARAMETER(reason);
214 #endif
215     return true; // keep the device
216 }
217 
218 
219 void
generateOutput() const220 MSDevice_Bluelight::generateOutput() const {
221     if (OptionsCont::getOptions().isSet("tripinfo-output")) {
222         OutputDevice& os = OutputDevice::getDeviceByOption("tripinfo-output");
223         os.openTag("example_device");
224         os.writeAttr("customValue1", toString(myCustomValue1));
225         os.writeAttr("customValue2", toString(myCustomValue2));
226         os.closeTag();
227     }
228 }
229 
230 std::string
getParameter(const std::string & key) const231 MSDevice_Bluelight::getParameter(const std::string& key) const {
232     if (key == "customValue1") {
233         return toString(myCustomValue1);
234     } else if (key == "customValue2") {
235         return toString(myCustomValue2);
236     } else if (key == "meaningOfLife") {
237         return "42";
238     }
239     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
240 }
241 
242 
243 void
setParameter(const std::string & key,const std::string & value)244 MSDevice_Bluelight::setParameter(const std::string& key, const std::string& value) {
245     double doubleValue;
246     try {
247         doubleValue = StringUtils::toDouble(value);
248     } catch (NumberFormatException&) {
249         throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
250     }
251     if (key == "customValue1") {
252         myCustomValue1 = doubleValue;
253     } else {
254         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
255     }
256 }
257 
258 
259 /****************************************************************************/
260 
261