LCOV - code coverage report
Current view: top level - src/mesosim - MEVehicle.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 86.1 % 296 255
Test Date: 2025-12-06 15:35:27 Functions: 84.4 % 32 27

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2025 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       743157 : MEVehicle::MEVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
      54       743157 :                      MSVehicleType* type, const double speedFactor) :
      55              :     MSBaseVehicle(pars, route, type, speedFactor),
      56       743157 :     mySegment(nullptr),
      57       743157 :     myQueIndex(0),
      58       743157 :     myEventTime(SUMOTime_MIN),
      59       743157 :     myLastEntryTime(SUMOTime_MIN),
      60       743157 :     myBlockTime(SUMOTime_MAX),
      61       743157 :     myInfluencer(nullptr) {
      62       743157 : }
      63              : 
      64              : 
      65              : double
      66            0 : MEVehicle::getBackPositionOnLane(const MSLane* /* lane */) const {
      67            0 :     return getPositionOnLane() - getVehicleType().getLength();
      68              : }
      69              : 
      70              : 
      71              : double
      72      7106176 : MEVehicle::getPositionOnLane() const {
      73              : // the following interpolation causes problems with arrivals and calibrators
      74              : //    const double fracOnSegment = MIN2(double(1), STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - myLastEntryTime) / STEPS2TIME(myEventTime - myLastEntryTime));
      75      7106176 :     return mySegment == nullptr ? 0 : (double(mySegment->getIndex()) /* + fracOnSegment */) * mySegment->getLength();
      76              : }
      77              : 
      78              : 
      79              : double
      80        52954 : MEVehicle::getAngle() const {
      81        52954 :     const MSLane* const lane = getEdge()->getLanes()[0];
      82        52954 :     return lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      83              : }
      84              : 
      85              : 
      86              : double
      87       160694 : MEVehicle::getSlope() const {
      88       160694 :     const MSLane* const lane = getEdge()->getLanes()[0];
      89       160694 :     return lane->getShape().slopeDegreeAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
      90              : }
      91              : 
      92              : 
      93              : Position
      94       100585 : MEVehicle::getPosition(const double offset) const {
      95       100585 :     const MSLane* const lane = getEdge()->getLanes()[0];
      96       100585 :     return lane->geometryPositionAtOffset(getPositionOnLane() + offset);
      97              : }
      98              : 
      99              : PositionVector
     100            0 : MEVehicle::getBoundingBox(double offset) const {
     101            0 :     double a = getAngle() + M_PI; // angle pointing backwards
     102            0 :     double l = getLength();
     103            0 :     Position pos = getPosition();
     104            0 :     Position backPos = pos + Position(l * cos(a), l * sin(a));
     105            0 :     PositionVector centerLine;
     106            0 :     centerLine.push_back(pos);
     107            0 :     centerLine.push_back(backPos);
     108            0 :     if (offset != 0) {
     109            0 :         centerLine.extrapolate2D(offset);
     110              :     }
     111              :     PositionVector result = centerLine;
     112            0 :     result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
     113            0 :     centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
     114            0 :     result.append(centerLine.reverse(), POSITION_EPS);
     115            0 :     return result;
     116            0 : }
     117              : 
     118              : double
     119     62280838 : MEVehicle::getSpeed() const {
     120     62280838 :     if (getWaitingTime() > 0 || isStopped()) {
     121     34664485 :         return 0;
     122              :     } else {
     123     27616353 :         return getAverageSpeed();
     124              :     }
     125              : }
     126              : 
     127              : 
     128              : double
     129     27616353 : MEVehicle::getAverageSpeed() const {
     130              :     // cache for thread safety
     131     27616353 :     MESegment* s = mySegment;
     132     27616353 :     if (s == nullptr || myQueIndex == MESegment::PARKING_QUEUE) {
     133              :         return 0;
     134              :     } else {
     135     27610929 :         return MIN2(s->getLength() / STEPS2TIME(myEventTime - myLastEntryTime),
     136     27610929 :                     getEdge()->getLanes()[myQueIndex]->getVehicleMaxSpeed(this));
     137              :     }
     138              : }
     139              : 
     140              : 
     141              : double
     142      8409408 : MEVehicle::estimateLeaveSpeed(const MSLink* link) const {
     143              :     /// @see MSVehicle.cpp::estimateLeaveSpeed
     144      8409408 :     const double v = getSpeed();
     145      8409408 :     return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
     146      8409408 :                 (double)sqrt(2 * link->getLength() * getVehicleType().getCarFollowModel().getMaxAccel() + v * v));
     147              : }
     148              : 
     149              : 
     150              : double
     151    106310608 : MEVehicle::getConservativeSpeed(SUMOTime& earliestArrival) const {
     152    106310608 :     earliestArrival = MAX2(myEventTime, earliestArrival - DELTA_T); // event times have subsecond resolution
     153    106310608 :     return mySegment->getLength() / STEPS2TIME(earliestArrival - myLastEntryTime);
     154              : }
     155              : 
     156              : 
     157              : bool
     158      2870165 : MEVehicle::moveRoutePointer() {
     159              :     // vehicle has just entered a new edge. Position is 0
     160      2870165 :     if (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) { // may happen during teleport
     161          113 :         return true;
     162              :     }
     163              :     ++myCurrEdge;
     164      2870052 :     if ((*myCurrEdge)->isVaporizing()) {
     165              :         return true;
     166              :     }
     167              :     // update via
     168      2869948 :     if (myParameter->via.size() > 0 && (*myCurrEdge)->getID() == myParameter->via.front()) {
     169         2908 :         myParameter->via.erase(myParameter->via.begin());
     170              :     }
     171      2869948 :     return hasArrived();
     172              : }
     173              : 
     174              : 
     175              : bool
     176     26265123 : MEVehicle::hasArrived() const {
     177              :     // mySegment may be 0 due to teleporting or arrival
     178     26265123 :     return (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) && (
     179      4805813 :                (mySegment == nullptr)
     180      4804269 :                || myEventTime == SUMOTime_MIN
     181      4804269 :                || getPositionOnLane() > myArrivalPos - POSITION_EPS);
     182              : }
     183              : 
     184              : 
     185              : bool
     186    477663735 : MEVehicle::isOnRoad() const {
     187    477663735 :     return getSegment() != nullptr;
     188              : }
     189              : 
     190              : 
     191              : bool
     192        22360 : MEVehicle::isIdling() const {
     193        22360 :     return false;
     194              : }
     195              : 
     196              : 
     197              : void
     198     33981528 : MEVehicle::setApproaching(MSLink* link) {
     199     33981528 :     if (link != nullptr) {
     200     10158668 :         const double speed = getSpeed();
     201     10211594 :         link->setApproaching(this, getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
     202              :                              (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
     203              :                              speed, link->getViaLaneOrLane()->getVehicleMaxSpeed(this), true,
     204     10158668 :                              speed, getWaitingTime(),
     205              :                              // @note: dist is not used by meso (getZipperSpeed is never called)
     206              :                              getSegment()->getLength(), 0);
     207              :     }
     208     33981528 : }
     209              : 
     210              : 
     211              : bool
     212       325269 : MEVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info,  bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
     213       325269 :     MSLink* const oldLink = mySegment != nullptr ? mySegment->getLink(this) : nullptr;
     214       650537 :     if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
     215       325268 :         if (mySegment != nullptr) {
     216       138103 :             MSLink* const newLink = mySegment->getLink(this);
     217              :             // update approaching vehicle information
     218       138103 :             if (oldLink != newLink) {
     219          355 :                 if (oldLink != nullptr) {
     220          305 :                     oldLink->removeApproaching(this);
     221              :                 }
     222          355 :                 setApproaching(newLink);
     223              :             }
     224              :         }
     225       325268 :         return true;
     226              :     }
     227              :     return false;
     228              : }
     229              : 
     230              : 
     231              : SUMOTime
     232     24070205 : MEVehicle::checkStop(SUMOTime time) {
     233              :     const SUMOTime initialTime = time;
     234              :     bool hadStop = false;
     235     24085012 :     for (MSStop& stop : myStops) {
     236       117586 :         if (stop.joinTriggered) {
     237         1155 :             WRITE_WARNINGF(TL("Join stops are not available in meso yet (vehicle '%', segment '%')."),
     238              :                            getID(), mySegment->getID());
     239          385 :             continue;
     240              :         }
     241       117201 :         if (stop.edge != myCurrEdge || stop.segment != mySegment) {
     242              :             break;
     243              :         }
     244              :         const SUMOTime cur = time;
     245        14422 :         if (stop.duration > 0) { // it might be a triggered stop with duration -1
     246         6728 :             time += stop.duration;
     247              :         }
     248        14422 :         if (stop.pars.until > time) {
     249              :             // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     250              :             // travel time is overestimated of the stop is not at the start of the segment
     251              :             time = stop.pars.until;
     252              :         }
     253        14422 :         if (MSGlobals::gUseStopEnded && stop.pars.ended >= 0) {
     254              :             time = MAX2(cur, stop.pars.ended);
     255              :         }
     256        14422 :         if (!stop.reached) {
     257        14422 :             stop.reached = true;
     258        14422 :             stop.pars.started = myLastEntryTime;
     259        14422 :             stop.endBoarding = stop.pars.extension >= 0 ? time + stop.pars.extension : SUMOTime_MAX;
     260        14422 :             if (MSStopOut::active()) {
     261          960 :                 if (!hadStop) {
     262          920 :                     MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     263              :                 } else {
     264          120 :                     WRITE_WARNINGF(TL("Vehicle '%' has multiple stops on segment '%', time=% (stop-output will be merged)."),
     265              :                                    getID(), mySegment->getID(), time2string(time));
     266              :                 }
     267              :             }
     268        14422 :             MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     269              :             if (taxi != nullptr) {
     270         1147 :                 taxi->notifyMove(*this, 0, 0, 0);
     271              :             }
     272              :         }
     273        14422 :         if (stop.triggered || stop.containerTriggered || stop.joinTriggered) {
     274          771 :             time = MAX2(time, cur + DELTA_T);
     275              :         }
     276              :         hadStop = true;
     277              :     }
     278     24070205 :     MSDevice_Tripinfo* tripinfo = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
     279              :     if (tripinfo != nullptr) {
     280     13280581 :         tripinfo->updateStopTime(time - initialTime);
     281              :     }
     282     24070205 :     return time;
     283              : }
     284              : 
     285              : 
     286              : bool
     287        13683 : MEVehicle::resumeFromStopping() {
     288        13683 :     if (isStopped()) {
     289        13677 :         const SUMOTime now = SIMSTEP;
     290              :         MSStop& stop = myStops.front();
     291        13677 :         stop.pars.ended = now;
     292        26905 :         for (const auto& rem : myMoveReminders) {
     293        13228 :             rem.first->notifyStopEnded();
     294              :         }
     295        13677 :         if (MSStopOut::active()) {
     296          912 :             MSStopOut::getInstance()->stopEnded(this, stop.pars, mySegment->getEdge().getID());
     297              :         }
     298        13677 :         myPastStops.push_back(stop.pars);
     299        13677 :         myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
     300        13677 :         if (myAmRegisteredAsWaiting && (stop.triggered || stop.containerTriggered || stop.joinTriggered)) {
     301           30 :             MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
     302           30 :             myAmRegisteredAsWaiting = false;
     303              :         }
     304        13677 :         myStops.pop_front();
     305        13677 :         if (myEventTime > now) {
     306              :             // if this is an aborted stop we need to change the event time of the vehicle
     307            6 :             if (MSGlobals::gMesoNet->removeLeaderCar(this)) {
     308            6 :                 myEventTime = now + 1;
     309            6 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     310              :             }
     311              :         }
     312        13677 :         return true;
     313              :     }
     314              :     return false;
     315              : }
     316              : 
     317              : 
     318              : double
     319            0 : MEVehicle::getCurrentStoppingTimeSeconds() const {
     320            0 :     SUMOTime time = myLastEntryTime;
     321            0 :     for (const MSStop& stop : myStops) {
     322            0 :         if (stop.reached) {
     323            0 :             time += stop.duration;
     324            0 :             if (stop.pars.until > time) {
     325              :                 // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
     326              :                 // travel time is overestimated of the stop is not at the start of the segment
     327              :                 time = stop.pars.until;
     328              :             }
     329              :         } else {
     330              :             break;
     331              :         }
     332              :     }
     333            0 :     return STEPS2TIME(time - myLastEntryTime);
     334              : }
     335              : 
     336              : 
     337              : void
     338        12989 : MEVehicle::processStop() {
     339              :     assert(isStopped());
     340              :     double lastPos = -1;
     341              :     bool hadStop = false;
     342        26665 :     while (!myStops.empty()) {
     343              :         MSStop& stop = myStops.front();
     344        21300 :         if (stop.edge != myCurrEdge || stop.segment != mySegment || stop.pars.endPos <= lastPos) {
     345              :             break;
     346              :         }
     347              :         lastPos = stop.pars.endPos;
     348        13676 :         MSNet* const net = MSNet::getInstance();
     349        13676 :         SUMOTime dummy = -1; // boarding- and loading-time are not considered
     350        13676 :         if (hadStop && MSStopOut::active()) {
     351           40 :             stop.reached = true;
     352           40 :             MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
     353              :         }
     354        13676 :         if (net->hasPersons()) {
     355         5173 :             net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     356              :         }
     357        13676 :         if (net->hasContainers()) {
     358          244 :             net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
     359              :         }
     360        13676 :         resumeFromStopping();
     361              :         hadStop = true;
     362              :     }
     363        12989 :     mySegment->getEdge().removeWaiting(this);
     364        12989 : }
     365              : 
     366              : 
     367              : bool
     368     31722292 : MEVehicle::mayProceed() {
     369     31722292 :     if (mySegment == nullptr) {
     370              :         return true;
     371              :     }
     372     31722292 :     MSNet* const net = MSNet::getInstance();
     373     31722292 :     SUMOTime dummy = -1; // boarding- and loading-time are not considered
     374     39210378 :     for (MSStop& stop : myStops) {
     375     15257321 :         if (!stop.reached) {
     376              :             break;
     377              :         }
     378      7675541 :         if (net->getCurrentTimeStep() > stop.endBoarding) {
     379           63 :             if (stop.triggered || stop.containerTriggered) {
     380           27 :                 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
     381              :                 if (taxiDevice != nullptr) {
     382           24 :                     taxiDevice->cancelCurrentCustomers();
     383              :                 }
     384           27 :                 stop.triggered = false;
     385           27 :                 stop.containerTriggered = false;
     386              :             }
     387           63 :             if (myAmRegisteredAsWaiting) {
     388              :                 net->getVehicleControl().unregisterOneWaiting();
     389           27 :                 myAmRegisteredAsWaiting = false;
     390              :             }
     391              :         }
     392      7675541 :         if (stop.triggered) {
     393       171780 :             if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
     394              :                 // we could not check this on entering the segment because there may be persons who still want to leave
     395            0 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     396            0 :                 stop.triggered = false;
     397            0 :                 if (myAmRegisteredAsWaiting) {
     398              :                     net->getVehicleControl().unregisterOneWaiting();
     399            0 :                     myAmRegisteredAsWaiting = false;
     400              :                 }
     401       171780 :             } else if (!net->hasPersons() || !net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     402       171331 :                 if (!myAmRegisteredAsWaiting) {
     403          390 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     404          390 :                     myAmRegisteredAsWaiting = true;
     405              :                 }
     406       171331 :                 return false;
     407              :             }
     408              :         }
     409      7504210 :         if (stop.containerTriggered) {
     410        16198 :             if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
     411              :                 // we could not check this on entering the segment because there may be containers who still want to leave
     412            6 :                 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
     413            2 :                 stop.containerTriggered = false;
     414            2 :                 if (myAmRegisteredAsWaiting) {
     415              :                     net->getVehicleControl().unregisterOneWaiting();
     416            0 :                     myAmRegisteredAsWaiting = false;
     417              :                 }
     418        16196 :             } else if (!net->hasContainers() || !net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
     419        16124 :                 if (!myAmRegisteredAsWaiting) {
     420           44 :                     MSNet::getInstance()->getVehicleControl().registerOneWaiting();
     421           44 :                     myAmRegisteredAsWaiting = true;
     422              :                 }
     423        16124 :                 return false;
     424              :             }
     425              :         }
     426      7488086 :         if (stop.joinTriggered) {
     427              :             // TODO do something useful here
     428              :             return false;
     429              :         }
     430              :     }
     431     31534837 :     return mySegment->isOpen(this);
     432              : }
     433              : 
     434              : 
     435              : double
     436            0 : MEVehicle::getCurrentLinkPenaltySeconds() const {
     437            0 :     if (mySegment == nullptr) {
     438              :         return 0;
     439              :     } else {
     440            0 :         return STEPS2TIME(mySegment->getLinkPenalty(this));
     441              :     }
     442              : }
     443              : 
     444              : 
     445              : void
     446      1300102 : MEVehicle::updateDetectorForWriting(MSMoveReminder* rem, SUMOTime currentTime, SUMOTime exitTime) {
     447      2184067 :     for (MoveReminderCont::iterator i = myMoveReminders.begin(); i != myMoveReminders.end(); ++i) {
     448      2172753 :         if (i->first == rem) {
     449      1288788 :             rem->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     450      1288788 :                                 (mySegment->getIndex() + 1) * mySegment->getLength(),
     451              :                                 getLastEntryTime(), currentTime, exitTime, false);
     452              : #ifdef _DEBUG
     453              :             if (myTraceMoveReminders) {
     454              :                 traceMoveReminder("notifyMove", i->first, i->second, true);
     455              :             }
     456              : #endif
     457              :             return;
     458              :         }
     459              :     }
     460              : }
     461              : 
     462              : 
     463              : void
     464     24062294 : MEVehicle::updateDetectors(const SUMOTime currentTime, const SUMOTime exitTime, const bool isLeave, const MSMoveReminder::Notification reason) {
     465              :     // segments of the same edge have the same reminder so no cleaning up must take place
     466     24062294 :     const bool cleanUp = isLeave && (reason != MSMoveReminder::NOTIFICATION_SEGMENT);
     467     54634067 :     for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
     468     30571773 :         if (currentTime != getLastEntryTime() && reason < MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR) {
     469     30515738 :             rem->first->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
     470     30515738 :                                        (mySegment->getIndex() + 1) * mySegment->getLength(),
     471              :                                        getLastEntryTime(), currentTime, exitTime, cleanUp);
     472              : #ifdef _DEBUG
     473              :             if (myTraceMoveReminders) {
     474              :                 traceMoveReminder("notifyMove", rem->first, rem->second, true);
     475              :             }
     476              : #endif
     477              :         }
     478     30571773 :         if (!isLeave || rem->first->notifyLeave(*this, mySegment->getLength(), reason)) {
     479              : #ifdef _DEBUG
     480              :             if (isLeave && myTraceMoveReminders) {
     481              :                 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
     482              :             }
     483              : #endif
     484              : 
     485     21336782 :             if (isLeave) {
     486     21334492 :                 rem->second += getEdge()->getLength();
     487              : #ifdef _DEBUG
     488              :                 if (myTraceMoveReminders) {
     489              :                     traceMoveReminder("adaptedPos", rem->first, rem->second, true);
     490              :                 }
     491              : #endif
     492              :             }
     493              :             ++rem;
     494              :         } else {
     495              : #ifdef _DEBUG
     496              :             if (myTraceMoveReminders) {
     497              :                 traceMoveReminder("remove", rem->first, rem->second, false);
     498              :             }
     499              : #endif
     500              :             rem = myMoveReminders.erase(rem);
     501              :         }
     502              :     }
     503     24062294 :     if (reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
     504      2867814 :         myOdometer += getEdge()->getLength();
     505              :     }
     506     24062294 : }
     507              : 
     508              : 
     509              : MEVehicle::BaseInfluencer&
     510            3 : MEVehicle::getBaseInfluencer() {
     511            3 :     if (myInfluencer == nullptr) {
     512            2 :         myInfluencer = new BaseInfluencer();
     513              :     }
     514            3 :     return *myInfluencer;
     515              : }
     516              : 
     517              : 
     518              : const MEVehicle::BaseInfluencer*
     519           46 : MEVehicle::getBaseInfluencer() const {
     520           46 :     return myInfluencer;
     521              : }
     522              : 
     523              : 
     524              : void
     525            2 : MEVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
     526            2 :     MSGlobals::gMesoNet->removeLeaderCar(this);
     527            2 :     MSGlobals::gMesoNet->changeSegment(this, MSNet::getInstance()->getCurrentTimeStep(), nullptr, reason);
     528            2 : }
     529              : 
     530              : 
     531              : int
     532         5732 : MEVehicle::getSegmentIndex() const {
     533         5732 :     return getSegment() != nullptr ? getSegment()->getIndex() : -1;
     534              : }
     535              : 
     536              : 
     537              : double
     538            0 : MEVehicle::getRightSideOnEdge(const MSLane* /*lane*/) const {
     539            0 :     if (mySegment == nullptr || mySegment->getIndex() >= getEdge()->getNumLanes()) {
     540            0 :         return 0;
     541              :     }
     542            0 :     const MSLane* lane = getEdge()->getLanes()[mySegment->getIndex()];
     543            0 :     return lane->getRightSideOnEdge() + lane->getWidth() * 0.5 - 0.5 * getVehicleType().getWidth();
     544              : 
     545              : }
     546              : 
     547              : 
     548              : void
     549         1782 : MEVehicle::saveState(OutputDevice& out) {
     550         1782 :     if (mySegment != nullptr && MESegment::isInvalid(mySegment)) {
     551              :         // segment is vaporization target, do not write this vehicle
     552            0 :         return;
     553              :     }
     554         1782 :     MSBaseVehicle::saveState(out);
     555              :     assert(mySegment == nullptr || *myCurrEdge == &mySegment->getEdge());
     556              :     std::vector<SUMOTime> internals;
     557         1782 :     internals.push_back(myParameter->parametersSet);
     558         1782 :     internals.push_back(myDeparture);
     559         1782 :     internals.push_back((SUMOTime)distance(myRoute->begin(), myCurrEdge));
     560         1782 :     internals.push_back((SUMOTime)myDepartPos * 1000); // store as mm
     561         1782 :     internals.push_back(mySegment == nullptr ? (SUMOTime) - 1 : (SUMOTime)mySegment->getIndex());
     562         1782 :     internals.push_back((SUMOTime)getQueIndex());
     563         1782 :     internals.push_back(myEventTime);
     564         1782 :     internals.push_back(myLastEntryTime);
     565         1782 :     internals.push_back(myBlockTime);
     566         3564 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     567              :     // save past stops
     568         4827 :     for (SUMOVehicleParameter::Stop stop : myPastStops) {
     569         3045 :         stop.write(out, false);
     570              :         // do not write started and ended twice
     571         3045 :         if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
     572         6090 :             out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
     573              :         }
     574         3045 :         if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
     575         6090 :             out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
     576              :         }
     577         3045 :         out.closeTag();
     578         3045 :     }
     579              :     // save upcoming stops
     580         2144 :     for (const MSStop& stop : myStops) {
     581          362 :         stop.write(out);
     582              :     }
     583              :     // save parameters
     584         1782 :     myParameter->writeParams(out);
     585         4579 :     for (MSDevice* dev : myDevices) {
     586         2797 :         dev->saveState(out);
     587              :     }
     588         4176 :     for (const auto& item : myMoveReminders) {
     589         2394 :         item.first->saveReminderState(out, *this);
     590              :     }
     591         1782 :     out.closeTag();
     592         1782 : }
     593              : 
     594              : 
     595              : void
     596         1382 : MEVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
     597         1382 :     if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
     598            0 :         throw ProcessError(TL("Error: Invalid vehicles in state (may be a micro state)!"));
     599              :     }
     600              :     int routeOffset;
     601              :     int segIndex;
     602              :     int queIndex;
     603         1382 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     604         1382 :     bis >> myParameter->parametersSet;
     605         1382 :     bis >> myDeparture;
     606         1382 :     bis >> routeOffset;
     607         1382 :     bis >> myDepartPos;
     608         1382 :     bis >> segIndex;
     609         1382 :     bis >> queIndex;
     610         1382 :     bis >> myEventTime;
     611         1382 :     bis >> myLastEntryTime;
     612         1382 :     bis >> myBlockTime;
     613         1382 :     myDepartPos /= 1000.; // was stored as mm
     614              : 
     615         1382 :     if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_RANDOMIZED)) {
     616              :         bool ok;
     617            9 :         myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
     618              :     }
     619              : 
     620              :     // load stops
     621              :     myStops.clear();
     622         1382 :     addStops(!MSGlobals::gCheckRoutes, &myCurrEdge, false);
     623              : 
     624         1382 :     if (hasDeparted()) {
     625          707 :         myDeparture -= offset;
     626          707 :         myEventTime -= offset;
     627          707 :         myLastEntryTime -= offset;
     628          707 :         myCurrEdge = myRoute->begin() + routeOffset;
     629          707 :         if (segIndex >= 0) {
     630          707 :             MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(**myCurrEdge);
     631          972 :             while (seg->getIndex() != (int)segIndex) {
     632              :                 seg = seg->getNextSegment();
     633          266 :                 if (seg == nullptr) {
     634            4 :                     throw ProcessError(TLF("Unknown segment '%:%' for vehicle '%' in loaded state.", (*myCurrEdge)->getID(), segIndex, getID()));
     635              :                 }
     636              :             }
     637          706 :             setSegment(seg, queIndex);
     638          706 :             if (queIndex == MESegment::PARKING_QUEUE) {
     639          260 :                 MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     640              :             }
     641              :         } else {
     642              :             // on teleport
     643            0 :             setSegment(nullptr, 0);
     644              :             assert(myEventTime != SUMOTime_MIN);
     645            0 :             MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
     646              :         }
     647              :         // see MSBaseVehicle constructor
     648          706 :         if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
     649          396 :             calculateArrivalParams(true);
     650              :         }
     651              :     }
     652         1381 :     if (myBlockTime != SUMOTime_MAX) {
     653           31 :         myBlockTime -= offset;
     654              :     }
     655         1381 :     std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
     656         1381 :     dis >> myOdometer >> myNumberReroutes;
     657         1382 : }
     658              : 
     659              : 
     660              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1