Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MEVehicle.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @date Tue, May 2005
18 : ///
19 : // A vehicle from the mesoscopic point of view
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <iostream>
24 : #include <cassert>
25 : #include <utils/common/StdDefs.h>
26 : #include <utils/common/FileHelpers.h>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/geom/GeomHelper.h>
29 : #include <utils/iodevices/OutputDevice.h>
30 : #include <utils/xml/SUMOSAXAttributes.h>
31 : #include <microsim/devices/MSDevice_Tripinfo.h>
32 : #include <microsim/devices/MSDevice_Vehroutes.h>
33 : #include <microsim/devices/MSDevice_Taxi.h>
34 : #include <microsim/output/MSStopOut.h>
35 : #include <microsim/MSGlobals.h>
36 : #include <microsim/MSEdge.h>
37 : #include <microsim/MSLane.h>
38 : #include <microsim/MSNet.h>
39 : #include <microsim/MSVehicleType.h>
40 : #include <microsim/MSLink.h>
41 : #include <microsim/MSStop.h>
42 : #include <microsim/MSVehicleControl.h>
43 : #include <microsim/transportables/MSTransportableControl.h>
44 : #include <microsim/devices/MSDevice.h>
45 : #include "MELoop.h"
46 : #include "MEVehicle.h"
47 : #include "MESegment.h"
48 :
49 :
50 : // ===========================================================================
51 : // method definitions
52 : // ===========================================================================
53 769114 : MEVehicle::MEVehicle(SUMOVehicleParameter* pars, ConstMSRoutePtr route,
54 769114 : MSVehicleType* type, const double speedFactor) :
55 : MSBaseVehicle(pars, route, type, speedFactor),
56 769114 : mySegment(nullptr),
57 769114 : myQueIndex(0),
58 769114 : myEventTime(SUMOTime_MIN),
59 769114 : myLastEntryTime(SUMOTime_MIN),
60 769114 : myBlockTime(SUMOTime_MAX),
61 769114 : myInfluencer(nullptr) {
62 769114 : }
63 :
64 :
65 : double
66 0 : MEVehicle::getBackPositionOnLane(const MSLane* /* lane */) const {
67 0 : return getPositionOnLane() - getVehicleType().getLength();
68 : }
69 :
70 :
71 : double
72 7352296 : 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 7352296 : return mySegment == nullptr ? 0 : (double(mySegment->getIndex()) /* + fracOnSegment */) * mySegment->getLength();
76 : }
77 :
78 :
79 : double
80 64873 : MEVehicle::getAngle() const {
81 64873 : const MSLane* const lane = getEdge()->getLanes()[0];
82 64873 : return lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
83 : }
84 :
85 :
86 : double
87 172597 : MEVehicle::getSlope() const {
88 172597 : const MSLane* const lane = getEdge()->getLanes()[0];
89 172597 : return lane->getShape().slopeDegreeAtOffset(lane->interpolateLanePosToGeometryPos(getPositionOnLane()));
90 : }
91 :
92 :
93 : const MSEdge*
94 2549641 : MEVehicle::getCurrentEdge() const {
95 2549641 : return mySegment != nullptr ? &mySegment->getEdge() : getEdge();
96 : }
97 :
98 :
99 : Position
100 426670 : MEVehicle::getPosition(const double offset) const {
101 426670 : const MSLane* const lane = getEdge()->getLanes()[0];
102 426670 : return lane->geometryPositionAtOffset(getPositionOnLane() + offset);
103 : }
104 :
105 : PositionVector
106 0 : MEVehicle::getBoundingBox(double offset) const {
107 0 : double a = getAngle() + M_PI; // angle pointing backwards
108 0 : double l = getLength();
109 0 : Position pos = getPosition();
110 0 : Position backPos = pos + Position(l * cos(a), l * sin(a));
111 0 : PositionVector centerLine;
112 0 : centerLine.push_back(pos);
113 0 : centerLine.push_back(backPos);
114 0 : if (offset != 0) {
115 0 : centerLine.extrapolate2D(offset);
116 : }
117 : PositionVector result = centerLine;
118 0 : result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
119 0 : centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
120 0 : result.append(centerLine.reverse(), POSITION_EPS);
121 0 : return result;
122 0 : }
123 :
124 : double
125 69713526 : MEVehicle::getSpeed() const {
126 69713526 : if (getWaitingTime() > 0 || isStopped()) {
127 38994987 : return 0;
128 : } else {
129 30718539 : return getAverageSpeed();
130 : }
131 : }
132 :
133 :
134 : double
135 30718539 : MEVehicle::getAverageSpeed() const {
136 : // cache for thread safety
137 30718539 : MESegment* s = mySegment;
138 30718539 : if (s == nullptr || myQueIndex == MESegment::PARKING_QUEUE) {
139 : return 0;
140 : } else {
141 30713049 : return MIN2(s->getLength() / STEPS2TIME(myEventTime - myLastEntryTime),
142 30713049 : getEdge()->getLanes()[myQueIndex]->getVehicleMaxSpeed(this));
143 : }
144 : }
145 :
146 :
147 : double
148 9171804 : MEVehicle::estimateLeaveSpeed(const MSLink* link) const {
149 : /// @see MSVehicle.cpp::estimateLeaveSpeed
150 9171804 : const double v = getSpeed();
151 9171804 : return MIN2(link->getViaLaneOrLane()->getVehicleMaxSpeed(this),
152 9171804 : (double)sqrt(2 * link->getLength() * getVehicleType().getCarFollowModel().getMaxAccel() + v * v));
153 : }
154 :
155 :
156 : double
157 159698696 : MEVehicle::getConservativeSpeed(SUMOTime& earliestArrival) const {
158 159698696 : earliestArrival = MAX2(myEventTime, earliestArrival - DELTA_T); // event times have subsecond resolution
159 159698696 : return mySegment->getLength() / STEPS2TIME(earliestArrival - myLastEntryTime);
160 : }
161 :
162 :
163 : bool
164 2948081 : MEVehicle::moveRoutePointer() {
165 : // vehicle has just entered a new edge. Position is 0
166 2948081 : if (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) { // may happen during teleport
167 113 : return true;
168 : }
169 : ++myCurrEdge;
170 2947968 : if ((*myCurrEdge)->isVaporizing()) {
171 : return true;
172 : }
173 : // update via
174 2947864 : if (myParameter->via.size() > 0 && (*myCurrEdge)->getID() == myParameter->via.front()) {
175 2918 : myParameter->via.erase(myParameter->via.begin());
176 : }
177 2947864 : return hasArrived();
178 : }
179 :
180 :
181 : bool
182 28277410 : MEVehicle::hasArrived() const {
183 : // mySegment may be 0 due to teleporting or arrival
184 28277410 : return (myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge)) && (
185 4859794 : (mySegment == nullptr)
186 4856844 : || myEventTime == SUMOTime_MIN
187 4856844 : || getPositionOnLane() > myArrivalPos - POSITION_EPS);
188 : }
189 :
190 :
191 : bool
192 478949259 : MEVehicle::isOnRoad() const {
193 478949259 : return getSegment() != nullptr;
194 : }
195 :
196 :
197 : bool
198 22360 : MEVehicle::isIdling() const {
199 22360 : return false;
200 : }
201 :
202 :
203 : void
204 37330152 : MEVehicle::setApproaching(MSLink* link) {
205 37330152 : if (link != nullptr) {
206 12110144 : const double speed = getSpeed();
207 12162685 : link->setApproaching(this, getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
208 : (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
209 : speed, link->getViaLaneOrLane()->getVehicleMaxSpeed(this), true,
210 12110144 : speed, getWaitingTime(),
211 : // @note: dist is not used by meso (getZipperSpeed is never called)
212 : getSegment()->getLength(), 0);
213 : }
214 37330152 : }
215 :
216 :
217 : bool
218 331078 : MEVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
219 331078 : MSLink* const oldLink = mySegment != nullptr ? mySegment->getLink(this) : nullptr;
220 662156 : if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
221 331078 : if (mySegment != nullptr) {
222 138111 : MSLink* const newLink = mySegment->getLink(this);
223 : // update approaching vehicle information
224 138111 : if (oldLink != newLink) {
225 719 : if (oldLink != nullptr) {
226 670 : oldLink->removeApproaching(this);
227 : }
228 719 : setApproaching(newLink);
229 : }
230 : }
231 331078 : return true;
232 : }
233 : return false;
234 : }
235 :
236 :
237 : SUMOTime
238 26030013 : MEVehicle::checkStop(SUMOTime time) {
239 : const SUMOTime initialTime = time;
240 : bool hadStop = false;
241 26045717 : for (MSStop& stop : myStops) {
242 145148 : if (stop.joinTriggered) {
243 1494 : WRITE_WARNINGF(TL("Join stops are not available in meso yet (vehicle '%', segment '%')."),
244 : getID(), mySegment->getID());
245 498 : continue;
246 : }
247 144650 : if (stop.edge != myCurrEdge || stop.segment != mySegment) {
248 : break;
249 : }
250 : const SUMOTime cur = time;
251 15206 : if (stop.duration > 0) { // it might be a triggered stop with duration -1
252 7327 : time += stop.duration;
253 : }
254 15206 : if (stop.pars.until > time) {
255 : // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
256 : // travel time is overestimated of the stop is not at the start of the segment
257 : time = stop.pars.until;
258 : }
259 15206 : if (MSGlobals::gUseStopEnded && stop.pars.ended >= 0) {
260 : time = MAX2(cur, stop.pars.ended);
261 : }
262 15206 : if (!stop.reached) {
263 15206 : stop.reached = true;
264 15206 : stop.pars.started = myLastEntryTime;
265 15206 : stop.endBoarding = stop.pars.extension >= 0 ? time + stop.pars.extension : SUMOTime_MAX;
266 15206 : if (MSStopOut::active()) {
267 1016 : if (!hadStop) {
268 976 : MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
269 : } else {
270 120 : WRITE_WARNINGF(TL("Vehicle '%' has multiple stops on segment '%', time=% (stop-output will be merged)."),
271 : getID(), mySegment->getID(), time2string(time));
272 : }
273 : }
274 15206 : MSDevice_Taxi* taxi = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
275 : if (taxi != nullptr) {
276 1479 : taxi->notifyMove(*this, 0, 0, 0);
277 : }
278 : }
279 15206 : if (stop.triggered || stop.containerTriggered || stop.joinTriggered) {
280 960 : time = MAX2(time, cur + DELTA_T);
281 : }
282 : hadStop = true;
283 : }
284 26030013 : MSDevice_Tripinfo* tripinfo = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
285 : if (tripinfo != nullptr) {
286 14311221 : tripinfo->updateStopTime(time - initialTime);
287 : }
288 26030013 : return time;
289 : }
290 :
291 :
292 : bool
293 14386 : MEVehicle::resumeFromStopping() {
294 14386 : if (isStopped()) {
295 14377 : const SUMOTime now = SIMSTEP;
296 : MSStop& stop = myStops.front();
297 14377 : stop.pars.ended = now;
298 28965 : for (const auto& rem : myMoveReminders) {
299 14588 : rem.first->notifyStopEnded();
300 : }
301 14377 : if (MSStopOut::active()) {
302 964 : MSStopOut::getInstance()->stopEnded(this, stop);
303 : }
304 14377 : myPastStops.push_back(stop.pars);
305 14377 : myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
306 14377 : if (myAmRegisteredAsWaiting && (stop.triggered || stop.containerTriggered || stop.joinTriggered)) {
307 31 : MSNet::getInstance()->getVehicleControl().unregisterOneWaiting();
308 31 : myAmRegisteredAsWaiting = false;
309 : }
310 14377 : myStops.pop_front();
311 14377 : if (myEventTime > now) {
312 : // if this is an aborted stop we need to change the event time of the vehicle
313 16 : if (MSGlobals::gMesoNet->removeLeaderCar(this)) {
314 12 : myEventTime = now + 1;
315 12 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
316 : }
317 : }
318 14377 : return true;
319 : }
320 : return false;
321 : }
322 :
323 :
324 : double
325 0 : MEVehicle::getCurrentStoppingTimeSeconds() const {
326 0 : SUMOTime time = myLastEntryTime;
327 0 : for (const MSStop& stop : myStops) {
328 0 : if (stop.reached) {
329 0 : time += stop.duration;
330 0 : if (stop.pars.until > time) {
331 : // @note: this assumes the stop is reached at time. With the way this is called in MESegment (time == entryTime),
332 : // travel time is overestimated of the stop is not at the start of the segment
333 : time = stop.pars.until;
334 : }
335 : } else {
336 : break;
337 : }
338 : }
339 0 : return STEPS2TIME(time - myLastEntryTime);
340 : }
341 :
342 :
343 : void
344 13700 : MEVehicle::processStop() {
345 : assert(isStopped());
346 : double lastPos = -1;
347 : bool hadStop = false;
348 28068 : while (!myStops.empty()) {
349 : MSStop& stop = myStops.front();
350 22356 : if (stop.edge != myCurrEdge || stop.segment != mySegment || stop.pars.endPos <= lastPos) {
351 : break;
352 : }
353 : lastPos = stop.pars.endPos;
354 14368 : MSNet* const net = MSNet::getInstance();
355 14368 : SUMOTime dummy = -1; // boarding- and loading-time are not considered
356 14368 : if (hadStop && MSStopOut::active()) {
357 40 : stop.reached = true;
358 40 : MSStopOut::getInstance()->stopStarted(this, getPersonNumber(), getContainerNumber(), myLastEntryTime);
359 : }
360 14368 : if (net->hasPersons()) {
361 5440 : net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
362 : }
363 14368 : if (net->hasContainers()) {
364 244 : net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy);
365 : }
366 14368 : resumeFromStopping();
367 : hadStop = true;
368 : }
369 13700 : if (getWaitingTime() > 0) {
370 : // entry back onto the road was blocked for some time
371 155 : MSDevice_Tripinfo* tripinfoDevice = static_cast<MSDevice_Tripinfo*>(getDevice(typeid(MSDevice_Tripinfo)));
372 : if (tripinfoDevice != nullptr) {
373 5 : tripinfoDevice->recordMesoParkingTimeLoss(getWaitingTime());
374 : }
375 : }
376 13700 : mySegment->getEdge().removeWaiting(this);
377 13700 : }
378 :
379 :
380 : bool
381 34381902 : MEVehicle::mayProceed() {
382 34381902 : if (mySegment == nullptr) {
383 : return true;
384 : }
385 34381902 : MSNet* const net = MSNet::getInstance();
386 34381902 : SUMOTime dummy = -1; // boarding- and loading-time are not considered
387 42624963 : for (MSStop& stop : myStops) {
388 16791328 : if (!stop.reached) {
389 : break;
390 : }
391 8427549 : if (net->getCurrentTimeStep() > stop.endBoarding) {
392 62 : if (stop.triggered || stop.containerTriggered) {
393 26 : MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
394 : if (taxiDevice != nullptr) {
395 23 : taxiDevice->cancelCurrentCustomers();
396 : }
397 26 : stop.triggered = false;
398 26 : stop.containerTriggered = false;
399 : }
400 62 : if (myAmRegisteredAsWaiting) {
401 : net->getVehicleControl().unregisterOneWaiting();
402 26 : myAmRegisteredAsWaiting = false;
403 : }
404 : }
405 8427549 : if (stop.triggered) {
406 168916 : if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
407 : // we could not check this on entering the segment because there may be persons who still want to leave
408 0 : WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
409 0 : stop.triggered = false;
410 0 : if (myAmRegisteredAsWaiting) {
411 : net->getVehicleControl().unregisterOneWaiting();
412 0 : myAmRegisteredAsWaiting = false;
413 : }
414 168916 : } else if (!net->hasPersons() || !net->getPersonControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
415 168318 : if (!myAmRegisteredAsWaiting) {
416 461 : MSNet::getInstance()->getVehicleControl().registerOneWaiting();
417 461 : myAmRegisteredAsWaiting = true;
418 : }
419 168318 : return false;
420 : }
421 : }
422 8259231 : if (stop.containerTriggered) {
423 16244 : if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
424 : // we could not check this on entering the segment because there may be containers who still want to leave
425 6 : WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
426 2 : stop.containerTriggered = false;
427 2 : if (myAmRegisteredAsWaiting) {
428 : net->getVehicleControl().unregisterOneWaiting();
429 0 : myAmRegisteredAsWaiting = false;
430 : }
431 16242 : } else if (!net->hasContainers() || !net->getContainerControl().loadAnyWaiting(&mySegment->getEdge(), this, dummy, dummy)) {
432 16170 : if (!myAmRegisteredAsWaiting) {
433 44 : MSNet::getInstance()->getVehicleControl().registerOneWaiting();
434 44 : myAmRegisteredAsWaiting = true;
435 : }
436 16170 : return false;
437 : }
438 : }
439 8243061 : if (stop.joinTriggered) {
440 : // TODO do something useful here
441 : return false;
442 : }
443 : }
444 34197414 : return mySegment->isOpen(this);
445 : }
446 :
447 :
448 : double
449 0 : MEVehicle::getCurrentLinkPenaltySeconds() const {
450 0 : if (mySegment == nullptr) {
451 : return 0;
452 : } else {
453 0 : return STEPS2TIME(mySegment->getLinkPenalty(this));
454 : }
455 : }
456 :
457 :
458 : void
459 1301111 : MEVehicle::updateDetectorForWriting(MSMoveReminder* rem, SUMOTime currentTime, SUMOTime exitTime) {
460 2186408 : for (MoveReminderCont::iterator i = myMoveReminders.begin(); i != myMoveReminders.end(); ++i) {
461 2175094 : if (i->first == rem) {
462 1289797 : rem->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
463 1289797 : (mySegment->getIndex() + 1) * mySegment->getLength(),
464 : getLastEntryTime(), currentTime, exitTime, false);
465 : #ifdef _DEBUG
466 : if (myTraceMoveReminders) {
467 : traceMoveReminder("notifyMove", i->first, i->second, true);
468 : }
469 : #endif
470 : return;
471 : }
472 : }
473 : }
474 :
475 :
476 : void
477 26021233 : MEVehicle::updateDetectors(const SUMOTime currentTime, const SUMOTime exitTime, const bool isLeave, const MSMoveReminder::Notification reason) {
478 : // segments of the same edge have the same reminder so no cleaning up must take place
479 26021233 : const bool cleanUp = isLeave && (reason != MSMoveReminder::NOTIFICATION_SEGMENT);
480 58564766 : for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
481 32543533 : if (currentTime != getLastEntryTime() && reason < MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR) {
482 32486913 : rem->first->updateDetector(*this, mySegment->getIndex() * mySegment->getLength(),
483 32486913 : (mySegment->getIndex() + 1) * mySegment->getLength(),
484 : getLastEntryTime(), currentTime, exitTime, cleanUp);
485 : #ifdef _DEBUG
486 : if (myTraceMoveReminders) {
487 : traceMoveReminder("notifyMove", rem->first, rem->second, true);
488 : }
489 : #endif
490 : }
491 65084079 : if (!isLeave || rem->first->notifyLeave(*this, mySegment == nullptr ? 0 : mySegment->getLength(), reason)) {
492 : #ifdef _DEBUG
493 : if (isLeave && myTraceMoveReminders) {
494 : traceMoveReminder("notifyLeave", rem->first, rem->second, true);
495 : }
496 : #endif
497 :
498 23235219 : if (isLeave) {
499 23232923 : rem->second += getEdge()->getLength();
500 : #ifdef _DEBUG
501 : if (myTraceMoveReminders) {
502 : traceMoveReminder("adaptedPos", rem->first, rem->second, true);
503 : }
504 : #endif
505 : }
506 : ++rem;
507 : } else {
508 : #ifdef _DEBUG
509 : if (myTraceMoveReminders) {
510 : traceMoveReminder("remove", rem->first, rem->second, false);
511 : }
512 : #endif
513 : rem = myMoveReminders.erase(rem);
514 : }
515 : }
516 26021233 : if (reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) {
517 4746097 : myOdometer += getEdge()->getLength();
518 : }
519 26021233 : }
520 :
521 :
522 : MEVehicle::BaseInfluencer&
523 3 : MEVehicle::getBaseInfluencer() {
524 3 : if (myInfluencer == nullptr) {
525 2 : myInfluencer = new BaseInfluencer();
526 : }
527 3 : return *myInfluencer;
528 : }
529 :
530 :
531 : const MEVehicle::BaseInfluencer*
532 46 : MEVehicle::getBaseInfluencer() const {
533 46 : return myInfluencer;
534 : }
535 :
536 :
537 : void
538 2 : MEVehicle::onRemovalFromNet(const MSMoveReminder::Notification reason) {
539 2 : MSGlobals::gMesoNet->removeLeaderCar(this);
540 2 : MSGlobals::gMesoNet->changeSegment(this, MSNet::getInstance()->getCurrentTimeStep(), nullptr, reason);
541 2 : }
542 :
543 :
544 : int
545 5732 : MEVehicle::getSegmentIndex() const {
546 5732 : return getSegment() != nullptr ? getSegment()->getIndex() : -1;
547 : }
548 :
549 :
550 : double
551 0 : MEVehicle::getRightSideOnEdge(const MSLane* /*lane*/) const {
552 0 : if (mySegment == nullptr || mySegment->getIndex() >= getEdge()->getNumLanes()) {
553 0 : return 0;
554 : }
555 0 : const MSLane* lane = getEdge()->getLanes()[mySegment->getIndex()];
556 0 : return lane->getRightSideOnEdge() + lane->getWidth() * 0.5 - 0.5 * getVehicleType().getWidth();
557 :
558 : }
559 :
560 :
561 : void
562 1841 : MEVehicle::saveState(OutputDevice& out) {
563 1841 : if (mySegment != nullptr && MESegment::isInvalid(mySegment)) {
564 : // segment is vaporization target, do not write this vehicle
565 0 : return;
566 : }
567 1841 : MSBaseVehicle::saveState(out);
568 : assert(mySegment == nullptr || *myCurrEdge == &mySegment->getEdge());
569 : std::vector<SUMOTime> internals;
570 1841 : internals.push_back(myParameter->parametersSet);
571 1841 : internals.push_back(myDeparture);
572 1841 : internals.push_back((SUMOTime)distance(myRoute->begin(), myCurrEdge));
573 1841 : internals.push_back((SUMOTime)myDepartPos * 1000); // store as mm
574 1841 : internals.push_back(mySegment == nullptr ? (SUMOTime) - 1 : (SUMOTime)mySegment->getIndex());
575 1841 : internals.push_back((SUMOTime)getQueIndex());
576 1841 : internals.push_back(myEventTime);
577 1841 : internals.push_back(myLastEntryTime);
578 1841 : internals.push_back(myBlockTime);
579 1841 : internals.push_back(isStopped());
580 1841 : internals.push_back(myPastStops.size());
581 1841 : out.writeAttr(SUMO_ATTR_STATE, toString(internals));
582 : // save past stops
583 4893 : for (SUMOVehicleParameter::Stop stop : myPastStops) {
584 3052 : stop.write(out, false);
585 : // do not write started and ended twice
586 3052 : if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
587 3052 : out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
588 : }
589 3052 : if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
590 3052 : out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
591 : }
592 3052 : out.closeTag();
593 3052 : }
594 : // save upcoming stops
595 2223 : for (const MSStop& stop : myStops) {
596 382 : stop.write(out);
597 : }
598 : // save parameters
599 1841 : myParameter->writeParams(out);
600 4724 : for (MSDevice* dev : myDevices) {
601 2883 : dev->saveState(out);
602 : }
603 4302 : for (const auto& item : myMoveReminders) {
604 2461 : item.first->saveReminderState(out, *this);
605 : }
606 1841 : out.closeTag();
607 1841 : }
608 :
609 :
610 : void
611 1082 : MEVehicle::loadState(const SUMOSAXAttributes& attrs, const SUMOTime offset) {
612 1082 : if (attrs.hasAttribute(SUMO_ATTR_POSITION)) {
613 10 : throw ProcessError(TL("Error: Invalid vehicles in state (may be a micro state)!"));
614 : }
615 : int routeOffset;
616 : bool stopped;
617 : int pastStops;
618 : int segIndex;
619 : int queIndex;
620 1077 : std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
621 1077 : bis >> myParameter->parametersSet;
622 1077 : bis >> myDeparture;
623 1077 : bis >> routeOffset;
624 1077 : bis >> myDepartPos;
625 1077 : bis >> segIndex;
626 1077 : bis >> queIndex;
627 1077 : bis >> myEventTime;
628 1077 : bis >> myLastEntryTime;
629 1077 : bis >> myBlockTime;
630 : bis >> stopped;
631 1077 : bis >> pastStops;
632 1077 : myDepartPos /= 1000.; // was stored as mm
633 :
634 1077 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS_RANDOMIZED)) {
635 : bool ok;
636 9 : myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
637 : }
638 :
639 : // load stops
640 : myStops.clear();
641 1077 : addStops(!MSGlobals::gCheckRoutes, &myCurrEdge, false);
642 :
643 1077 : if (hasDeparted()) {
644 719 : myDeparture -= offset;
645 719 : myEventTime -= offset;
646 719 : myLastEntryTime -= offset;
647 719 : myCurrEdge = myRoute->begin() + routeOffset;
648 : // fix stops
649 3767 : while (pastStops > 0) {
650 3048 : myPastStops.push_back(myStops.front().pars);
651 3048 : myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
652 3048 : myStops.pop_front();
653 3048 : pastStops--;
654 : }
655 719 : if (segIndex >= 0) {
656 719 : MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(**myCurrEdge);
657 1020 : while (seg->getIndex() != (int)segIndex) {
658 : seg = seg->getNextSegment();
659 302 : if (seg == nullptr) {
660 4 : throw ProcessError(TLF("Unknown segment '%:%' for vehicle '%' in loaded state.", (*myCurrEdge)->getID(), segIndex, getID()));
661 : }
662 : }
663 718 : setSegment(seg, queIndex);
664 718 : if (queIndex == MESegment::PARKING_QUEUE) {
665 265 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
666 265 : getCurrentEdge()->getLanes()[0]->addParking(this);
667 : }
668 : } else {
669 : // on teleport
670 0 : setSegment(nullptr, 0);
671 : assert(myEventTime != SUMOTime_MIN);
672 0 : MSGlobals::gMesoNet->addLeaderCar(this, nullptr);
673 : }
674 : // see MSBaseVehicle constructor
675 718 : if (myParameter->wasSet(VEHPARS_FORCE_REROUTE)) {
676 396 : calculateArrivalParams(true);
677 : }
678 : }
679 1076 : if (myBlockTime != SUMOTime_MAX) {
680 7 : myBlockTime -= offset;
681 : }
682 1076 : std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
683 1076 : dis >> myOdometer >> myNumberReroutes;
684 1076 : if (stopped) {
685 278 : myStops.front().startedFromState = true;
686 278 : myStops.front().reached = true;
687 : }
688 1077 : }
689 :
690 :
691 : /****************************************************************************/
|