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