LCOV - code coverage report
Current view: top level - src/microsim - MSVehicleTransfer.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 98.4 % 122 120
Test Date: 2025-11-13 15:38:19 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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    MSVehicleTransfer.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Sep 2003
      19              : ///
      20              : // A mover of vehicles that got stucked due to grid locks
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <iostream>
      25              : #include <utils/common/MsgHandler.h>
      26              : #include <utils/xml/SUMOSAXAttributes.h>
      27              : #include "MSNet.h"
      28              : #include "MSLane.h"
      29              : #include "MSEdge.h"
      30              : #include "MSVehicle.h"
      31              : #include "MSParkingArea.h"
      32              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      33              : #include <microsim/devices/MSDevice_Taxi.h>
      34              : #include "MSVehicleControl.h"
      35              : #include "MSInsertionControl.h"
      36              : #include "MSVehicleTransfer.h"
      37              : 
      38              : 
      39              : // ===========================================================================
      40              : // static member definitions
      41              : // ===========================================================================
      42              : MSVehicleTransfer* MSVehicleTransfer::myInstance = nullptr;
      43              : const double MSVehicleTransfer::TeleportMinSpeed = 1;
      44              : 
      45              : 
      46              : // ===========================================================================
      47              : // member method definitions
      48              : // ===========================================================================
      49              : bool
      50     37995575 : MSVehicleTransfer::VehicleInformation::operator<(const VehicleInformation& v2) const {
      51     37995575 :     return myVeh->getNumericalID() < v2.myVeh->getNumericalID();
      52              : }
      53              : 
      54              : 
      55              : void
      56        28749 : MSVehicleTransfer::add(const SUMOTime t, MSVehicle* veh) {
      57        28749 :     const bool jumping = veh->isJumping();
      58        28749 :     const SUMOTime proceed = jumping ? MAX2(t + veh->getPastStops().back().jump, veh->getPastStops().back().jumpUntil) : -1;
      59        28749 :     if (veh->isParking()) {
      60        15451 :         veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_PARKING);
      61        15451 :         MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_PARKING);
      62        15451 :         veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_PARKING);
      63              :     } else {
      64        13298 :         veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_TELEPORT);
      65        13298 :         MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_TELEPORT);
      66        13298 :         if (veh->succEdge(1) == nullptr) {
      67         7503 :             WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), veh->getID(), veh->getEdge()->getID(), time2string(t));
      68         2501 :             veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
      69         2501 :             MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
      70         2501 :             return;
      71              :         }
      72        10797 :         veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
      73        10797 :         veh->enterLaneAtMove(veh->succEdge(1)->getLanes()[0], true);
      74              :     }
      75        26248 :     myVehicles.push_back(VehicleInformation(t, veh, proceed, veh->isParking(), jumping));
      76              : }
      77              : 
      78              : 
      79              : void
      80      2949745 : MSVehicleTransfer::remove(MSVehicle* veh) {
      81              :     auto& vehInfos = myVehicles.getContainer();
      82      3783821 :     for (auto i = vehInfos.begin(); i != vehInfos.end(); ++i) {
      83       834097 :         if (i->myVeh == veh) {
      84           21 :             if (i->myParking) {
      85           21 :                 veh->getMutableLane()->removeParking(veh);
      86              :             }
      87              :             vehInfos.erase(i);
      88           21 :             break;
      89              :         }
      90              :     }
      91              :     myVehicles.unlock();
      92      2949745 : }
      93              : 
      94              : 
      95              : void
      96     63625736 : MSVehicleTransfer::checkInsertions(SUMOTime time) {
      97              :     // go through vehicles
      98              :     auto& vehInfos = myVehicles.getContainer();
      99     63625736 :     std::sort(vehInfos.begin(), vehInfos.end());
     100     72286448 :     for (auto i = vehInfos.begin(); i != vehInfos.end();) {
     101              :         // vehicle information cannot be const because we need to assign the proceed time
     102              :         VehicleInformation& desc = *i;
     103              : 
     104      8660712 :         if (desc.myParking) {
     105              :             // handle parking vehicles
     106      8367209 :             if (time != desc.myTransferTime) {
     107              :                 // avoid calling processNextStop twice in the transfer step
     108      8351758 :                 const MSLane* lane = desc.myVeh->getLane();
     109              :                 // lane must be locked because pedestrians may be added in during stop processing while existing passengers are being drawn simultaneously
     110      8351758 :                 if (lane != nullptr) {
     111      8351758 :                     lane->getVehiclesSecure();
     112              :                 }
     113      8351758 :                 desc.myVeh->processNextStop(1);
     114      8351758 :                 desc.myVeh->updateParkingState();
     115      8351758 :                 if (lane != nullptr) {
     116      8351758 :                     lane->releaseVehicles();
     117              :                 }
     118              :             }
     119      8367209 :             if (desc.myVeh->keepStopping(true)) {
     120              :                 i++;
     121      8249949 :                 continue;
     122              :             }
     123              :             // parking finished, head back into traffic
     124              :         }
     125       410763 :         const SUMOVehicleClass vclass = desc.myVeh->getVehicleType().getVehicleClass();
     126       410763 :         const MSEdge* e = desc.myVeh->getEdge();
     127       410763 :         const MSEdge* nextEdge = desc.myVeh->succEdge(1);
     128              : 
     129              : 
     130       410763 :         if (desc.myParking) {
     131       117260 :             MSParkingArea* pa = desc.myVeh->getCurrentParkingArea();
     132       117260 :             const double departPos = pa != nullptr ? pa->getInsertionPosition(*desc.myVeh) : desc.myVeh->getPositionOnLane();
     133              :             // handle parking vehicles
     134       117260 :             desc.myVeh->setIdling(true);
     135       117260 :             if (desc.myVeh->getMutableLane()->isInsertionSuccess(desc.myVeh, 0, departPos, desc.myVeh->getLateralPositionOnLane(),
     136              :                     false, MSMoveReminder::NOTIFICATION_PARKING)) {
     137        11981 :                 MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_PARKING);
     138        11981 :                 desc.myVeh->getMutableLane()->removeParking(desc.myVeh);
     139              :                 // at this point we are in the lane, blocking traffic & if required we configure the exit manoeuvre
     140        11981 :                 if (MSGlobals::gModelParkingManoeuver && desc.myVeh->setExitManoeuvre()) {
     141           64 :                     MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::MANEUVERING);
     142              :                 }
     143        11981 :                 desc.myVeh->setIdling(false);
     144              :                 i = vehInfos.erase(i);
     145              :             } else {
     146              :                 // blocked from entering the road - engine assumed to be idling.
     147       105279 :                 desc.myVeh->workOnIdleReminders();
     148       105279 :                 if (!desc.myVeh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
     149              :                     // signal wish to re-enter the road
     150         1723 :                     desc.myVeh->switchOnSignal(MSGlobals::gLefthand ? MSVehicle::VEH_SIGNAL_BLINKER_RIGHT : MSVehicle::VEH_SIGNAL_BLINKER_LEFT);
     151         1723 :                     if (pa) {
     152              :                         // update freePosition so other vehicles can help with insertion
     153         1284 :                         desc.myVeh->getCurrentParkingArea()->notifyEgressBlocked();
     154              :                     }
     155              :                 }
     156              :                 i++;
     157              :             }
     158       293503 :         } else if (desc.myJumping && desc.myProceedTime > time) {
     159              :             ++i;
     160              :         } else {
     161              :             const double departPos = 0;
     162              :             // get the lane on which this vehicle should continue
     163              :             // first select all the lanes which allow continuation onto nextEdge
     164              :             //   then pick the one which is least occupied
     165       288344 :             MSLane* l = (nextEdge != nullptr ? e->getFreeLane(e->allowedLanes(*nextEdge, vclass), vclass, departPos) :
     166        89832 :                          e->getFreeLane(nullptr, vclass, departPos));
     167              :             // handle teleporting vehicles, lane may be 0 because permissions were modified by a closing rerouter or TraCI
     168       288344 :             const bool busyBidi = l != nullptr && l->getBidiLane() != nullptr && l->getBidiLane()->getVehicleNumberWithPartials() > 0;
     169       574682 :             if (l != nullptr && !busyBidi && l->freeInsertion(*(desc.myVeh), MIN2(l->getSpeedLimit(), desc.myVeh->getMaxSpeed()), 0, MSMoveReminder::NOTIFICATION_TELEPORT)) {
     170        10414 :                 if (!desc.myJumping) {
     171        39860 :                     WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
     172              :                 }
     173        20828 :                 MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_TELEPORT);
     174              :                 i = vehInfos.erase(i);
     175       277930 :             } else if (desc.myJumping) {
     176              :                 // try again later
     177              :                 ++i;
     178              :             } else {
     179              :                 // vehicle is visible while show-route is active. Make its state more obvious
     180       275597 :                 desc.myVeh->computeAngle();
     181       275597 :                 desc.myVeh->setLateralPositionOnLane(-desc.myVeh->getLane()->getWidth() / 2);
     182       275597 :                 desc.myVeh->invalidateCachedPosition();
     183              :                 // could not insert. maybe we should proceed in virtual space
     184       275597 :                 if (desc.myProceedTime < 0) {
     185              :                     // initialize proceed time (delayed to avoid lane-order dependency in executeMove)
     186         2943 :                     desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
     187       272654 :                 } else if (desc.myProceedTime < time) {
     188         6176 :                     if (desc.myVeh->succEdge(1) == nullptr) {
     189          287 :                         if (desc.myVeh->getDevice(typeid(MSDevice_Taxi)) != nullptr) {
     190              :                             // never teleport a taxi beyond the end of it's route
     191           20 :                             desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
     192              :                         } else {
     193         1068 :                             WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
     194          267 :                             desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
     195          267 :                             MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(desc.myVeh);
     196              :                             i = vehInfos.erase(i);
     197              :                         }
     198          287 :                         continue;
     199              :                     }
     200              :                     // let the vehicle move to the next edge
     201         5889 :                     desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION);
     202              :                     // active move reminders (i.e. rerouters)
     203         5889 :                     const std::vector<MSLane*>* allowedLanes = nextEdge->allowedLanes(vclass);
     204        11778 :                     MSLane* laneToEnter = (allowedLanes != nullptr) ? allowedLanes->at(0) : nextEdge->getLanes()[0];
     205         5889 :                     desc.myVeh->enterLaneAtMove(laneToEnter, true);
     206              :                     // use current travel time to determine when to move the vehicle forward
     207         5889 :                     desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
     208              :                 }
     209              :                 ++i;
     210              :             }
     211              :         }
     212              :     }
     213              :     myVehicles.unlock();
     214     63625736 : }
     215              : 
     216              : 
     217              : MSVehicleTransfer*
     218     66643763 : MSVehicleTransfer::getInstance() {
     219     66643763 :     if (myInstance == nullptr) {
     220        38672 :         myInstance = new MSVehicleTransfer();
     221              :     }
     222     66643763 :     return myInstance;
     223              : }
     224              : 
     225              : 
     226        38672 : MSVehicleTransfer::MSVehicleTransfer() : myVehicles(MSGlobals::gNumSimThreads > 1) {}
     227              : 
     228              : 
     229        77340 : MSVehicleTransfer::~MSVehicleTransfer() {
     230        38670 :     myInstance = nullptr;
     231        77340 : }
     232              : 
     233              : 
     234              : void
     235          476 : MSVehicleTransfer::saveState(OutputDevice& out) {
     236          676 :     for (const VehicleInformation& vehInfo : myVehicles.getContainer()) {
     237          200 :         out.openTag(SUMO_TAG_VEHICLETRANSFER);
     238          200 :         out.writeAttr(SUMO_ATTR_ID, vehInfo.myVeh->getID());
     239          200 :         out.writeAttr(SUMO_ATTR_DEPART, vehInfo.myProceedTime);
     240          200 :         if (vehInfo.myParking) {
     241          198 :             out.writeAttr(SUMO_ATTR_PARKING, vehInfo.myVeh->getLane()->getID());
     242              :         }
     243          200 :         if (vehInfo.myJumping) {
     244            0 :             out.writeAttr(SUMO_ATTR_JUMP, true);
     245              :         }
     246          400 :         out.closeTag();
     247              :     }
     248              :     myVehicles.unlock();
     249          476 : }
     250              : 
     251              : 
     252              : void
     253          187 : MSVehicleTransfer::clearState() {
     254          187 :     myVehicles.clear();
     255          187 : }
     256              : 
     257              : 
     258              : void
     259          200 : MSVehicleTransfer::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset, MSVehicleControl& vc) {
     260          200 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vc.getVehicle(attrs.getString(SUMO_ATTR_ID)));
     261          200 :     if (veh == nullptr) {
     262              :         // deleted
     263            0 :         return;
     264              :     }
     265          200 :     SUMOTime proceedTime = (SUMOTime)attrs.getLong(SUMO_ATTR_DEPART);
     266          200 :     MSLane* parkingLane = attrs.hasAttribute(SUMO_ATTR_PARKING) ? MSLane::dictionary(attrs.getString(SUMO_ATTR_PARKING)) : nullptr;
     267          200 :     bool ok = true;
     268          200 :     const bool jumping = attrs.getOpt<bool>(SUMO_ATTR_JUMP, veh->getID().c_str(), ok, false);
     269          200 :     myVehicles.push_back(VehicleInformation(-1, veh, proceedTime - offset, parkingLane != nullptr, jumping));
     270          200 :     if (parkingLane != nullptr) {
     271          198 :         parkingLane->addParking(veh);
     272          198 :         veh->setTentativeLaneAndPosition(parkingLane, veh->getPositionOnLane());
     273          198 :         veh->processNextStop(veh->getSpeed());
     274              :     }
     275          200 :     MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
     276              : }
     277              : 
     278              : 
     279              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1