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/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 724563 : MEVehicle::MEVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
54 724563 : MSVehicleType* type, const double speedFactor) :
55 : MSBaseVehicle(pars, route, type, speedFactor),
56 724563 : mySegment(nullptr),
57 724563 : myQueIndex(0),
58 724563 : myEventTime(SUMOTime_MIN),
59 724563 : myLastEntryTime(SUMOTime_MIN),
60 724563 : myBlockTime(SUMOTime_MAX),
61 724563 : myInfluencer(nullptr) {
62 724563 : }
63 :
64 :
65 : double
66 0 : MEVehicle::getBackPositionOnLane(const MSLane* /* lane */) const {
67 0 : return getPositionOnLane() - getVehicleType().getLength();
68 : }
69 :
70 :
71 : double
72 6952972 : 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 6952972 : return mySegment == nullptr ? 0 : (double(mySegment->getIndex()) /* + fracOnSegment */) * mySegment->getLength();
76 : }
77 :
78 :
79 : double
80 60781 : MEVehicle::getAngle() const {
81 60781 : const MSLane* const lane = getEdge()->getLanes()[0];
82 60781 : return lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
83 : }
84 :
85 :
86 : double
87 119519 : MEVehicle::getSlope() const {
88 119519 : const MSLane* const lane = getEdge()->getLanes()[0];
89 119519 : return lane->getShape().slopeDegreeAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
90 : }
91 :
92 :
93 : Position
94 279572 : MEVehicle::getPosition(const double offset) const {
95 279572 : const MSLane* const lane = getEdge()->getLanes()[0];
96 279572 : 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 62973997 : MEVehicle::getSpeed() const {
120 62973997 : if (getWaitingTime() > 0 || isStopped()) {
121 35688237 : return 0;
122 : } else {
123 27285760 : return getAverageSpeed();
124 : }
125 : }
126 :
127 :
128 : double
129 27285760 : MEVehicle::getAverageSpeed() const {
130 27285760 : if (mySegment == nullptr || myQueIndex == MESegment::PARKING_QUEUE) {
131 : return 0;
132 : } else {
133 27284677 : return MIN2(mySegment->getLength() / STEPS2TIME(myEventTime - myLastEntryTime),
134 27284677 : getEdge()->getLanes()[myQueIndex]->getVehicleMaxSpeed(this));
135 : }
136 : }
137 :
138 :
139 : double
140 8658908 : MEVehicle::estimateLeaveSpeed(const MSLink* link) const {
141 : /// @see MSVehicle.cpp::estimateLeaveSpeed
142 8658908 : const double v = getSpeed();
143 8658908 : return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
144 8658908 : (double)sqrt(2 * link->getLength() * getVehicleType().getCarFollowModel().getMaxAccel() + v * v));
145 : }
146 :
147 :
148 : double
149 104802075 : MEVehicle::getConservativeSpeed(SUMOTime& earliestArrival) const {
150 104802075 : earliestArrival = MAX2(myEventTime, earliestArrival - DELTA_T); // event times have subsecond resolution
151 104802075 : return mySegment->getLength() / STEPS2TIME(earliestArrival - myLastEntryTime);
152 : }
153 :
154 :
155 : bool
156 2760273 : MEVehicle::moveRoutePointer() {
157 : // vehicle has just entered a new edge. Position is 0
158 2760273 : if (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) { // may happen during teleport
159 108 : return true;
160 : }
161 : ++myCurrEdge;
162 2760165 : if ((*myCurrEdge)->isVaporizing()) {
163 : return true;
164 : }
165 : // update via
166 2760061 : if (myParameter->via.size() > 0 && (*myCurrEdge)->getID() == myParameter->via.front()) {
167 94 : myParameter->via.erase(myParameter->via.begin());
168 : }
169 2760061 : return hasArrived();
170 : }
171 :
172 :
173 : bool
174 25949689 : MEVehicle::hasArrived() const {
175 : // mySegment may be 0 due to teleporting or arrival
176 25949689 : return (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) && (
177 4756328 : (mySegment == nullptr)
178 4754716 : || myEventTime == SUMOTime_MIN
179 4754716 : || getPositionOnLane() > myArrivalPos - POSITION_EPS);
180 : }
181 :
182 :
183 : bool
184 481107435 : MEVehicle::isOnRoad() const {
185 481107435 : return getSegment() != nullptr;
186 : }
187 :
188 :
189 : bool
190 21960 : MEVehicle::isIdling() const {
191 21960 : return false;
192 : }
193 :
194 :
195 : void
196 33857473 : MEVehicle::setApproaching(MSLink* link) {
197 33857473 : if (link != nullptr) {
198 10381745 : const double speed = getSpeed();
199 10434671 : link->setApproaching(this, getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
200 : (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
201 : speed, speed, true,
202 10381745 : speed, getWaitingTime(),
203 : // @note: dist is not used by meso (getZipperSpeed is never called)
204 : getSegment()->getLength(), 0);
205 : }
206 33857473 : }
207 :
208 :
209 : bool
210 309666 : MEVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
211 309666 : MSLink* const oldLink = mySegment != nullptr ? mySegment->getLink(this) : nullptr;
212 619332 : if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
213 309666 : if (mySegment != nullptr) {
214 132790 : MSLink* const newLink = mySegment->getLink(this);
215 : // update approaching vehicle information
216 132790 : if (oldLink != newLink) {
217 375 : if (oldLink != nullptr) {
218 301 : oldLink->removeApproaching(this);
219 : }
220 375 : setApproaching(newLink);
221 : }
222 : }
223 309666 : return true;
224 : }
225 : return false;
226 : }
227 :
228 :
229 : SUMOTime
230 23791582 : MEVehicle::checkStop(SUMOTime time) {
231 : const SUMOTime initialTime = time;
232 : bool hadStop = false;
233 23801037 : for (MSStop& stop : myStops) {
234 91163 : if (stop.joinTriggered) {
235 1155 : WRITE_WARNINGF(TL("Join stops are not available in meso yet (vehicle '%', segment '%')."),
236 : getID(), mySegment->getID());
237 385 : continue;
238 : }
239 90778 : if (stop.edge != myCurrEdge || stop.segment != mySegment) {
240 : break;
241 : }
242 : const SUMOTime cur = time;
243 9070 : if (stop.duration > 0) { // it might be a triggered stop with duration -1
244 4860 : time += stop.duration;
245 : }
246 9070 : if (stop.pars.until > time) {
247 : // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
248 : // travel time is overestimated of the stop is not at the start of the segment
249 : time = stop.pars.until;
250 : }
251 9070 : if (MSGlobals::gUseStopEnded && stop.pars.ended >= 0) {
252 : time = MAX2(cur, stop.pars.ended);
253 : }
254 9070 : if (!stop.reached) {
255 9070 : stop.reached = true;
256 9070 : stop.pars.started = myLastEntryTime;
257 9070 : stop.endBoarding = stop.pars.extension >= 0 ? time + stop.pars.extension : SUMOTime_MAX;
258 9070 : if (MSStopOut::active()) {
259 863 : if (!hadStop) {
260 823 : MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
261 : } else {
262 120 : WRITE_WARNINGF(TL("Vehicle '%' has multiple stops on segment '%', time=% (stop-output will be merged)."),
263 : getID(), mySegment->getID(), time2string(time));
264 : }
265 : }
266 9070 : MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
267 : if (taxi != nullptr) {
268 984 : taxi->notifyMove(*this, 0, 0, 0);
269 : }
270 : }
271 9070 : if (stop.triggered || stop.containerTriggered || stop.joinTriggered) {
272 667 : time = MAX2(time, cur + DELTA_T);
273 : }
274 : hadStop = true;
275 : }
276 23791582 : MSDevice_Tripinfo* tripinfo = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
277 : if (tripinfo != nullptr) {
278 13061236 : tripinfo->updateStopTime(time - initialTime);
279 : }
280 23791582 : return time;
281 : }
282 :
283 :
284 : bool
285 8465 : MEVehicle::resumeFromStopping() {
286 8465 : if (isStopped()) {
287 8459 : const SUMOTime now = SIMSTEP;
288 : MSStop& stop = myStops.front();
289 8459 : stop.pars.ended = now;
290 19625 : for (const auto& rem : myMoveReminders) {
291 11166 : rem.first->notifyStopEnded();
292 : }
293 8459 : if (MSStopOut::active()) {
294 825 : MSStopOut::getInstance()->stopEnded(this, stop.pars, mySegment->getEdge().getID());
295 : }
296 8459 : myPastStops.push_back(stop.pars);
297 8459 : myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
298 8459 : if (myAmRegisteredAsWaiting && (stop.triggered || stop.containerTriggered || stop.joinTriggered)) {
299 30 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
300 30 : myAmRegisteredAsWaiting = false;
301 : }
302 8459 : myStops.pop_front();
303 8459 : if (myEventTime > now) {
304 : // if this is an aborted stop we need to change the event time of the vehicle
305 6 : if (MSGlobals::gMesoNet->removeLeaderCar(this)) {
306 6 : myEventTime = now + 1;
307 6 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
308 : }
309 : }
310 8459 : return true;
311 : }
312 : return false;
313 : }
314 :
315 :
316 : double
317 0 : MEVehicle::getCurrentStoppingTimeSeconds() const {
318 0 : SUMOTime time = myLastEntryTime;
319 0 : for (const MSStop& stop : myStops) {
320 0 : if (stop.reached) {
321 0 : time += stop.duration;
322 0 : if (stop.pars.until > time) {
323 : // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
324 : // travel time is overestimated of the stop is not at the start of the segment
325 : time = stop.pars.until;
326 : }
327 : } else {
328 : break;
329 : }
330 : }
331 0 : return STEPS2TIME(time - myLastEntryTime);
332 : }
333 :
334 :
335 : void
336 8373 : MEVehicle::processStop() {
337 : assert(isStopped());
338 : double lastPos = -1;
339 : bool hadStop = false;
340 16831 : while (!myStops.empty()) {
341 : MSStop& stop = myStops.front();
342 12569 : if (stop.edge != myCurrEdge || stop.segment != mySegment || stop.pars.endPos <= lastPos) {
343 : break;
344 : }
345 : lastPos = stop.pars.endPos;
346 8458 : MSNet* const net = MSNet::getInstance();
347 8458 : SUMOTime dummy = -1; // boarding- and loading-time are not considered
348 8458 : if (hadStop && MSStopOut::active()) {
349 40 : stop.reached = true;
350 40 : MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
351 : }
352 8458 : if (net->hasPersons()) {
353 4734 : net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
354 : }
355 8458 : if (net->hasContainers()) {
356 244 : net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
357 : }
358 8458 : resumeFromStopping();
359 : hadStop = true;
360 : }
361 8373 : mySegment->getEdge().removeWaiting(this);
362 8373 : }
363 :
364 :
365 : bool
366 31630956 : MEVehicle::mayProceed() {
367 31630956 : if (mySegment == nullptr) {
368 : return true;
369 : }
370 31630956 : MSNet* const net = MSNet::getInstance();
371 31630956 : SUMOTime dummy = -1; // boarding- and loading-time are not considered
372 39358511 : for (MSStop& stop : myStops) {
373 15631349 : if (!stop.reached) {
374 : break;
375 : }
376 7826183 : if (net->getCurrentTimeStep() > stop.endBoarding) {
377 61 : if (stop.triggered || stop.containerTriggered) {
378 25 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
379 : if (taxiDevice != nullptr) {
380 22 : taxiDevice->cancelCurrentCustomers();
381 : }
382 25 : stop.triggered = false;
383 25 : stop.containerTriggered = false;
384 : }
385 61 : if (myAmRegisteredAsWaiting) {
386 : net->getVehicleControl().unregisterOneWaiting();
387 25 : myAmRegisteredAsWaiting = false;
388 : }
389 : }
390 7826183 : if (stop.triggered) {
391 82883 : if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
392 : // we could not check this on entering the segment because there may be persons who still want to leave
393 0 : WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
394 0 : stop.triggered = false;
395 0 : if (myAmRegisteredAsWaiting) {
396 : net->getVehicleControl().unregisterOneWaiting();
397 0 : myAmRegisteredAsWaiting = false;
398 : }
399 82883 : } else if (!net->hasPersons() || !net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
400 82504 : if (!myAmRegisteredAsWaiting) {
401 341 : MSNet::getInstance()->getVehicleControl().registerOneWaiting();
402 341 : myAmRegisteredAsWaiting = true;
403 : }
404 82504 : return false;
405 : }
406 : }
407 7743679 : if (stop.containerTriggered) {
408 16198 : if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
409 : // we could not check this on entering the segment because there may be containers who still want to leave
410 6 : WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
411 2 : stop.containerTriggered = false;
412 2 : if (myAmRegisteredAsWaiting) {
413 : net->getVehicleControl().unregisterOneWaiting();
414 0 : myAmRegisteredAsWaiting = false;
415 : }
416 16196 : } else if (!net->hasContainers() || !net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
417 16124 : if (!myAmRegisteredAsWaiting) {
418 44 : MSNet::getInstance()->getVehicleControl().registerOneWaiting();
419 44 : myAmRegisteredAsWaiting = true;
420 : }
421 16124 : return false;
422 : }
423 : }
424 7727555 : if (stop.joinTriggered) {
425 : // TODO do something useful here
426 : return false;
427 : }
428 : }
429 31532328 : return mySegment->isOpen(this);
430 : }
431 :
432 :
433 : double
434 0 : MEVehicle::getCurrentLinkPenaltySeconds() const {
435 0 : if (mySegment == nullptr) {
436 : return 0;
437 : } else {
438 0 : return STEPS2TIME(mySegment->getLinkPenalty(this));
439 : }
440 : }
441 :
442 :
443 : void
444 1374310 : MEVehicle::updateDetectorForWriting(MSMoveReminder* rem, SUMOTime currentTime, SUMOTime exitTime) {
445 2342404 : for (MoveReminderCont::iterator i = myMoveReminders.begin(); i != myMoveReminders.end(); ++i) {
446 2331066 : if (i->first == rem) {
447 1362972 : rem->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
448 1362972 : (mySegment->getIndex() + 1) * mySegment->getLength(),
449 : getLastEntryTime(), currentTime, exitTime, false);
450 : #ifdef _DEBUG
451 : if (myTraceMoveReminders) {
452 : traceMoveReminder("notifyMove", i->first, i->second, true);
453 : }
454 : #endif
455 : return;
456 : }
457 : }
458 : }
459 :
460 :
461 : void
462 23787316 : MEVehicle::updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason) {
463 : // segments of the same edge have the same reminder so no cleaning up must take place
464 23787316 : const bool cleanUp = isLeave && (reason != MSMoveReminder::NOTIFICATION_SEGMENT);
465 53757569 : for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
466 29970253 : if (currentTime != getLastEntryTime()) {
467 29946380 : rem->first->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
468 29946380 : (mySegment->getIndex() + 1) * mySegment->getLength(),
469 : getLastEntryTime(), currentTime, getEventTime(), cleanUp);
470 : #ifdef _DEBUG
471 : if (myTraceMoveReminders) {
472 : traceMoveReminder("notifyMove", rem->first, rem->second, true);
473 : }
474 : #endif
475 : }
476 29970253 : if (!isLeave || rem->first->notifyLeave(*this, mySegment->getLength(), reason)) {
477 : #ifdef _DEBUG
478 : if (isLeave && myTraceMoveReminders) {
479 : traceMoveReminder("notifyLeave", rem->first, rem->second, true);
480 : }
481 : #endif
482 :
483 20797178 : if (isLeave) {
484 20794893 : rem->second += getEdge()->getLength();
485 : #ifdef _DEBUG
486 : if (myTraceMoveReminders) {
487 : traceMoveReminder("adaptedPos", rem->first, rem->second, true);
488 : }
489 : #endif
490 : }
491 : ++rem;
492 : } else {
493 : #ifdef _DEBUG
494 : if (myTraceMoveReminders) {
495 : traceMoveReminder("remove", rem->first, rem->second, false);
496 : }
497 : #endif
498 : rem = myMoveReminders.erase(rem);
499 : }
500 : }
501 23787316 : if (reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
502 2757996 : myOdometer += getEdge()->getLength();
503 : }
504 23787316 : }
505 :
506 :
507 : MEVehicle::BaseInfluencer&
508 3 : MEVehicle::getBaseInfluencer() {
509 3 : if (myInfluencer == nullptr) {
510 2 : myInfluencer = new BaseInfluencer();
511 : }
512 3 : return *myInfluencer;
513 : }
514 :
515 :
516 : const MEVehicle::BaseInfluencer*
517 46 : MEVehicle::getBaseInfluencer() const {
518 46 : return myInfluencer;
519 : }
520 :
521 :
522 : void
523 2 : MEVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
524 2 : MSGlobals::gMesoNet->removeLeaderCar(this);
525 2 : MSGlobals::gMesoNet->changeSegment(this, MSNet::getInstance()->getCurrentTimeStep(), nullptr, reason);
526 2 : }
527 :
528 :
529 : int
530 55840 : MEVehicle::getSegmentIndex() const {
531 55840 : return getSegment() != nullptr ? getSegment()->getIndex() : -1;
532 : }
533 :
534 :
535 : double
536 0 : MEVehicle::getRightSideOnEdge(const MSLane* /*lane*/) const {
537 0 : if (mySegment == nullptr || mySegment->getIndex() >= getEdge()->getNumLanes()) {
538 0 : return 0;
539 : }
540 0 : const MSLane* lane = getEdge()->getLanes()[mySegment->getIndex()];
541 0 : return lane->getRightSideOnEdge() + lane->getWidth() * 0.5 - 0.5 * getVehicleType().getWidth();
542 :
543 : }
544 :
545 :
546 : void
547 658 : MEVehicle::saveState(OutputDevice& out) {
548 658 : if (mySegment != nullptr && MESegment::isInvalid(mySegment)) {
549 : // segment is vaporization target, do not write this vehicle
550 0 : return;
551 : }
552 658 : MSBaseVehicle::saveState(out);
553 : assert(mySegment == nullptr || *myCurrEdge == &mySegment->getEdge());
554 : std::vector<SUMOTime> internals;
555 658 : internals.push_back(myParameter->parametersSet);
556 658 : internals.push_back(myDeparture);
557 658 : internals.push_back((SUMOTime)distance(myRoute->begin(), myCurrEdge));
558 658 : internals.push_back((SUMOTime)myDepartPos * 1000); // store as mm
559 658 : internals.push_back(mySegment == nullptr ? (SUMOTime) - 1 : (SUMOTime)mySegment->getIndex());
560 658 : internals.push_back((SUMOTime)getQueIndex());
561 658 : internals.push_back(myEventTime);
562 658 : internals.push_back(myLastEntryTime);
563 658 : internals.push_back(myBlockTime);
564 1316 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
565 : // save past stops
566 676 : for (SUMOVehicleParameter::Stop stop : myPastStops) {
567 18 : stop.write(out, false);
568 : // do not write started and ended twice
569 18 : if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
570 36 : out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
571 : }
572 18 : if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
573 36 : out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
574 : }
575 18 : out.closeTag();
576 18 : }
577 : // save upcoming stops
578 745 : for (const MSStop& stop : myStops) {
579 87 : stop.write(out);
580 : }
581 : // save parameters
582 658 : myParameter->writeParams(out);
583 1560 : for (MSDevice* dev : myDevices) {
584 902 : dev->saveState(out);
585 : }
586 658 : out.closeTag();
587 658 : }
588 :
589 :
590 : void
591 568 : MEVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
592 568 : if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
593 0 : throw ProcessError(TL("Error: Invalid vehicles in state (may be a micro state)!"));
594 : }
595 : int routeOffset;
596 : int segIndex;
597 : int queIndex;
598 568 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
599 568 : bis >> myParameter->parametersSet;
600 568 : bis >> myDeparture;
601 568 : bis >> routeOffset;
602 568 : bis >> myDepartPos;
603 568 : bis >> segIndex;
604 568 : bis >> queIndex;
605 568 : bis >> myEventTime;
606 568 : bis >> myLastEntryTime;
607 568 : bis >> myBlockTime;
608 568 : myDepartPos /= 1000.; // was stored as mm
609 :
610 : // load stops
611 : myStops.clear();
612 568 : addStops(!MSGlobals::gCheckRoutes, &myCurrEdge, false);
613 :
614 568 : if (hasDeparted()) {
615 209 : myDeparture -= offset;
616 209 : myEventTime -= offset;
617 209 : myLastEntryTime -= offset;
618 209 : myCurrEdge = myRoute->begin() + routeOffset;
619 209 : if (segIndex >= 0) {
620 209 : MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(**myCurrEdge);
621 351 : while (seg->getIndex() != (int)segIndex) {
622 : seg = seg->getNextSegment();
623 : assert(seg != 0);
624 : }
625 209 : setSegment(seg, queIndex);
626 209 : if (queIndex == MESegment::PARKING_QUEUE) {
627 3 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
628 : }
629 : } else {
630 : // on teleport
631 0 : setSegment(nullptr, 0);
632 : assert(myEventTime != SUMOTime_MIN);
633 0 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
634 : }
635 : // see MSBaseVehicle constructor
636 209 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
637 30 : calculateArrivalParams(true);
638 : }
639 : }
640 568 : if (myBlockTime != SUMOTime_MAX) {
641 1 : myBlockTime -= offset;
642 : }
643 568 : std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
644 568 : dis >> myOdometer >> myNumberReroutes;
645 568 : }
646 :
647 :
648 : /****************************************************************************/
|