LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Bluelight.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.4 % 188 168
Test Date: 2024-11-22 15:46:21 Functions: 83.3 % 12 10

            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              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1