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

Generated by: LCOV version 2.0-1