LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Bluelight.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 161 181 89.0 %
Date: 2024-04-29 15:38:36 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.14