LCOV - code coverage report
Current view: top level - src/mesosim - MEVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 87.2 % 313 273
Test Date: 2026-04-16 16:39:47 Functions: 84.8 % 33 28

            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    MEVehicle.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @date    Tue, May 2005
      18              : ///
      19              : // A vehicle from the mesoscopic point of view
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <iostream>
      24              : #include <cassert>
      25              : #include <utils/common/StdDefs.h>
      26              : #include <utils/common/FileHelpers.h>
      27              : #include <utils/common/MsgHandler.h>
      28              : #include <utils/geom/GeomHelper.h>
      29              : #include <utils/iodevices/OutputDevice.h>
      30              : #include <utils/xml/SUMOSAXAttributes.h>
      31              : #include <microsim/devices/MSDevice_Tripinfo.h>
      32              : #include <microsim/devices/MSDevice_Vehroutes.h>
      33              : #include <microsim/devices/MSDevice_Taxi.h>
      34              : #include <microsim/output/MSStopOut.h>
      35              : #include <microsim/MSGlobals.h>
      36              : #include <microsim/MSEdge.h>
      37              : #include <microsim/MSLane.h>
      38              : #include <microsim/MSNet.h>
      39              : #include <microsim/MSVehicleType.h>
      40              : #include <microsim/MSLink.h>
      41              : #include <microsim/MSStop.h>
      42              : #include <microsim/MSVehicleControl.h>
      43              : #include <microsim/transportables/MSTransportableControl.h>
      44              : #include <microsim/devices/MSDevice.h>
      45              : #include "MELoop.h"
      46              : #include "MEVehicle.h"
      47              : #include "MESegment.h"
      48              : 
      49              : 
      50              : // ===========================================================================
      51              : // method definitions
      52              : // ===========================================================================
      53       769114 : MEVehicle::MEVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      54       769114 :                      MSVehicleType* type, const double speedFactor) :
      55              :     MSBaseVehicle(pars, route, type, speedFactor),
      56       769114 :     mySegment(nullptr),
      57       769114 :     myQueIndex(0),
      58       769114 :     myEventTime(SUMOTime_MIN),
      59       769114 :     myLastEntryTime(SUMOTime_MIN),
      60       769114 :     myBlockTime(SUMOTime_MAX),
      61       769114 :     myInfluencer(nullptr) {
      62       769114 : }
      63              : 
      64              : 
      65              : double
      66            0 : MEVehicle::getBackPositionOnLane(const MSLane* /* lane */) const {
      67            0 :     return getPositionOnLane() - getVehicleType().getLength();
      68              : }
      69              : 
      70              : 
      71              : double
      72      7352296 : MEVehicle::getPositionOnLane() const {
      73              : // the following interpolation causes problems with arrivals and calibrators
      74              : //    const double fracOnSegment = MIN2(double(1), STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myLastEntryTime) / STEPS2TIME(myEventTime - myLastEntryTime));
      75      7352296 :     return mySegment == nullptr ? 0 : (double(mySegment->getIndex()) /* + fracOnSegment */) * mySegment->getLength();
      76              : }
      77              : 
      78              : 
      79              : double
      80        64873 : MEVehicle::getAngle() const {
      81        64873 :     const MSLane* const lane = getEdge()->getLanes()[0];
      82        64873 :     return lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      83              : }
      84              : 
      85              : 
      86              : double
      87       172597 : MEVehicle::getSlope() const {
      88       172597 :     const MSLane* const lane = getEdge()->getLanes()[0];
      89       172597 :     return lane->getShape().slopeDegreeAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      90              : }
      91              : 
      92              : 
      93              : const MSEdge*
      94      2549641 : MEVehicle::getCurrentEdge() const {
      95      2549641 :     return mySegment != nullptr ? &mySegment->getEdge() : getEdge();
      96              : }
      97              : 
      98              : 
      99              : Position
     100       426670 : MEVehicle::getPosition(const double offset) const {
     101       426670 :     const MSLane* const lane = getEdge()->getLanes()[0];
     102       426670 :     return lane->geometryPositionAtOffset(getPositionOnLane() + offset);
     103              : }
     104              : 
     105              : PositionVector
     106            0 : MEVehicle::getBoundingBox(double offset) const {
     107            0 :     double a = getAngle() + M_PI; // angle pointing backwards
     108            0 :     double l = getLength();
     109            0 :     Position pos = getPosition();
     110            0 :     Position backPos = pos + Position(l * cos(a), l * sin(a));
     111            0 :     PositionVector centerLine;
     112            0 :     centerLine.push_back(pos);
     113            0 :     centerLine.push_back(backPos);
     114            0 :     if (offset != 0) {
     115            0 :         centerLine.extrapolate2D(offset);
     116              :     }
     117              :     PositionVector result = centerLine;
     118            0 :     result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
     119            0 :     centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
     120            0 :     result.append(centerLine.reverse(), POSITION_EPS);
     121            0 :     return result;
     122            0 : }
     123              : 
     124              : double
     125     69713526 : MEVehicle::getSpeed() const {
     126     69713526 :     if (getWaitingTime() > 0 || isStopped()) {
     127     38994987 :         return 0;
     128              :     } else {
     129     30718539 :         return getAverageSpeed();
     130              :     }
     131              : }
     132              : 
     133              : 
     134              : double
     135     30718539 : MEVehicle::getAverageSpeed() const {
     136              :     // cache for thread safety
     137     30718539 :     MESegment* s = mySegment;
     138     30718539 :     if (s == nullptr || myQueIndex == MESegment::PARKING_QUEUE) {
     139              :         return 0;
     140              :     } else {
     141     30713049 :         return MIN2(s->getLength() / STEPS2TIME(myEventTime - myLastEntryTime),
     142     30713049 :                     getEdge()->getLanes()[myQueIndex]->getVehicleMaxSpeed(this));
     143              :     }
     144              : }
     145              : 
     146              : 
     147              : double
     148      9171804 : MEVehicle::estimateLeaveSpeed(const MSLink* link) const {
     149              :     /// @see MSVehicle.cpp::estimateLeaveSpeed
     150      9171804 :     const double v = getSpeed();
     151      9171804 :     return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
     152      9171804 :                 (double)sqrt(2 * link->getLength() * getVehicleType().getCarFollowModel().getMaxAccel() + v * v));
     153              : }
     154              : 
     155              : 
     156              : double
     157    159698696 : MEVehicle::getConservativeSpeed(SUMOTime& earliestArrival) const {
     158    159698696 :     earliestArrival = MAX2(myEventTime, earliestArrival - DELTA_T); // event times have subsecond resolution
     159    159698696 :     return mySegment->getLength() / STEPS2TIME(earliestArrival - myLastEntryTime);
     160              : }
     161              : 
     162              : 
     163              : bool
     164      2948081 : MEVehicle::moveRoutePointer() {
     165              :     // vehicle has just entered a new edge. Position is 0
     166      2948081 :     if (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) { // may happen during teleport
     167          113 :         return true;
     168              :     }
     169              :     ++myCurrEdge;
     170      2947968 :     if ((*myCurrEdge)->isVaporizing()) {
     171              :         return true;
     172              :     }
     173              :     // update via
     174      2947864 :     if (myParameter->via.size() > 0 && (*myCurrEdge)->getID() == myParameter->via.front()) {
     175         2918 :         myParameter->via.erase(myParameter->via.begin());
     176              :     }
     177      2947864 :     return hasArrived();
     178              : }
     179              : 
     180              : 
     181              : bool
     182     28277410 : MEVehicle::hasArrived() const {
     183              :     // mySegment may be 0 due to teleporting or arrival
     184     28277410 :     return (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) && (
     185      4859794 :                (mySegment == nullptr)
     186      4856844 :                || myEventTime == SUMOTime_MIN
     187      4856844 :                || getPositionOnLane() > myArrivalPos - POSITION_EPS);
     188              : }
     189              : 
     190              : 
     191              : bool
     192    478949259 : MEVehicle::isOnRoad() const {
     193    478949259 :     return getSegment() != nullptr;
     194              : }
     195              : 
     196              : 
     197              : bool
     198        22360 : MEVehicle::isIdling() const {
     199        22360 :     return false;
     200              : }
     201              : 
     202              : 
     203              : void
     204     37330152 : MEVehicle::setApproaching(MSLink* link) {
     205     37330152 :     if (link != nullptr) {
     206     12110144 :         const double speed = getSpeed();
     207     12162685 :         link->setApproaching(this, getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
     208              :                              (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
     209              :                              speed, link->getViaLaneOrLane()->getVehicleMaxSpeed(this), true,
     210     12110144 :                              speed, getWaitingTime(),
     211              :                              // @note: dist is not used by meso (getZipperSpeed is never called)
     212              :                              getSegment()->getLength(), 0);
     213              :     }
     214     37330152 : }
     215              : 
     216              : 
     217              : bool
     218       331078 : MEVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info,  bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     219       331078 :     MSLink* const oldLink = mySegment != nullptr ? mySegment->getLink(this) : nullptr;
     220       662156 :     if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
     221       331078 :         if (mySegment != nullptr) {
     222       138111 :             MSLink* const newLink = mySegment->getLink(this);
     223              :             // update approaching vehicle information
     224       138111 :             if (oldLink != newLink) {
     225          719 :                 if (oldLink != nullptr) {
     226          670 :                     oldLink->removeApproaching(this);
     227              :                 }
     228          719 :                 setApproaching(newLink);
     229              :             }
     230              :         }
     231       331078 :         return true;
     232              :     }
     233              :     return false;
     234              : }
     235              : 
     236              : 
     237              : SUMOTime
     238     26030013 : MEVehicle::checkStop(SUMOTime time) {
     239              :     const SUMOTime initialTime = time;
     240              :     bool hadStop = false;
     241     26045717 :     for (MSStop& stop : myStops) {
     242       145148 :         if (stop.joinTriggered) {
     243         1494 :             WRITE_WARNINGF(TL("Join stops are not available in meso yet (vehicle '%', segment '%')."),
     244              :                            getID(), mySegment->getID());
     245          498 :             continue;
     246              :         }
     247       144650 :         if (stop.edge != myCurrEdge || stop.segment != mySegment) {
     248              :             break;
     249              :         }
     250              :         const SUMOTime cur = time;
     251        15206 :         if (stop.duration > 0) { // it might be a triggered stop with duration -1
     252         7327 :             time += stop.duration;
     253              :         }
     254        15206 :         if (stop.pars.until > time) {
     255              :             // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     256              :             // travel time is overestimated of the stop is not at the start of the segment
     257              :             time = stop.pars.until;
     258              :         }
     259        15206 :         if (MSGlobals::gUseStopEnded && stop.pars.ended >= 0) {
     260              :             time = MAX2(cur, stop.pars.ended);
     261              :         }
     262        15206 :         if (!stop.reached) {
     263        15206 :             stop.reached = true;
     264        15206 :             stop.pars.started = myLastEntryTime;
     265        15206 :             stop.endBoarding = stop.pars.extension >= 0 ? time + stop.pars.extension : SUMOTime_MAX;
     266        15206 :             if (MSStopOut::active()) {
     267         1016 :                 if (!hadStop) {
     268          976 :                     MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     269              :                 } else {
     270          120 :                     WRITE_WARNINGF(TL("Vehicle '%' has multiple stops on segment '%', time=% (stop-output will be merged)."),
     271              :                                    getID(), mySegment->getID(), time2string(time));
     272              :                 }
     273              :             }
     274        15206 :             MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     275              :             if (taxi != nullptr) {
     276         1479 :                 taxi->notifyMove(*this, 0, 0, 0);
     277              :             }
     278              :         }
     279        15206 :         if (stop.triggered || stop.containerTriggered || stop.joinTriggered) {
     280          960 :             time = MAX2(time, cur + DELTA_T);
     281              :         }
     282              :         hadStop = true;
     283              :     }
     284     26030013 :     MSDevice_Tripinfo* tripinfo = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
     285              :     if (tripinfo != nullptr) {
     286     14311221 :         tripinfo->updateStopTime(time - initialTime);
     287              :     }
     288     26030013 :     return time;
     289              : }
     290              : 
     291              : 
     292              : bool
     293        14386 : MEVehicle::resumeFromStopping() {
     294        14386 :     if (isStopped()) {
     295        14377 :         const SUMOTime now = SIMSTEP;
     296              :         MSStop& stop = myStops.front();
     297        14377 :         stop.pars.ended = now;
     298        28965 :         for (const auto& rem : myMoveReminders) {
     299        14588 :             rem.first->notifyStopEnded();
     300              :         }
     301        14377 :         if (MSStopOut::active()) {
     302          964 :             MSStopOut::getInstance()->stopEnded(this, stop);
     303              :         }
     304        14377 :         myPastStops.push_back(stop.pars);
     305        14377 :         myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
     306        14377 :         if (myAmRegisteredAsWaiting && (stop.triggered || stop.containerTriggered || stop.joinTriggered)) {
     307           31 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
     308           31 :             myAmRegisteredAsWaiting = false;
     309              :         }
     310        14377 :         myStops.pop_front();
     311        14377 :         if (myEventTime > now) {
     312              :             // if this is an aborted stop we need to change the event time of the vehicle
     313           16 :             if (MSGlobals::gMesoNet->removeLeaderCar(this)) {
     314           12 :                 myEventTime = now + 1;
     315           12 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     316              :             }
     317              :         }
     318        14377 :         return true;
     319              :     }
     320              :     return false;
     321              : }
     322              : 
     323              : 
     324              : double
     325            0 : MEVehicle::getCurrentStoppingTimeSeconds() const {
     326            0 :     SUMOTime time = myLastEntryTime;
     327            0 :     for (const MSStop& stop : myStops) {
     328            0 :         if (stop.reached) {
     329            0 :             time += stop.duration;
     330            0 :             if (stop.pars.until > time) {
     331              :                 // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     332              :                 // travel time is overestimated of the stop is not at the start of the segment
     333              :                 time = stop.pars.until;
     334              :             }
     335              :         } else {
     336              :             break;
     337              :         }
     338              :     }
     339            0 :     return STEPS2TIME(time - myLastEntryTime);
     340              : }
     341              : 
     342              : 
     343              : void
     344        13700 : MEVehicle::processStop() {
     345              :     assert(isStopped());
     346              :     double lastPos = -1;
     347              :     bool hadStop = false;
     348        28068 :     while (!myStops.empty()) {
     349              :         MSStop& stop = myStops.front();
     350        22356 :         if (stop.edge != myCurrEdge || stop.segment != mySegment || stop.pars.endPos <= lastPos) {
     351              :             break;
     352              :         }
     353              :         lastPos = stop.pars.endPos;
     354        14368 :         MSNet* const net = MSNet::getInstance();
     355        14368 :         SUMOTime dummy = -1; // boarding- and loading-time are not considered
     356        14368 :         if (hadStop && MSStopOut::active()) {
     357           40 :             stop.reached = true;
     358           40 :             MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     359              :         }
     360        14368 :         if (net->hasPersons()) {
     361         5440 :             net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     362              :         }
     363        14368 :         if (net->hasContainers()) {
     364          244 :             net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     365              :         }
     366        14368 :         resumeFromStopping();
     367              :         hadStop = true;
     368              :     }
     369        13700 :     if (getWaitingTime() > 0) {
     370              :         // entry back onto the road was blocked for some time
     371          155 :         MSDevice_Tripinfo* tripinfoDevice = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
     372              :         if (tripinfoDevice != nullptr) {
     373            5 :             tripinfoDevice->recordMesoParkingTimeLoss(getWaitingTime());
     374              :         }
     375              :     }
     376        13700 :     mySegment->getEdge().removeWaiting(this);
     377        13700 : }
     378              : 
     379              : 
     380              : bool
     381     34381902 : MEVehicle::mayProceed() {
     382     34381902 :     if (mySegment == nullptr) {
     383              :         return true;
     384              :     }
     385     34381902 :     MSNet* const net = MSNet::getInstance();
     386     34381902 :     SUMOTime dummy = -1; // boarding- and loading-time are not considered
     387     42624963 :     for (MSStop& stop : myStops) {
     388     16791328 :         if (!stop.reached) {
     389              :             break;
     390              :         }
     391      8427549 :         if (net->getCurrentTimeStep() > stop.endBoarding) {
     392           62 :             if (stop.triggered || stop.containerTriggered) {
     393           26 :                 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     394              :                 if (taxiDevice != nullptr) {
     395           23 :                     taxiDevice->cancelCurrentCustomers();
     396              :                 }
     397           26 :                 stop.triggered = false;
     398           26 :                 stop.containerTriggered = false;
     399              :             }
     400           62 :             if (myAmRegisteredAsWaiting) {
     401              :                 net->getVehicleControl().unregisterOneWaiting();
     402           26 :                 myAmRegisteredAsWaiting = false;
     403              :             }
     404              :         }
     405      8427549 :         if (stop.triggered) {
     406       168916 :             if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
     407              :                 // we could not check this on entering the segment because there may be persons who still want to leave
     408            0 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     409            0 :                 stop.triggered = false;
     410            0 :                 if (myAmRegisteredAsWaiting) {
     411              :                     net->getVehicleControl().unregisterOneWaiting();
     412            0 :                     myAmRegisteredAsWaiting = false;
     413              :                 }
     414       168916 :             } else if (!net->hasPersons() || !net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     415       168318 :                 if (!myAmRegisteredAsWaiting) {
     416          461 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     417          461 :                     myAmRegisteredAsWaiting = true;
     418              :                 }
     419       168318 :                 return false;
     420              :             }
     421              :         }
     422      8259231 :         if (stop.containerTriggered) {
     423        16244 :             if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
     424              :                 // we could not check this on entering the segment because there may be containers who still want to leave
     425            6 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     426            2 :                 stop.containerTriggered = false;
     427            2 :                 if (myAmRegisteredAsWaiting) {
     428              :                     net->getVehicleControl().unregisterOneWaiting();
     429            0 :                     myAmRegisteredAsWaiting = false;
     430              :                 }
     431        16242 :             } else if (!net->hasContainers() || !net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     432        16170 :                 if (!myAmRegisteredAsWaiting) {
     433           44 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     434           44 :                     myAmRegisteredAsWaiting = true;
     435              :                 }
     436        16170 :                 return false;
     437              :             }
     438              :         }
     439      8243061 :         if (stop.joinTriggered) {
     440              :             // TODO do something useful here
     441              :             return false;
     442              :         }
     443              :     }
     444     34197414 :     return mySegment->isOpen(this);
     445              : }
     446              : 
     447              : 
     448              : double
     449            0 : MEVehicle::getCurrentLinkPenaltySeconds() const {
     450            0 :     if (mySegment == nullptr) {
     451              :         return 0;
     452              :     } else {
     453            0 :         return STEPS2TIME(mySegment->getLinkPenalty(this));
     454              :     }
     455              : }
     456              : 
     457              : 
     458              : void
     459      1301111 : MEVehicle::updateDetectorForWriting(MSMoveReminder* rem, SUMOTime currentTime, SUMOTime exitTime) {
     460      2186408 :     for (MoveReminderCont::iterator i = myMoveReminders.begin(); i != myMoveReminders.end(); ++i) {
     461      2175094 :         if (i->first == rem) {
     462      1289797 :             rem->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     463      1289797 :                                 (mySegment->getIndex() + 1) * mySegment->getLength(),
     464              :                                 getLastEntryTime(), currentTime, exitTime, false);
     465              : #ifdef _DEBUG
     466              :             if (myTraceMoveReminders) {
     467              :                 traceMoveReminder("notifyMove", i->first, i->second, true);
     468              :             }
     469              : #endif
     470              :             return;
     471              :         }
     472              :     }
     473              : }
     474              : 
     475              : 
     476              : void
     477     26021233 : MEVehicle::updateDetectors(const SUMOTime currentTime, const SUMOTime exitTime, const bool isLeave, const MSMoveReminder::Notification reason) {
     478              :     // segments of the same edge have the same reminder so no cleaning up must take place
     479     26021233 :     const bool cleanUp = isLeave && (reason != MSMoveReminder::NOTIFICATION_SEGMENT);
     480     58564766 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
     481     32543533 :         if (currentTime != getLastEntryTime() && reason < MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR) {
     482     32486913 :             rem->first->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     483     32486913 :                                        (mySegment->getIndex() + 1) * mySegment->getLength(),
     484              :                                        getLastEntryTime(), currentTime, exitTime, cleanUp);
     485              : #ifdef _DEBUG
     486              :             if (myTraceMoveReminders) {
     487              :                 traceMoveReminder("notifyMove", rem->first, rem->second, true);
     488              :             }
     489              : #endif
     490              :         }
     491     65084079 :         if (!isLeave || rem->first->notifyLeave(*this, mySegment == nullptr ? 0 : mySegment->getLength(), reason)) {
     492              : #ifdef _DEBUG
     493              :             if (isLeave && myTraceMoveReminders) {
     494              :                 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
     495              :             }
     496              : #endif
     497              : 
     498     23235219 :             if (isLeave) {
     499     23232923 :                 rem->second += getEdge()->getLength();
     500              : #ifdef _DEBUG
     501              :                 if (myTraceMoveReminders) {
     502              :                     traceMoveReminder("adaptedPos", rem->first, rem->second, true);
     503              :                 }
     504              : #endif
     505              :             }
     506              :             ++rem;
     507              :         } else {
     508              : #ifdef _DEBUG
     509              :             if (myTraceMoveReminders) {
     510              :                 traceMoveReminder("remove", rem->first, rem->second, false);
     511              :             }
     512              : #endif
     513              :             rem = myMoveReminders.erase(rem);
     514              :         }
     515              :     }
     516     26021233 :     if (reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     517      4746097 :         myOdometer += getEdge()->getLength();
     518              :     }
     519     26021233 : }
     520              : 
     521              : 
     522              : MEVehicle::BaseInfluencer&
     523            3 : MEVehicle::getBaseInfluencer() {
     524            3 :     if (myInfluencer == nullptr) {
     525            2 :         myInfluencer = new BaseInfluencer();
     526              :     }
     527            3 :     return *myInfluencer;
     528              : }
     529              : 
     530              : 
     531              : const MEVehicle::BaseInfluencer*
     532           46 : MEVehicle::getBaseInfluencer() const {
     533           46 :     return myInfluencer;
     534              : }
     535              : 
     536              : 
     537              : void
     538            2 : MEVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
     539            2 :     MSGlobals::gMesoNet->removeLeaderCar(this);
     540            2 :     MSGlobals::gMesoNet->changeSegment(this, MSNet::getInstance()->getCurrentTimeStep(), nullptr, reason);
     541            2 : }
     542              : 
     543              : 
     544              : int
     545         5732 : MEVehicle::getSegmentIndex() const {
     546         5732 :     return getSegment() != nullptr ? getSegment()->getIndex() : -1;
     547              : }
     548              : 
     549              : 
     550              : double
     551            0 : MEVehicle::getRightSideOnEdge(const MSLane* /*lane*/) const {
     552            0 :     if (mySegment == nullptr || mySegment->getIndex() >= getEdge()->getNumLanes()) {
     553            0 :         return 0;
     554              :     }
     555            0 :     const MSLane* lane = getEdge()->getLanes()[mySegment->getIndex()];
     556            0 :     return lane->getRightSideOnEdge() + lane->getWidth() * 0.5 - 0.5 * getVehicleType().getWidth();
     557              : 
     558              : }
     559              : 
     560              : 
     561              : void
     562         1841 : MEVehicle::saveState(OutputDevice& out) {
     563         1841 :     if (mySegment != nullptr && MESegment::isInvalid(mySegment)) {
     564              :         // segment is vaporization target, do not write this vehicle
     565            0 :         return;
     566              :     }
     567         1841 :     MSBaseVehicle::saveState(out);
     568              :     assert(mySegment == nullptr || *myCurrEdge == &mySegment->getEdge());
     569              :     std::vector<SUMOTime> internals;
     570         1841 :     internals.push_back(myParameter->parametersSet);
     571         1841 :     internals.push_back(myDeparture);
     572         1841 :     internals.push_back((SUMOTime)distance(myRoute->begin(), myCurrEdge));
     573         1841 :     internals.push_back((SUMOTime)myDepartPos * 1000); // store as mm
     574         1841 :     internals.push_back(mySegment == nullptr ? (SUMOTime) - 1 : (SUMOTime)mySegment->getIndex());
     575         1841 :     internals.push_back((SUMOTime)getQueIndex());
     576         1841 :     internals.push_back(myEventTime);
     577         1841 :     internals.push_back(myLastEntryTime);
     578         1841 :     internals.push_back(myBlockTime);
     579         1841 :     internals.push_back(isStopped());
     580         1841 :     internals.push_back(myPastStops.size());
     581         1841 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     582              :     // save past stops
     583         4893 :     for (SUMOVehicleParameter::Stop stop : myPastStops) {
     584         3052 :         stop.write(out, false);
     585              :         // do not write started and ended twice
     586         3052 :         if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
     587         3052 :             out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     588              :         }
     589         3052 :         if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
     590         3052 :             out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
     591              :         }
     592         3052 :         out.closeTag();
     593         3052 :     }
     594              :     // save upcoming stops
     595         2223 :     for (const MSStop& stop : myStops) {
     596          382 :         stop.write(out);
     597              :     }
     598              :     // save parameters
     599         1841 :     myParameter->writeParams(out);
     600         4724 :     for (MSDevice* dev : myDevices) {
     601         2883 :         dev->saveState(out);
     602              :     }
     603         4302 :     for (const auto& item : myMoveReminders) {
     604         2461 :         item.first->saveReminderState(out, *this);
     605              :     }
     606         1841 :     out.closeTag();
     607         1841 : }
     608              : 
     609              : 
     610              : void
     611         1082 : MEVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
     612         1082 :     if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
     613           10 :         throw ProcessError(TL("Error: Invalid vehicles in state (may be a micro state)!"));
     614              :     }
     615              :     int routeOffset;
     616              :     bool stopped;
     617              :     int pastStops;
     618              :     int segIndex;
     619              :     int queIndex;
     620         1077 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     621         1077 :     bis >> myParameter->parametersSet;
     622         1077 :     bis >> myDeparture;
     623         1077 :     bis >> routeOffset;
     624         1077 :     bis >> myDepartPos;
     625         1077 :     bis >> segIndex;
     626         1077 :     bis >> queIndex;
     627         1077 :     bis >> myEventTime;
     628         1077 :     bis >> myLastEntryTime;
     629         1077 :     bis >> myBlockTime;
     630              :     bis >> stopped;
     631         1077 :     bis >> pastStops;
     632         1077 :     myDepartPos /= 1000.; // was stored as mm
     633              : 
     634         1077 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_RANDOMIZED)) {
     635              :         bool ok;
     636            9 :         myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
     637              :     }
     638              : 
     639              :     // load stops
     640              :     myStops.clear();
     641         1077 :     addStops(!MSGlobals::gCheckRoutes, &myCurrEdge, false);
     642              : 
     643         1077 :     if (hasDeparted()) {
     644          719 :         myDeparture -= offset;
     645          719 :         myEventTime -= offset;
     646          719 :         myLastEntryTime -= offset;
     647          719 :         myCurrEdge = myRoute->begin() + routeOffset;
     648              :         // fix stops
     649         3767 :         while (pastStops > 0) {
     650         3048 :             myPastStops.push_back(myStops.front().pars);
     651         3048 :             myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
     652         3048 :             myStops.pop_front();
     653         3048 :             pastStops--;
     654              :         }
     655          719 :         if (segIndex >= 0) {
     656          719 :             MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(**myCurrEdge);
     657         1020 :             while (seg->getIndex() != (int)segIndex) {
     658              :                 seg = seg->getNextSegment();
     659          302 :                 if (seg == nullptr) {
     660            4 :                     throw ProcessError(TLF("Unknown segment '%:%' for vehicle '%' in loaded state.", (*myCurrEdge)->getID(), segIndex, getID()));
     661              :                 }
     662              :             }
     663          718 :             setSegment(seg, queIndex);
     664          718 :             if (queIndex == MESegment::PARKING_QUEUE) {
     665          265 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     666          265 :                 getCurrentEdge()->getLanes()[0]->addParking(this);
     667              :             }
     668              :         } else {
     669              :             // on teleport
     670            0 :             setSegment(nullptr, 0);
     671              :             assert(myEventTime != SUMOTime_MIN);
     672            0 :             MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     673              :         }
     674              :         // see MSBaseVehicle constructor
     675          718 :         if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
     676          396 :             calculateArrivalParams(true);
     677              :         }
     678              :     }
     679         1076 :     if (myBlockTime != SUMOTime_MAX) {
     680            7 :         myBlockTime -= offset;
     681              :     }
     682         1076 :     std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
     683         1076 :     dis >> myOdometer >> myNumberReroutes;
     684         1076 :     if (stopped) {
     685          278 :         myStops.front().startedFromState = true;
     686          278 :         myStops.front().reached = true;
     687              :     }
     688         1077 : }
     689              : 
     690              : 
     691              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1