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