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

Generated by: LCOV version 2.0-1