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: 2026-06-15 15:46:12 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-2026 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     36406239 : MSVehicleTransfer::VehicleInformation::operator<(const VehicleInformation& v2) const {
      51     36406239 :     return myVeh->getNumericalID() < v2.myVeh->getNumericalID();
      52              : }
      53              : 
      54              : 
      55              : void
      56        31647 : MSVehicleTransfer::add(const SUMOTime t, MSVehicle* veh) {
      57        31647 :     const bool jumping = veh->isJumping();
      58        31647 :     const SUMOTime proceed = jumping ? MAX2(t + veh->getPastStops().back().jump, veh->getPastStops().back().jumpUntil) : -1;
      59        31647 :     if (veh->isParking()) {
      60        16386 :         veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_PARKING);
      61        16386 :         MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_PARKING);
      62        16386 :         veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_PARKING);
      63              :     } else {
      64        15261 :         veh->getLaneChangeModel().endLaneChangeManeuver(MSMoveReminder::NOTIFICATION_TELEPORT);
      65        15261 :         MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VehicleState::STARTING_TELEPORT);
      66        15261 :         if (veh->succEdge(1) == nullptr) {
      67         9036 :             WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), veh->getID(), veh->getEdge()->getID(), time2string(t));
      68         3012 :             veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
      69         3012 :             MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
      70         3012 :             return;
      71              :         }
      72        12249 :         veh->onRemovalFromNet(MSMoveReminder::NOTIFICATION_TELEPORT);
      73        12249 :         veh->enterLaneAtMove(veh->succEdge(1)->getLanes()[0], true);
      74              :     }
      75        28635 :     myVehicles.push_back(VehicleInformation(t, veh, proceed, veh->isParking(), jumping));
      76              : }
      77              : 
      78              : 
      79              : void
      80      3367324 : MSVehicleTransfer::remove(MSVehicle* veh) {
      81              :     auto& vehInfos = myVehicles.getContainer();
      82      4167598 :     for (auto i = vehInfos.begin(); i != vehInfos.end(); ++i) {
      83       800294 :         if (i->myVeh == veh) {
      84           20 :             if (i->myParking) {
      85           20 :                 veh->getMutableLane()->removeParking(veh);
      86              :             }
      87              :             vehInfos.erase(i);
      88           20 :             break;
      89              :         }
      90              :     }
      91              :     myVehicles.unlock();
      92      3367324 : }
      93              : 
      94              : 
      95              : void
      96     64914401 : MSVehicleTransfer::checkInsertions(SUMOTime time) {
      97              :     // go through vehicles
      98              :     auto& vehInfos = myVehicles.getContainer();
      99     64914401 :     std::sort(vehInfos.begin(), vehInfos.end());
     100     73406552 :     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      8492151 :         if (desc.myParking) {
     105              :             // handle parking vehicles
     106      8184036 :             if (time != desc.myTransferTime) {
     107              :                 // avoid calling processNextStop twice in the transfer step
     108      8167650 :                 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      8167650 :                 if (lane != nullptr) {
     111      8167650 :                     lane->getVehiclesSecure();
     112              :                 }
     113      8167650 :                 desc.myVeh->processNextStop(1);
     114      8167650 :                 desc.myVeh->updateParkingState();
     115      8167650 :                 if (lane != nullptr) {
     116      8167650 :                     lane->releaseVehicles();
     117              :                 }
     118              :             }
     119      8184036 :             if (desc.myVeh->keepStopping(true)) {
     120              :                 i++;
     121      8096310 :                 continue;
     122              :             }
     123              :             // parking finished, head back into traffic
     124              :         }
     125       395841 :         const SUMOVehicleClass vclass = desc.myVeh->getVehicleType().getVehicleClass();
     126       395841 :         const MSEdge* e = desc.myVeh->getEdge();
     127       395841 :         const MSEdge* nextEdge = desc.myVeh->succEdge(1);
     128              : 
     129              : 
     130       395841 :         if (desc.myParking) {
     131        87726 :             MSParkingArea* pa = desc.myVeh->getCurrentParkingArea();
     132        87726 :             const double departPos = pa != nullptr ? pa->getInsertionPosition(*desc.myVeh) : desc.myVeh->getPositionOnLane();
     133              :             // handle parking vehicles
     134        87726 :             desc.myVeh->setIdling(true);
     135        87726 :             if (desc.myVeh->getMutableLane()->isInsertionSuccess(desc.myVeh, 0, departPos, desc.myVeh->getLateralPositionOnLane(),
     136              :                     false, MSMoveReminder::NOTIFICATION_PARKING)) {
     137        12714 :                 MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_PARKING);
     138        12714 :                 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        12714 :                 if (MSGlobals::gModelParkingManoeuver && desc.myVeh->setExitManoeuvre()) {
     141           64 :                     MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::MANEUVERING);
     142              :                 }
     143        12714 :                 desc.myVeh->setIdling(false);
     144              :                 i = vehInfos.erase(i);
     145              :             } else {
     146              :                 // blocked from entering the road - engine assumed to be idling.
     147        75012 :                 desc.myVeh->workOnIdleReminders();
     148        75012 :                 if (!desc.myVeh->signalSet(MSVehicle::VEH_SIGNAL_BLINKER_LEFT | MSVehicle::VEH_SIGNAL_BLINKER_RIGHT)) {
     149              :                     // signal wish to re-enter the road
     150         1979 :                     desc.myVeh->switchOnSignal(MSGlobals::gLefthand ? MSVehicle::VEH_SIGNAL_BLINKER_RIGHT : MSVehicle::VEH_SIGNAL_BLINKER_LEFT);
     151         1979 :                     if (pa) {
     152              :                         // update freePosition so other vehicles can help with insertion
     153         1412 :                         desc.myVeh->getCurrentParkingArea()->notifyEgressBlocked();
     154              :                     }
     155              :                 }
     156              :                 i++;
     157              :             }
     158       308115 :         } 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       301099 :             MSLane* l = (nextEdge != nullptr ? e->getFreeLane(e->allowedLanes(*nextEdge, vclass), vclass, departPos) :
     166        94584 :                          e->getFreeLane(nullptr, vclass, departPos));
     167              :             // handle teleporting vehicles, lane may be 0 because permissions were modified by a closing rerouter or TraCI
     168       301099 :             const bool busyBidi = l != nullptr && l->getBidiLane() != nullptr && l->getBidiLane()->getVehicleNumberWithPartials() > 0;
     169       590102 :             if (l != nullptr && !busyBidi && l->freeInsertion(*(desc.myVeh), MIN2(l->getSpeedLimit(), desc.myVeh->getMaxSpeed()), 0, MSMoveReminder::NOTIFICATION_TELEPORT)) {
     170        11780 :                 if (!desc.myJumping) {
     171        44816 :                     WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
     172              :                 }
     173        23560 :                 MSNet::getInstance()->informVehicleStateListener(desc.myVeh, MSNet::VehicleState::ENDING_TELEPORT);
     174              :                 i = vehInfos.erase(i);
     175       289319 :             } 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       287683 :                 desc.myVeh->computeAngle();
     181       287683 :                 desc.myVeh->setLateralPositionOnLane(-desc.myVeh->getLane()->getWidth() / 2);
     182       287683 :                 desc.myVeh->invalidateCachedPosition();
     183              :                 // could not insert. maybe we should proceed in virtual space
     184       287683 :                 if (desc.myProceedTime < 0) {
     185              :                     // initialize proceed time (delayed to avoid lane-order dependency in executeMove)
     186         3331 :                     desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
     187       284352 :                 } else if (desc.myProceedTime < time) {
     188         6560 :                     if (desc.myVeh->succEdge(1) == nullptr) {
     189          373 :                         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         1412 :                             WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."), desc.myVeh->getID(), e->getID(), time2string(time));
     194          353 :                             desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
     195          353 :                             MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(desc.myVeh);
     196              :                             i = vehInfos.erase(i);
     197              :                         }
     198          373 :                         continue;
     199              :                     }
     200              :                     // let the vehicle move to the next edge
     201         6187 :                     desc.myVeh->leaveLane(MSMoveReminder::NOTIFICATION_TELEPORT_CONTINUATION);
     202              :                     // active move reminders (i.e. rerouters)
     203         6187 :                     const std::vector<MSLane*>* allowedLanes = nextEdge->allowedLanes(vclass);
     204        12374 :                     MSLane* laneToEnter = (allowedLanes != nullptr) ? allowedLanes->at(0) : nextEdge->getLanes()[0];
     205         6187 :                     desc.myVeh->enterLaneAtMove(laneToEnter, true);
     206              :                     // use current travel time to determine when to move the vehicle forward
     207         6187 :                     desc.myProceedTime = time + TIME2STEPS(e->getCurrentTravelTime(TeleportMinSpeed));
     208              :                 }
     209              :                 ++i;
     210              :             }
     211              :         }
     212              :     }
     213              :     myVehicles.unlock();
     214     64914401 : }
     215              : 
     216              : 
     217              : MSVehicleTransfer*
     218     68356443 : MSVehicleTransfer::getInstance() {
     219     68356443 :     if (myInstance == nullptr) {
     220        42172 :         myInstance = new MSVehicleTransfer();
     221              :     }
     222     68356443 :     return myInstance;
     223              : }
     224              : 
     225              : 
     226        42172 : MSVehicleTransfer::MSVehicleTransfer() : myVehicles(MSGlobals::gNumSimThreads > 1) {}
     227              : 
     228              : 
     229        84338 : MSVehicleTransfer::~MSVehicleTransfer() {
     230        42169 :     myInstance = nullptr;
     231        84338 : }
     232              : 
     233              : 
     234              : void
     235          529 : MSVehicleTransfer::saveState(OutputDevice& out) {
     236          734 :     for (const VehicleInformation& vehInfo : myVehicles.getContainer()) {
     237          205 :         out.openTag(SUMO_TAG_VEHICLETRANSFER);
     238          205 :         out.writeAttr(SUMO_ATTR_ID, vehInfo.myVeh->getID());
     239          205 :         out.writeAttr(SUMO_ATTR_DEPART, vehInfo.myProceedTime);
     240          205 :         if (vehInfo.myParking) {
     241          203 :             out.writeAttr(SUMO_ATTR_PARKING, vehInfo.myVeh->getLane()->getID());
     242              :         }
     243          205 :         if (vehInfo.myJumping) {
     244            0 :             out.writeAttr(SUMO_ATTR_JUMP, true);
     245              :         }
     246          410 :         out.closeTag();
     247              :     }
     248              :     myVehicles.unlock();
     249          529 : }
     250              : 
     251              : 
     252              : void
     253          168 : MSVehicleTransfer::clearState() {
     254          168 :     myVehicles.clear();
     255          168 : }
     256              : 
     257              : 
     258              : void
     259          205 : MSVehicleTransfer::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset, MSVehicleControl& vc) {
     260          205 :     MSVehicle* veh = dynamic_cast<MSVehicle*>(vc.getVehicle(attrs.getString(SUMO_ATTR_ID)));
     261          205 :     if (veh == nullptr) {
     262              :         // deleted
     263            0 :         return;
     264              :     }
     265          205 :     SUMOTime proceedTime = (SUMOTime)attrs.getLong(SUMO_ATTR_DEPART);
     266          205 :     MSLane* parkingLane = attrs.hasAttribute(SUMO_ATTR_PARKING) ? MSLane::dictionary(attrs.getString(SUMO_ATTR_PARKING)) : nullptr;
     267          205 :     bool ok = true;
     268          205 :     const bool jumping = attrs.getOpt<bool>(SUMO_ATTR_JUMP, veh->getID().c_str(), ok, false);
     269          205 :     myVehicles.push_back(VehicleInformation(-1, veh, proceedTime - offset, parkingLane != nullptr, jumping));
     270          205 :     if (parkingLane != nullptr) {
     271          203 :         parkingLane->addParking(veh);
     272          203 :         veh->setTentativeLaneAndPosition(parkingLane, veh->getPositionOnLane());
     273          203 :         veh->processNextStop(veh->getSpeed());
     274              :     }
     275          205 :     MSNet::getInstance()->getInsertionControl().alreadyDeparted(veh);
     276              : }
     277              : 
     278              : 
     279              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1