LCOV - code coverage report
Current view: top level - src/mesosim - MEVehicle.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 238 266 89.5 %
Date: 2024-04-27 15:34:54 Functions: 25 30 83.3 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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/iodevices/OutputDevice.h>
      29             : #include <utils/xml/SUMOSAXAttributes.h>
      30             : #include <microsim/devices/MSDevice_Tripinfo.h>
      31             : #include <microsim/devices/MSDevice_Vehroutes.h>
      32             : #include <microsim/devices/MSDevice_Taxi.h>
      33             : #include <microsim/output/MSStopOut.h>
      34             : #include <microsim/MSGlobals.h>
      35             : #include <microsim/MSEdge.h>
      36             : #include <microsim/MSLane.h>
      37             : #include <microsim/MSNet.h>
      38             : #include <microsim/MSVehicleType.h>
      39             : #include <microsim/MSLink.h>
      40             : #include <microsim/MSStop.h>
      41             : #include <microsim/MSVehicleControl.h>
      42             : #include <microsim/transportables/MSTransportableControl.h>
      43             : #include <microsim/devices/MSDevice.h>
      44             : #include "MELoop.h"
      45             : #include "MEVehicle.h"
      46             : #include "MESegment.h"
      47             : 
      48             : 
      49             : // ===========================================================================
      50             : // method definitions
      51             : // ===========================================================================
      52      844373 : MEVehicle::MEVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      53      844373 :                      MSVehicleType* type, const double speedFactor) :
      54             :     MSBaseVehicle(pars, route, type, speedFactor),
      55      844373 :     mySegment(nullptr),
      56      844373 :     myQueIndex(0),
      57      844373 :     myEventTime(SUMOTime_MIN),
      58      844373 :     myLastEntryTime(SUMOTime_MIN),
      59      844373 :     myBlockTime(SUMOTime_MAX),
      60      844373 :     myInfluencer(nullptr) {
      61      844373 : }
      62             : 
      63             : 
      64             : double
      65           0 : MEVehicle::getBackPositionOnLane(const MSLane* /* lane */) const {
      66           0 :     return getPositionOnLane() - getVehicleType().getLength();
      67             : }
      68             : 
      69             : 
      70             : double
      71     8537382 : MEVehicle::getPositionOnLane() const {
      72             : // the following interpolation causes problems with arrivals and calibrators
      73             : //    const double fracOnSegment = MIN2(double(1), STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myLastEntryTime) / STEPS2TIME(myEventTime - myLastEntryTime));
      74     8537382 :     return mySegment == nullptr ? 0 : (double(mySegment->getIndex()) /* + fracOnSegment */) * mySegment->getLength();
      75             : }
      76             : 
      77             : 
      78             : double
      79       53946 : MEVehicle::getAngle() const {
      80       53946 :     const MSLane* const lane = getEdge()->getLanes()[0];
      81       53946 :     return lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      82             : }
      83             : 
      84             : 
      85             : double
      86      109389 : MEVehicle::getSlope() const {
      87      109389 :     const MSLane* const lane = getEdge()->getLanes()[0];
      88      109389 :     return lane->getShape().slopeDegreeAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      89             : }
      90             : 
      91             : 
      92             : Position
      93      258560 : MEVehicle::getPosition(const double offset) const {
      94      258560 :     const MSLane* const lane = getEdge()->getLanes()[0];
      95      258560 :     return lane->geometryPositionAtOffset(getPositionOnLane() + offset);
      96             : }
      97             : 
      98             : 
      99             : double
     100    69597610 : MEVehicle::getSpeed() const {
     101    69597610 :     if (getWaitingTime() > 0 || isStopped()) {
     102    31139092 :         return 0;
     103             :     } else {
     104    38458518 :         return getAverageSpeed();
     105             :     }
     106             : }
     107             : 
     108             : 
     109             : double
     110    38458518 : MEVehicle::getAverageSpeed() const {
     111    38458518 :     if (mySegment == nullptr || myQueIndex == MESegment::PARKING_QUEUE ) {
     112             :         return 0;
     113             :     } else {
     114    38457604 :         return MIN2(mySegment->getLength() / STEPS2TIME(myEventTime - myLastEntryTime),
     115    38457604 :                     getEdge()->getLanes()[myQueIndex]->getVehicleMaxSpeed(this));
     116             :     }
     117             : }
     118             : 
     119             : 
     120             : double
     121     7718537 : MEVehicle::estimateLeaveSpeed(const MSLink* link) const {
     122             :     /// @see MSVehicle.cpp::estimateLeaveSpeed
     123     7718537 :     const double v = getSpeed();
     124     7718537 :     return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
     125     7718537 :                 (double)sqrt(2 * link->getLength() * getVehicleType().getCarFollowModel().getMaxAccel() + v * v));
     126             : }
     127             : 
     128             : 
     129             : double
     130   151603154 : MEVehicle::getConservativeSpeed(SUMOTime& earliestArrival) const {
     131   151603154 :     earliestArrival = MAX2(myEventTime, earliestArrival - DELTA_T); // event times have subsecond resolution
     132   151603154 :     return mySegment->getLength() / STEPS2TIME(earliestArrival - myLastEntryTime);
     133             : }
     134             : 
     135             : 
     136             : bool
     137     3668146 : MEVehicle::moveRoutePointer() {
     138             :     // vehicle has just entered a new edge. Position is 0
     139     3668146 :     if (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) { // may happen during teleport
     140         108 :         return true;
     141             :     }
     142             :     ++myCurrEdge;
     143     3668038 :     if ((*myCurrEdge)->isVaporizing()) {
     144             :         return true;
     145             :     }
     146             :     // update via
     147     3667934 :     if (myParameter->via.size() > 0 && (*myCurrEdge)->getID() == myParameter->via.front()) {
     148          42 :         myParameter->via.erase(myParameter->via.begin());
     149             :     }
     150     3667934 :     return hasArrived();
     151             : }
     152             : 
     153             : 
     154             : bool
     155    36717337 : MEVehicle::hasArrived() const {
     156             :     // mySegment may be 0 due to teleporting or arrival
     157    36717337 :     return (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) && (
     158     6107991 :                (mySegment == nullptr)
     159     6106391 :                || myEventTime == SUMOTime_MIN
     160     6106391 :                || getPositionOnLane() > myArrivalPos - POSITION_EPS);
     161             : }
     162             : 
     163             : 
     164             : bool
     165   456708804 : MEVehicle::isOnRoad() const {
     166   456708804 :     return getSegment() != nullptr;
     167             : }
     168             : 
     169             : 
     170             : bool
     171       21960 : MEVehicle::isIdling() const {
     172       21960 :     return false;
     173             : }
     174             : 
     175             : 
     176             : void
     177    42734575 : MEVehicle::setApproaching(MSLink* link) {
     178    42734575 :     if (link != nullptr) {
     179     9585866 :         const double speed = getSpeed();
     180     9585964 :         link->setApproaching(this, getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
     181             :                              (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
     182             :                              speed, speed, true,
     183     9585866 :                              speed, getWaitingTime(),
     184             :                              // @note: dist is not used by meso (getZipperSpeed is never called)
     185             :                              getSegment()->getLength(), 0);
     186             :     }
     187    42734575 : }
     188             : 
     189             : 
     190             : bool
     191      446832 : MEVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info,  bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     192      446832 :     MSLink* const oldLink = mySegment != nullptr ? mySegment->getLink(this) : nullptr;
     193      893664 :     if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
     194      446832 :         if (mySegment != nullptr) {
     195      132652 :             MSLink* const newLink = mySegment->getLink(this);
     196             :             // update approaching vehicle information
     197      132652 :             if (oldLink != newLink) {
     198         305 :                 if (oldLink != nullptr) {
     199         301 :                     oldLink->removeApproaching(this);
     200             :                 }
     201         305 :                 setApproaching(newLink);
     202             :             }
     203             :         }
     204      446832 :         return true;
     205             :     }
     206             :     return false;
     207             : }
     208             : 
     209             : 
     210             : SUMOTime
     211    33778887 : MEVehicle::checkStop(SUMOTime time) {
     212             :     const SUMOTime initialTime = time;
     213             :     bool hadStop = false;
     214    33787678 :     for (MSStop& stop : myStops) {
     215       88272 :         if (stop.joinTriggered) {
     216         999 :             WRITE_WARNINGF(TL("Join stops are not available in meso yet (vehicle '%', segment '%')."),
     217             :                            getID(), mySegment->getID());
     218         333 :             continue;
     219             :         }
     220       87939 :         if (stop.edge != myCurrEdge || stop.segment != mySegment) {
     221             :             break;
     222             :         }
     223             :         const SUMOTime cur = time;
     224        8458 :         if (stop.duration > 0) { // it might be a triggered stop with duration -1
     225        4387 :             time += stop.duration;
     226             :         }
     227        8458 :         if (stop.pars.until > time) {
     228             :             // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     229             :             // travel time is overestimated of the stop is not at the start of the segment
     230             :             time = stop.pars.until;
     231             :         }
     232        8458 :         if (MSGlobals::gUseStopEnded && stop.pars.ended >= 0) {
     233             :             time = MAX2(cur, stop.pars.ended);
     234             :         }
     235        8458 :         if (!stop.reached) {
     236        8458 :             stop.reached = true;
     237        8458 :             stop.pars.started = myLastEntryTime;
     238        8458 :             stop.endBoarding = stop.pars.extension >= 0 ? time + stop.pars.extension : SUMOTime_MAX;
     239        8458 :             if (MSStopOut::active()) {
     240         811 :                 if (!hadStop) {
     241         777 :                     MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     242             :                 } else {
     243         102 :                     WRITE_WARNINGF(TL("Vehicle '%' has multiple stops on segment '%', time=% (stop-output will be merged)."),
     244             :                                    getID(), mySegment->getID(), time2string(time));
     245             :                 }
     246             :             }
     247        8458 :             MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     248             :             if (taxi != nullptr) {
     249         847 :                 taxi->notifyMove(*this, 0, 0, 0);
     250             :             }
     251             :         }
     252        8458 :         if (stop.triggered || stop.containerTriggered || stop.joinTriggered) {
     253         590 :             time = MAX2(time, cur + DELTA_T);
     254             :         }
     255             :         hadStop = true;
     256             :     }
     257    33778887 :     MSDevice_Tripinfo* tripinfo = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
     258             :     if (tripinfo != nullptr) {
     259    23089423 :         tripinfo->updateStopTime(time - initialTime);
     260             :     }
     261    33778887 :     return time;
     262             : }
     263             : 
     264             : 
     265             : bool
     266        7952 : MEVehicle::resumeFromStopping() {
     267        7952 :     if (isStopped()) {
     268        7952 :         const SUMOTime now = SIMSTEP;
     269             :         MSStop& stop = myStops.front();
     270        7952 :         stop.pars.ended = now;
     271       17862 :         for (const auto& rem : myMoveReminders) {
     272        9910 :             rem.first->notifyStopEnded();
     273             :         }
     274        7952 :         if (MSStopOut::active()) {
     275         776 :             MSStopOut::getInstance()->stopEnded(this, stop.pars, mySegment->getEdge().getID());
     276             :         }
     277        7952 :         myPastStops.push_back(stop.pars);
     278        7952 :         if (myAmRegisteredAsWaiting && (stop.triggered || stop.containerTriggered || stop.joinTriggered)) {
     279          74 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
     280          74 :             myAmRegisteredAsWaiting = false;
     281             :         }
     282        7952 :         myStops.pop_front();
     283        7952 :         if (myEventTime > now) {
     284             :             // if this is an aborted stop we need to change the event time of the vehicle
     285         164 :             if (MSGlobals::gMesoNet->removeLeaderCar(this)) {
     286         164 :                 myEventTime = now + 1;
     287         164 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     288             :             }
     289             :         }
     290        7952 :         return true;
     291             :     }
     292             :     return false;
     293             : }
     294             : 
     295             : 
     296             : double
     297           0 : MEVehicle::getCurrentStoppingTimeSeconds() const {
     298           0 :     SUMOTime time = myLastEntryTime;
     299           0 :     for (const MSStop& stop : myStops) {
     300           0 :         if (stop.reached) {
     301           0 :             time += stop.duration;
     302           0 :             if (stop.pars.until > time) {
     303             :                 // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     304             :                 // travel time is overestimated of the stop is not at the start of the segment
     305             :                 time = stop.pars.until;
     306             :             }
     307             :         } else {
     308             :             break;
     309             :         }
     310             :     }
     311           0 :     return STEPS2TIME(time - myLastEntryTime);
     312             : }
     313             : 
     314             : 
     315             : void
     316        7659 : MEVehicle::processStop() {
     317             :     assert(isStopped());
     318             :     double lastPos = -1;
     319             :     bool hadStop = false;
     320       15431 :     while (!myStops.empty()) {
     321             :         MSStop& stop = myStops.front();
     322       11392 :         if (stop.edge != myCurrEdge || stop.segment != mySegment || stop.pars.endPos <= lastPos) {
     323             :             break;
     324             :         }
     325             :         lastPos = stop.pars.endPos;
     326        7772 :         MSNet* const net = MSNet::getInstance();
     327        7772 :         SUMOTime dummy = -1; // boarding- and loading-time are not considered
     328        7772 :         if (net->hasPersons()) {
     329        4476 :             net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     330             :         }
     331        7772 :         if (net->hasContainers()) {
     332         148 :             net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     333             :         }
     334        7772 :         if (hadStop && MSStopOut::active()) {
     335          34 :             MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     336             :         }
     337        7772 :         resumeFromStopping();
     338             :         hadStop = true;
     339             :     }
     340        7659 :     mySegment->getEdge().removeWaiting(this);
     341        7659 : }
     342             : 
     343             : 
     344             : bool
     345    40403767 : MEVehicle::mayProceed() {
     346    40403767 :     if (mySegment == nullptr) {
     347             :         return true;
     348             :     }
     349    40403767 :     MSNet* const net = MSNet::getInstance();
     350    40403767 :     SUMOTime dummy = -1; // boarding- and loading-time are not considered
     351    46952393 :     for (MSStop& stop : myStops) {
     352    13252415 :         if (!stop.reached) {
     353             :             break;
     354             :         }
     355     6630362 :         if (net->getCurrentTimeStep() > stop.endBoarding) {
     356          59 :             if (stop.triggered || stop.containerTriggered) {
     357          23 :                 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     358             :                 if (taxiDevice != nullptr) {
     359          20 :                     taxiDevice->cancelCurrentCustomers();
     360             :                 }
     361          23 :                 stop.triggered = false;
     362          23 :                 stop.containerTriggered = false;
     363             :             }
     364          59 :             if (myAmRegisteredAsWaiting) {
     365             :                 net->getVehicleControl().unregisterOneWaiting();
     366          23 :                 myAmRegisteredAsWaiting = false;
     367             :             }
     368             :         }
     369     6630362 :         if (stop.triggered) {
     370       80661 :             if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
     371             :                 // we could not check this on entering the segment because there may be persons who still want to leave
     372           0 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     373           0 :                 stop.triggered = false;
     374           0 :                 if (myAmRegisteredAsWaiting) {
     375             :                     net->getVehicleControl().unregisterOneWaiting();
     376           0 :                     myAmRegisteredAsWaiting = false;
     377             :                 }
     378       80661 :             } else if (!net->hasPersons() || !net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     379       80302 :                 if (!myAmRegisteredAsWaiting) {
     380         318 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     381         318 :                     myAmRegisteredAsWaiting = true;
     382             :                 }
     383       80302 :                 return false;
     384             :             }
     385             :         }
     386     6550060 :         if (stop.containerTriggered) {
     387        1466 :             if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
     388             :                 // we could not check this on entering the segment because there may be containers who still want to leave
     389           6 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     390           2 :                 stop.containerTriggered = false;
     391           2 :                 if (myAmRegisteredAsWaiting) {
     392             :                     net->getVehicleControl().unregisterOneWaiting();
     393           0 :                     myAmRegisteredAsWaiting = false;
     394             :                 }
     395        1464 :             } else if (!net->hasContainers() || !net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     396        1434 :                 if (!myAmRegisteredAsWaiting) {
     397          32 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     398          32 :                     myAmRegisteredAsWaiting = true;
     399             :                 }
     400        1434 :                 return false;
     401             :             }
     402             :         }
     403     6548626 :         if (stop.joinTriggered) {
     404             :             // TODO do something useful here
     405             :             return false;
     406             :         }
     407             :     }
     408    40322031 :     return mySegment->isOpen(this);
     409             : }
     410             : 
     411             : 
     412             : double
     413           0 : MEVehicle::getCurrentLinkPenaltySeconds() const {
     414           0 :     if (mySegment == nullptr) {
     415             :         return 0;
     416             :     } else {
     417           0 :         return STEPS2TIME(mySegment->getLinkPenalty(this));
     418             :     }
     419             : }
     420             : 
     421             : 
     422             : void
     423     1369390 : MEVehicle::updateDetectorForWriting(MSMoveReminder* rem, SUMOTime currentTime, SUMOTime exitTime) {
     424     2333924 :     for (MoveReminderCont::iterator i = myMoveReminders.begin(); i != myMoveReminders.end(); ++i) {
     425     2322586 :         if (i->first == rem) {
     426     1358052 :             rem->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     427     1358052 :                                 (mySegment->getIndex() + 1) * mySegment->getLength(),
     428             :                                 getLastEntryTime(), currentTime, exitTime, false);
     429             : #ifdef _DEBUG
     430             :             if (myTraceMoveReminders) {
     431             :                 traceMoveReminder("notifyMove", i->first, i->second, true);
     432             :             }
     433             : #endif
     434             :             return;
     435             :         }
     436             :     }
     437             : }
     438             : 
     439             : 
     440             : void
     441    33774971 : MEVehicle::updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason) {
     442             :     // segments of the same edge have the same reminder so no cleaning up must take place
     443    33774971 :     const bool cleanUp = isLeave && (reason != MSMoveReminder::NOTIFICATION_SEGMENT);
     444    73642726 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
     445    39867755 :         if (currentTime != getLastEntryTime()) {
     446    39843972 :             rem->first->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     447    39843972 :                                        (mySegment->getIndex() + 1) * mySegment->getLength(),
     448             :                                        getLastEntryTime(), currentTime, getEventTime(), cleanUp);
     449             : #ifdef _DEBUG
     450             :             if (myTraceMoveReminders) {
     451             :                 traceMoveReminder("notifyMove", rem->first, rem->second, true);
     452             :             }
     453             : #endif
     454             :         }
     455    39867755 :         if (!isLeave || rem->first->notifyLeave(*this, mySegment->getLength(), reason)) {
     456             : #ifdef _DEBUG
     457             :             if (isLeave && myTraceMoveReminders) {
     458             :                 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
     459             :             }
     460             : #endif
     461             :             ++rem;
     462             :         } else {
     463             : #ifdef _DEBUG
     464             :             if (myTraceMoveReminders) {
     465             :                 traceMoveReminder("remove", rem->first, rem->second, false);
     466             :             }
     467             : #endif
     468             :             rem = myMoveReminders.erase(rem);
     469             :         }
     470             :     }
     471    33774971 :     if (reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     472     3665865 :         myOdometer += getEdge()->getLength();
     473             :     }
     474    33774971 : }
     475             : 
     476             : 
     477             : MEVehicle::BaseInfluencer&
     478           1 : MEVehicle::getBaseInfluencer() {
     479           1 :     if (myInfluencer == nullptr) {
     480           2 :         myInfluencer = new BaseInfluencer();
     481             :     }
     482           1 :     return *myInfluencer;
     483             : }
     484             : 
     485             : 
     486             : const MEVehicle::BaseInfluencer*
     487           0 : MEVehicle::getBaseInfluencer() const {
     488           0 :     return myInfluencer;
     489             : }
     490             : 
     491             : 
     492             : void
     493           1 : MEVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
     494           1 :     MSGlobals::gMesoNet->removeLeaderCar(this);
     495           1 :     MSGlobals::gMesoNet->changeSegment(this, MSNet::getInstance()->getCurrentTimeStep(), nullptr, reason);
     496           1 : }
     497             : 
     498             : double
     499           0 : MEVehicle::getRightSideOnEdge(const MSLane* /*lane*/) const {
     500           0 :     if (mySegment == nullptr || mySegment->getIndex() >= getEdge()->getNumLanes()) {
     501           0 :         return 0;
     502             :     }
     503           0 :     const MSLane* lane = getEdge()->getLanes()[mySegment->getIndex()];
     504           0 :     return lane->getRightSideOnEdge() + lane->getWidth() * 0.5 - 0.5 * getVehicleType().getWidth();
     505             : 
     506             : }
     507             : 
     508             : 
     509             : void
     510         669 : MEVehicle::saveState(OutputDevice& out) {
     511         669 :     if (mySegment != nullptr && MESegment::isInvalid(mySegment)) {
     512             :         // segment is vaporization target, do not write this vehicle
     513           0 :         return;
     514             :     }
     515         669 :     MSBaseVehicle::saveState(out);
     516             :     assert(mySegment == nullptr || *myCurrEdge == &mySegment->getEdge());
     517             :     std::vector<SUMOTime> internals;
     518         669 :     internals.push_back(myParameter->parametersSet);
     519         669 :     internals.push_back(myDeparture);
     520         669 :     internals.push_back((SUMOTime)distance(myRoute->begin(), myCurrEdge));
     521         669 :     internals.push_back((SUMOTime)myDepartPos * 1000); // store as mm
     522         669 :     internals.push_back(mySegment == nullptr ? (SUMOTime) - 1 : (SUMOTime)mySegment->getIndex());
     523         669 :     internals.push_back((SUMOTime)getQueIndex());
     524         669 :     internals.push_back(myEventTime);
     525         669 :     internals.push_back(myLastEntryTime);
     526         669 :     internals.push_back(myBlockTime);
     527        1338 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     528             :     // save past stops
     529         687 :     for (SUMOVehicleParameter::Stop stop : myPastStops) {
     530          18 :         stop.write(out, false);
     531             :         // do not write started and ended twice
     532          18 :         if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
     533          36 :             out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     534             :         }
     535          18 :         if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
     536          36 :             out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
     537             :         }
     538          18 :         out.closeTag();
     539          18 :     }
     540             :     // save upcoming stops
     541         761 :     for (const MSStop& stop : myStops) {
     542          92 :         stop.write(out);
     543             :     }
     544             :     // save parameters
     545         669 :     myParameter->writeParams(out);
     546        1589 :     for (MSDevice* dev : myDevices) {
     547         920 :         dev->saveState(out);
     548             :     }
     549        1338 :     out.closeTag();
     550             : }
     551             : 
     552             : 
     553             : void
     554         574 : MEVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
     555         574 :     if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
     556           0 :         throw ProcessError(TL("Error: Invalid vehicles in state (may be a micro state)!"));
     557             :     }
     558             :     int routeOffset;
     559             :     int segIndex;
     560             :     int queIndex;
     561         574 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     562         574 :     bis >> myParameter->parametersSet;
     563         574 :     bis >> myDeparture;
     564         574 :     bis >> routeOffset;
     565         574 :     bis >> myDepartPos;
     566         574 :     bis >> segIndex;
     567         574 :     bis >> queIndex;
     568         574 :     bis >> myEventTime;
     569         574 :     bis >> myLastEntryTime;
     570         574 :     bis >> myBlockTime;
     571         574 :     myDepartPos /= 1000.; // was stored as mm
     572         574 :     if (hasDeparted()) {
     573         216 :         myDeparture -= offset;
     574         216 :         myEventTime -= offset;
     575         216 :         myLastEntryTime -= offset;
     576         216 :         myCurrEdge = myRoute->begin() + routeOffset;
     577         216 :         if (segIndex >= 0) {
     578         216 :             MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(**myCurrEdge);
     579         362 :             while (seg->getIndex() != (int)segIndex) {
     580             :                 seg = seg->getNextSegment();
     581             :                 assert(seg != 0);
     582             :             }
     583         216 :             setSegment(seg, queIndex);
     584         216 :             if (queIndex == MESegment::PARKING_QUEUE) {
     585           3 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     586             :             }
     587             :         } else {
     588             :             // on teleport
     589           0 :             setSegment(nullptr, 0);
     590             :             assert(myEventTime != SUMOTime_MIN);
     591           0 :             MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     592             :         }
     593             :         // see MSBaseVehicle constructor
     594         216 :         if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
     595          34 :             calculateArrivalParams(true);
     596             :         }
     597             :     }
     598         574 :     if (myBlockTime != SUMOTime_MAX) {
     599           1 :         myBlockTime -= offset;
     600             :     }
     601         574 :     std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
     602         574 :     dis >> myOdometer >> myNumberReroutes;
     603         574 : }
     604             : 
     605             : 
     606             : /****************************************************************************/

Generated by: LCOV version 1.14