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