Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSVehicle.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
31// Representation of a vehicle in the micro simulation
32/****************************************************************************/
33#include <config.h>
34
35#include <iostream>
36#include <cassert>
37#include <cmath>
38#include <cstdlib>
39#include <algorithm>
40#include <map>
41#include <memory>
71#include "MSEdgeControl.h"
72#include "MSVehicleControl.h"
73#include "MSInsertionControl.h"
74#include "MSVehicleTransfer.h"
75#include "MSGlobals.h"
76#include "MSJunctionLogic.h"
77#include "MSStop.h"
78#include "MSStoppingPlace.h"
79#include "MSParkingArea.h"
80#include "MSMoveReminder.h"
81#include "MSLane.h"
82#include "MSJunction.h"
83#include "MSEdge.h"
84#include "MSVehicleType.h"
85#include "MSNet.h"
86#include "MSRoute.h"
87#include "MSLeaderInfo.h"
88#include "MSDriverState.h"
89#include "MSVehicle.h"
90
91
92//#define DEBUG_PLAN_MOVE
93//#define DEBUG_PLAN_MOVE_LEADERINFO
94//#define DEBUG_CHECKREWINDLINKLANES
95//#define DEBUG_EXEC_MOVE
96//#define DEBUG_FURTHER
97//#define DEBUG_SETFURTHER
98//#define DEBUG_TARGET_LANE
99//#define DEBUG_STOPS
100//#define DEBUG_BESTLANES
101//#define DEBUG_IGNORE_RED
102//#define DEBUG_ACTIONSTEPS
103//#define DEBUG_NEXT_TURN
104//#define DEBUG_TRACI
105//#define DEBUG_REVERSE_BIDI
106//#define DEBUG_EXTRAPOLATE_DEPARTPOS
107//#define DEBUG_REMOTECONTROL
108//#define DEBUG_MOVEREMINDERS
109//#define DEBUG_COND (getID() == "ego")
110//#define DEBUG_COND (true)
111#define DEBUG_COND (isSelected())
112//#define DEBUG_COND2(obj) (obj->getID() == "ego")
113#define DEBUG_COND2(obj) (obj->isSelected())
114
115//#define PARALLEL_STOPWATCH
116
117
118#define STOPPING_PLACE_OFFSET 0.5
119
120#define CRLL_LOOK_AHEAD 5
121
122#define JUNCTION_BLOCKAGE_TIME 5 // s
123
124// @todo Calibrate with real-world values / make configurable
125#define DIST_TO_STOPLINE_EXPECT_PRIORITY 1.0
126
127#define NUMERICAL_EPS_SPEED (0.1 * NUMERICAL_EPS * TS)
128
129// ===========================================================================
130// static value definitions
131// ===========================================================================
132std::vector<MSLane*> MSVehicle::myEmptyLaneVector;
133
134
135// ===========================================================================
136// method definitions
137// ===========================================================================
138/* -------------------------------------------------------------------------
139 * methods of MSVehicle::State
140 * ----------------------------------------------------------------------- */
142 myPos = state.myPos;
143 mySpeed = state.mySpeed;
144 myPosLat = state.myPosLat;
145 myBackPos = state.myBackPos;
148}
149
150
153 myPos = state.myPos;
154 mySpeed = state.mySpeed;
155 myPosLat = state.myPosLat;
156 myBackPos = state.myBackPos;
157 myPreviousSpeed = state.myPreviousSpeed;
158 myLastCoveredDist = state.myLastCoveredDist;
159 return *this;
160}
161
162
163bool
165 return (myPos != state.myPos ||
166 mySpeed != state.mySpeed ||
167 myPosLat != state.myPosLat ||
168 myLastCoveredDist != state.myLastCoveredDist ||
169 myPreviousSpeed != state.myPreviousSpeed ||
170 myBackPos != state.myBackPos);
171}
172
173
174MSVehicle::State::State(double pos, double speed, double posLat, double backPos, double previousSpeed) :
175 myPos(pos), mySpeed(speed), myPosLat(posLat), myBackPos(backPos), myPreviousSpeed(previousSpeed), myLastCoveredDist(SPEED2DIST(speed)) {}
176
177
178
179/* -------------------------------------------------------------------------
180 * methods of MSVehicle::WaitingTimeCollector
181 * ----------------------------------------------------------------------- */
183
184
187 assert(memorySpan <= myMemorySize);
188 if (memorySpan == -1) {
189 memorySpan = myMemorySize;
190 }
191 SUMOTime totalWaitingTime = 0;
192 for (const auto& interval : myWaitingIntervals) {
193 if (interval.second >= memorySpan) {
194 if (interval.first >= memorySpan) {
195 break;
196 } else {
197 totalWaitingTime += memorySpan - interval.first;
198 }
199 } else {
200 totalWaitingTime += interval.second - interval.first;
201 }
202 }
203 return totalWaitingTime;
204}
205
206
207void
209 auto i = myWaitingIntervals.begin();
210 const auto end = myWaitingIntervals.end();
211 const bool startNewInterval = i == end || (i->first != 0);
212 while (i != end) {
213 i->first += dt;
214 if (i->first >= myMemorySize) {
215 break;
216 }
217 i->second += dt;
218 i++;
219 }
220
221 // remove intervals beyond memorySize
222 auto d = std::distance(i, end);
223 while (d > 0) {
224 myWaitingIntervals.pop_back();
225 d--;
226 }
227
228 if (!waiting) {
229 return;
230 } else if (!startNewInterval) {
231 myWaitingIntervals.begin()->first = 0;
232 } else {
233 myWaitingIntervals.push_front(std::make_pair(0, dt));
234 }
235 return;
236}
237
238
239const std::string
241 std::ostringstream state;
242 state << myMemorySize << " " << myWaitingIntervals.size();
243 for (const auto& interval : myWaitingIntervals) {
244 state << " " << interval.first << " " << interval.second;
245 }
246 return state.str();
247}
248
249
250void
252 std::istringstream is(state);
253 int numIntervals;
254 SUMOTime begin, end;
255 is >> myMemorySize >> numIntervals;
256 while (numIntervals-- > 0) {
257 is >> begin >> end;
258 myWaitingIntervals.emplace_back(begin, end);
259 }
260}
261
262
263/* -------------------------------------------------------------------------
264 * methods of MSVehicle::Influencer::GapControlState
265 * ----------------------------------------------------------------------- */
266void
268// std::cout << "GapControlVehStateListener::vehicleStateChanged() vehicle=" << vehicle->getID() << ", to=" << to << std::endl;
269 switch (to) {
273 // Vehicle left road
274// Look up reference vehicle in refVehMap and in case deactivate corresponding gap control
275 const MSVehicle* msVeh = static_cast<const MSVehicle*>(vehicle);
276// std::cout << "GapControlVehStateListener::vehicleStateChanged() vehicle=" << vehicle->getID() << " left the road." << std::endl;
277 if (GapControlState::refVehMap.find(msVeh) != end(GapControlState::refVehMap)) {
278// std::cout << "GapControlVehStateListener::deactivating ref vehicle=" << vehicle->getID() << std::endl;
279 GapControlState::refVehMap[msVeh]->deactivate();
280 }
281 }
282 break;
283 default:
284 {};
285 // do nothing, vehicle still on road
286 }
287}
288
289std::map<const MSVehicle*, MSVehicle::Influencer::GapControlState*>
291
293
295 tauOriginal(-1), tauCurrent(-1), tauTarget(-1), addGapCurrent(-1), addGapTarget(-1),
296 remainingDuration(-1), changeRate(-1), maxDecel(-1), referenceVeh(nullptr), active(false), gapAttained(false), prevLeader(nullptr),
297 lastUpdate(-1), timeHeadwayIncrement(0.0), spaceHeadwayIncrement(0.0) {}
298
299
303
304void
306 if (MSNet::hasInstance()) {
307 if (myVehStateListener == nullptr) {
308 //std::cout << "GapControlState::init()" << std::endl;
309 myVehStateListener = new GapControlVehStateListener();
310 MSNet::getInstance()->addVehicleStateListener(myVehStateListener);
311 }
312 } else {
313 WRITE_ERROR("MSVehicle::Influencer::GapControlState::init(): No MSNet instance found!")
314 }
315}
316
317void
319 if (myVehStateListener != nullptr) {
320 MSNet::getInstance()->removeVehicleStateListener(myVehStateListener);
321 delete myVehStateListener;
322 }
323}
324
325void
326MSVehicle::Influencer::GapControlState::activate(double tauOrig, double tauNew, double additionalGap, double dur, double rate, double decel, const MSVehicle* refVeh) {
328 WRITE_ERROR(TL("No gap control available for meso."))
329 } else {
330 // always deactivate control before activating (triggers clean-up of refVehMap)
331// std::cout << "activate gap control with refVeh=" << (refVeh==nullptr? "NULL" : refVeh->getID()) << std::endl;
332 tauOriginal = tauOrig;
333 tauCurrent = tauOrig;
334 tauTarget = tauNew;
335 addGapCurrent = 0.0;
336 addGapTarget = additionalGap;
337 remainingDuration = dur;
338 changeRate = rate;
339 maxDecel = decel;
340 referenceVeh = refVeh;
341 active = true;
342 gapAttained = false;
343 prevLeader = nullptr;
344 lastUpdate = SIMSTEP - DELTA_T;
345 timeHeadwayIncrement = changeRate * TS * (tauTarget - tauOriginal);
346 spaceHeadwayIncrement = changeRate * TS * addGapTarget;
347
348 if (referenceVeh != nullptr) {
349 // Add refVeh to refVehMap
350 GapControlState::refVehMap[referenceVeh] = this;
351 }
352 }
353}
354
355void
357 active = false;
358 if (referenceVeh != nullptr) {
359 // Remove corresponding refVehMapEntry if appropriate
360 GapControlState::refVehMap.erase(referenceVeh);
361 referenceVeh = nullptr;
362 }
363}
364
365
366/* -------------------------------------------------------------------------
367 * methods of MSVehicle::Influencer
368 * ----------------------------------------------------------------------- */
389
390
392
393void
395 GapControlState::init();
396}
397
398void
400 GapControlState::cleanup();
401}
402
403void
404MSVehicle::Influencer::setSpeedTimeLine(const std::vector<std::pair<SUMOTime, double> >& speedTimeLine) {
405 mySpeedAdaptationStarted = true;
406 mySpeedTimeLine = speedTimeLine;
407}
408
409void
410MSVehicle::Influencer::activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, MSVehicle* refVeh) {
411 if (myGapControlState == nullptr) {
412 myGapControlState = std::make_shared<GapControlState>();
413 init(); // only does things on first call
414 }
415 myGapControlState->activate(originalTau, newTimeHeadway, newSpaceHeadway, duration, changeRate, maxDecel, refVeh);
416}
417
418void
420 if (myGapControlState != nullptr && myGapControlState->active) {
421 myGapControlState->deactivate();
422 }
423}
424
425void
426MSVehicle::Influencer::setLaneTimeLine(const std::vector<std::pair<SUMOTime, int> >& laneTimeLine) {
427 myLaneTimeLine = laneTimeLine;
428}
429
430
431void
433 for (auto& item : myLaneTimeLine) {
434 item.second += indexShift;
435 }
436}
437
438
439void
441 myLatDist = latDist;
442}
443
444int
446 return (1 * myConsiderSafeVelocity +
447 2 * myConsiderMaxAcceleration +
448 4 * myConsiderMaxDeceleration +
449 8 * myRespectJunctionPriority +
450 16 * myEmergencyBrakeRedLight +
451 32 * !myRespectJunctionLeaderPriority // inverted!
452 );
453}
454
455
456int
458 return (1 * myStrategicLC +
459 4 * myCooperativeLC +
460 16 * mySpeedGainLC +
461 64 * myRightDriveLC +
462 256 * myTraciLaneChangePriority +
463 1024 * mySublaneLC);
464}
465
468 SUMOTime duration = -1;
469 for (std::vector<std::pair<SUMOTime, int>>::iterator i = myLaneTimeLine.begin(); i != myLaneTimeLine.end(); ++i) {
470 if (duration < 0) {
471 duration = i->first;
472 } else {
473 duration -= i->first;
474 }
475 }
476 return -duration;
477}
478
481 if (!myLaneTimeLine.empty()) {
482 return myLaneTimeLine.back().first;
483 } else {
484 return -1;
485 }
486}
487
488
489double
490MSVehicle::Influencer::influenceSpeed(SUMOTime currentTime, double speed, double vSafe, double vMin, double vMax) {
491 // remove leading commands which are no longer valid
492 while (mySpeedTimeLine.size() == 1 || (mySpeedTimeLine.size() > 1 && currentTime > mySpeedTimeLine[1].first)) {
493 mySpeedTimeLine.erase(mySpeedTimeLine.begin());
494 }
495
496 if (!(mySpeedTimeLine.size() < 2 || currentTime < mySpeedTimeLine[0].first)) {
497 // Speed advice is active -> compute new speed according to speedTimeLine
498 if (!mySpeedAdaptationStarted) {
499 mySpeedTimeLine[0].second = speed;
500 mySpeedAdaptationStarted = true;
501 }
502 currentTime += DELTA_T;
503 const double td = STEPS2TIME(currentTime - mySpeedTimeLine[0].first) / STEPS2TIME(mySpeedTimeLine[1].first + DELTA_T - mySpeedTimeLine[0].first);
504 speed = mySpeedTimeLine[0].second - (mySpeedTimeLine[0].second - mySpeedTimeLine[1].second) * td;
505 if (myConsiderSafeVelocity) {
506 speed = MIN2(speed, vSafe);
507 }
508 if (myConsiderMaxAcceleration) {
509 speed = MIN2(speed, vMax);
510 }
511 if (myConsiderMaxDeceleration) {
512 speed = MAX2(speed, vMin);
513 }
514 }
515 return speed;
516}
517
518double
519MSVehicle::Influencer::gapControlSpeed(SUMOTime currentTime, const SUMOVehicle* veh, double speed, double vSafe, double vMin, double vMax) {
520#ifdef DEBUG_TRACI
521 if DEBUG_COND2(veh) {
522 std::cout << currentTime << " Influencer::gapControlSpeed(): speed=" << speed
523 << ", vSafe=" << vSafe
524 << ", vMin=" << vMin
525 << ", vMax=" << vMax
526 << std::endl;
527 }
528#endif
529 double gapControlSpeed = speed;
530 if (myGapControlState != nullptr && myGapControlState->active) {
531 // Determine leader and the speed that would be chosen by the gap controller
532 const double currentSpeed = veh->getSpeed();
533 const MSVehicle* msVeh = dynamic_cast<const MSVehicle*>(veh);
534 assert(msVeh != nullptr);
535 const double desiredTargetTimeSpacing = myGapControlState->tauTarget * currentSpeed;
536 std::pair<const MSVehicle*, double> leaderInfo;
537 if (myGapControlState->referenceVeh == nullptr) {
538 // No reference vehicle specified -> use current leader as reference
539 const double brakeGap = msVeh->getBrakeGap(true);
540 leaderInfo = msVeh->getLeader(MAX2(desiredTargetTimeSpacing, myGapControlState->addGapCurrent) + MAX2(brakeGap, 20.0));
541#ifdef DEBUG_TRACI
542 if DEBUG_COND2(veh) {
543 std::cout << " --- no refVeh; myGapControlState->addGapCurrent: " << myGapControlState->addGapCurrent << ", brakeGap: " << brakeGap << " in simstep: " << SIMSTEP << std::endl;
544 }
545#endif
546 } else {
547 // Control gap wrt reference vehicle
548 const MSVehicle* leader = myGapControlState->referenceVeh;
549 double dist = msVeh->getDistanceToPosition(leader->getPositionOnLane(), leader->getLane()) - leader->getLength();
550 if (dist > 100000) {
551 // Reference vehicle was not found downstream the ego's route
552 // Maybe, it is behind the ego vehicle
553 dist = - leader->getDistanceToPosition(msVeh->getPositionOnLane(), msVeh->getLane()) - leader->getLength();
554#ifdef DEBUG_TRACI
555 if DEBUG_COND2(veh) {
556 if (dist < -100000) {
557 // also the ego vehicle is not ahead of the reference vehicle -> no CF-relation
558 std::cout << " Ego and reference vehicle are not in CF relation..." << std::endl;
559 } else {
560 std::cout << " Reference vehicle is behind ego..." << std::endl;
561 }
562 }
563#endif
564 }
565 leaderInfo = std::make_pair(leader, dist - msVeh->getVehicleType().getMinGap());
566 }
567 const double fakeDist = MAX2(0.0, leaderInfo.second - myGapControlState->addGapCurrent);
568#ifdef DEBUG_TRACI
569 if DEBUG_COND2(veh) {
570 const double desiredCurrentSpacing = myGapControlState->tauCurrent * currentSpeed;
571 std::cout << " Gap control active:"
572 << " currentSpeed=" << currentSpeed
573 << ", desiredTargetTimeSpacing=" << desiredTargetTimeSpacing
574 << ", desiredCurrentSpacing=" << desiredCurrentSpacing
575 << ", leader=" << (leaderInfo.first == nullptr ? "NULL" : leaderInfo.first->getID())
576 << ", dist=" << leaderInfo.second
577 << ", fakeDist=" << fakeDist
578 << ",\n tauOriginal=" << myGapControlState->tauOriginal
579 << ", tauTarget=" << myGapControlState->tauTarget
580 << ", tauCurrent=" << myGapControlState->tauCurrent
581 << std::endl;
582 }
583#endif
584 if (leaderInfo.first != nullptr) {
585 if (myGapControlState->prevLeader != nullptr && myGapControlState->prevLeader != leaderInfo.first) {
586 // TODO: The leader changed. What to do?
587 }
588 // Remember leader
589 myGapControlState->prevLeader = leaderInfo.first;
590
591 // Calculate desired following speed assuming the alternative headway time
592 MSCFModel* cfm = (MSCFModel*) & (msVeh->getVehicleType().getCarFollowModel());
593 const double origTau = cfm->getHeadwayTime();
594 cfm->setHeadwayTime(myGapControlState->tauCurrent);
595 gapControlSpeed = MIN2(gapControlSpeed,
596 cfm->followSpeed(msVeh, currentSpeed, fakeDist, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first));
597 cfm->setHeadwayTime(origTau);
598#ifdef DEBUG_TRACI
599 if DEBUG_COND2(veh) {
600 std::cout << " -> gapControlSpeed=" << gapControlSpeed;
601 if (myGapControlState->maxDecel > 0) {
602 std::cout << ", with maxDecel bound: " << MAX2(gapControlSpeed, currentSpeed - TS * myGapControlState->maxDecel);
603 }
604 std::cout << std::endl;
605 }
606#endif
607 if (myGapControlState->maxDecel > 0) {
608 gapControlSpeed = MAX2(gapControlSpeed, currentSpeed - TS * myGapControlState->maxDecel);
609 }
610 }
611
612 // Update gap controller
613 // Check (1) if the gap control has established the desired gap,
614 // and (2) if it has maintained active for the given duration afterwards
615 if (myGapControlState->lastUpdate < currentTime) {
616#ifdef DEBUG_TRACI
617 if DEBUG_COND2(veh) {
618 std::cout << " Updating GapControlState." << std::endl;
619 }
620#endif
621 if (myGapControlState->tauCurrent == myGapControlState->tauTarget && myGapControlState->addGapCurrent == myGapControlState->addGapTarget) {
622 if (!myGapControlState->gapAttained) {
623 // Check if the desired gap was established (add the POSITION_EPS to avoid infinite asymptotic behavior without having established the gap)
624 myGapControlState->gapAttained = leaderInfo.first == nullptr || leaderInfo.second > MAX2(desiredTargetTimeSpacing, myGapControlState->addGapTarget) - POSITION_EPS;
625#ifdef DEBUG_TRACI
626 if DEBUG_COND2(veh) {
627 if (myGapControlState->gapAttained) {
628 std::cout << " Target gap was established." << std::endl;
629 }
630 }
631#endif
632 } else {
633 // Count down remaining time if desired gap was established
634 myGapControlState->remainingDuration -= TS;
635#ifdef DEBUG_TRACI
636 if DEBUG_COND2(veh) {
637 std::cout << " Gap control remaining duration: " << myGapControlState->remainingDuration << std::endl;
638 }
639#endif
640 if (myGapControlState->remainingDuration <= 0) {
641#ifdef DEBUG_TRACI
642 if DEBUG_COND2(veh) {
643 std::cout << " Gap control duration expired, deactivating control." << std::endl;
644 }
645#endif
646 // switch off gap control
647 myGapControlState->deactivate();
648 }
649 }
650 } else {
651 // Adjust current headway values
652 myGapControlState->tauCurrent = MIN2(myGapControlState->tauCurrent + myGapControlState->timeHeadwayIncrement, myGapControlState->tauTarget);
653 myGapControlState->addGapCurrent = MIN2(myGapControlState->addGapCurrent + myGapControlState->spaceHeadwayIncrement, myGapControlState->addGapTarget);
654 }
655 }
656 if (myConsiderSafeVelocity) {
657 gapControlSpeed = MIN2(gapControlSpeed, vSafe);
658 }
659 if (myConsiderMaxAcceleration) {
660 gapControlSpeed = MIN2(gapControlSpeed, vMax);
661 }
662 if (myConsiderMaxDeceleration) {
663 gapControlSpeed = MAX2(gapControlSpeed, vMin);
664 }
665 return MIN2(speed, gapControlSpeed);
666 } else {
667 return speed;
668 }
669}
670
671double
673 return myOriginalSpeed;
674}
675
676void
678 myOriginalSpeed = speed;
679}
680
681
682int
683MSVehicle::Influencer::influenceChangeDecision(const SUMOTime currentTime, const MSEdge& currentEdge, const int currentLaneIndex, int state) {
684 // remove leading commands which are no longer valid
685 while (myLaneTimeLine.size() == 1 || (myLaneTimeLine.size() > 1 && currentTime > myLaneTimeLine[1].first)) {
686 myLaneTimeLine.erase(myLaneTimeLine.begin());
687 }
688 ChangeRequest changeRequest = REQUEST_NONE;
689 // do nothing if the time line does not apply for the current time
690 if (myLaneTimeLine.size() >= 2 && currentTime >= myLaneTimeLine[0].first) {
691 const int destinationLaneIndex = myLaneTimeLine[1].second;
692 if (destinationLaneIndex < (int)currentEdge.getLanes().size()) {
693 if (currentLaneIndex > destinationLaneIndex) {
694 changeRequest = REQUEST_RIGHT;
695 } else if (currentLaneIndex < destinationLaneIndex) {
696 changeRequest = REQUEST_LEFT;
697 } else {
698 changeRequest = REQUEST_HOLD;
699 }
700 } else if (currentEdge.getLanes().back()->getOpposite() != nullptr) { // change to opposite direction driving
701 changeRequest = REQUEST_LEFT;
702 state = state | LCA_TRACI;
703 }
704 }
705 // check whether the current reason shall be canceled / overridden
706 if ((state & LCA_WANTS_LANECHANGE_OR_STAY) != 0) {
707 // flags for the current reason
709 if ((state & LCA_TRACI) != 0 && myLatDist != 0) {
710 // security checks
711 if ((myTraciLaneChangePriority == LCP_ALWAYS)
712 || (myTraciLaneChangePriority == LCP_NOOVERLAP && (state & LCA_OVERLAPPING) == 0)) {
713 state &= ~(LCA_BLOCKED | LCA_OVERLAPPING);
714 }
715 // continue sublane change manoeuvre
716 return state;
717 } else if ((state & LCA_STRATEGIC) != 0) {
718 mode = myStrategicLC;
719 } else if ((state & LCA_COOPERATIVE) != 0) {
720 mode = myCooperativeLC;
721 } else if ((state & LCA_SPEEDGAIN) != 0) {
722 mode = mySpeedGainLC;
723 } else if ((state & LCA_KEEPRIGHT) != 0) {
724 mode = myRightDriveLC;
725 } else if ((state & LCA_SUBLANE) != 0) {
726 mode = mySublaneLC;
727 } else if ((state & LCA_TRACI) != 0) {
728 mode = LC_NEVER;
729 } else {
730 WRITE_WARNINGF(TL("Lane change model did not provide a reason for changing (state=%, time=%\n"), toString(state), time2string(currentTime));
731 }
732 if (mode == LC_NEVER) {
733 // cancel all lcModel requests
734 state &= ~LCA_WANTS_LANECHANGE_OR_STAY;
735 state &= ~LCA_URGENT;
736 } else if (mode == LC_NOCONFLICT && changeRequest != REQUEST_NONE) {
737 if (
738 ((state & LCA_LEFT) != 0 && changeRequest != REQUEST_LEFT) ||
739 ((state & LCA_RIGHT) != 0 && changeRequest != REQUEST_RIGHT) ||
740 ((state & LCA_STAY) != 0 && changeRequest != REQUEST_HOLD)) {
741 // cancel conflicting lcModel request
742 state &= ~LCA_WANTS_LANECHANGE_OR_STAY;
743 state &= ~LCA_URGENT;
744 }
745 } else if (mode == LC_ALWAYS) {
746 // ignore any TraCI requests
747 return state;
748 }
749 }
750 // apply traci requests
751 if (changeRequest == REQUEST_NONE) {
752 return state;
753 } else {
754 state |= LCA_TRACI;
755 // security checks
756 if ((myTraciLaneChangePriority == LCP_ALWAYS)
757 || (myTraciLaneChangePriority == LCP_NOOVERLAP && (state & LCA_OVERLAPPING) == 0)) {
758 state &= ~(LCA_BLOCKED | LCA_OVERLAPPING);
759 }
760 if (changeRequest != REQUEST_HOLD && myTraciLaneChangePriority != LCP_OPPORTUNISTIC) {
761 state |= LCA_URGENT;
762 }
763 switch (changeRequest) {
764 case REQUEST_HOLD:
765 return state | LCA_STAY;
766 case REQUEST_LEFT:
767 return state | LCA_LEFT;
768 case REQUEST_RIGHT:
769 return state | LCA_RIGHT;
770 default:
771 throw ProcessError(TL("should not happen"));
772 }
773 }
774}
775
776
777double
779 assert(myLaneTimeLine.size() >= 2);
780 assert(currentTime >= myLaneTimeLine[0].first);
781 return STEPS2TIME(myLaneTimeLine[1].first - currentTime);
782}
783
784
785void
787 myConsiderSafeVelocity = ((speedMode & 1) != 0);
788 myConsiderMaxAcceleration = ((speedMode & 2) != 0);
789 myConsiderMaxDeceleration = ((speedMode & 4) != 0);
790 myRespectJunctionPriority = ((speedMode & 8) != 0);
791 myEmergencyBrakeRedLight = ((speedMode & 16) != 0);
792 myRespectJunctionLeaderPriority = ((speedMode & 32) == 0); // inverted!
793}
794
795
796void
798 myStrategicLC = (LaneChangeMode)(value & (1 + 2));
799 myCooperativeLC = (LaneChangeMode)((value & (4 + 8)) >> 2);
800 mySpeedGainLC = (LaneChangeMode)((value & (16 + 32)) >> 4);
801 myRightDriveLC = (LaneChangeMode)((value & (64 + 128)) >> 6);
802 myTraciLaneChangePriority = (TraciLaneChangePriority)((value & (256 + 512)) >> 8);
803 mySublaneLC = (LaneChangeMode)((value & (1024 + 2048)) >> 10);
804}
805
806
807void
808MSVehicle::Influencer::setRemoteControlled(Position xyPos, MSLane* l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector& route, SUMOTime t) {
809 myRemoteXYPos = xyPos;
810 myRemoteLane = l;
811 myRemotePos = pos;
812 myRemotePosLat = posLat;
813 myRemoteAngle = angle;
814 myRemoteEdgeOffset = edgeOffset;
815 myRemoteRoute = route;
816 myLastRemoteAccess = t;
817}
818
819
820bool
822 return myLastRemoteAccess == MSNet::getInstance()->getCurrentTimeStep();
823}
824
825
826bool
828 return myLastRemoteAccess >= t - TIME2STEPS(10);
829}
830
831
832void
834 if (myRemoteRoute.size() != 0 && myRemoteRoute != v->getRoute().getEdges()) {
835 // only replace route at this time if the vehicle is moving with the flow
836 const bool isForward = v->getLane() != 0 && &v->getLane()->getEdge() == myRemoteRoute[0];
837#ifdef DEBUG_REMOTECONTROL
838 std::cout << SIMSTEP << " updateRemoteControlRoute veh=" << v->getID() << " old=" << toString(v->getRoute().getEdges()) << " new=" << toString(myRemoteRoute) << " fwd=" << isForward << "\n";
839#endif
840 if (isForward) {
841 v->replaceRouteEdges(myRemoteRoute, -1, 0, "traci:moveToXY", true);
842 v->updateBestLanes();
843 }
844 }
845}
846
847
848void
850 const bool wasOnRoad = v->isOnRoad();
851 const bool withinLane = myRemoteLane != nullptr && fabs(myRemotePosLat) < 0.5 * (myRemoteLane->getWidth() + v->getVehicleType().getWidth());
852 const bool keepLane = wasOnRoad && v->getLane() == myRemoteLane;
853 if (v->isOnRoad() && !(keepLane && withinLane)) {
854 if (myRemoteLane != nullptr && &v->getLane()->getEdge() == &myRemoteLane->getEdge()) {
855 // correct odometer which gets incremented via onRemovalFromNet->leaveLane
856 v->myOdometer -= v->getLane()->getLength();
857 }
860 }
861 if (myRemoteRoute.size() != 0 && myRemoteRoute != v->getRoute().getEdges()) {
862 // needed for the insertion step
863#ifdef DEBUG_REMOTECONTROL
864 std::cout << SIMSTEP << " postProcessRemoteControl veh=" << v->getID()
865 << "\n oldLane=" << Named::getIDSecure(v->getLane())
866 << " oldRoute=" << toString(v->getRoute().getEdges())
867 << "\n newLane=" << Named::getIDSecure(myRemoteLane)
868 << " newRoute=" << toString(myRemoteRoute)
869 << " newRouteEdge=" << myRemoteRoute[myRemoteEdgeOffset]->getID()
870 << "\n";
871#endif
872 // clear any prior stops because they cannot apply to the new route
873 const_cast<SUMOVehicleParameter&>(v->getParameter()).stops.clear();
874 v->replaceRouteEdges(myRemoteRoute, -1, 0, "traci:moveToXY", true);
875 myRemoteRoute.clear();
876 }
877 v->myCurrEdge = v->getRoute().begin() + myRemoteEdgeOffset;
878 if (myRemoteLane != nullptr && myRemotePos > myRemoteLane->getLength()) {
879 myRemotePos = myRemoteLane->getLength();
880 }
881 if (myRemoteLane != nullptr && withinLane) {
882 if (keepLane) {
883 // TODO this handles only the case when the new vehicle is completely on the edge
884 const bool needFurtherUpdate = v->myState.myPos < v->getVehicleType().getLength() && myRemotePos >= v->getVehicleType().getLength();
885 v->myState.myPos = myRemotePos;
886 v->myState.myPosLat = myRemotePosLat;
887 if (needFurtherUpdate) {
888 v->myState.myBackPos = v->updateFurtherLanes(v->myFurtherLanes, v->myFurtherLanesPosLat, std::vector<MSLane*>());
889 }
890 } else {
894 if (!v->isOnRoad()) {
895 MSVehicleTransfer::getInstance()->remove(v); // TODO may need optimization, this is linear in the number of vehicles in transfer
896 }
897 myRemoteLane->forceVehicleInsertion(v, myRemotePos, notify, myRemotePosLat);
898 v->updateBestLanes();
899 }
900 if (!wasOnRoad) {
901 v->drawOutsideNetwork(false);
902 }
903 //std::cout << "on road network p=" << myRemoteXYPos << " a=" << myRemoteAngle << " l=" << Named::getIDSecure(myRemoteLane) << " pos=" << myRemotePos << " posLat=" << myRemotePosLat << "\n";
904 myRemoteLane->requireCollisionCheck();
905 } else {
906 if (v->getDeparture() == NOT_YET_DEPARTED) {
907 v->onDepart();
908 }
909 v->drawOutsideNetwork(true);
910 // see updateState
911 double vNext = v->processTraCISpeedControl(
912 v->getMaxSpeed(), v->getSpeed());
913 v->setBrakingSignals(vNext);
915 v->myAcceleration = SPEED2ACCEL(vNext - v->getSpeed());
916 v->myState.mySpeed = vNext;
917 v->updateWaitingTime(vNext);
918 //std::cout << "outside network p=" << myRemoteXYPos << " a=" << myRemoteAngle << " l=" << Named::getIDSecure(myRemoteLane) << "\n";
919 }
920 // ensure that the position is correct (i.e. when the lanePosition is ambiguous at corners)
921 v->setRemoteState(myRemoteXYPos);
922 v->setAngle(GeomHelper::fromNaviDegree(myRemoteAngle));
923}
924
925
926double
928 if (veh->getPosition() == Position::INVALID) {
929 return oldSpeed;
930 }
931 double dist = veh->getPosition().distanceTo2D(myRemoteXYPos);
932 if (myRemoteLane != nullptr) {
933 // if the vehicles is frequently placed on a new edge, the route may
934 // consist only of a single edge. In this case the new edge may not be
935 // on the route so distAlongRoute will be double::max.
936 // In this case we still want a sensible speed value
937 const double distAlongRoute = veh->getDistanceToPosition(myRemotePos, myRemoteLane);
938 if (distAlongRoute != std::numeric_limits<double>::max()) {
939 dist = distAlongRoute;
940 }
941 }
942 //std::cout << SIMTIME << " veh=" << veh->getID() << " oldPos=" << veh->getPosition() << " traciPos=" << myRemoteXYPos << " dist=" << dist << "\n";
943 const double minSpeed = myConsiderMaxDeceleration ?
944 veh->getCarFollowModel().minNextSpeedEmergency(oldSpeed, veh) : 0;
945 const double maxSpeed = (myRemoteLane != nullptr
946 ? myRemoteLane->getVehicleMaxSpeed(veh)
947 : (veh->getLane() != nullptr
948 ? veh->getLane()->getVehicleMaxSpeed(veh)
949 : veh->getMaxSpeed()));
950 return MIN2(maxSpeed, MAX2(minSpeed, DIST2SPEED(dist)));
951}
952
953
954double
956 double dist = 0;
957 if (myRemoteLane == nullptr) {
958 dist = veh->getPosition().distanceTo2D(myRemoteXYPos);
959 } else {
960 // if the vehicles is frequently placed on a new edge, the route may
961 // consist only of a single edge. In this case the new edge may not be
962 // on the route so getDistanceToPosition will return double::max.
963 // In this case we would rather not move the vehicle in executeMove
964 // (updateState) as it would result in emergency braking
965 dist = veh->getDistanceToPosition(myRemotePos, myRemoteLane);
966 }
967 if (dist == std::numeric_limits<double>::max()) {
968 return 0;
969 } else {
970 if (DIST2SPEED(dist) > veh->getMaxSpeed() * 1.1) {
971 WRITE_WARNINGF(TL("Vehicle '%' moved by TraCI from % to % (dist %) with implied speed of % (exceeding maximum speed %). time=%."),
972 veh->getID(), veh->getPosition(), myRemoteXYPos, dist, DIST2SPEED(dist), veh->getMaxSpeed(), time2string(SIMSTEP));
973 // some sanity check here
974 dist = MIN2(dist, SPEED2DIST(veh->getMaxSpeed() * 2));
975 }
976 return dist;
977 }
978}
979
980
981/* -------------------------------------------------------------------------
982 * MSVehicle-methods
983 * ----------------------------------------------------------------------- */
985 MSVehicleType* type, const double speedFactor) :
986 MSBaseVehicle(pars, route, type, speedFactor),
987 myWaitingTime(0),
989 myTimeLoss(0),
990 myState(0, 0, 0, 0, 0),
991 myDriverState(nullptr),
992 myActionStep(true),
994 myLane(nullptr),
995 myLaneChangeModel(nullptr),
996 myLastBestLanesEdge(nullptr),
999 myNextTurn(0., nullptr),
1000 mySignals(0),
1001 myAmOnNet(false),
1002 myAmIdling(false),
1004 myAngle(0),
1005 myStopDist(std::numeric_limits<double>::max()),
1011 myTimeSinceStartup(TIME2STEPS(3600 * 24)),
1012 myHaveStoppedFor(nullptr),
1013 myInfluencer(nullptr) {
1016}
1017
1018
1028
1029
1030void
1032 for (MSLane* further : myFurtherLanes) {
1033 further->resetPartialOccupation(this);
1034 if (further->getBidiLane() != nullptr
1035 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
1036 further->getBidiLane()->resetPartialOccupation(this);
1037 }
1038 }
1039 if (myLaneChangeModel != nullptr) {
1043 // still needed when calling resetPartialOccupation (getShadowLane) and when removing
1044 // approach information from parallel links
1045 }
1046 myFurtherLanes.clear();
1047 myFurtherLanesPosLat.clear();
1048}
1049
1050
1051void
1053#ifdef DEBUG_ACTIONSTEPS
1054 if (DEBUG_COND) {
1055 std::cout << SIMTIME << " Removing vehicle '" << getID() << "' (reason: " << toString(reason) << ")" << std::endl;
1056 }
1057#endif
1060 leaveLane(reason);
1063 }
1064}
1065
1066
1067void
1074
1075
1076// ------------ interaction with the route
1077bool
1079 // note: not a const method because getDepartLane may call updateBestLanes
1080 if (!(*myCurrEdge)->isTazConnector()) {
1082 if ((*myCurrEdge)->getDepartLane(*this) == nullptr) {
1083 msg = "Invalid departlane definition for vehicle '" + getID() + "'.";
1084 if (myParameter->departLane >= (int)(*myCurrEdge)->getLanes().size()) {
1086 } else {
1088 }
1089 return false;
1090 }
1091 } else {
1092 if ((*myCurrEdge)->allowedLanes(getVClass()) == nullptr) {
1093 msg = "Vehicle '" + getID() + "' is not allowed to depart on any lane of edge '" + (*myCurrEdge)->getID() + "'.";
1095 return false;
1096 }
1097 }
1099 msg = "Departure speed for vehicle '" + getID() + "' is too high for the vehicle type '" + myType->getID() + "'.";
1101 return false;
1102 }
1103 }
1105 return true;
1106}
1107
1108
1109bool
1111 return hasArrivedInternal(false);
1112}
1113
1114
1115bool
1116MSVehicle::hasArrivedInternal(bool oppositeTransformed) const {
1117 return ((myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge))
1118 && (myStops.empty() || myStops.front().edge != myCurrEdge || myStops.front().getSpeed() > 0)
1119 && ((myLaneChangeModel->isOpposite() && !oppositeTransformed) ? myLane->getLength() - myState.myPos : myState.myPos) > myArrivalPos - POSITION_EPS
1120 && !isRemoteControlled());
1121}
1122
1123
1124bool
1125MSVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
1126 if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
1127 // update best lanes (after stops were added)
1128 myLastBestLanesEdge = nullptr;
1130 updateBestLanes(true, onInit ? (*myCurrEdge)->getLanes().front() : 0);
1131 assert(!removeStops || haveValidStopEdges());
1132 if (myStops.size() == 0) {
1133 myStopDist = std::numeric_limits<double>::max();
1134 }
1135 return true;
1136 }
1137 return false;
1138}
1139
1140
1141// ------------ Interaction with move reminders
1142void
1143MSVehicle::workOnMoveReminders(double oldPos, double newPos, double newSpeed) {
1144 // This erasure-idiom works for all stl-sequence-containers
1145 // See Meyers: Effective STL, Item 9
1146 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
1147 // XXX: calling notifyMove with newSpeed seems not the best choice. For the ballistic update, the average speed is calculated and used
1148 // although a higher order quadrature-formula might be more adequate.
1149 // For the euler case (where the speed is considered constant for each time step) it is conceivable that
1150 // the current calculations may lead to systematic errors for large time steps (compared to reality). Refs. #2579
1151 if (!rem->first->notifyMove(*this, oldPos + rem->second, newPos + rem->second, MAX2(0., newSpeed))) {
1152#ifdef _DEBUG
1153 if (myTraceMoveReminders) {
1154 traceMoveReminder("notifyMove", rem->first, rem->second, false);
1155 }
1156#endif
1157 rem = myMoveReminders.erase(rem);
1158 } else {
1159#ifdef _DEBUG
1160 if (myTraceMoveReminders) {
1161 traceMoveReminder("notifyMove", rem->first, rem->second, true);
1162 }
1163#endif
1164 ++rem;
1165 }
1166 }
1167 if (myEnergyParams != nullptr) {
1168 // TODO make the vehicle energy params a derived class which is a move reminder
1170 }
1171}
1172
1173
1174void
1176 updateWaitingTime(0.); // cf issue 2233
1177
1178 // vehicle move reminders
1179 for (const auto& rem : myMoveReminders) {
1180 rem.first->notifyIdle(*this);
1181 }
1182
1183 // lane move reminders - for aggregated values
1184 for (MSMoveReminder* rem : getLane()->getMoveReminders()) {
1185 rem->notifyIdle(*this);
1186 }
1187}
1188
1189// XXX: consider renaming...
1190void
1192 // save the old work reminders, patching the position information
1193 // add the information about the new offset to the old lane reminders
1194 const double oldLaneLength = myLane->getLength();
1195 for (auto& rem : myMoveReminders) {
1196 rem.second += oldLaneLength;
1197#ifdef _DEBUG
1198// if (rem->first==0) std::cout << "Null reminder (?!)" << std::endl;
1199// std::cout << "Adapted MoveReminder on lane " << ((rem->first->getLane()==0) ? "NULL" : rem->first->getLane()->getID()) <<" position to " << rem->second << std::endl;
1200 if (myTraceMoveReminders) {
1201 traceMoveReminder("adaptedPos", rem.first, rem.second, true);
1202 }
1203#endif
1204 }
1205 for (MSMoveReminder* const rem : enteredLane.getMoveReminders()) {
1206 addReminder(rem);
1207 }
1208}
1209
1210
1211// ------------ Other getter methods
1212double
1214 if (isParking() && getStops().begin()->parkingarea != nullptr) {
1215 return getStops().begin()->parkingarea->getVehicleSlope(*this);
1216 }
1217 if (myLane == nullptr) {
1218 return 0;
1219 }
1220 const double posLat = myState.myPosLat; // @todo get rid of the '-'
1221 Position p1 = getPosition();
1223 if (p2 == Position::INVALID) {
1224 // Handle special case of vehicle's back reaching out of the network
1225 if (myFurtherLanes.size() > 0) {
1226 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1227 if (p2 == Position::INVALID) {
1228 // unsuitable lane geometry
1229 p2 = myLane->geometryPositionAtOffset(0, posLat);
1230 }
1231 } else {
1232 p2 = myLane->geometryPositionAtOffset(0, posLat);
1233 }
1234 }
1236}
1237
1238
1240MSVehicle::getPosition(const double offset) const {
1241 if (myLane == nullptr) {
1242 // when called in the context of GUI-Drawing, the simulation step is already incremented
1244 return myCachedPosition;
1245 } else {
1246 return Position::INVALID;
1247 }
1248 }
1249 if (isParking()) {
1250 if (myStops.begin()->parkingarea != nullptr) {
1251 return myStops.begin()->parkingarea->getVehiclePosition(*this);
1252 } else {
1253 // position beside the road
1254 PositionVector shp = myLane->getEdge().getLanes()[0]->getShape();
1257 }
1258 }
1259 const bool changingLanes = myLaneChangeModel->isChangingLanes();
1260 const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
1261 if (offset == 0. && !changingLanes) {
1264 if (MSNet::getInstance()->hasElevation() && MSGlobals::gSublane) {
1266 }
1267 }
1268 return myCachedPosition;
1269 }
1270 Position result = validatePosition(myLane->geometryPositionAtOffset(getPositionOnLane() + offset, posLat), offset);
1271 interpolateLateralZ(result, getPositionOnLane() + offset, posLat);
1272 return result;
1273}
1274
1275
1276void
1277MSVehicle::interpolateLateralZ(Position& pos, double offset, double posLat) const {
1278 const MSLane* shadow = myLaneChangeModel->getShadowLane();
1279 if (shadow != nullptr && pos != Position::INVALID) {
1280 // ignore negative offset
1281 const Position shadowPos = shadow->geometryPositionAtOffset(MAX2(0.0, offset));
1282 if (shadowPos != Position::INVALID && pos.z() != shadowPos.z()) {
1283 const double centerDist = (myLane->getWidth() + shadow->getWidth()) * 0.5;
1284 double relOffset = fabs(posLat) / centerDist;
1285 double newZ = (1 - relOffset) * pos.z() + relOffset * shadowPos.z();
1286 pos.setz(newZ);
1287 }
1288 }
1289}
1290
1291
1292double
1294 double result = getLength() - getPositionOnLane();
1295 if (myLane->isNormal()) {
1296 return MAX2(0.0, result);
1297 }
1298 const MSLane* lane = myLane;
1299 while (lane->isInternal()) {
1300 result += lane->getLength();
1301 lane = lane->getCanonicalSuccessorLane();
1302 }
1303 return result;
1304}
1305
1306
1310 if (!isOnRoad()) {
1311 return Position::INVALID;
1312 }
1313 const std::vector<MSLane*>& bestLanes = getBestLanesContinuation();
1314 auto nextBestLane = bestLanes.begin();
1315 const bool opposite = myLaneChangeModel->isOpposite();
1316 double pos = opposite ? myLane->getLength() - myState.myPos : myState.myPos;
1317 const MSLane* lane = opposite ? myLane->getParallelOpposite() : getLane();
1318 assert(lane != 0);
1319 bool success = true;
1320
1321 while (offset > 0) {
1322 // take into account lengths along internal lanes
1323 while (lane->isInternal() && offset > 0) {
1324 if (offset > lane->getLength() - pos) {
1325 offset -= lane->getLength() - pos;
1326 lane = lane->getLinkCont()[0]->getViaLaneOrLane();
1327 pos = 0.;
1328 if (lane == nullptr) {
1329 success = false;
1330 offset = 0.;
1331 }
1332 } else {
1333 pos += offset;
1334 offset = 0;
1335 }
1336 }
1337 // set nextBestLane to next non-internal lane
1338 while (nextBestLane != bestLanes.end() && *nextBestLane == nullptr) {
1339 ++nextBestLane;
1340 }
1341 if (offset > 0) {
1342 assert(!lane->isInternal());
1343 assert(lane == *nextBestLane);
1344 if (offset > lane->getLength() - pos) {
1345 offset -= lane->getLength() - pos;
1346 ++nextBestLane;
1347 assert(nextBestLane == bestLanes.end() || *nextBestLane != 0);
1348 if (nextBestLane == bestLanes.end()) {
1349 success = false;
1350 offset = 0.;
1351 } else {
1352 const MSLink* link = lane->getLinkTo(*nextBestLane);
1353 assert(link != nullptr);
1354 lane = link->getViaLaneOrLane();
1355 pos = 0.;
1356 }
1357 } else {
1358 pos += offset;
1359 offset = 0;
1360 }
1361 }
1362
1363 }
1364
1365 if (success) {
1367 } else {
1368 return Position::INVALID;
1369 }
1370}
1371
1372
1373double
1375 if (myLane != nullptr) {
1376 return myLane->getVehicleMaxSpeed(this);
1377 }
1378 return myType->getMaxSpeed();
1379}
1380
1381
1383MSVehicle::validatePosition(Position result, double offset) const {
1384 int furtherIndex = 0;
1385 double lastLength = getPositionOnLane();
1386 while (result == Position::INVALID) {
1387 if (furtherIndex >= (int)myFurtherLanes.size()) {
1388 //WRITE_WARNINGF(TL("Could not compute position for vehicle '%', time=%."), getID(), time2string(MSNet::getInstance()->getCurrentTimeStep()));
1389 break;
1390 }
1391 //std::cout << SIMTIME << " veh=" << getID() << " lane=" << myLane->getID() << " pos=" << getPositionOnLane() << " posLat=" << getLateralPositionOnLane() << " offset=" << offset << " result=" << result << " i=" << furtherIndex << " further=" << myFurtherLanes.size() << "\n";
1392 MSLane* further = myFurtherLanes[furtherIndex];
1393 offset += lastLength;
1394 result = further->geometryPositionAtOffset(further->getLength() + offset, -getLateralPositionOnLane());
1395 lastLength = further->getLength();
1396 furtherIndex++;
1397 //std::cout << SIMTIME << " newResult=" << result << "\n";
1398 }
1399 return result;
1400}
1401
1402
1403ConstMSEdgeVector::const_iterator
1405 // too close to the next junction, so avoid an emergency brake here
1406 if (myLane != nullptr && (myCurrEdge + 1) != myRoute->end()) {
1407 if (myLane->isInternal()) {
1408 return myCurrEdge + 1;
1409 }
1410 if (myState.myPos > myLane->getLength() - getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)) {
1411 return myCurrEdge + 1;
1412 }
1414 return myCurrEdge + 1;
1415 }
1416 }
1417 return myCurrEdge;
1418}
1419
1420void
1421MSVehicle::setAngle(double angle, bool straightenFurther) {
1422#ifdef DEBUG_FURTHER
1423 if (DEBUG_COND) {
1424 std::cout << SIMTIME << " veh '" << getID() << " setAngle(" << angle << ") straightenFurther=" << straightenFurther << std::endl;
1425 }
1426#endif
1427 myAngle = angle;
1428 MSLane* next = myLane;
1429 if (straightenFurther && myFurtherLanesPosLat.size() > 0) {
1430 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
1431 MSLane* further = myFurtherLanes[i];
1432 const MSLink* link = further->getLinkTo(next);
1433 if (link != nullptr) {
1435 next = further;
1436 } else {
1437 break;
1438 }
1439 }
1440 }
1441}
1442
1443
1444void
1445MSVehicle::setActionStepLength(double actionStepLength, bool resetOffset) {
1446 SUMOTime actionStepLengthMillisecs = SUMOVehicleParserHelper::processActionStepLength(actionStepLength);
1447 SUMOTime previousActionStepLength = getActionStepLength();
1448 const bool newActionStepLength = actionStepLengthMillisecs != previousActionStepLength;
1449 if (newActionStepLength) {
1450 getSingularType().setActionStepLength(actionStepLengthMillisecs, resetOffset);
1451 if (!resetOffset) {
1452 updateActionOffset(previousActionStepLength, actionStepLengthMillisecs);
1453 }
1454 }
1455 if (resetOffset) {
1457 }
1458}
1459
1460
1461bool
1463 return myState.mySpeed < (60.0 / 3.6) || myLane->getSpeedLimit() < (60.1 / 3.6);
1464}
1465
1466
1467double
1469 Position p1;
1470 const double posLat = -myState.myPosLat; // @todo get rid of the '-'
1471 const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
1472
1473 // if parking manoeuvre is happening then rotate vehicle on each step
1476 }
1477
1478 if (isParking()) {
1479 if (myStops.begin()->parkingarea != nullptr) {
1480 return myStops.begin()->parkingarea->getVehicleAngle(*this);
1481 } else {
1483 }
1484 }
1486 // cannot use getPosition() because it already includes the offset to the side and thus messes up the angle
1487 p1 = myLane->geometryPositionAtOffset(myState.myPos, lefthandSign * posLat);
1488 if (p1 == Position::INVALID && myLane->getShape().length2D() == 0. && myLane->isInternal()) {
1489 // workaround: extrapolate the preceding lane shape
1490 MSLane* predecessorLane = myLane->getCanonicalPredecessorLane();
1491 p1 = predecessorLane->geometryPositionAtOffset(predecessorLane->getLength() + myState.myPos, lefthandSign * posLat);
1492 }
1493 } else {
1494 p1 = getPosition();
1495 }
1496
1497 Position p2;
1498 if (getVehicleType().getParameter().locomotiveLength > 0) {
1499 // articulated vehicle should use the heading of the first part
1500 const double locoLength = MIN2(getVehicleType().getParameter().locomotiveLength, getLength());
1501 p2 = getPosition(-locoLength);
1502 } else {
1503 p2 = getBackPosition();
1504 }
1505 if (p2 == Position::INVALID) {
1506 // Handle special case of vehicle's back reaching out of the network
1507 if (myFurtherLanes.size() > 0) {
1508 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1509 if (p2 == Position::INVALID) {
1510 // unsuitable lane geometry
1511 p2 = myLane->geometryPositionAtOffset(0, posLat);
1512 }
1513 } else {
1514 p2 = myLane->geometryPositionAtOffset(0, posLat);
1515 }
1516 }
1517 double result = (p1 != p2 ? p2.angleTo2D(p1) :
1519
1520 result += lefthandSign * myLaneChangeModel->calcAngleOffset();
1521
1522#ifdef DEBUG_FURTHER
1523 if (DEBUG_COND) {
1524 std::cout << SIMTIME << " computeAngle veh=" << getID() << " p1=" << p1 << " p2=" << p2 << " angle=" << RAD2DEG(result) << " naviDegree=" << GeomHelper::naviDegree(result) << "\n";
1525 }
1526#endif
1527 return result;
1528}
1529
1530
1531const Position
1533 const double posLat = MSGlobals::gLefthand ? myState.myPosLat : -myState.myPosLat;
1534 Position result;
1535 if (myState.myPos >= myType->getLength()) {
1536 // vehicle is fully on the new lane
1538 } else {
1540 // special case where the target lane has no predecessor
1541#ifdef DEBUG_FURTHER
1542 if (DEBUG_COND) {
1543 std::cout << " getBackPosition veh=" << getID() << " specialCase using myLane=" << myLane->getID() << " pos=0 posLat=" << myState.myPosLat << " result=" << myLane->geometryPositionAtOffset(0, posLat) << "\n";
1544 }
1545#endif
1546 result = myLane->geometryPositionAtOffset(0, posLat);
1547 } else {
1548#ifdef DEBUG_FURTHER
1549 if (DEBUG_COND) {
1550 std::cout << " getBackPosition veh=" << getID() << " myLane=" << myLane->getID() << " further=" << toString(myFurtherLanes) << " myFurtherLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
1551 }
1552#endif
1553 if (myFurtherLanes.size() > 0 && !myLaneChangeModel->isChangingLanes()) {
1554 // truncate to 0 if vehicle starts on an edge that is shorter than its length
1555 const double backPos = MAX2(0.0, getBackPositionOnLane(myFurtherLanes.back()));
1556 result = myFurtherLanes.back()->geometryPositionAtOffset(backPos, -myFurtherLanesPosLat.back() * (MSGlobals::gLefthand ? -1 : 1));
1557 } else {
1558 result = myLane->geometryPositionAtOffset(0, posLat);
1559 }
1560 }
1561 }
1563 interpolateLateralZ(result, myState.myPos - myType->getLength(), posLat);
1564 }
1565 return result;
1566}
1567
1568
1569bool
1571 return !isStopped() && !myStops.empty() && myLane != nullptr && &myStops.front().lane->getEdge() == &myLane->getEdge();
1572}
1573
1574bool
1576 return isStopped() && myStops.front().lane == myLane;
1577}
1578
1579bool
1580MSVehicle::keepStopping(bool afterProcessing) const {
1581 if (isStopped()) {
1582 // when coming out of vehicleTransfer we must shift the time forward
1583 return (myStops.front().duration - (afterProcessing ? DELTA_T : 0) > 0 || isStoppedTriggered() || myStops.front().pars.collision
1584 || myStops.front().pars.breakDown || (myStops.front().getSpeed() > 0
1585 && (myState.myPos < MIN2(myStops.front().pars.endPos, myStops.front().lane->getLength() - POSITION_EPS))
1586 && (myStops.front().pars.parking == ParkingType::ONROAD || getSpeed() >= SUMO_const_haltingSpeed)));
1587 } else {
1588 return false;
1589 }
1590}
1591
1592
1595 if (isStopped()) {
1596 return myStops.front().duration;
1597 }
1598 return 0;
1599}
1600
1601
1604 return (myStops.empty() || !myStops.front().pars.collision) ? myCollisionImmunity : MAX2((SUMOTime)0, myStops.front().duration);
1605}
1606
1607
1608bool
1610 return isStopped() && !myStops.empty() && myStops.front().pars.breakDown;
1611}
1612
1613
1614bool
1616 return myCollisionImmunity > 0;
1617}
1618
1619
1620double
1621MSVehicle::processNextStop(double currentVelocity) {
1622 if (myStops.empty()) {
1623 // no stops; pass
1624 return currentVelocity;
1625 }
1626
1627#ifdef DEBUG_STOPS
1628 if (DEBUG_COND) {
1629 std::cout << "\nPROCESS_NEXT_STOP\n" << SIMTIME << " vehicle '" << getID() << "'" << std::endl;
1630 }
1631#endif
1632
1633 MSStop& stop = myStops.front();
1635 if (stop.reached) {
1636 stop.duration -= getActionStepLength();
1637
1638#ifdef DEBUG_STOPS
1639 if (DEBUG_COND) {
1640 std::cout << SIMTIME << " vehicle '" << getID() << "' reached stop.\n"
1641 << "Remaining duration: " << STEPS2TIME(stop.duration) << std::endl;
1642 if (stop.getSpeed() > 0) {
1643 std::cout << " waypointSpeed=" << stop.getSpeed() << " vehPos=" << myState.myPos << " endPos=" << stop.pars.endPos << "\n";
1644 }
1645 }
1646#endif
1647 if (stop.duration <= 0 && stop.pars.join != "") {
1648 // join this train (part) to another one
1649 MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
1650 if (joinVeh && joinVeh->hasDeparted() && (joinVeh->joinTrainPart(this) || joinVeh->joinTrainPartFront(this))) {
1651 stop.joinTriggered = false;
1655 }
1656 // avoid collision warning before this vehicle is removed (joinVeh was already made longer)
1658 // mark this vehicle as arrived
1660 const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = getRoutePosition();
1661 // handle transportables that want to continue in the other vehicle
1662 if (myPersonDevice != nullptr) {
1664 }
1665 if (myContainerDevice != nullptr) {
1667 }
1668 }
1669 }
1670 boardTransportables(stop);
1671 if (time > stop.endBoarding) {
1672 // for taxi: cancel customers
1673 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1674 if (taxiDevice != nullptr) {
1675 // may invalidate stops including the current reference
1676 taxiDevice->cancelCurrentCustomers();
1678 return currentVelocity;
1679 }
1680 }
1681 if (!keepStopping() && isOnRoad()) {
1682#ifdef DEBUG_STOPS
1683 if (DEBUG_COND) {
1684 std::cout << SIMTIME << " vehicle '" << getID() << "' resumes from stopping." << std::endl;
1685 }
1686#endif
1688 if (isRail() && hasStops()) {
1689 // stay on the current lane in case of a double stop
1690 const MSStop& nextStop = getNextStop();
1691 if (nextStop.edge == myCurrEdge) {
1692 const double stopSpeed = getCarFollowModel().stopSpeed(this, getSpeed(), nextStop.pars.endPos - myState.myPos);
1693 //std::cout << SIMTIME << " veh=" << getID() << " resumedFromStopping currentVelocity=" << currentVelocity << " stopSpeed=" << stopSpeed << "\n";
1694 return stopSpeed;
1695 }
1696 }
1697 } else {
1698 if (stop.triggered) {
1699 if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
1700 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1701 stop.triggered = false;
1702 } else if (!myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1703 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1706#ifdef DEBUG_STOPS
1707 if (DEBUG_COND) {
1708 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for person." << std::endl;
1709 }
1710#endif
1711 }
1712 }
1713 if (stop.containerTriggered) {
1714 if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
1715 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1716 stop.containerTriggered = false;
1717 } else if (stop.containerTriggered && !myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1718 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1721#ifdef DEBUG_STOPS
1722 if (DEBUG_COND) {
1723 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for container." << std::endl;
1724 }
1725#endif
1726 }
1727 }
1728 // joining only takes place after stop duration is over
1730 && stop.duration <= (stop.pars.extension >= 0 ? -stop.pars.extension : 0)) {
1731 if (stop.pars.extension >= 0) {
1732 WRITE_WARNINGF(TL("Vehicle '%' aborts joining after extension of %s at time %."), getID(), STEPS2TIME(stop.pars.extension), time2string(SIMSTEP));
1733 stop.joinTriggered = false;
1734 } else {
1735 // keep stopping indefinitely but ensure that simulation terminates
1738 }
1739 }
1740 if (stop.getSpeed() > 0) {
1741 //waypoint mode
1742 if (stop.duration == 0) {
1743 return stop.getSpeed();
1744 } else {
1745 // stop for 'until' (computed in planMove)
1746 return currentVelocity;
1747 }
1748 } else {
1749 // brake
1751 return 0;
1752 } else {
1753 // ballistic:
1754 return getSpeed() - getCarFollowModel().getMaxDecel();
1755 }
1756 }
1757 }
1758 } else {
1759
1760#ifdef DEBUG_STOPS
1761 if (DEBUG_COND) {
1762 std::cout << SIMTIME << " vehicle '" << getID() << "' hasn't reached next stop." << std::endl;
1763 }
1764#endif
1765 //std::cout << SIMTIME << " myStopDist=" << myStopDist << " bGap=" << getBrakeGap(myLane->getVehicleMaxSpeed(this)) << "\n";
1766 if (stop.pars.onDemand && !stop.skipOnDemand && myStopDist <= getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this))) {
1767 MSNet* const net = MSNet::getInstance();
1768 const bool noExits = ((myPersonDevice == nullptr || !myPersonDevice->anyLeavingAtStop(stop))
1769 && (myContainerDevice == nullptr || !myContainerDevice->anyLeavingAtStop(stop)));
1770 const bool noEntries = ((!net->hasPersons() || !net->getPersonControl().hasAnyWaiting(stop.getEdge(), this))
1771 && (!net->hasContainers() || !net->getContainerControl().hasAnyWaiting(stop.getEdge(), this)));
1772 if (noExits && noEntries) {
1773 //std::cout << " skipOnDemand\n";
1774 stop.skipOnDemand = true;
1775 }
1776 }
1777 // is the next stop on the current lane?
1778 if (stop.edge == myCurrEdge) {
1779 // get the stopping position
1780 bool useStoppingPlace = stop.busstop != nullptr || stop.containerstop != nullptr || stop.parkingarea != nullptr;
1781 bool fitsOnStoppingPlace = true;
1782 if (!stop.skipOnDemand) { // no need to check available space if we skip it anyway
1783 if (stop.busstop != nullptr) {
1784 fitsOnStoppingPlace &= stop.busstop->fits(myState.myPos, *this);
1785 }
1786 if (stop.containerstop != nullptr) {
1787 fitsOnStoppingPlace &= stop.containerstop->fits(myState.myPos, *this);
1788 }
1789 // if the stop is a parking area we check if there is a free position on the area
1790 if (stop.parkingarea != nullptr) {
1791 fitsOnStoppingPlace &= myState.myPos > stop.parkingarea->getBeginLanePosition();
1792 if (stop.parkingarea->getOccupancy() >= stop.parkingarea->getCapacity()) {
1793 fitsOnStoppingPlace = false;
1794 // trigger potential parkingZoneReroute
1795 MSParkingArea* oldParkingArea = stop.parkingarea;
1796 for (MSMoveReminder* rem : myLane->getMoveReminders()) {
1797 if (rem->isParkingRerouter()) {
1798 rem->notifyEnter(*this, MSMoveReminder::NOTIFICATION_PARKING_REROUTE, myLane);
1799 }
1800 }
1801 if (myStops.empty() || myStops.front().parkingarea != oldParkingArea) {
1802 // rerouted, keep driving
1803 return currentVelocity;
1804 }
1805 } else if (stop.parkingarea->getOccupancyIncludingBlocked() >= stop.parkingarea->getCapacity()) {
1806 fitsOnStoppingPlace = false;
1807 } else if (stop.parkingarea->parkOnRoad() && stop.parkingarea->getLotIndex(this) < 0) {
1808 fitsOnStoppingPlace = false;
1809 }
1810 }
1811 }
1812 const double targetPos = myState.myPos + myStopDist + (stop.getSpeed() > 0 ? (stop.pars.startPos - stop.pars.endPos) : 0);
1813 const double reachedThreshold = (useStoppingPlace ? targetPos - STOPPING_PLACE_OFFSET : stop.getReachedThreshold()) - NUMERICAL_EPS;
1814#ifdef DEBUG_STOPS
1815 if (DEBUG_COND) {
1816 std::cout << " pos=" << myState.pos() << " speed=" << currentVelocity << " targetPos=" << targetPos << " fits=" << fitsOnStoppingPlace
1817 << " reachedThresh=" << reachedThreshold
1818 << " myLane=" << Named::getIDSecure(myLane)
1819 << " stopLane=" << Named::getIDSecure(stop.lane)
1820 << "\n";
1821 }
1822#endif
1823 if (myState.pos() >= reachedThreshold && fitsOnStoppingPlace && currentVelocity <= stop.getSpeed() + SUMO_const_haltingSpeed && myLane == stop.lane
1825 // ok, we may stop (have reached the stop) and either we are not modelling maneuvering or have completed entry
1826 stop.reached = true;
1827 if (!stop.startedFromState) {
1828 stop.pars.started = time;
1829 }
1830#ifdef DEBUG_STOPS
1831 if (DEBUG_COND) {
1832 std::cout << SIMTIME << " vehicle '" << getID() << "' reached next stop." << std::endl;
1833 }
1834#endif
1835 if (MSStopOut::active()) {
1837 }
1838 myLane->getEdge().addWaiting(this);
1841 // compute stopping time
1842 stop.duration = stop.getMinDuration(time);
1843 stop.endBoarding = stop.pars.extension >= 0 ? time + stop.duration + stop.pars.extension : SUMOTime_MAX;
1844 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1845 if (taxiDevice != nullptr && stop.pars.extension >= 0) {
1846 // earliestPickupTime is set with waitUntil
1847 stop.endBoarding = MAX2(time, stop.pars.waitUntil) + stop.pars.extension;
1848 }
1849 if (stop.getSpeed() > 0) {
1850 // ignore duration parameter in waypoint mode unless 'until' or 'ended' are set
1851 if (stop.getUntil() > time) {
1852 stop.duration = stop.getUntil() - time;
1853 } else {
1854 stop.duration = 0;
1855 }
1856 }
1857 if (stop.busstop != nullptr) {
1858 // let the bus stop know the vehicle
1859 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
1860 }
1861 if (stop.containerstop != nullptr) {
1862 // let the container stop know the vehicle
1864 }
1865 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
1866 // let the parking area know the vehicle
1867 stop.parkingarea->enter(this);
1868 }
1869 if (stop.chargingStation != nullptr) {
1870 // let the container stop know the vehicle
1872 }
1873
1874 if (stop.pars.tripId != "") {
1875 ((SUMOVehicleParameter&)getParameter()).setParameter("tripId", stop.pars.tripId);
1876 }
1877 if (stop.pars.line != "") {
1878 ((SUMOVehicleParameter&)getParameter()).line = stop.pars.line;
1879 }
1880 if (stop.pars.split != "") {
1881 // split the train
1882 MSVehicle* splitVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.split));
1883 if (splitVeh == nullptr) {
1884 WRITE_WARNINGF(TL("Vehicle '%' to split from vehicle '%' is not known. time=%."), stop.pars.split, getID(), SIMTIME)
1885 } else {
1887 splitVeh->getRoute().getEdges()[0]->removeWaiting(splitVeh);
1889 const double newLength = MAX2(myType->getLength() - splitVeh->getVehicleType().getLength(),
1891 getSingularType().setLength(newLength);
1892 // handle transportables that want to continue in the split part
1893 if (myPersonDevice != nullptr) {
1895 }
1896 if (myContainerDevice != nullptr) {
1898 }
1900 const double backShift = splitVeh->getLength() + getVehicleType().getMinGap();
1901 myState.myPos -= backShift;
1902 myState.myBackPos -= backShift;
1903 }
1904 }
1905 }
1906
1907 boardTransportables(stop);
1908 if (stop.pars.posLat != INVALID_DOUBLE) {
1909 myState.myPosLat = stop.pars.posLat;
1910 }
1911 }
1912 }
1913 }
1914 return currentVelocity;
1915}
1916
1917
1918void
1920 if (stop.skipOnDemand) {
1921 return;
1922 }
1923 // we have reached the stop
1924 // any waiting persons may board now
1926 MSNet* const net = MSNet::getInstance();
1927 const bool boarded = (time <= stop.endBoarding
1928 && net->hasPersons()
1930 && stop.numExpectedPerson == 0);
1931 // load containers
1932 const bool loaded = (time <= stop.endBoarding
1933 && net->hasContainers()
1935 && stop.numExpectedContainer == 0);
1936
1937 bool unregister = false;
1938 if (time > stop.endBoarding) {
1939 stop.triggered = false;
1940 stop.containerTriggered = false;
1942 unregister = true;
1944 }
1945 }
1946 if (boarded) {
1947 // the triggering condition has been fulfilled. Maybe we want to wait a bit longer for additional riders (car pooling)
1949 unregister = true;
1950 }
1951 stop.triggered = false;
1953 }
1954 if (loaded) {
1955 // the triggering condition has been fulfilled
1957 unregister = true;
1958 }
1959 stop.containerTriggered = false;
1961 }
1962
1963 if (unregister) {
1965#ifdef DEBUG_STOPS
1966 if (DEBUG_COND) {
1967 std::cout << SIMTIME << " vehicle '" << getID() << "' unregisters as waiting for transportable." << std::endl;
1968 }
1969#endif
1970 }
1971}
1972
1973bool
1975 // check if veh is close enough to be joined to the rear of this vehicle
1976 MSLane* backLane = myFurtherLanes.size() == 0 ? myLane : myFurtherLanes.back();
1977 double gap = getBackPositionOnLane() - veh->getPositionOnLane();
1978 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == veh->getLane()
1979 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
1980 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
1981 getSingularType().setLength(newLength);
1982 myStops.begin()->joinTriggered = false;
1986 }
1987 return true;
1988 } else {
1989 return false;
1990 }
1991}
1992
1993
1994bool
1996 // check if veh is close enough to be joined to the front of this vehicle
1997 MSLane* backLane = veh->myFurtherLanes.size() == 0 ? veh->myLane : veh->myFurtherLanes.back();
1998 double gap = veh->getBackPositionOnLane(backLane) - getPositionOnLane();
1999 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == getLane()
2000 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
2001 double skippedLaneLengths = 0;
2002 if (veh->myFurtherLanes.size() > 0) {
2003 skippedLaneLengths += getLane()->getLength();
2004 // this vehicle must be moved to the lane of veh
2005 // ensure that lane and furtherLanes of veh match our route
2006 int routeIndex = getRoutePosition();
2007 if (myLane->isInternal()) {
2008 routeIndex++;
2009 }
2010 for (int i = (int)veh->myFurtherLanes.size() - 1; i >= 0; i--) {
2011 MSEdge* edge = &veh->myFurtherLanes[i]->getEdge();
2012 if (edge->isInternal()) {
2013 continue;
2014 }
2015 if (!edge->isInternal() && edge != myRoute->getEdges()[routeIndex]) {
2016 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
2017 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
2018 return false;
2019 }
2020 routeIndex++;
2021 }
2022 if (veh->getCurrentEdge()->getNormalSuccessor() != myRoute->getEdges()[routeIndex]) {
2023 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
2024 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
2025 return false;
2026 }
2027 for (int i = (int)veh->myFurtherLanes.size() - 2; i >= 0; i--) {
2028 skippedLaneLengths += veh->myFurtherLanes[i]->getLength();
2029 }
2030 }
2031
2032 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
2033 getSingularType().setLength(newLength);
2034 // lane will be advanced just as for regular movement
2035 myState.myPos = skippedLaneLengths + veh->getPositionOnLane();
2036 myStops.begin()->joinTriggered = false;
2040 }
2041 return true;
2042 } else {
2043 return false;
2044 }
2045}
2046
2047double
2048MSVehicle::getBrakeGap(bool delayed) const {
2049 return getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), delayed ? getCarFollowModel().getHeadwayTime() : 0);
2050}
2051
2052
2053bool
2056 if (myActionStep) {
2057 myLastActionTime = t;
2058 }
2059 return myActionStep;
2060}
2061
2062
2063void
2064MSVehicle::resetActionOffset(const SUMOTime timeUntilNextAction) {
2065 myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + timeUntilNextAction;
2066}
2067
2068
2069void
2070MSVehicle::updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength) {
2072 SUMOTime timeSinceLastAction = now - myLastActionTime;
2073 if (timeSinceLastAction == 0) {
2074 // Action was scheduled now, may be delayed be new action step length
2075 timeSinceLastAction = oldActionStepLength;
2076 }
2077 if (timeSinceLastAction >= newActionStepLength) {
2078 // Action point required in this step
2079 myLastActionTime = now;
2080 } else {
2081 SUMOTime timeUntilNextAction = newActionStepLength - timeSinceLastAction;
2082 resetActionOffset(timeUntilNextAction);
2083 }
2084}
2085
2086
2087
2088void
2089MSVehicle::planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront) {
2090#ifdef DEBUG_PLAN_MOVE
2091 if (DEBUG_COND) {
2092 std::cout
2093 << "\nPLAN_MOVE\n"
2094 << SIMTIME
2095 << std::setprecision(gPrecision)
2096 << " veh=" << getID()
2097 << " lane=" << myLane->getID()
2098 << " pos=" << getPositionOnLane()
2099 << " posLat=" << getLateralPositionOnLane()
2100 << " speed=" << getSpeed()
2101 << "\n";
2102 }
2103#endif
2104 // Update the driver state
2105 if (hasDriverState()) {
2107 setActionStepLength(myDriverState->getDriverState()->getActionStepLength(), false);
2108 }
2109
2110 if (!checkActionStep(t)) {
2111#ifdef DEBUG_ACTIONSTEPS
2112 if (DEBUG_COND) {
2113 std::cout << STEPS2TIME(t) << " vehicle '" << getID() << "' skips action." << std::endl;
2114 }
2115#endif
2116 // During non-action passed drive items still need to be removed
2117 // @todo rather work with updating myCurrentDriveItem (refs #3714)
2119 return;
2120 } else {
2121#ifdef DEBUG_ACTIONSTEPS
2122 if (DEBUG_COND) {
2123 std::cout << STEPS2TIME(t) << " vehicle = '" << getID() << "' takes action." << std::endl;
2124 }
2125#endif
2127 if (myInfluencer != nullptr) {
2129 }
2131#ifdef DEBUG_PLAN_MOVE
2132 if (DEBUG_COND) {
2133 DriveItemVector::iterator i;
2134 for (i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
2135 std::cout
2136 << " vPass=" << (*i).myVLinkPass
2137 << " vWait=" << (*i).myVLinkWait
2138 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
2139 << " request=" << (*i).mySetRequest
2140 << "\n";
2141 }
2142 }
2143#endif
2144 checkRewindLinkLanes(lengthsInFront, myLFLinkLanes);
2146 // ideally would only do this with the call inside planMoveInternal - but that needs a const method
2147 // so this is a kludge here - nuisance as it adds an extra check in a busy loop
2151 }
2152 }
2153 }
2155}
2156
2157
2158bool
2159MSVehicle::brakeForOverlap(const MSLink* link, const MSLane* lane) const {
2160 // @review needed
2161 //const double futurePosLat = getLateralPositionOnLane() + link->getLateralShift();
2162 //const double overlap = getLateralOverlap(futurePosLat, link->getViaLaneOrLane());
2163 //const double edgeWidth = link->getViaLaneOrLane()->getEdge().getWidth();
2164 const double futurePosLat = getLateralPositionOnLane() + (
2165 lane != myLane && lane->isInternal() ? lane->getIncomingLanes()[0].viaLink->getLateralShift() : 0);
2166 const double overlap = getLateralOverlap(futurePosLat, lane);
2167 const double edgeWidth = lane->getEdge().getWidth();
2168 const bool result = (overlap > POSITION_EPS
2169 // do not get stuck on narrow edges
2170 && getVehicleType().getWidth() <= edgeWidth
2171 && link->getViaLane() == nullptr
2172 // this is the exit link of a junction. The normal edge should support the shadow
2173 && ((myLaneChangeModel->getShadowLane(link->getLane()) == nullptr)
2174 // the internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
2175 || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
2176 // ignore situations where the shadow lane is part of a double-connection with the current lane
2177 && (myLaneChangeModel->getShadowLane() == nullptr
2178 || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
2179 || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != link->getLane()));
2180
2181#ifdef DEBUG_PLAN_MOVE
2182 if (DEBUG_COND) {
2183 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getDescription() << " lane=" << lane->getID()
2184 << " shift=" << link->getLateralShift()
2185 << " fpLat=" << futurePosLat << " overlap=" << overlap << " w=" << getVehicleType().getWidth() << " result=" << result << "\n";
2186 }
2187#endif
2188 return result;
2189}
2190
2191
2192
2193void
2194MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, std::pair<double, const MSLink*>& nextTurn) const {
2195 lfLinks.clear();
2196 newStopDist = std::numeric_limits<double>::max();
2197 //
2198 const MSCFModel& cfModel = getCarFollowModel();
2199 const double vehicleLength = getVehicleType().getLength();
2200 const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
2201 const bool opposite = myLaneChangeModel->isOpposite();
2202 double laneMaxV = myLane->getVehicleMaxSpeed(this);
2203 const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
2204 double lateralShift = 0;
2205 if (isRail()) {
2206 // speed limits must hold for the whole length of the train
2207 for (MSLane* l : myFurtherLanes) {
2208 laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this));
2209#ifdef DEBUG_PLAN_MOVE
2210 if (DEBUG_COND) {
2211 std::cout << " laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
2212 }
2213#endif
2214 }
2215 }
2216 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2217 laneMaxV = MAX2(laneMaxV, vMinComfortable);
2219 laneMaxV = std::numeric_limits<double>::max();
2220 }
2221 // v is the initial maximum velocity of this vehicle in this step
2222 double v = cfModel.maximumLaneSpeedCF(this, maxV, laneMaxV);
2223 // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
2224 // in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
2227 }
2228
2229 if (myInfluencer != nullptr) {
2230 const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
2231#ifdef DEBUG_TRACI
2232 if (DEBUG_COND) {
2233 std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
2234 }
2235#endif
2236 v = myInfluencer->influenceSpeed(t, v, v, vMin, maxV);
2237#ifdef DEBUG_TRACI
2238 if (DEBUG_COND) {
2239 std::cout << " influencedSpeed=" << v;
2240 }
2241#endif
2242 v = myInfluencer->gapControlSpeed(t, this, v, v, vMin, maxV);
2243#ifdef DEBUG_TRACI
2244 if (DEBUG_COND) {
2245 std::cout << " gapControlSpeed=" << v << "\n";
2246 }
2247#endif
2248 }
2249 // all links within dist are taken into account (potentially)
2250 const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
2251
2252 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
2253#ifdef DEBUG_PLAN_MOVE
2254 if (DEBUG_COND) {
2255 std::cout << " dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
2256 << "\n maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
2257 }
2258#endif
2259 assert(bestLaneConts.size() > 0);
2260 bool hadNonInternal = false;
2261 // the distance already "seen"; in the following always up to the end of the current "lane"
2262 double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
2263 nextTurn.first = seen;
2264 nextTurn.second = nullptr;
2265 bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
2266 double seenNonInternal = 0;
2267 double seenInternal = myLane->isInternal() ? seen : 0;
2268 double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2269 int view = 0;
2270 DriveProcessItem* lastLink = nullptr;
2271 bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
2272 double mustSeeBeforeReversal = 0;
2273 // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
2274 const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
2275 assert(lane != 0);
2276 const MSLane* leaderLane = myLane;
2277 bool foundRailSignal = !isRail();
2278 bool planningToStop = false;
2279#ifdef PARALLEL_STOPWATCH
2280 myLane->getStopWatch()[0].start();
2281#endif
2282
2283 // optionally slow down to match arrival time
2284 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2285 if (v > vMinComfortable && hasStops() && myStops.front().pars.arrival >= 0 && sfp > 0
2286 && v > myLane->getSpeedLimit() * sfp
2287 && !myStops.front().reached) {
2288 const double vSlowDown = slowDownForSchedule(vMinComfortable);
2289 v = MIN2(v, vSlowDown);
2290 }
2291 auto stopIt = myStops.begin();
2292 while (true) {
2293 // check leader on lane
2294 // leader is given for the first edge only
2295 if (opposite &&
2296 (leaderLane->getVehicleNumberWithPartials() > 1
2297 || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
2298 ahead.clear();
2299 // find opposite-driving leader that must be respected on the currently looked at lane
2300 // (only looking at one lane at a time)
2301 const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
2302 const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
2303 const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
2304 MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
2305 const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 * myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
2306 for (int i = 0; i < cands.numSublanes(); i++) {
2307 CLeaderDist cand = cands[i];
2308 if (cand.first != 0) {
2309 if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
2310 || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
2311 // respect leaders that also drive in the opposite direction (fully or with some overlap)
2312 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
2313 } else {
2314 // avoid frontal collision
2315 const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
2316 const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
2317 if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
2318 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
2319 }
2320 }
2321 }
2322 }
2323#ifdef DEBUG_PLAN_MOVE
2324 if (DEBUG_COND) {
2325 std::cout << " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
2326 << " cands=" << cands.toString() << " oppositeLeaders=" << oppositeLeaders.toString() << "\n";
2327 }
2328#endif
2329 adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
2330 } else {
2332 const double rightOL = getRightSideOnLane(lane) + lateralShift;
2333 const double leftOL = getLeftSideOnLane(lane) + lateralShift;
2334 const bool outsideLeft = leftOL > lane->getWidth();
2335#ifdef DEBUG_PLAN_MOVE
2336 if (DEBUG_COND) {
2337 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
2338 }
2339#endif
2340 if (rightOL < 0 || outsideLeft) {
2341 MSLeaderInfo outsideLeaders(lane->getWidth());
2342 // if ego is driving outside lane bounds we must consider
2343 // potential leaders that are also outside bounds
2344 int sublaneOffset = 0;
2345 if (outsideLeft) {
2346 sublaneOffset = MIN2(-1, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution));
2347 } else {
2348 sublaneOffset = MAX2(1, (int)ceil(-rightOL / MSGlobals::gLateralResolution));
2349 }
2350 outsideLeaders.setSublaneOffset(sublaneOffset);
2351#ifdef DEBUG_PLAN_MOVE
2352 if (DEBUG_COND) {
2353 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
2354 }
2355#endif
2356 for (const MSVehicle* cand : lane->getVehiclesSecure()) {
2357 if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
2358 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
2359 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
2360 outsideLeaders.addLeader(cand, true);
2361#ifdef DEBUG_PLAN_MOVE
2362 if (DEBUG_COND) {
2363 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << outsideLeaders.toString() << "\n";
2364 }
2365#endif
2366 }
2367 }
2368 lane->releaseVehicles();
2369 if (outsideLeaders.hasVehicles()) {
2370 adaptToLeaders(outsideLeaders, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2371 }
2372 }
2373 }
2374 adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2375 }
2376 if (lastLink != nullptr) {
2377 lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
2378 }
2379#ifdef DEBUG_PLAN_MOVE
2380 if (DEBUG_COND) {
2381 std::cout << "\nv = " << v << "\n";
2382
2383 }
2384#endif
2385 // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
2386 if (myLaneChangeModel->getShadowLane() != nullptr) {
2387 // also slow down for leaders on the shadowLane relative to the current lane
2388 const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
2389 if (shadowLane != nullptr
2390 && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
2391 // continous lane change cannot be stopped so we must adapt to the leader on the target lane
2393 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
2396 // ego posLat is added when retrieving sublanes but it
2397 // should be negated (subtract twice to compensate)
2398 latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
2399 - 2 * getLateralPositionOnLane());
2400
2401 }
2402 MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
2403#ifdef DEBUG_PLAN_MOVE
2405 std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2406 }
2407#endif
2409 // ignore oncoming vehicles on the shadow lane
2410 shadowLeaders.removeOpposite(shadowLane);
2411 }
2412 const double turningDifference = MAX2(0.0, leaderLane->getLength() - shadowLane->getLength());
2413 adaptToLeaders(shadowLeaders, latOffset, seen - turningDifference, lastLink, shadowLane, v, vLinkPass);
2414 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
2415 // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
2416 // (and thus in the same direction as ego)
2417 MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
2418 const double latOffset = 0;
2419#ifdef DEBUG_PLAN_MOVE
2420 if (DEBUG_COND) {
2421 std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
2422 << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2423 }
2424#endif
2425 shadowLeaders.fixOppositeGaps(true);
2426#ifdef DEBUG_PLAN_MOVE
2427 if (DEBUG_COND) {
2428 std::cout << " shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
2429 }
2430#endif
2431 adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
2432 }
2433 }
2434 }
2435 // adapt to pedestrians on the same lane
2436 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2437 const double relativePos = lane->getLength() - seen;
2438#ifdef DEBUG_PLAN_MOVE
2439 if (DEBUG_COND) {
2440 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2441 }
2442#endif
2443 const double stopTime = MAX2(1.0, ceil(getSpeed() / cfModel.getMaxDecel()));
2444 PersonDist leader = lane->nextBlocking(relativePos,
2445 getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
2446 if (leader.first != 0) {
2447 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2448 v = MIN2(v, stopSpeed);
2449#ifdef DEBUG_PLAN_MOVE
2450 if (DEBUG_COND) {
2451 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2452 }
2453#endif
2454 }
2455 }
2456 if (lane->getBidiLane() != nullptr) {
2457 // adapt to pedestrians on the bidi lane
2458 const MSLane* bidiLane = lane->getBidiLane();
2459 if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
2460 const double relativePos = seen;
2461#ifdef DEBUG_PLAN_MOVE
2462 if (DEBUG_COND) {
2463 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2464 }
2465#endif
2466 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2467 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
2468 PersonDist leader = bidiLane->nextBlocking(relativePos,
2469 leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
2470 if (leader.first != 0) {
2471 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2472 v = MIN2(v, stopSpeed);
2473#ifdef DEBUG_PLAN_MOVE
2474 if (DEBUG_COND) {
2475 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2476 }
2477#endif
2478 }
2479 }
2480 }
2481
2482 // process all stops and waypoints on the current edge
2483 bool foundRealStop = false;
2484 while (stopIt != myStops.end()
2485 && ((&stopIt->lane->getEdge() == &lane->getEdge())
2486 || (stopIt->isOpposite && stopIt->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
2487 // ignore stops that occur later in a looped route
2488 && stopIt->edge == myCurrEdge + view) {
2489 double stopDist = std::numeric_limits<double>::max();
2490 const MSStop& stop = *stopIt;
2491 const bool isFirstStop = stopIt == myStops.begin();
2492 stopIt++;
2493 if (!stop.reached || (stop.getSpeed() > 0 && keepStopping())) {
2494 // we are approaching a stop on the edge; must not drive further
2495 bool isWaypoint = stop.getSpeed() > 0;
2496 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
2497 if (stop.parkingarea != nullptr) {
2498 // leave enough space so parking vehicles can exit
2499 const double brakePos = getBrakeGap() + lane->getLength() - seen;
2500 endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
2501 } else if (isWaypoint && !stop.reached) {
2502 endPos = stop.pars.startPos;
2503 }
2504 stopDist = seen + endPos - lane->getLength();
2505#ifdef DEBUG_STOPS
2506 if (DEBUG_COND) {
2507 std::cout << SIMTIME << " veh=" << getID() << " stopDist=" << stopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
2508 }
2509#endif
2510 // regular stops are not emergencies
2511 double stopSpeed = laneMaxV;
2512 if (isWaypoint) {
2513 bool waypointWithStop = false;
2514 if (stop.getUntil() > t) {
2515 // check if we have to slow down or even stop
2516 SUMOTime time2end = 0;
2517 if (stop.reached) {
2518 time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
2519 } else {
2520 time2end = TIME2STEPS(
2521 // time to reach waypoint start
2522 stopDist / ((getSpeed() + stop.getSpeed()) / 2)
2523 // time to reach waypoint end
2524 + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
2525 }
2526 if (stop.getUntil() > t + time2end) {
2527 // we need to stop
2528 double distToEnd = stopDist;
2529 if (!stop.reached) {
2530 distToEnd += stop.pars.endPos - stop.pars.startPos;
2531 }
2532 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
2533 waypointWithStop = true;
2534 }
2535 }
2536 if (stop.reached) {
2537 stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
2538 if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
2539 stopDist = std::numeric_limits<double>::max();
2540 }
2541 } else {
2542 stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), stopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
2543 if (!stop.reached) {
2544 stopDist += stop.pars.endPos - stop.pars.startPos;
2545 }
2546 if (lastLink != nullptr) {
2547 lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
2548 }
2549 }
2550 } else {
2551 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), stopDist), vMinComfortable);
2552 if (lastLink != nullptr) {
2553 lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
2554 }
2555 }
2556 v = MIN2(v, stopSpeed);
2557 if (lane->isInternal()) {
2558 std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2559 assert(!lane->isLinkEnd(exitLink));
2560 bool dummySetRequest;
2561 double dummyVLinkWait;
2562 checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
2563 }
2564
2565#ifdef DEBUG_PLAN_MOVE
2566 if (DEBUG_COND) {
2567 std::cout << "\n" << SIMTIME << " next stop: distance = " << stopDist << " requires stopSpeed = " << stopSpeed << "\n";
2568
2569 }
2570#endif
2571 if (isFirstStop) {
2572 newStopDist = stopDist;
2573 // if the vehicle is going to stop we don't need to look further
2574 // (except for trains that make use of further link-approach registration for safety purposes)
2575 if (!isWaypoint) {
2576 planningToStop = true;
2577 if (!isRail()) {
2578 lfLinks.emplace_back(v, stopDist);
2579 foundRealStop = true;
2580 break;
2581 }
2582 }
2583 }
2584 }
2585 }
2586 if (foundRealStop) {
2587 break;
2588 }
2589
2590 // move to next lane
2591 // get the next link used
2592 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2593
2594 // Check whether this is a turn (to save info about the next upcoming turn)
2595 if (!encounteredTurn) {
2596 if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
2597 LinkDirection linkDir = (*link)->getDirection();
2598 switch (linkDir) {
2601 break;
2602 default:
2603 nextTurn.first = seen;
2604 nextTurn.second = *link;
2605 encounteredTurn = true;
2606#ifdef DEBUG_NEXT_TURN
2607 if (DEBUG_COND) {
2608 std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(linkDir)
2609 << " at " << nextTurn.first << "m." << std::endl;
2610 }
2611#endif
2612 }
2613 }
2614 }
2615
2616 // check whether the vehicle is on its final edge
2617 if (myCurrEdge + view + 1 == myRoute->end()
2618 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
2619 const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
2620 myParameter->arrivalSpeed : laneMaxV);
2621 // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
2622 // XXX: This does not work for ballistic update refs #2579
2623 const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
2624 const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
2625 v = MIN2(v, va);
2626 if (lastLink != nullptr) {
2627 lastLink->adaptLeaveSpeed(va);
2628 }
2629 lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
2630 break;
2631 }
2632 // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
2633 if (lane->isLinkEnd(link)
2634 || (MSGlobals::gSublane && brakeForOverlap(*link, lane))
2635 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
2637 double va = cfModel.stopSpeed(this, getSpeed(), seen);
2638 if (lastLink != nullptr) {
2639 lastLink->adaptLeaveSpeed(va);
2640 }
2643 } else {
2644 v = MIN2(va, v);
2645 }
2646#ifdef DEBUG_PLAN_MOVE
2647 if (DEBUG_COND) {
2648 std::cout << " braking for link end lane=" << lane->getID() << " seen=" << seen
2649 << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
2650
2651 }
2652#endif
2653 if (lane->isLinkEnd(link)) {
2654 lfLinks.emplace_back(v, seen);
2655 break;
2656 }
2657 }
2658 lateralShift += (*link)->getLateralShift();
2659 const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
2660 // We distinguish 3 cases when determining the point at which a vehicle stops:
2661 // - allway_stop: the vehicle should stop close to the stop line but may stop at larger distance
2662 // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
2663 // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
2664 // to minimize the time window for passing the junction. If the
2665 // vehicle 'decides' to accelerate and cannot enter the junction in
2666 // the next step, new foes may appear and cause a collision (see #1096)
2667 // - major links: stopping point is irrelevant
2668 double laneStopOffset;
2669 const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
2670 // override low desired decel at yellow and red
2671 const double stopDecel = yellowOrRed && !isRail() ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
2672 const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
2673 const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
2674 const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
2675 if (yellowOrRed) {
2676 // Wait at red traffic light with full distance if possible
2677 laneStopOffset = majorStopOffset;
2678 } else if ((*link)->havePriority()) {
2679 // On priority link, we should never stop below visibility distance
2680 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
2681 } else {
2682 double minorStopOffset = MAX2(lane->getVehicleStopOffset(this),
2683 getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
2684#ifdef DEBUG_PLAN_MOVE
2685 if (DEBUG_COND) {
2686 std::cout << " minorStopOffset=" << minorStopOffset << " distToFoePedCrossing=" << (*link)->getDistToFoePedCrossing() << "\n";
2687 }
2688#endif
2689 if ((*link)->getState() == LINKSTATE_ALLWAY_STOP) {
2690 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, 0));
2691 } else {
2692 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP_MINOR, 0));
2693 }
2694 // On minor link, we should likewise never stop below visibility distance
2695 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
2696 }
2697#ifdef DEBUG_PLAN_MOVE
2698 if (DEBUG_COND) {
2699 std::cout << SIMTIME << " veh=" << getID() << " desired stopOffset on lane '" << lane->getID() << "' is " << laneStopOffset << "\n";
2700 }
2701#endif
2702 if (canBrakeBeforeLaneEnd) {
2703 // avoid emergency braking if possible
2704 laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
2705 }
2706 laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
2707 double stopDist = MAX2(0., seen - laneStopOffset);
2708 if (yellowOrRed && getDevice(typeid(MSDevice_GLOSA)) != nullptr
2709 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->getOverrideSafety()
2710 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->isSpeedAdviceActive()) {
2711 stopDist = std::numeric_limits<double>::max();
2712 }
2713 if (newStopDist != std::numeric_limits<double>::max()) {
2714 stopDist = MAX2(stopDist, newStopDist);
2715 }
2716#ifdef DEBUG_PLAN_MOVE
2717 if (DEBUG_COND) {
2718 std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
2719 << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
2720 }
2721#endif
2722 if (isRail()
2723 && !lane->isInternal()) {
2724 // check for train direction reversal
2725 if (lane->getBidiLane() != nullptr
2726 && (*link)->getLane()->getBidiLane() == lane) {
2727 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
2728 if (seen < 1) {
2729 mustSeeBeforeReversal = 2 * seen + getLength();
2730 }
2731 v = MIN2(v, vMustReverse);
2732 }
2733 // signal that is passed in the current step does not count
2734 foundRailSignal |= ((*link)->getTLLogic() != nullptr
2735 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
2736 && seen > SPEED2DIST(v));
2737 }
2738
2739 bool canReverseEventually = false;
2740 const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
2741 v = MIN2(v, vReverse);
2742#ifdef DEBUG_PLAN_MOVE
2743 if (DEBUG_COND) {
2744 std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
2745 }
2746#endif
2747
2748 // check whether we need to slow down in order to finish a continuous lane change
2750 if ( // slow down to finish lane change before a turn lane
2751 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
2752 // slow down to finish lane change before the shadow lane ends
2753 (myLaneChangeModel->getShadowLane() != nullptr &&
2754 (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
2755 // XXX maybe this is too harsh. Vehicles could cut some corners here
2756 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
2757 assert(timeRemaining != 0);
2758 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
2759 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
2760 (seen - POSITION_EPS) / timeRemaining);
2761#ifdef DEBUG_PLAN_MOVE
2762 if (DEBUG_COND) {
2763 std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
2764 << " link=" << (*link)->getViaLaneOrLane()->getID()
2765 << " timeRemaining=" << timeRemaining
2766 << " v=" << v
2767 << " va=" << va
2768 << std::endl;
2769 }
2770#endif
2771 v = MIN2(va, v);
2772 }
2773 }
2774
2775 // - always issue a request to leave the intersection we are currently on
2776 const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
2777 // - do not issue a request to enter an intersection after we already slowed down for an earlier one
2778 const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
2779 // - even if red, if we cannot break we should issue a request
2780 bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
2781
2782 double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
2783 double vLinkWait = MIN2(v, stopSpeed);
2784#ifdef DEBUG_PLAN_MOVE
2785 if (DEBUG_COND) {
2786 std::cout
2787 << " stopDist=" << stopDist
2788 << " stopDecel=" << stopDecel
2789 << " vLinkWait=" << vLinkWait
2790 << " brakeDist=" << brakeDist
2791 << " seen=" << seen
2792 << " leaveIntersection=" << leavingCurrentIntersection
2793 << " setRequest=" << setRequest
2794 //<< std::setprecision(16)
2795 //<< " v=" << v
2796 //<< " speedEps=" << NUMERICAL_EPS_SPEED
2797 //<< std::setprecision(gPrecision)
2798 << "\n";
2799 }
2800#endif
2801
2802 if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
2803 if (lane->isInternal()) {
2804 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2805 }
2806 // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
2807 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
2808 // the vehicle is able to brake in front of a yellow/red traffic light
2809 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
2810 //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
2811 break;
2812 }
2813
2814 const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
2815 if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
2816 // restrict speed when ignoring a red light
2817 const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
2818 const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
2819 v = MIN2(va, v);
2820#ifdef DEBUG_PLAN_MOVE
2821 if (DEBUG_COND) std::cout
2822 << " ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
2823 << " redSpeed=" << redSpeed
2824 << " va=" << va
2825 << " v=" << v
2826 << "\n";
2827#endif
2828 }
2829
2830 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2831
2832 if (lastLink != nullptr) {
2833 lastLink->adaptLeaveSpeed(laneMaxV);
2834 }
2835 double arrivalSpeed = vLinkPass;
2836 // vehicles should decelerate when approaching a minor link
2837 // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
2838 // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
2839
2840 // whether the vehicle/driver is close enough to the link to see all possible foes #2123
2841 const double visibilityDistance = (*link)->getFoeVisibilityDistance();
2842 const double determinedFoePresence = seen <= visibilityDistance;
2843// // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
2844// double foeRecognitionTime = 0.0;
2845// double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
2846
2847#ifdef DEBUG_PLAN_MOVE
2848 if (DEBUG_COND) {
2849 std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
2850 }
2851#endif
2852
2853 const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
2854 if (couldBrakeForMinor && !determinedFoePresence) {
2855 // vehicle decelerates just enough to be able to stop if necessary and then accelerates
2856 double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0., false);
2857 // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
2858 double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
2859 arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
2860 slowedDownForMinor = true;
2861#ifdef DEBUG_PLAN_MOVE
2862 if (DEBUG_COND) {
2863 std::cout << " slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
2864 }
2865#endif
2866 } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
2867 // check for deadlock (circular yielding)
2868 //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
2869 std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
2870 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2871 int n = 100;
2872 while (blocker.second != nullptr && blocker.second != *link && n > 0) {
2873 blocker = blocker.second->getFirstApproachingFoe(*link);
2874 n--;
2875 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2876 }
2877 if (n == 0) {
2878 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
2879 }
2880 //std::cout << " blockerLink=" << blocker.second << " link=" << *link << "\n";
2881 if (blocker.second == *link) {
2882 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
2883 if (RandHelper::rand(getRNG()) < threshold) {
2884 //std::cout << " abort request, threshold=" << threshold << "\n";
2885 setRequest = false;
2886 }
2887 }
2888 }
2889
2890 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
2891 if (couldBrakeForMinor && determinedFoePresence && (*link)->getLane()->getEdge().isRoundabout()) {
2892 const bool wasOpened = (*link)->opened(arrivalTime, arrivalSpeed, arrivalSpeed,
2894 getCarFollowModel().getMaxDecel(),
2896 nullptr, false, this);
2897 if (!wasOpened) {
2898 slowedDownForMinor = true;
2899 }
2900#ifdef DEBUG_PLAN_MOVE
2901 if (DEBUG_COND) {
2902 std::cout << " slowedDownForMinor at roundabout=" << (!wasOpened) << "\n";
2903 }
2904#endif
2905 }
2906
2907 // compute arrival speed and arrival time if vehicle starts braking now
2908 // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
2909 double arrivalSpeedBraking = 0;
2910 const double bGap = cfModel.brakeGap(v);
2911 if (seen < bGap && !isStopped() && !planningToStop) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
2912 // vehicle cannot come to a complete stop in time
2914 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
2915 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
2916 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
2917 } else {
2918 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
2919 }
2920 }
2921
2922 // estimate leave speed for passing time computation
2923 // l=linkLength, a=accel, t=continuousTime, v=vLeave
2924 // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
2925 const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this),
2926 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
2927 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
2928 arrivalTime, arrivalSpeed,
2929 arrivalSpeedBraking,
2930 seen, estimatedLeaveSpeed));
2931 if ((*link)->getViaLane() == nullptr) {
2932 hadNonInternal = true;
2933 ++view;
2934 }
2935#ifdef DEBUG_PLAN_MOVE
2936 if (DEBUG_COND) {
2937 std::cout << " checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
2938 << " seenNonInternal=" << seenNonInternal
2939 << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
2940 }
2941#endif
2942 // we need to look ahead far enough to see available space for checkRewindLinkLanes
2943 if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
2944 break;
2945 }
2946 // get the following lane
2947 lane = (*link)->getViaLaneOrLane();
2948 laneMaxV = lane->getVehicleMaxSpeed(this);
2950 laneMaxV = std::numeric_limits<double>::max();
2951 }
2952 // the link was passed
2953 // compute the velocity to use when the link is not blocked by other vehicles
2954 // the vehicle shall be not faster when reaching the next lane than allowed
2955 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2956 const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable);
2957 v = MIN2(va, v);
2958#ifdef DEBUG_PLAN_MOVE
2959 if (DEBUG_COND) {
2960 std::cout << " laneMaxV=" << laneMaxV << " freeSpeed=" << va << " v=" << v << "\n";
2961 }
2962#endif
2963 if (lane->getEdge().isInternal()) {
2964 seenInternal += lane->getLength();
2965 } else {
2966 seenNonInternal += lane->getLength();
2967 }
2968 // do not restrict results to the current vehicle to allow caching for the current time step
2969 leaderLane = opposite ? lane->getParallelOpposite() : lane;
2970 if (leaderLane == nullptr) {
2971
2972 break;
2973 }
2974 ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
2975 seen += lane->getLength();
2976 vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2977 lastLink = &lfLinks.back();
2978 }
2979
2980//#ifdef DEBUG_PLAN_MOVE
2981// if(DEBUG_COND){
2982// std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
2983// }
2984//#endif
2985
2986#ifdef PARALLEL_STOPWATCH
2987 myLane->getStopWatch()[0].stop();
2988#endif
2989}
2990
2991
2992double
2993MSVehicle::slowDownForSchedule(double vMinComfortable) const {
2994 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2995 const MSStop& stop = myStops.front();
2996 std::pair<double, double> timeDist = estimateTimeToNextStop();
2997 double arrivalDelay = SIMTIME + timeDist.first - STEPS2TIME(stop.pars.arrival);
2998 double t = STEPS2TIME(stop.pars.arrival - SIMSTEP);
3001 arrivalDelay += STEPS2TIME(stop.pars.arrival - flexStart);
3002 t = STEPS2TIME(flexStart - SIMSTEP);
3003 } else if (stop.pars.started >= 0 && MSGlobals::gUseStopStarted) {
3004 arrivalDelay += STEPS2TIME(stop.pars.arrival - stop.pars.started);
3005 t = STEPS2TIME(stop.pars.started - SIMSTEP);
3006 }
3007 if (arrivalDelay < 0 && sfp < getChosenSpeedFactor()) {
3008 // we can slow down to better match the schedule (and increase energy efficiency)
3009 const double vSlowDownMin = MAX2(myLane->getSpeedLimit() * sfp, vMinComfortable);
3010 const double s = timeDist.second;
3011 const double b = getCarFollowModel().getMaxDecel();
3012 // x = speed for arriving in t seconds
3013 // u = time at full speed
3014 // u * x + (t - u) * 0.5 * x = s
3015 // t - u = x / b
3016 // eliminate u, solve x
3017 const double radicand = 4 * t * t * b * b - 8 * s * b;
3018 const double x = radicand >= 0 ? t * b - sqrt(radicand) * 0.5 : vSlowDownMin;
3019 double vSlowDown = x < vSlowDownMin ? vSlowDownMin : x;
3020#ifdef DEBUG_PLAN_MOVE
3021 if (DEBUG_COND) {
3022 std::cout << SIMTIME << " veh=" << getID() << " ad=" << arrivalDelay << " t=" << t << " vsm=" << vSlowDownMin
3023 << " r=" << radicand << " vs=" << vSlowDown << "\n";
3024 }
3025#endif
3026 return vSlowDown;
3027 } else if (arrivalDelay > 0 && sfp > getChosenSpeedFactor()) {
3028 // in principle we could up to catch up with the schedule
3029 // but at this point we can only lower the speed, the
3030 // information would have to be used when computing getVehicleMaxSpeed
3031 }
3032 return getMaxSpeed();
3033}
3034
3036MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
3037 const MSCFModel& cfModel = getCarFollowModel();
3038 SUMOTime arrivalTime;
3040 // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
3041 // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
3042 // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
3043 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
3044 } else {
3045 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
3046 }
3047 if (isStopped()) {
3048 arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
3049 }
3050 return arrivalTime;
3051}
3052
3053
3054void
3055MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
3056 const double seen, DriveProcessItem* const lastLink,
3057 const MSLane* const lane, double& v, double& vLinkPass) const {
3058 int rightmost;
3059 int leftmost;
3060 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3061#ifdef DEBUG_PLAN_MOVE
3062 if (DEBUG_COND) std::cout << SIMTIME
3063 << "\nADAPT_TO_LEADERS\nveh=" << getID()
3064 << " lane=" << lane->getID()
3065 << " latOffset=" << latOffset
3066 << " rm=" << rightmost
3067 << " lm=" << leftmost
3068 << " shift=" << ahead.getSublaneOffset()
3069 << " ahead=" << ahead.toString()
3070 << "\n";
3071#endif
3072 /*
3073 if (myLaneChangeModel->getCommittedSpeed() > 0) {
3074 v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
3075 vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
3076 #ifdef DEBUG_PLAN_MOVE
3077 if (DEBUG_COND) std::cout << " hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
3078 #endif
3079 return;
3080 }
3081 */
3082 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3083 const MSVehicle* pred = ahead[sublane];
3084 if (pred != nullptr && pred != this) {
3085 // @todo avoid multiple adaptations to the same leader
3086 const double predBack = pred->getBackPositionOnLane(lane);
3087 double gap = (lastLink == nullptr
3088 ? predBack - myState.myPos - getVehicleType().getMinGap()
3089 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3090 bool oncoming = false;
3092 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
3093 // ego might and leader are driving against lane
3094 gap = (lastLink == nullptr
3095 ? myState.myPos - predBack - getVehicleType().getMinGap()
3096 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3097 } else {
3098 // ego and leader are driving in the same direction as lane (shadowlane for ego)
3099 gap = (lastLink == nullptr
3100 ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
3101 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3102 }
3103 } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
3104 // must react to stopped / dangerous oncoming vehicles
3105 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
3106 // try to avoid collision in the next second
3107 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
3108#ifdef DEBUG_PLAN_MOVE
3109 if (DEBUG_COND) {
3110 std::cout << " fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
3111 }
3112#endif
3113 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
3114 gap -= predMaxDist;
3115 }
3116 } else if (pred->getLane() == lane->getBidiLane()) {
3117 gap -= pred->getVehicleType().getLengthWithGap();
3118 oncoming = true;
3119 }
3120#ifdef DEBUG_PLAN_MOVE
3121 if (DEBUG_COND) {
3122 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << gap << " predBack=" << predBack << " seen=" << seen << " lane=" << lane->getID() << " myLane=" << myLane->getID() << " lastLink=" << (lastLink == nullptr ? "NULL" : lastLink->myLink->getDescription()) << " oncoming=" << oncoming << "\n";
3123 }
3124#endif
3125 if (oncoming && gap >= 0) {
3126 adaptToOncomingLeader(std::make_pair(pred, gap), lastLink, v, vLinkPass);
3127 } else {
3128 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
3129 }
3130 }
3131 }
3132}
3133
3134void
3136 double seen,
3137 DriveProcessItem* const lastLink,
3138 double& v, double& vLinkPass) const {
3139 int rightmost;
3140 int leftmost;
3141 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3142#ifdef DEBUG_PLAN_MOVE
3143 if (DEBUG_COND) std::cout << SIMTIME
3144 << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
3145 << " latOffset=" << latOffset
3146 << " rm=" << rightmost
3147 << " lm=" << leftmost
3148 << " ahead=" << ahead.toString()
3149 << "\n";
3150#endif
3151 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3152 CLeaderDist predDist = ahead[sublane];
3153 const MSVehicle* pred = predDist.first;
3154 if (pred != nullptr && pred != this) {
3155#ifdef DEBUG_PLAN_MOVE
3156 if (DEBUG_COND) {
3157 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
3158 }
3159#endif
3160 adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
3161 }
3162 }
3163}
3164
3165
3166void
3167MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3168 double seen,
3169 DriveProcessItem* const lastLink,
3170 double& v, double& vLinkPass) const {
3171 if (leaderInfo.first != 0) {
3172 if (ignoreFoe(leaderInfo.first)) {
3173#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3174 if (DEBUG_COND) {
3175 std::cout << " foe ignored\n";
3176 }
3177#endif
3178 return;
3179 }
3180 const MSCFModel& cfModel = getCarFollowModel();
3181 double vsafeLeader = 0;
3183 vsafeLeader = -std::numeric_limits<double>::max();
3184 }
3185 bool backOnRoute = true;
3186 if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
3187 backOnRoute = false;
3188 // this can either be
3189 // a) a merging situation (leader back is is not our route) or
3190 // b) a minGap violation / collision
3191 MSLane* current = lastLink->myLink->getViaLaneOrLane();
3192 if (leaderInfo.first->getBackLane() == current) {
3193 backOnRoute = true;
3194 } else {
3195 for (MSLane* lane : getBestLanesContinuation()) {
3196 if (lane == current) {
3197 break;
3198 }
3199 if (leaderInfo.first->getBackLane() == lane) {
3200 backOnRoute = true;
3201 }
3202 }
3203 }
3204#ifdef DEBUG_PLAN_MOVE
3205 if (DEBUG_COND) {
3206 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
3207 }
3208#endif
3209 if (!backOnRoute) {
3210 double stopDist = seen - current->getLength() - POSITION_EPS;
3211 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
3212 // do not drive onto the junction conflict area
3213 stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
3214 }
3215 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
3216 }
3217 }
3218 if (backOnRoute) {
3219 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3220 }
3221 if (lastLink != nullptr) {
3222 const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
3223 lastLink->adaptLeaveSpeed(futureVSafe);
3224#ifdef DEBUG_PLAN_MOVE
3225 if (DEBUG_COND) {
3226 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3227 }
3228#endif
3229 }
3230 v = MIN2(v, vsafeLeader);
3231 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3232#ifdef DEBUG_PLAN_MOVE
3233 if (DEBUG_COND) std::cout
3234 << SIMTIME
3235 //std::cout << std::setprecision(10);
3236 << " veh=" << getID()
3237 << " lead=" << leaderInfo.first->getID()
3238 << " leadSpeed=" << leaderInfo.first->getSpeed()
3239 << " gap=" << leaderInfo.second
3240 << " leadLane=" << leaderInfo.first->getLane()->getID()
3241 << " predPos=" << leaderInfo.first->getPositionOnLane()
3242 << " myLane=" << myLane->getID()
3243 << " v=" << v
3244 << " vSafeLeader=" << vsafeLeader
3245 << " vLinkPass=" << vLinkPass
3246 << "\n";
3247#endif
3248 }
3249}
3250
3251
3252void
3253MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3254 const double seen, DriveProcessItem* const lastLink,
3255 const MSLane* const lane, double& v, double& vLinkPass,
3256 double distToCrossing) const {
3257 if (leaderInfo.first != 0) {
3258 if (ignoreFoe(leaderInfo.first)) {
3259#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3260 if (DEBUG_COND) {
3261 std::cout << " junction foe ignored\n";
3262 }
3263#endif
3264 return;
3265 }
3266 const MSCFModel& cfModel = getCarFollowModel();
3267 double vsafeLeader = 0;
3269 vsafeLeader = -std::numeric_limits<double>::max();
3270 }
3271 if (leaderInfo.second >= 0) {
3272 if (hasDeparted()) {
3273 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3274 } else {
3275 // called in the context of MSLane::isInsertionSuccess
3276 vsafeLeader = cfModel.insertionFollowSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3277 }
3278 } else if (leaderInfo.first != this) {
3279 // the leading, in-lapping vehicle is occupying the complete next lane
3280 // stop before entering this lane
3281 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
3282#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3283 if (DEBUG_COND) {
3284 std::cout << SIMTIME << " veh=" << getID() << " stopping before junction: lane=" << lane->getID() << " seen=" << seen
3285 << " laneLength=" << lane->getLength()
3286 << " stopDist=" << seen - lane->getLength() - POSITION_EPS
3287 << " vsafeLeader=" << vsafeLeader
3288 << " distToCrossing=" << distToCrossing
3289 << "\n";
3290 }
3291#endif
3292 }
3293 if (distToCrossing >= 0) {
3294 // can the leader still stop in the way?
3295 const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
3296 if (leaderInfo.first == this) {
3297 // braking for pedestrian
3298 const double vStopCrossing = cfModel.stopSpeed(this, getSpeed(), distToCrossing);
3299 vsafeLeader = vStopCrossing;
3300#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3301 if (DEBUG_COND) {
3302 std::cout << " breaking for pedestrian distToCrossing=" << distToCrossing << " vStopCrossing=" << vStopCrossing << "\n";
3303 }
3304#endif
3305 if (lastLink != nullptr) {
3306 lastLink->adaptStopSpeed(vsafeLeader);
3307 }
3308 } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
3309 // drive up to the crossing point and stop
3310#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3311 if (DEBUG_COND) {
3312 std::cout << " stop at crossing point for critical leader vStop=" << vStop << "\n";
3313 };
3314#endif
3315 vsafeLeader = MAX2(vsafeLeader, vStop);
3316 } else {
3317 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
3318 // estimate the time at which the leader has gone past the crossing point
3319 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
3320 // reach distToCrossing after that time
3321 // avgSpeed * leaderPastCPTime = distToCrossing
3322 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
3323 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
3324 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
3325 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
3326#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3327 if (DEBUG_COND) {
3328 std::cout << " driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
3329 << " leaderPastCPTime=" << leaderPastCPTime
3330 << " vFinal=" << vFinal
3331 << " v2=" << v2
3332 << " vStop=" << vStop
3333 << " vsafeLeader=" << vsafeLeader << "\n";
3334 }
3335#endif
3336 }
3337 }
3338 if (lastLink != nullptr) {
3339 lastLink->adaptLeaveSpeed(vsafeLeader);
3340 }
3341 v = MIN2(v, vsafeLeader);
3342 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3343#ifdef DEBUG_PLAN_MOVE
3344 if (DEBUG_COND) std::cout
3345 << SIMTIME
3346 //std::cout << std::setprecision(10);
3347 << " veh=" << getID()
3348 << " lead=" << leaderInfo.first->getID()
3349 << " leadSpeed=" << leaderInfo.first->getSpeed()
3350 << " gap=" << leaderInfo.second
3351 << " leadLane=" << leaderInfo.first->getLane()->getID()
3352 << " predPos=" << leaderInfo.first->getPositionOnLane()
3353 << " seen=" << seen
3354 << " lane=" << lane->getID()
3355 << " myLane=" << myLane->getID()
3356 << " dTC=" << distToCrossing
3357 << " v=" << v
3358 << " vSafeLeader=" << vsafeLeader
3359 << " vLinkPass=" << vLinkPass
3360 << "\n";
3361#endif
3362 }
3363}
3364
3365
3366void
3367MSVehicle::adaptToOncomingLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3368 DriveProcessItem* const lastLink,
3369 double& v, double& vLinkPass) const {
3370 if (leaderInfo.first != 0) {
3371 if (ignoreFoe(leaderInfo.first)) {
3372#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3373 if (DEBUG_COND) {
3374 std::cout << " oncoming foe ignored\n";
3375 }
3376#endif
3377 return;
3378 }
3379 const MSCFModel& cfModel = getCarFollowModel();
3380 const MSVehicle* lead = leaderInfo.first;
3381 const MSCFModel& cfModelL = lead->getCarFollowModel();
3382 // assume the leader reacts symmetrically (neither stopping instantly nor ignoring ego)
3383 const double leaderBrakeGap = cfModelL.brakeGap(lead->getSpeed(), cfModelL.getMaxDecel(), 0);
3384 const double egoBrakeGap = cfModel.brakeGap(getSpeed(), cfModel.getMaxDecel(), 0);
3385 const double gapSum = leaderBrakeGap + egoBrakeGap;
3386 // ensure that both vehicles can leave an intersection if they are currently on it
3387 double egoExit = getDistanceToLeaveJunction();
3388 const double leaderExit = lead->getDistanceToLeaveJunction();
3389 double gap = leaderInfo.second;
3390 if (egoExit + leaderExit < gap) {
3391 gap -= egoExit + leaderExit;
3392 } else {
3393 egoExit = 0;
3394 }
3395 // split any distance in excess of brakeGaps evenly
3396 const double freeGap = MAX2(0.0, gap - gapSum);
3397 const double splitGap = MIN2(gap, gapSum);
3398 // assume remaining distance is allocated in proportion to braking distance
3399 const double gapRatio = gapSum > 0 ? egoBrakeGap / gapSum : 0.5;
3400 const double vsafeLeader = cfModel.stopSpeed(this, getSpeed(), splitGap * gapRatio + egoExit + 0.5 * freeGap);
3401 if (lastLink != nullptr) {
3402 const double futureVSafe = cfModel.stopSpeed(this, lastLink->accelV, leaderInfo.second, MSCFModel::CalcReason::FUTURE);
3403 lastLink->adaptLeaveSpeed(futureVSafe);
3404#ifdef DEBUG_PLAN_MOVE
3405 if (DEBUG_COND) {
3406 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3407 }
3408#endif
3409 }
3410 v = MIN2(v, vsafeLeader);
3411 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3412#ifdef DEBUG_PLAN_MOVE
3413 if (DEBUG_COND) std::cout
3414 << SIMTIME
3415 //std::cout << std::setprecision(10);
3416 << " veh=" << getID()
3417 << " oncomingLead=" << lead->getID()
3418 << " leadSpeed=" << lead->getSpeed()
3419 << " gap=" << leaderInfo.second
3420 << " gap2=" << gap
3421 << " gapRatio=" << gapRatio
3422 << " leadLane=" << lead->getLane()->getID()
3423 << " predPos=" << lead->getPositionOnLane()
3424 << " myLane=" << myLane->getID()
3425 << " v=" << v
3426 << " vSafeLeader=" << vsafeLeader
3427 << " vLinkPass=" << vLinkPass
3428 << "\n";
3429#endif
3430 }
3431}
3432
3433
3434void
3435MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
3436 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
3438 // we want to pass the link but need to check for foes on internal lanes
3439 checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
3440 if (myLaneChangeModel->getShadowLane() != nullptr) {
3441 const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
3442 if (parallelLink != nullptr) {
3443 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
3444 }
3445 }
3446 }
3447
3448}
3449
3450void
3451MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
3452 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
3453 bool isShadowLink) const {
3454#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3455 if (DEBUG_COND) {
3456 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3457 }
3458#endif
3459 const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
3460#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3461 if (DEBUG_COND) {
3462 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3463 }
3464#endif
3465 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3466 // the vehicle to enter the junction first has priority
3467 const MSVehicle* leader = (*it).vehAndGap.first;
3468 if (leader == nullptr) {
3469 // leader is a pedestrian. Passing 'this' as a dummy.
3470#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3471 if (DEBUG_COND) {
3472 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
3473 }
3474#endif
3477#ifdef DEBUG_PLAN_MOVE
3478 if (DEBUG_COND) {
3479 std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
3480 }
3481#endif
3482 continue;
3483 }
3484 adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3485 // if blocked by a pedestrian for too long we must yield our request
3487 setRequest = false;
3488#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3489 if (DEBUG_COND) {
3490 std::cout << " aborting request\n";
3491 }
3492#endif
3493 }
3494 } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay()) {
3497#ifdef DEBUG_PLAN_MOVE
3498 if (DEBUG_COND) {
3499 std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
3500 }
3501#endif
3502 continue;
3503 }
3505 // sibling link (XXX: could also be partial occupator where this check fails)
3506 &leader->getLane()->getEdge() == &lane->getEdge()) {
3507 // check for sublane obstruction (trivial for sibling link leaders)
3508 const MSLane* conflictLane = link->getInternalLaneBefore();
3509 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
3510 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
3511 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
3512 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
3513 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
3514#ifdef DEBUG_PLAN_MOVE
3515 if (DEBUG_COND) {
3516 std::cout << SIMTIME << " veh=" << getID()
3517 << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
3518 << " isShadowLink=" << isShadowLink
3519 << " lane=" << lane->getID()
3520 << " foe=" << leader->getID()
3521 << " foeLane=" << leader->getLane()->getID()
3522 << " latOffset=" << latOffset
3523 << " latOffsetFoe=" << leader->getLatOffset(lane)
3524 << " linkLeadersAhead=" << linkLeadersAhead.toString()
3525 << "\n";
3526 }
3527#endif
3528 } else {
3529#ifdef DEBUG_PLAN_MOVE
3530 if (DEBUG_COND) {
3531 std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
3532 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3533 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3534 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3535 << "\n";
3536 }
3537#endif
3538 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3539 }
3540 if (lastLink != nullptr) {
3541 // we are not yet on the junction with this linkLeader.
3542 // at least we can drive up to the previous link and stop there
3543 v = MAX2(v, lastLink->myVLinkWait);
3544 }
3545 // if blocked by a leader from the same or next lane we must yield our request
3546 // also, if blocked by a stopped or blocked leader
3548 //&& leader->getSpeed() < SUMO_const_haltingSpeed
3550 || leader->getLane()->getLogicalPredecessorLane() == myLane
3551 || leader->isStopped()
3553 setRequest = false;
3554#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3555 if (DEBUG_COND) {
3556 std::cout << " aborting request\n";
3557 }
3558#endif
3559 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
3560 // we are not yet on the junction so must abort that request as well
3561 // (or maybe we are already on the junction and the leader is a partial occupator beyond)
3562 lastLink->mySetRequest = false;
3563#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3564 if (DEBUG_COND) {
3565 std::cout << " aborting previous request\n";
3566 }
3567#endif
3568 }
3569 }
3570 }
3571#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3572 else {
3573 if (DEBUG_COND) {
3574 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
3575 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3576 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3577 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3578 << "\n";
3579 }
3580 }
3581#endif
3582 }
3583 // if this is the link between two internal lanes we may have to slow down for pedestrians
3584 vLinkWait = MIN2(vLinkWait, v);
3585}
3586
3587
3588double
3589MSVehicle::getDeltaPos(const double accel) const {
3590 double vNext = myState.mySpeed + ACCEL2SPEED(accel);
3592 // apply implicit Euler positional update
3593 return SPEED2DIST(MAX2(vNext, 0.));
3594 } else {
3595 // apply ballistic update
3596 if (vNext >= 0) {
3597 // assume constant acceleration during this time step
3598 return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
3599 } else {
3600 // negative vNext indicates a stop within the middle of time step
3601 // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
3602 // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
3603 // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
3604 // until the vehicle stops.
3605 return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
3606 }
3607 }
3608}
3609
3610void
3611MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
3612
3613 // Speed limit due to zipper merging
3614 double vSafeZipper = std::numeric_limits<double>::max();
3615
3616 myHaveToWaitOnNextLink = false;
3617 bool canBrakeVSafeMin = false;
3618
3619 // Get safe velocities from DriveProcessItems.
3620 assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
3621 for (const DriveProcessItem& dpi : myLFLinkLanes) {
3622 MSLink* const link = dpi.myLink;
3623
3624#ifdef DEBUG_EXEC_MOVE
3625 if (DEBUG_COND) {
3626 std::cout
3627 << SIMTIME
3628 << " veh=" << getID()
3629 << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
3630 << " req=" << dpi.mySetRequest
3631 << " vP=" << dpi.myVLinkPass
3632 << " vW=" << dpi.myVLinkWait
3633 << " d=" << dpi.myDistance
3634 << "\n";
3635 gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
3636 }
3637#endif
3638
3639 // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
3640 if (link != nullptr && dpi.mySetRequest) {
3641
3642 const LinkState ls = link->getState();
3643 // vehicles should brake when running onto a yellow light if the distance allows to halt in front
3644 const bool yellow = link->haveYellow();
3645 const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
3647 assert(link->getLaneBefore() != nullptr);
3648 const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
3649 const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
3650 if (yellow && canBrake && !ignoreRedLink) {
3651 vSafe = dpi.myVLinkWait;
3653#ifdef DEBUG_CHECKREWINDLINKLANES
3654 if (DEBUG_COND) {
3655 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
3656 }
3657#endif
3658 break;
3659 }
3660 const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
3661 MSLink::BlockingFoes collectFoes;
3662 bool opened = (yellow || influencerPrio
3663 || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3665 canBrake ? getImpatience() : 1,
3668 ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
3669 ignoreRedLink, this, dpi.myDistance));
3670 if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
3671 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
3672 if (parallelLink != nullptr) {
3673 const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
3675 opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3678 getWaitingTimeFor(link), shadowLatPos, nullptr,
3679 ignoreRedLink, this, dpi.myDistance));
3680#ifdef DEBUG_EXEC_MOVE
3681 if (DEBUG_COND) {
3682 std::cout << SIMTIME
3683 << " veh=" << getID()
3684 << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
3685 << " shadowDir=" << myLaneChangeModel->getShadowDirection()
3686 << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
3687 << " opened=" << opened
3688 << "\n";
3689 }
3690#endif
3691 }
3692 }
3693 // vehicles should decelerate when approaching a minor link
3694#ifdef DEBUG_EXEC_MOVE
3695 if (DEBUG_COND) {
3696 std::cout << SIMTIME
3697 << " opened=" << opened
3698 << " influencerPrio=" << influencerPrio
3699 << " linkPrio=" << link->havePriority()
3700 << " lastContMajor=" << link->lastWasContMajor()
3701 << " isCont=" << link->isCont()
3702 << " ignoreRed=" << ignoreRedLink
3703 << "\n";
3704 }
3705#endif
3706 double visibilityDistance = link->getFoeVisibilityDistance();
3707 bool determinedFoePresence = dpi.myDistance <= visibilityDistance;
3708 if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
3709 if (!determinedFoePresence && (canBrake || !yellow)) {
3710 vSafe = dpi.myVLinkWait;
3712#ifdef DEBUG_CHECKREWINDLINKLANES
3713 if (DEBUG_COND) {
3714 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
3715 }
3716#endif
3717 break;
3718 } else {
3719 // past the point of no return. we need to drive fast enough
3720 // to make it across the link. However, minor slowdowns
3721 // should be permissible to follow leading traffic safely
3722 // basically, this code prevents dawdling
3723 // (it's harder to do this later using
3724 // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
3725 // vehicle is already too close to stop at that part of the code)
3726 //
3727 // XXX: There is a problem in subsecond simulation: If we cannot
3728 // make it across the minor link in one step, new traffic
3729 // could appear on a major foe link and cause a collision. Refs. #1845, #2123
3730 vSafeMinDist = dpi.myDistance; // distance that must be covered
3732 vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3733 } else {
3734 vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3735 }
3736 canBrakeVSafeMin = canBrake;
3737#ifdef DEBUG_EXEC_MOVE
3738 if (DEBUG_COND) {
3739 std::cout << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
3740 }
3741#endif
3742 }
3743 }
3744 // have waited; may pass if opened...
3745 if (opened) {
3746 vSafe = dpi.myVLinkPass;
3747 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
3748 // this vehicle is probably not gonna drive across the next junction (heuristic)
3750#ifdef DEBUG_CHECKREWINDLINKLANES
3751 if (DEBUG_COND) {
3752 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
3753 }
3754#endif
3755 }
3756 if (link->mustStop() && determinedFoePresence && myHaveStoppedFor == nullptr) {
3757 myHaveStoppedFor = link;
3758 }
3759 } else if (link->getState() == LINKSTATE_ZIPPER) {
3760 vSafeZipper = MIN2(vSafeZipper,
3761 link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
3762 } else if (!canBrake
3763 // always brake hard for traffic lights (since an emergency stop is necessary anyway)
3764 && link->getTLLogic() == nullptr
3765 // cannot brake even with emergency deceleration
3766 && dpi.myDistance < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0.)) {
3767#ifdef DEBUG_EXEC_MOVE
3768 if (DEBUG_COND) {
3769 std::cout << SIMTIME << " too fast to brake for closed link\n";
3770 }
3771#endif
3772 vSafe = dpi.myVLinkPass;
3773 } else {
3774 vSafe = dpi.myVLinkWait;
3776#ifdef DEBUG_CHECKREWINDLINKLANES
3777 if (DEBUG_COND) {
3778 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
3779 }
3780#endif
3781#ifdef DEBUG_EXEC_MOVE
3782 if (DEBUG_COND) {
3783 std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
3784 }
3785#endif
3786 break;
3787 }
3788 } else {
3789 if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
3790 // blocked on the junction. yield request so other vehicles may
3791 // become junction leader
3792#ifdef DEBUG_EXEC_MOVE
3793 if (DEBUG_COND) {
3794 std::cout << SIMTIME << " resetting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
3795 }
3796#endif
3799 }
3800 // we have: i->link == 0 || !i->setRequest
3801 vSafe = dpi.myVLinkWait;
3802 if (vSafe < getSpeed()) {
3804#ifdef DEBUG_CHECKREWINDLINKLANES
3805 if (DEBUG_COND) {
3806 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
3807 }
3808#endif
3809 } else if (vSafe < SUMO_const_haltingSpeed) {
3811#ifdef DEBUG_CHECKREWINDLINKLANES
3812 if (DEBUG_COND) {
3813 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
3814 }
3815#endif
3816 }
3817 if (link == nullptr && myLFLinkLanes.size() == 1
3818 && getBestLanesContinuation().size() > 1
3819 && getBestLanesContinuation()[1]->hadPermissionChanges()
3820 && myLane->getFirstAnyVehicle() == this) {
3821 // temporal lane closing without notification, visible to the
3822 // vehicle at the front of the queue
3823 updateBestLanes(true);
3824 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
3825 }
3826 break;
3827 }
3828 }
3829
3830//#ifdef DEBUG_EXEC_MOVE
3831// if (DEBUG_COND) {
3832// std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
3833// std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
3834// std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
3835// std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
3836//
3837// double gap = getLeader().second;
3838// std::cout << "gap = " << toString(gap, 24) << std::endl;
3839// std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
3840// << "\n" << std::endl;
3841// }
3842//#endif
3843
3844 if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
3845 || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
3846 // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
3847 // For the Euler update the term '+ NUMERICAL_EPS' prevented a call here... Recheck, consider of -INVALID_SPEED instead of 0 to indicate absence of vSafeMin restrictions. Refs. #2577
3848#ifdef DEBUG_EXEC_MOVE
3849 if (DEBUG_COND) {
3850 std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
3851 }
3852#endif
3853 if (canBrakeVSafeMin && vSafe < getSpeed()) {
3854 // cannot drive across a link so we need to stop before it
3855 vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
3856 getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
3857 vSafeMin = 0;
3859#ifdef DEBUG_CHECKREWINDLINKLANES
3860 if (DEBUG_COND) {
3861 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
3862 }
3863#endif
3864 } else {
3865 // if the link is yellow or visibility distance is large
3866 // then we might not make it across the link in one step anyway..
3867 // Possibly, the lane after the intersection has a lower speed limit so
3868 // we really need to drive slower already
3869 // -> keep driving without dawdling
3870 vSafeMin = vSafe;
3871 }
3872 }
3873
3874 // vehicles inside a roundabout should maintain their requests
3875 if (myLane->getEdge().isRoundabout()) {
3876 myHaveToWaitOnNextLink = false;
3877 }
3878
3879 vSafe = MIN2(vSafe, vSafeZipper);
3880}
3881
3882
3883double
3884MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
3885 if (myInfluencer != nullptr) {
3887#ifdef DEBUG_TRACI
3888 if DEBUG_COND2(this) {
3889 std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
3890 << " vSafe=" << vSafe << " (init)vNext=" << vNext << " keepStopping=" << keepStopping();
3891 }
3892#endif
3895 }
3896 const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
3899 vMin = MAX2(0., vMin);
3900 }
3901 vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
3902 if (keepStopping() && myStops.front().getSpeed() == 0) {
3903 // avoid driving while stopped (unless it's actually a waypoint
3904 vNext = myInfluencer->getOriginalSpeed();
3905 }
3906#ifdef DEBUG_TRACI
3907 if DEBUG_COND2(this) {
3908 std::cout << " (processed)vNext=" << vNext << std::endl;
3909 }
3910#endif
3911 }
3912 return vNext;
3913}
3914
3915
3916void
3918#ifdef DEBUG_ACTIONSTEPS
3919 if (DEBUG_COND) {
3920 std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
3921 << " Current items: ";
3922 for (auto& j : myLFLinkLanes) {
3923 if (j.myLink == 0) {
3924 std::cout << "\n Stop at distance " << j.myDistance;
3925 } else {
3926 const MSLane* to = j.myLink->getViaLaneOrLane();
3927 const MSLane* from = j.myLink->getLaneBefore();
3928 std::cout << "\n Link at distance " << j.myDistance << ": '"
3929 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3930 }
3931 }
3932 std::cout << "\n myNextDriveItem: ";
3933 if (myLFLinkLanes.size() != 0) {
3934 if (myNextDriveItem->myLink == 0) {
3935 std::cout << "\n Stop at distance " << myNextDriveItem->myDistance;
3936 } else {
3937 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
3938 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
3939 std::cout << "\n Link at distance " << myNextDriveItem->myDistance << ": '"
3940 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3941 }
3942 }
3943 std::cout << std::endl;
3944 }
3945#endif
3946 for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
3947#ifdef DEBUG_ACTIONSTEPS
3948 if (DEBUG_COND) {
3949 std::cout << " Removing item: ";
3950 if (j->myLink == 0) {
3951 std::cout << "Stop at distance " << j->myDistance;
3952 } else {
3953 const MSLane* to = j->myLink->getViaLaneOrLane();
3954 const MSLane* from = j->myLink->getLaneBefore();
3955 std::cout << "Link at distance " << j->myDistance << ": '"
3956 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3957 }
3958 std::cout << std::endl;
3959 }
3960#endif
3961 if (j->myLink != nullptr) {
3962 j->myLink->removeApproaching(this);
3963 }
3964 }
3967}
3968
3969
3970void
3972#ifdef DEBUG_ACTIONSTEPS
3973 if (DEBUG_COND) {
3974 std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
3975 for (const auto& dpi : myLFLinkLanes) {
3976 std::cout
3977 << " vPass=" << dpi.myVLinkPass
3978 << " vWait=" << dpi.myVLinkWait
3979 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
3980 << " request=" << dpi.mySetRequest
3981 << "\n";
3982 }
3983 std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
3984 }
3985#endif
3986 if (myLFLinkLanes.size() == 0) {
3987 // nothing to update
3988 return;
3989 }
3990 const MSLink* nextPlannedLink = nullptr;
3991// auto i = myLFLinkLanes.begin();
3992 auto i = myNextDriveItem;
3993 while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
3994 nextPlannedLink = i->myLink;
3995 ++i;
3996 }
3997
3998 if (nextPlannedLink == nullptr) {
3999 // No link for upcoming item -> no need for an update
4000#ifdef DEBUG_ACTIONSTEPS
4001 if (DEBUG_COND) {
4002 std::cout << "Found no link-related drive item." << std::endl;
4003 }
4004#endif
4005 return;
4006 }
4007
4008 if (getLane() == nextPlannedLink->getLaneBefore()) {
4009 // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
4010#ifdef DEBUG_ACTIONSTEPS
4011 if (DEBUG_COND) {
4012 std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
4013 }
4014#endif
4015 return;
4016 }
4017 // Lane must have been changed, determine the change direction
4018 const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
4019 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4020 // lcDir = 1;
4021 } else {
4022 parallelLink = nextPlannedLink->getParallelLink(-1);
4023 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4024 // lcDir = -1;
4025 } else {
4026 // If the vehicle's current lane is not the approaching lane for the next
4027 // drive process item's link, it is expected to lead to a parallel link,
4028 // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
4029 // Then a stop item should be scheduled! -> TODO!
4030 //assert(false);
4031 return;
4032 }
4033 }
4034#ifdef DEBUG_ACTIONSTEPS
4035 if (DEBUG_COND) {
4036 std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
4037 }
4038#endif
4039 // Trace link sequence along current best lanes and transfer drive items to the corresponding links
4040// DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
4041 DriveItemVector::iterator driveItemIt = myNextDriveItem;
4042 // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
4043 const MSLane* lane = myLane;
4044 assert(myLane == parallelLink->getLaneBefore());
4045 // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
4046 std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
4047 // Pointer to the new link for the current drive process item
4048 MSLink* newLink = nullptr;
4049 while (driveItemIt != myLFLinkLanes.end()) {
4050 if (driveItemIt->myLink == nullptr) {
4051 // Items not related to a specific link are not updated
4052 // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
4053 // the update necessary, this may slow down the vehicle's continuation on the new lane...)
4054 ++driveItemIt;
4055 continue;
4056 }
4057 // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
4058 // We just remove the leftover link-items, as they cannot be mapped to new links.
4059 if (bestLaneIt == getBestLanesContinuation().end()) {
4060#ifdef DEBUG_ACTIONSTEPS
4061 if (DEBUG_COND) {
4062 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
4063 }
4064#endif
4065 while (driveItemIt != myLFLinkLanes.end()) {
4066 if (driveItemIt->myLink == nullptr) {
4067 ++driveItemIt;
4068 continue;
4069 } else {
4070 driveItemIt->myLink->removeApproaching(this);
4071 driveItemIt = myLFLinkLanes.erase(driveItemIt);
4072 }
4073 }
4074 break;
4075 }
4076 // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
4077 const MSLane* const target = *bestLaneIt;
4078 assert(!target->isInternal());
4079 newLink = nullptr;
4080 for (MSLink* const link : lane->getLinkCont()) {
4081 if (link->getLane() == target) {
4082 newLink = link;
4083 break;
4084 }
4085 }
4086
4087 if (newLink == driveItemIt->myLink) {
4088 // new continuation merged into previous - stop update
4089#ifdef DEBUG_ACTIONSTEPS
4090 if (DEBUG_COND) {
4091 std::cout << "Old and new continuation sequences merge at link\n"
4092 << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
4093 << "\nNo update beyond merge required." << std::endl;
4094 }
4095#endif
4096 break;
4097 }
4098
4099#ifdef DEBUG_ACTIONSTEPS
4100 if (DEBUG_COND) {
4101 std::cout << "lane=" << lane->getID() << "\nUpdating link\n '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
4102 << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
4103 }
4104#endif
4105 newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
4106 driveItemIt->myLink->removeApproaching(this);
4107 driveItemIt->myLink = newLink;
4108 lane = newLink->getViaLaneOrLane();
4109 ++driveItemIt;
4110 if (!lane->isInternal()) {
4111 ++bestLaneIt;
4112 }
4113 }
4114#ifdef DEBUG_ACTIONSTEPS
4115 if (DEBUG_COND) {
4116 std::cout << "Updated drive items:" << std::endl;
4117 for (const auto& dpi : myLFLinkLanes) {
4118 std::cout
4119 << " vPass=" << dpi.myVLinkPass
4120 << " vWait=" << dpi.myVLinkWait
4121 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4122 << " request=" << dpi.mySetRequest
4123 << "\n";
4124 }
4125 }
4126#endif
4127}
4128
4129
4130void
4132 // To avoid casual blinking brake lights at high speeds due to dawdling of the
4133 // leading vehicle, we don't show brake lights when the deceleration could be caused
4134 // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
4135 double pseudoFriction = (0.05 + 0.005 * getSpeed()) * getSpeed();
4136 bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
4137
4138 if (vNext <= SUMO_const_haltingSpeed) {
4139 brakelightsOn = true;
4140 }
4141 if (brakelightsOn && !isStopped()) {
4143 } else {
4145 }
4146}
4147
4148
4149void
4154 } else {
4155 myWaitingTime = 0;
4157 if (hasInfluencer()) {
4159 }
4160 }
4161}
4162
4163
4164void
4166 // update time loss (depends on the updated edge)
4167 if (!isStopped()) {
4168 const double vmax = myLane->getVehicleMaxSpeed(this);
4169 if (vmax > 0) {
4170 myTimeLoss += TS * (vmax - vNext) / vmax;
4171 }
4172 }
4173}
4174
4175
4176double
4177MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
4178 const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
4179 || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
4180#ifdef DEBUG_REVERSE_BIDI
4181 if (DEBUG_COND) std::cout << SIMTIME << " checkReversal lane=" << myLane->getID()
4182 << " pos=" << myState.myPos
4183 << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
4184 << " speedThreshold=" << speedThreshold
4185 << " seen=" << seen
4186 << " isRail=" << isRail()
4187 << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
4188 << " posOK=" << (myState.myPos <= myLane->getLength())
4189 << " normal=" << !myLane->isInternal()
4190 << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
4191 << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
4192 << " stopOk=" << stopOk
4193 << "\n";
4194#endif
4195 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4196 && getPreviousSpeed() <= speedThreshold
4197 && myState.myPos <= myLane->getLength()
4198 && !myLane->isInternal()
4199 && (myCurrEdge + 1) != myRoute->end()
4200 && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
4201 // ensure there are no further stops on this edge
4202 && stopOk
4203 ) {
4204 //if (isSelected()) std::cout << " check1 passed\n";
4205
4206 // ensure that the vehicle is fully on bidi edges that allow reversal
4207 const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
4208 ? myFurtherLanes.size()
4209 : ceil((double)myFurtherLanes.size() / 2.0));
4210 const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
4211 if (remainingRoute < neededFutureRoute) {
4212#ifdef DEBUG_REVERSE_BIDI
4213 if (DEBUG_COND) {
4214 std::cout << " fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
4215 }
4216#endif
4217 return getMaxSpeed();
4218 }
4219 //if (isSelected()) std::cout << " check2 passed\n";
4220
4221 // ensure that the turn-around connection exists from the current edge to its bidi-edge
4222 const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
4223 if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
4224#ifdef DEBUG_REVERSE_BIDI
4225 if (DEBUG_COND) {
4226 std::cout << " noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
4227 }
4228#endif
4229 return getMaxSpeed();
4230 }
4231 //if (isSelected()) std::cout << " check3 passed\n";
4232
4233 // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
4234 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
4235 const double stopPos = myStops.front().getEndPos(*this);
4236 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4237 const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
4238 if (newPos > stopPos) {
4239#ifdef DEBUG_REVERSE_BIDI
4240 if (DEBUG_COND) {
4241 std::cout << " reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
4242 }
4243#endif
4244 if (seen > MAX2(brakeDist, 1.0)) {
4245 return getMaxSpeed();
4246 } else {
4247#ifdef DEBUG_REVERSE_BIDI
4248 if (DEBUG_COND) {
4249 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4250 }
4251#endif
4252 }
4253 }
4254 }
4255 //if (isSelected()) std::cout << " check4 passed\n";
4256
4257 // ensure that bidi-edges exist for all further edges
4258 // and that no stops will be skipped when reversing
4259 // and that the train will not be on top of a red rail signal after reversal
4260 const MSLane* bidi = myLane->getBidiLane();
4261 int view = 2;
4262 for (MSLane* further : myFurtherLanes) {
4263 if (!further->getEdge().isInternal()) {
4264 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
4265#ifdef DEBUG_REVERSE_BIDI
4266 if (DEBUG_COND) {
4267 std::cout << " noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
4268 }
4269#endif
4270 return getMaxSpeed();
4271 }
4272 const MSLane* nextBidi = further->getBidiLane();
4273 const MSLink* toNext = bidi->getLinkTo(nextBidi);
4274 if (toNext == nullptr) {
4275 // can only happen if the route is invalid
4276 return getMaxSpeed();
4277 }
4278 if (toNext->haveRed()) {
4279#ifdef DEBUG_REVERSE_BIDI
4280 if (DEBUG_COND) {
4281 std::cout << " do not reverse on a red signal\n";
4282 }
4283#endif
4284 return getMaxSpeed();
4285 }
4286 bidi = nextBidi;
4287 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
4288 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4289 const double stopPos = myStops.front().getEndPos(*this);
4290 const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
4291 if (newPos > stopPos) {
4292#ifdef DEBUG_REVERSE_BIDI
4293 if (DEBUG_COND) {
4294 std::cout << " reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
4295 }
4296#endif
4297 if (seen > MAX2(brakeDist, 1.0)) {
4298 canReverse = false;
4299 return getMaxSpeed();
4300 } else {
4301#ifdef DEBUG_REVERSE_BIDI
4302 if (DEBUG_COND) {
4303 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4304 }
4305#endif
4306 }
4307 }
4308 }
4309 view++;
4310 }
4311 }
4312 // reverse as soon as comfortably possible
4313 const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
4314#ifdef DEBUG_REVERSE_BIDI
4315 if (DEBUG_COND) {
4316 std::cout << SIMTIME << " seen=" << seen << " vReverseOK=" << vMinComfortable << "\n";
4317 }
4318#endif
4319 canReverse = true;
4320 return vMinComfortable;
4321 }
4322 return getMaxSpeed();
4323}
4324
4325
4326void
4327MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
4328 for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
4329 passedLanes.push_back(*i);
4330 }
4331 if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
4332 passedLanes.push_back(myLane);
4333 }
4334 // let trains reverse direction
4335 bool reverseTrain = false;
4336 checkReversal(reverseTrain);
4337 if (reverseTrain) {
4338 // Train is 'reversing' so toggle the logical state
4340 // add some slack to ensure that the back of train does appear looped
4341 myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
4342 myState.mySpeed = 0;
4343#ifdef DEBUG_REVERSE_BIDI
4344 if (DEBUG_COND) {
4345 std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
4346 }
4347#endif
4348 }
4349 // move on lane(s)
4350 if (myState.myPos > myLane->getLength()) {
4351 // The vehicle has moved at least to the next lane (maybe it passed even more than one)
4352 if (myCurrEdge != myRoute->end() - 1) {
4353 MSLane* approachedLane = myLane;
4354 // move the vehicle forward
4356 while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
4357 const MSLink* link = myNextDriveItem->myLink;
4358 const double linkDist = myNextDriveItem->myDistance;
4360 // check whether the vehicle was allowed to enter lane
4361 // otherwise it is decelerated and we do not need to test for it's
4362 // approach on the following lanes when a lane changing is performed
4363 // proceed to the next lane
4364 if (approachedLane->mustCheckJunctionCollisions()) {
4365 // vehicle moves past approachedLane within a single step, collision checking must still be done
4367 }
4368 if (link != nullptr) {
4369 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4370 && !myLane->isInternal()
4371 && myLane->getBidiLane() != nullptr
4372 && link->getLane()->getBidiLane() == myLane
4373 && !reverseTrain) {
4374 emergencyReason = " because it must reverse direction";
4375 approachedLane = nullptr;
4376 break;
4377 }
4378 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4379 && myState.myPos < myLane->getLength() + NUMERICAL_EPS
4380 && hasStops() && getNextStop().edge == myCurrEdge) {
4381 // avoid skipping stop due to numerical instability
4382 // this is a special case for rail vehicles because they
4383 // continue myLFLinkLanes past stops
4384 approachedLane = myLane;
4386 break;
4387 }
4388 approachedLane = link->getViaLaneOrLane();
4390 bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
4391 if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
4392 emergencyReason = " because of a red traffic light";
4393 break;
4394 }
4395 }
4396 if (reverseTrain && approachedLane->isInternal()) {
4397 // avoid getting stuck on a slow turn-around internal lane
4398 myState.myPos += approachedLane->getLength();
4399 }
4400 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4401 // avoid warning due to numerical instability
4402 approachedLane = myLane;
4404 } else if (reverseTrain) {
4405 approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
4406 link = myLane->getLinkTo(approachedLane);
4407 assert(link != 0);
4408 while (link->getViaLane() != nullptr) {
4409 link = link->getViaLane()->getLinkCont()[0];
4410 }
4412 } else {
4413 emergencyReason = " because there is no connection to the next edge";
4414 approachedLane = nullptr;
4415 break;
4416 }
4417 if (approachedLane != myLane && approachedLane != nullptr) {
4420 assert(myState.myPos > 0);
4421 enterLaneAtMove(approachedLane);
4422 if (link->isEntryLink()) {
4425 myHaveStoppedFor = nullptr;
4426 }
4427 if (link->isConflictEntryLink()) {
4429 // renew yielded request
4431 }
4432 if (link->isExitLink()) {
4433 // passed junction, reset for approaching the next one
4437 }
4438#ifdef DEBUG_PLAN_MOVE_LEADERINFO
4439 if (DEBUG_COND) {
4440 std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
4441 << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
4442 << " ET=" << myJunctionEntryTime
4443 << " ETN=" << myJunctionEntryTimeNeverYield
4444 << " CET=" << myJunctionConflictEntryTime
4445 << "\n";
4446 }
4447#endif
4448 if (hasArrivedInternal()) {
4449 break;
4450 }
4453 // abort lane change
4454 WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
4455 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4457 }
4458 }
4459 if (approachedLane->getEdge().isVaporizing()) {
4461 break;
4462 }
4463 passedLanes.push_back(approachedLane);
4464 }
4465 }
4466 // NOTE: Passed drive items will be erased in the next simstep's planMove()
4467
4468#ifdef DEBUG_ACTIONSTEPS
4469 if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
4470 std::cout << "Updated drive items:" << std::endl;
4471 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
4472 std::cout
4473 << " vPass=" << (*i).myVLinkPass
4474 << " vWait=" << (*i).myVLinkWait
4475 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
4476 << " request=" << (*i).mySetRequest
4477 << "\n";
4478 }
4479 }
4480#endif
4481 } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4482 // avoid warning due to numerical instability when stopping at the end of the route
4484 }
4485
4486 }
4487}
4488
4489
4490
4491bool
4493#ifdef DEBUG_EXEC_MOVE
4494 if (DEBUG_COND) {
4495 std::cout << "\nEXECUTE_MOVE\n"
4496 << SIMTIME
4497 << " veh=" << getID()
4498 << " speed=" << getSpeed() // toString(getSpeed(), 24)
4499 << std::endl;
4500 }
4501#endif
4502
4503
4504 // Maximum safe velocity
4505 double vSafe = std::numeric_limits<double>::max();
4506 // Minimum safe velocity (lower bound).
4507 double vSafeMin = -std::numeric_limits<double>::max();
4508 // The distance to a link, which should either be crossed this step
4509 // or in front of which we need to stop.
4510 double vSafeMinDist = 0;
4511
4512 if (myActionStep) {
4513 // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
4514 processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
4515#ifdef DEBUG_ACTIONSTEPS
4516 if (DEBUG_COND) {
4517 std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
4518 " vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
4519 }
4520#endif
4521 } else {
4522 // Continue with current acceleration
4523 vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
4524#ifdef DEBUG_ACTIONSTEPS
4525 if (DEBUG_COND) {
4526 std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
4527 " continues with constant accel " << myAcceleration << "...\n"
4528 << "speed: " << getSpeed() << " -> " << vSafe << std::endl;
4529 }
4530#endif
4531 }
4532
4533
4534//#ifdef DEBUG_EXEC_MOVE
4535// if (DEBUG_COND) {
4536// std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
4537// }
4538//#endif
4539
4540 // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
4541 // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
4542 double vNext = vSafe;
4543 const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
4544 if (vNext <= SUMO_const_haltingSpeed * TS && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting() && myActionStep) {
4546 } else if (isStopped()) {
4547 // do not apply startupDelay for waypoints
4548 if (getCarFollowModel().startupDelayStopped() && getNextStop().pars.speed <= 0) {
4550 } else {
4551 // do not apply startupDelay but signal that a stop has taken place
4553 }
4554 } else {
4555 // identify potential startup (before other effects reduce the speed again)
4557 }
4558 if (myActionStep) {
4559 vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
4560 if (vNext > 0) {
4561 vNext = MAX2(vNext, vSafeMin);
4562 }
4563 }
4564 // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
4565 // (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
4566 // (Jakob) We also need to make sure to reach a stop at the start of the next edge
4567 if (fabs(vNext) < NUMERICAL_EPS_SPEED && myStopDist > POSITION_EPS) {
4568 vNext = 0.;
4569 }
4570#ifdef DEBUG_EXEC_MOVE
4571 if (DEBUG_COND) {
4572 std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
4573 << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
4574 }
4575#endif
4576
4577 // vNext may be higher than vSafe without implying a bug:
4578 // - when approaching a green light that suddenly switches to yellow
4579 // - when using unregulated junctions
4580 // - when using tau < step-size
4581 // - when using unsafe car following models
4582 // - when using TraCI and some speedMode / laneChangeMode settings
4583 //if (vNext > vSafe + NUMERICAL_EPS) {
4584 // WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
4585 // + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
4586 // + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4587 //}
4588
4590 vNext = MAX2(vNext, 0.);
4591 } else {
4592 // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
4593 }
4594
4595 // Check for speed advices from the traci client
4596 vNext = processTraCISpeedControl(vSafe, vNext);
4597
4598 // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
4599 MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
4600 if (elecHybridOfVehicle != nullptr) {
4601 // this is the consumption given by the car following model-computed acceleration
4602 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4603 // but the maximum power of the electric motor may be lower
4604 // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
4605 double maxPower = getEmissionParameters()->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 100000.) / 3600;
4606 if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
4607 // no, we cannot accelerate that fast, recompute the maximum possible acceleration
4608 double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
4609 // and update the speed of the vehicle
4610 vNext = MIN2(vNext, this->getSpeed() + accel * TS);
4611 vNext = MAX2(vNext, 0.);
4612 // and set the vehicle consumption to reflect this
4613 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4614 }
4615 }
4616
4617 setBrakingSignals(vNext);
4618
4619 // update position and speed
4620 int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
4621 const MSLane* oldLaneMaybeOpposite = myLane;
4623 // transform to the forward-direction lane, move and then transform back
4626 }
4627 updateState(vNext);
4628 updateWaitingTime(vNext);
4629
4630 // Lanes, which the vehicle touched at some moment of the executed simstep
4631 std::vector<MSLane*> passedLanes;
4632 // remember previous lane (myLane is updated in processLaneAdvances)
4633 const MSLane* oldLane = myLane;
4634 // Reason for a possible emergency stop
4635 std::string emergencyReason;
4636 processLaneAdvances(passedLanes, emergencyReason);
4637
4638 updateTimeLoss(vNext);
4640
4642 if (myState.myPos > myLane->getLength()) {
4643 if (emergencyReason == "") {
4644 emergencyReason = TL(" for unknown reasons");
4645 }
4646 WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
4647 getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
4652 myState.mySpeed = 0;
4653 myAcceleration = 0;
4654 }
4655 const MSLane* oldBackLane = getBackLane();
4657 passedLanes.clear(); // ignore back occupation
4658 }
4659#ifdef DEBUG_ACTIONSTEPS
4660 if (DEBUG_COND) {
4661 std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
4662 }
4663#endif
4665 if (passedLanes.size() > 1 && isRail()) {
4666 for (auto pi = passedLanes.rbegin(); pi != passedLanes.rend(); ++pi) {
4667 MSLane* pLane = *pi;
4668 if (pLane != myLane && std::find(myFurtherLanes.begin(), myFurtherLanes.end(), pLane) == myFurtherLanes.end()) {
4670 }
4671 }
4672 }
4673 // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
4675 if (myLane != oldLane || oldBackLane != getBackLane()) {
4676 if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
4677 // shadow lane must be updated if the front or back lane changed
4678 // either if we already have a shadowLane or if there is lateral overlap
4680 }
4682 // The vehicles target lane must be also be updated if the front or back lane changed
4684 }
4685 }
4686 setBlinkerInformation(); // needs updated bestLanes
4687 //change the blue light only for emergency vehicles SUMOVehicleClass
4689 setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
4690 }
4691 // must be done before angle computation
4692 // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
4693 if (myActionStep) {
4694 // check (#2681): Can this be skipped?
4696 } else {
4698#ifdef DEBUG_ACTIONSTEPS
4699 if (DEBUG_COND) {
4700 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
4701 }
4702#endif
4703 }
4706 }
4707
4708#ifdef DEBUG_EXEC_MOVE
4709 if (DEBUG_COND) {
4710 std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
4711 gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
4712 }
4713#endif
4715 // transform back to the opposite-direction lane
4716 MSLane* newOpposite = nullptr;
4717 const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
4718 if (newOppositeEdge != nullptr) {
4719 newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
4720#ifdef DEBUG_EXEC_MOVE
4721 if (DEBUG_COND) {
4722 std::cout << SIMTIME << " newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
4723 }
4724#endif
4725 }
4726 if (newOpposite == nullptr) {
4728 // unusual overtaking at junctions is ok for emergency vehicles
4729 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
4731 }
4733 if (myState.myPos < getLength()) {
4734 // further lanes is always cleared during opposite driving
4735 MSLane* oldOpposite = oldLane->getOpposite();
4736 if (oldOpposite != nullptr) {
4737 myFurtherLanes.push_back(oldOpposite);
4738 myFurtherLanesPosLat.push_back(0);
4739 // small value since the lane is going in the other direction
4742 } else {
4743 SOFT_ASSERT(false);
4744 }
4745 }
4746 } else {
4748 myLane = newOpposite;
4749 oldLane = oldLaneMaybeOpposite;
4750 //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
4753 }
4754 }
4756 // Return whether the vehicle did move to another lane
4757 return myLane != oldLane;
4758}
4759
4760void
4762 myState.myPos += dist;
4765
4766 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
4768 for (int i = 0; i < (int)lanes.size(); i++) {
4769 MSLink* link = nullptr;
4770 if (i + 1 < (int)lanes.size()) {
4771 const MSLane* const to = lanes[i + 1];
4772 const bool internal = to->isInternal();
4773 for (MSLink* const l : lanes[i]->getLinkCont()) {
4774 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
4775 link = l;
4776 break;
4777 }
4778 }
4779 }
4780 myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
4781 }
4782 // minimum execute move:
4783 std::vector<MSLane*> passedLanes;
4784 // Reason for a possible emergency stop
4785 if (lanes.size() > 1) {
4787 }
4788 std::string emergencyReason;
4789 processLaneAdvances(passedLanes, emergencyReason);
4790#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
4791 if (DEBUG_COND) {
4792 std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
4793 << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
4794 << " finalPos=" << myState.myPos
4795 << " speed=" << getSpeed()
4796 << " myFurtherLanes=" << toString(myFurtherLanes)
4797 << "\n";
4798 }
4799#endif
4801 if (lanes.size() > 1) {
4802 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
4803#ifdef DEBUG_FURTHER
4804 if (DEBUG_COND) {
4805 std::cout << SIMTIME << " leaveLane \n";
4806 }
4807#endif
4808 (*i)->resetPartialOccupation(this);
4809 }
4810 myFurtherLanes.clear();
4811 myFurtherLanesPosLat.clear();
4813 }
4814}
4815
4816
4817void
4819 // update position and speed
4820 double deltaPos; // positional change
4822 // euler
4823 deltaPos = SPEED2DIST(vNext);
4824 } else {
4825 // ballistic
4826 deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
4827 }
4828
4829 // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
4830 // NOTE: for the ballistic update vNext may be negative, indicating a stop.
4832
4833#ifdef DEBUG_EXEC_MOVE
4834 if (DEBUG_COND) {
4835 std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
4836 << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
4837 }
4838#endif
4839 double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
4840 if (decelPlus > 0) {
4841 const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
4842 if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
4843 // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
4844 decelPlus += 2 * NUMERICAL_EPS;
4845 const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
4846 if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
4847 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
4848 //+ " decelPlus=" + toString(decelPlus)
4849 //+ " prevAccel=" + toString(previousAcceleration)
4850 //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
4851 getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
4853 }
4854 }
4855 }
4856
4858 myState.mySpeed = MAX2(vNext, 0.);
4859
4860 if (isRemoteControlled()) {
4861 deltaPos = myInfluencer->implicitDeltaPosRemote(this);
4862 }
4863
4864 myState.myPos += deltaPos;
4865 myState.myLastCoveredDist = deltaPos;
4866 myNextTurn.first -= deltaPos;
4867
4869}
4870
4871void
4873 updateState(0);
4874 // deboard while parked
4875 if (myPersonDevice != nullptr) {
4877 }
4878 if (myContainerDevice != nullptr) {
4880 }
4881 for (MSVehicleDevice* const dev : myDevices) {
4882 dev->notifyParking();
4883 }
4884}
4885
4886
4887void
4893
4894
4895const MSLane*
4897 if (myFurtherLanes.size() > 0) {
4898 return myFurtherLanes.back();
4899 } else {
4900 return myLane;
4901 }
4902}
4903
4904
4905double
4906MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
4907 const std::vector<MSLane*>& passedLanes) {
4908#ifdef DEBUG_SETFURTHER
4909 if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
4910 << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
4911 << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
4912 << " passed=" << toString(passedLanes)
4913 << "\n";
4914#endif
4915 for (MSLane* further : furtherLanes) {
4916 further->resetPartialOccupation(this);
4917 if (further->getBidiLane() != nullptr
4918 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4919 further->getBidiLane()->resetPartialOccupation(this);
4920 }
4921 }
4922
4923 std::vector<MSLane*> newFurther;
4924 std::vector<double> newFurtherPosLat;
4925 double backPosOnPreviousLane = myState.myPos - getLength();
4926 bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
4927 if (passedLanes.size() > 1) {
4928 // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
4929 std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
4930 std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
4931 for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
4932 // As long as vehicle back reaches into passed lane, add it to the further lanes
4933 MSLane* further = *pi;
4934 newFurther.push_back(further);
4935 backPosOnPreviousLane += further->setPartialOccupation(this);
4936 if (further->getBidiLane() != nullptr
4937 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4938 further->getBidiLane()->setPartialOccupation(this);
4939 }
4940 if (fi != furtherLanes.end() && further == *fi) {
4941 // Lateral position on this lane is already known. Assume constant and use old value.
4942 newFurtherPosLat.push_back(*fpi);
4943 ++fi;
4944 ++fpi;
4945 } else {
4946 // The lane *pi was not in furtherLanes before.
4947 // If it is downstream, we assume as lateral position the current position
4948 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
4949 // we assign the last known lateral position.
4950 if (newFurtherPosLat.size() == 0) {
4951 if (widthShift) {
4952 newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
4953 } else {
4954 newFurtherPosLat.push_back(myState.myPosLat);
4955 }
4956 } else {
4957 newFurtherPosLat.push_back(newFurtherPosLat.back());
4958 }
4959 }
4960#ifdef DEBUG_SETFURTHER
4961 if (DEBUG_COND) {
4962 std::cout << SIMTIME << " updateFurtherLanes \n"
4963 << " further lane '" << further->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
4964 << std::endl;
4965 }
4966#endif
4967 }
4968 furtherLanes = newFurther;
4969 furtherLanesPosLat = newFurtherPosLat;
4970 } else {
4971 furtherLanes.clear();
4972 furtherLanesPosLat.clear();
4973 }
4974#ifdef DEBUG_SETFURTHER
4975 if (DEBUG_COND) std::cout
4976 << " newFurther=" << toString(furtherLanes)
4977 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
4978 << " newBackPos=" << backPosOnPreviousLane
4979 << "\n";
4980#endif
4981 return backPosOnPreviousLane;
4982}
4983
4984
4985double
4986MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
4987#ifdef DEBUG_FURTHER
4988 if (DEBUG_COND) {
4989 std::cout << SIMTIME
4990 << " getBackPositionOnLane veh=" << getID()
4991 << " lane=" << Named::getIDSecure(lane)
4992 << " cbgP=" << calledByGetPosition
4993 << " pos=" << myState.myPos
4994 << " backPos=" << myState.myBackPos
4995 << " myLane=" << myLane->getID()
4996 << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
4997 << " further=" << toString(myFurtherLanes)
4998 << " furtherPosLat=" << toString(myFurtherLanesPosLat)
4999 << "\n shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
5000 << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
5001 << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
5002 << "\n targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
5003 << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
5004 << std::endl;
5005 }
5006#endif
5007 if (lane == myLane
5008 || lane == myLaneChangeModel->getShadowLane()
5009 || lane == myLaneChangeModel->getTargetLane()) {
5011 if (lane == myLaneChangeModel->getShadowLane()) {
5012 return lane->getLength() - myState.myPos - myType->getLength();
5013 } else {
5014 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5015 }
5016 } else if (&lane->getEdge() != &myLane->getEdge()) {
5017 return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5018 } else {
5019 // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
5020 return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
5021 }
5022 } else if (lane == myLane->getBidiLane()) {
5023 return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
5024 } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
5025 return myState.myBackPos;
5026 } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
5027 || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
5028 assert(myFurtherLanes.size() > 0);
5029 if (lane->getLength() == myFurtherLanes.back()->getLength()) {
5030 return myState.myBackPos;
5031 } else {
5032 // interpolate
5033 //if (DEBUG_COND) {
5034 //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
5035 // std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
5036 // << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
5037 // << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
5038 //}
5039 return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
5040 }
5041 } else {
5042 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
5043 double leftLength = myType->getLength() - myState.myPos;
5044
5045 std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
5046 while (leftLength > 0 && i != myFurtherLanes.end()) {
5047 leftLength -= (*i)->getLength();
5048 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5049 if (*i == lane) {
5050 return -leftLength;
5051 } else if (*i == lane->getBidiLane()) {
5052 return lane->getLength() + leftLength - (calledByGetPosition ? 2 * myType->getLength() : 0);
5053 }
5054 ++i;
5055 }
5056 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
5057 leftLength = myType->getLength() - myState.myPos;
5059 while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
5060 leftLength -= (*i)->getLength();
5061 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5062 if (*i == lane) {
5063 return -leftLength;
5064 }
5065 ++i;
5066 }
5067 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
5068 leftLength = myType->getLength() - myState.myPos;
5069 i = getFurtherLanes().begin();
5070 const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
5071 auto j = furtherTargetLanes.begin();
5072 while (leftLength > 0 && j != furtherTargetLanes.end()) {
5073 leftLength -= (*i)->getLength();
5074 // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5075 if (*j == lane) {
5076 return -leftLength;
5077 }
5078 ++i;
5079 ++j;
5080 }
5081 WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
5082 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
5083 SOFT_ASSERT(false);
5084 return myState.myBackPos;
5085 }
5086}
5087
5088
5089double
5091 return getBackPositionOnLane(lane, true) + myType->getLength();
5092}
5093
5094
5095bool
5097 return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
5098}
5099
5100
5101void
5102MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
5104 double seenSpace = -lengthsInFront;
5105#ifdef DEBUG_CHECKREWINDLINKLANES
5106 if (DEBUG_COND) {
5107 std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
5108 };
5109#endif
5110 bool foundStopped = false;
5111 // compute available space until a stopped vehicle is found
5112 // this is the sum of non-interal lane length minus in-between vehicle lengths
5113 for (int i = 0; i < (int)lfLinks.size(); ++i) {
5114 // skip unset links
5115 DriveProcessItem& item = lfLinks[i];
5116#ifdef DEBUG_CHECKREWINDLINKLANES
5117 if (DEBUG_COND) std::cout << SIMTIME
5118 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5119 << " foundStopped=" << foundStopped;
5120#endif
5121 if (item.myLink == nullptr || foundStopped) {
5122 if (!foundStopped) {
5123 item.availableSpace += seenSpace;
5124 } else {
5125 item.availableSpace = seenSpace;
5126 }
5127#ifdef DEBUG_CHECKREWINDLINKLANES
5128 if (DEBUG_COND) {
5129 std::cout << " avail=" << item.availableSpace << "\n";
5130 }
5131#endif
5132 continue;
5133 }
5134 // get the next lane, determine whether it is an internal lane
5135 const MSLane* approachedLane = item.myLink->getViaLane();
5136 if (approachedLane != nullptr) {
5137 if (keepClear(item.myLink)) {
5138 seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
5139 if (approachedLane == myLane) {
5140 seenSpace += getVehicleType().getLengthWithGap();
5141 }
5142 } else {
5143 seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
5144 }
5145 item.availableSpace = seenSpace;
5146#ifdef DEBUG_CHECKREWINDLINKLANES
5147 if (DEBUG_COND) std::cout
5148 << " approached=" << approachedLane->getID()
5149 << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
5150 << " avail=" << item.availableSpace
5151 << " seenSpace=" << seenSpace
5152 << " hadStoppedVehicle=" << item.hadStoppedVehicle
5153 << " lengthsInFront=" << lengthsInFront
5154 << "\n";
5155#endif
5156 continue;
5157 }
5158 approachedLane = item.myLink->getLane();
5159 const MSVehicle* last = approachedLane->getLastAnyVehicle();
5160 if (last == nullptr || last == this) {
5161 if (approachedLane->getLength() > getVehicleType().getLength()
5162 || keepClear(item.myLink)) {
5163 seenSpace += approachedLane->getLength();
5164 }
5165 item.availableSpace = seenSpace;
5166#ifdef DEBUG_CHECKREWINDLINKLANES
5167 if (DEBUG_COND) {
5168 std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
5169 }
5170#endif
5171 } else {
5172 bool foundStopped2 = false;
5173 double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
5174 if (approachedLane->getBidiLane() != nullptr) {
5175 const MSVehicle* oncomingVeh = approachedLane->getBidiLane()->getFirstFullVehicle();
5176 if (oncomingVeh) {
5177 const double oncomingGap = approachedLane->getLength() - oncomingVeh->getPositionOnLane();
5178 const double oncomingBGap = oncomingVeh->getBrakeGap(true);
5179 // oncoming movement until ego enters the junction
5180 const double oncomingMove = STEPS2TIME(item.myArrivalTime - SIMSTEP) * oncomingVeh->getSpeed();
5181 const double spaceTillOncoming = oncomingGap - oncomingBGap - oncomingMove;
5182 spaceTillLastStanding = MIN2(spaceTillLastStanding, spaceTillOncoming);
5183 if (spaceTillOncoming <= getVehicleType().getLengthWithGap()) {
5184 foundStopped = true;
5185 }
5186#ifdef DEBUG_CHECKREWINDLINKLANES
5187 if (DEBUG_COND) {
5188 std::cout << " oVeh=" << oncomingVeh->getID()
5189 << " oGap=" << oncomingGap
5190 << " bGap=" << oncomingBGap
5191 << " mGap=" << oncomingMove
5192 << " sto=" << spaceTillOncoming;
5193 }
5194#endif
5195 }
5196 }
5197 seenSpace += spaceTillLastStanding;
5198 if (foundStopped2) {
5199 foundStopped = true;
5200 item.hadStoppedVehicle = true;
5201 }
5202 item.availableSpace = seenSpace;
5203 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
5204 foundStopped = true;
5205 item.hadStoppedVehicle = true;
5206 }
5207#ifdef DEBUG_CHECKREWINDLINKLANES
5208 if (DEBUG_COND) std::cout
5209 << " approached=" << approachedLane->getID()
5210 << " last=" << last->getID()
5211 << " lastHasToWait=" << last->myHaveToWaitOnNextLink
5212 << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
5213 << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
5214 << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
5215 // gap of last up to the next intersection
5216 - last->getVehicleType().getMinGap())
5217 << " stls=" << spaceTillLastStanding
5218 << " avail=" << item.availableSpace
5219 << " seenSpace=" << seenSpace
5220 << " foundStopped=" << foundStopped
5221 << " foundStopped2=" << foundStopped2
5222 << "\n";
5223#endif
5224 }
5225 }
5226
5227 // check which links allow continuation and add pass available to the previous item
5228 for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
5229 DriveProcessItem& item = lfLinks[i - 1];
5230 DriveProcessItem& nextItem = lfLinks[i];
5231 const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
5232 const bool opened = (item.myLink != nullptr
5233 && (canLeaveJunction || (
5234 // indirect bicycle turn
5235 nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
5236 && (
5237 item.myLink->havePriority()
5238 || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
5240 || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
5243 bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
5244#ifdef DEBUG_CHECKREWINDLINKLANES
5245 if (DEBUG_COND) std::cout
5246 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5247 << " canLeave=" << canLeaveJunction
5248 << " opened=" << opened
5249 << " allowsContinuation=" << allowsContinuation
5250 << " foundStopped=" << foundStopped
5251 << "\n";
5252#endif
5253 if (!opened && item.myLink != nullptr) {
5254 foundStopped = true;
5255 if (i > 1) {
5256 DriveProcessItem& item2 = lfLinks[i - 2];
5257 if (item2.myLink != nullptr && item2.myLink->isCont()) {
5258 allowsContinuation = true;
5259 }
5260 }
5261 }
5262 if (allowsContinuation) {
5263 item.availableSpace = nextItem.availableSpace;
5264#ifdef DEBUG_CHECKREWINDLINKLANES
5265 if (DEBUG_COND) std::cout
5266 << " link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5267 << " copy nextAvail=" << nextItem.availableSpace
5268 << "\n";
5269#endif
5270 }
5271 }
5272
5273 // find removalBegin
5274 int removalBegin = -1;
5275 for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
5276 // skip unset links
5277 const DriveProcessItem& item = lfLinks[i];
5278 if (item.myLink == nullptr) {
5279 continue;
5280 }
5281 /*
5282 double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
5283 if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
5284 removalBegin = lastLinkToInternal;
5285 }
5286 */
5287
5288 const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
5289#ifdef DEBUG_CHECKREWINDLINKLANES
5290 if (DEBUG_COND) std::cout
5291 << SIMTIME
5292 << " veh=" << getID()
5293 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5294 << " avail=" << item.availableSpace
5295 << " leftSpace=" << leftSpace
5296 << "\n";
5297#endif
5298 if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
5299 double impatienceCorrection = 0;
5300 /*
5301 if(item.myLink->getState()==LINKSTATE_MINOR) {
5302 impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
5303 }
5304 */
5305 // may ignore keepClear rules
5306 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
5307 removalBegin = i;
5308 }
5309 //removalBegin = i;
5310 }
5311 }
5312 // abort requests
5313 if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
5314 const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
5315 while (removalBegin < (int)(lfLinks.size())) {
5316 DriveProcessItem& dpi = lfLinks[removalBegin];
5317 if (dpi.myLink == nullptr) {
5318 break;
5319 }
5320 dpi.myVLinkPass = dpi.myVLinkWait;
5321#ifdef DEBUG_CHECKREWINDLINKLANES
5322 if (DEBUG_COND) {
5323 std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
5324 }
5325#endif
5326 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
5327 // always leave junctions after requesting to enter
5328 if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
5329 dpi.mySetRequest = false;
5330 }
5331 }
5332 ++removalBegin;
5333 }
5334 }
5335 }
5336}
5337
5338
5339void
5341 if (!checkActionStep(t)) {
5342 return;
5343 }
5345 for (DriveProcessItem& dpi : myLFLinkLanes) {
5346 if (dpi.myLink != nullptr) {
5347 if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
5348 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
5349 }
5350 dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5351 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance, getLateralPositionOnLane());
5352 }
5353 }
5354 if (isRail()) {
5355 for (DriveProcessItem& dpi : myLFLinkLanes) {
5356 if (dpi.myLink != nullptr && dpi.myLink->getTLLogic() != nullptr && dpi.myLink->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
5358 }
5359 }
5360 }
5361 if (myLaneChangeModel->getShadowLane() != nullptr) {
5362 // register on all shadow links
5363 for (const DriveProcessItem& dpi : myLFLinkLanes) {
5364 if (dpi.myLink != nullptr) {
5365 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
5366 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
5367 // register on opposite direction entry link to warn foes at minor side road
5368 parallelLink = dpi.myLink->getOppositeDirectionLink();
5369 }
5370 if (parallelLink != nullptr) {
5371 const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
5372 parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5373 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance,
5374 latOffset);
5376 }
5377 }
5378 }
5379 }
5380#ifdef DEBUG_PLAN_MOVE
5381 if (DEBUG_COND) {
5382 std::cout << SIMTIME
5383 << " veh=" << getID()
5384 << " after checkRewindLinkLanes\n";
5385 for (DriveProcessItem& dpi : myLFLinkLanes) {
5386 std::cout
5387 << " vPass=" << dpi.myVLinkPass
5388 << " vWait=" << dpi.myVLinkWait
5389 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
5390 << " request=" << dpi.mySetRequest
5391 << " atime=" << dpi.myArrivalTime
5392 << "\n";
5393 }
5394 }
5395#endif
5396}
5397
5398
5399void
5401 DriveProcessItem dpi(0, dist);
5402 dpi.myLink = link;
5403 const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
5404 link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
5405 // ensure cleanup in the next step
5406 myLFLinkLanes.push_back(dpi);
5408}
5409
5410
5411void
5412MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
5413 myAmOnNet = !onTeleporting;
5414 // vaporizing edge?
5415 /*
5416 if (enteredLane->getEdge().isVaporizing()) {
5417 // yep, let's do the vaporization...
5418 myLane = enteredLane;
5419 return true;
5420 }
5421 */
5422 // Adjust MoveReminder offset to the next lane
5423 adaptLaneEntering2MoveReminder(*enteredLane);
5424 // set the entered lane as the current lane
5425 MSLane* oldLane = myLane;
5426 myLane = enteredLane;
5427 myLastBestLanesEdge = nullptr;
5428
5429 // internal edges are not a part of the route...
5430 if (!enteredLane->getEdge().isInternal()) {
5431 ++myCurrEdge;
5433 }
5434 if (myInfluencer != nullptr) {
5436 }
5437 if (!onTeleporting) {
5440 // transform lateral position when the lane width changes
5441 assert(oldLane != nullptr);
5442 const MSLink* const link = oldLane->getLinkTo(myLane);
5443 if (link != nullptr) {
5445 myState.myPosLat += link->getLateralShift();
5446 }
5447 } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
5448 const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
5449 const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5450 const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5451 myState.myPosLat *= range2 / range;
5452 }
5453 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5454 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5455 // (unless the lane is shared with cars)
5457 }
5458 } else {
5459 // normal move() isn't called so reset position here. must be done
5460 // before calling reminders
5461 myState.myPos = 0;
5464 }
5465 // update via
5466 if (myParameter->via.size() > 0 && myLane->getEdge().getID() == myParameter->via.front()) {
5467 myParameter->via.erase(myParameter->via.begin());
5468 }
5469}
5470
5471
5472void
5474 myAmOnNet = true;
5475 myLane = enteredLane;
5477 // need to update myCurrentLaneInBestLanes
5479 // switch to and activate the new lane's reminders
5480 // keep OldLaneReminders
5481 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5482 addReminder(*rem);
5483 }
5485 MSLane* lane = myLane;
5486 double leftLength = getVehicleType().getLength() - myState.myPos;
5487 int deleteFurther = 0;
5488#ifdef DEBUG_SETFURTHER
5489 if (DEBUG_COND) {
5490 std::cout << SIMTIME << " enterLaneAtLaneChange entered=" << Named::getIDSecure(enteredLane) << " oldFurther=" << toString(myFurtherLanes) << "\n";
5491 }
5492#endif
5493 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5494 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5495 // (unless the lane is shared with cars)
5497 }
5498 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
5499 if (lane != nullptr) {
5501 }
5502#ifdef DEBUG_SETFURTHER
5503 if (DEBUG_COND) {
5504 std::cout << " enterLaneAtLaneChange i=" << i << " lane=" << Named::getIDSecure(lane) << " leftLength=" << leftLength << "\n";
5505 }
5506#endif
5507 if (leftLength > 0) {
5508 if (lane != nullptr) {
5510 if (myFurtherLanes[i]->getBidiLane() != nullptr
5511 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5512 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5513 }
5514 // lane changing onto longer lanes may reduce the number of
5515 // remaining further lanes
5516 myFurtherLanes[i] = lane;
5518 leftLength -= lane->setPartialOccupation(this);
5519 if (lane->getBidiLane() != nullptr
5520 && (!isRailway(getVClass()) || (lane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5521 lane->getBidiLane()->setPartialOccupation(this);
5522 }
5523 myState.myBackPos = -leftLength;
5524#ifdef DEBUG_SETFURTHER
5525 if (DEBUG_COND) {
5526 std::cout << SIMTIME << " newBackPos=" << myState.myBackPos << "\n";
5527 }
5528#endif
5529 } else {
5530 // keep the old values, but ensure there is no shadow
5533 }
5534 if (myState.myBackPos < 0) {
5535 myState.myBackPos += myFurtherLanes[i]->getLength();
5536 }
5537#ifdef DEBUG_SETFURTHER
5538 if (DEBUG_COND) {
5539 std::cout << SIMTIME << " i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
5540 }
5541#endif
5542 }
5543 } else {
5544 myFurtherLanes[i]->resetPartialOccupation(this);
5545 if (myFurtherLanes[i]->getBidiLane() != nullptr
5546 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5547 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5548 }
5549 deleteFurther++;
5550 }
5551 }
5552 if (deleteFurther > 0) {
5553#ifdef DEBUG_SETFURTHER
5554 if (DEBUG_COND) {
5555 std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
5556 }
5557#endif
5558 myFurtherLanes.erase(myFurtherLanes.end() - deleteFurther, myFurtherLanes.end());
5559 myFurtherLanesPosLat.erase(myFurtherLanesPosLat.end() - deleteFurther, myFurtherLanesPosLat.end());
5560 }
5561#ifdef DEBUG_SETFURTHER
5562 if (DEBUG_COND) {
5563 std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
5564 << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
5565 }
5566#endif
5568}
5569
5570
5571void
5572MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
5573 // build the list of lanes the vehicle is lapping into
5574 if (!myLaneChangeModel->isOpposite()) {
5575 double leftLength = myType->getLength() - pos;
5576 MSLane* clane = enteredLane;
5577 int routeIndex = getRoutePosition();
5578 while (leftLength > 0) {
5579 if (routeIndex > 0 && clane->getEdge().isNormal()) {
5580 // get predecessor lane that corresponds to prior route
5581 routeIndex--;
5582 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
5583 MSLane* target = clane;
5584 clane = nullptr;
5585 for (auto ili : target->getIncomingLanes()) {
5586 if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
5587 clane = ili.lane;
5588 break;
5589 }
5590 }
5591 } else {
5592 clane = clane->getLogicalPredecessorLane();
5593 }
5594 if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
5595 || (clane->isInternal() && (
5596 clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
5597 || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
5598 break;
5599 }
5600 if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
5601 myFurtherLanes.push_back(clane);
5603 clane->setPartialOccupation(this);
5604 if (clane->getBidiLane() != nullptr
5605 && (!isRailway(getVClass()) || (clane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5606 clane->getBidiLane()->setPartialOccupation(this);
5607 }
5608 }
5609 leftLength -= clane->getLength();
5610 }
5611 myState.myBackPos = -leftLength;
5612#ifdef DEBUG_SETFURTHER
5613 if (DEBUG_COND) {
5614 std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
5615 }
5616#endif
5617 } else {
5618 // clear partial occupation
5619 for (MSLane* further : myFurtherLanes) {
5620#ifdef DEBUG_SETFURTHER
5621 if (DEBUG_COND) {
5622 std::cout << SIMTIME << " opposite: resetPartialOccupation " << further->getID() << " \n";
5623 }
5624#endif
5625 further->resetPartialOccupation(this);
5626 if (further->getBidiLane() != nullptr
5627 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5628 further->getBidiLane()->resetPartialOccupation(this);
5629 }
5630 }
5631 myFurtherLanes.clear();
5632 myFurtherLanesPosLat.clear();
5633 }
5634}
5635
5636
5637void
5638MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
5639 myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
5641 onDepart();
5642 }
5644 assert(myState.myPos >= 0);
5645 assert(myState.mySpeed >= 0);
5646 myLane = enteredLane;
5647 myAmOnNet = true;
5648 // schedule action for the next timestep
5650 if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
5651 // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
5652 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5653 addReminder(*rem);
5654 }
5655 activateReminders(notification, enteredLane);
5656 } else {
5657 myLastBestLanesEdge = nullptr;
5660 }
5661 computeFurtherLanes(enteredLane, pos);
5665 } else if (MSGlobals::gLaneChangeDuration > 0) {
5667 }
5668 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5671 myAngle += M_PI;
5672 }
5673 }
5674 if (MSNet::getInstance()->hasPersons()) {
5675 for (MSLane* further : myFurtherLanes) {
5676 if (further->mustCheckJunctionCollisions()) {
5678 }
5679 }
5680 }
5681}
5682
5683
5684void
5685MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5686 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5687 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5688#ifdef _DEBUG
5689 if (myTraceMoveReminders) {
5690 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5691 }
5692#endif
5693 ++rem;
5694 } else {
5695#ifdef _DEBUG
5696 if (myTraceMoveReminders) {
5697 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5698 }
5699#endif
5700 rem = myMoveReminders.erase(rem);
5701 }
5702 }
5706 && myLane != nullptr) {
5708 }
5709 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
5710 && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5712 }
5714 // @note. In case of lane change, myFurtherLanes and partial occupation
5715 // are handled in enterLaneAtLaneChange()
5716 for (MSLane* further : myFurtherLanes) {
5717#ifdef DEBUG_FURTHER
5718 if (DEBUG_COND) {
5719 std::cout << SIMTIME << " leaveLane \n";
5720 }
5721#endif
5722 further->resetPartialOccupation(this);
5723 if (further->getBidiLane() != nullptr
5724 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5725 further->getBidiLane()->resetPartialOccupation(this);
5726 }
5727 }
5728 myFurtherLanes.clear();
5729 myFurtherLanesPosLat.clear();
5730 }
5732 myAmOnNet = false;
5733 myWaitingTime = 0;
5734 }
5736 myStopDist = std::numeric_limits<double>::max();
5737 if (myPastStops.back().speed <= 0) {
5738 WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
5739 }
5740 }
5742 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5743 if (myStops.front().getSpeed() <= 0) {
5744 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5745 time2string(MSNet::getInstance()->getCurrentTimeStep()))
5746 myStops.pop_front();
5747 } else {
5748 MSStop& stop = myStops.front();
5749 // passed waypoint at the end of the lane
5750 if (!stop.reached) {
5751 if (MSStopOut::active()) {
5753 }
5754 stop.reached = true;
5755 // enter stopping place so leaveFrom works as expected
5756 if (stop.busstop != nullptr) {
5757 // let the bus stop know the vehicle
5758 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5759 }
5760 if (stop.containerstop != nullptr) {
5761 // let the container stop know the vehicle
5763 }
5764 // do not enter parkingarea!
5765 if (stop.chargingStation != nullptr) {
5766 // let the container stop know the vehicle
5768 }
5769 }
5771 }
5772 myStopDist = std::numeric_limits<double>::max();
5773 }
5774 }
5775}
5776
5777
5778void
5780 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5781 if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
5782#ifdef _DEBUG
5783 if (myTraceMoveReminders) {
5784 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
5785 }
5786#endif
5787 ++rem;
5788 } else {
5789#ifdef _DEBUG
5790 if (myTraceMoveReminders) {
5791 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
5792 }
5793#endif
5794 rem = myMoveReminders.erase(rem);
5795 }
5796 }
5797#ifdef DEBUG_MOVEREMINDERS
5798 if (DEBUG_COND) {
5799 std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
5800 for (auto rem : myMoveReminders) {
5801 std::cout << rem.first->getDescription() << " ";
5802 }
5803 std::cout << "\n";
5804 }
5805#endif
5806}
5807
5808
5813
5814
5819
5820bool
5822 return (lane->isInternal()
5823 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5824 : &lane->getEdge() != *myCurrEdge);
5825}
5826
5827const std::vector<MSVehicle::LaneQ>&
5829 return *myBestLanes.begin();
5830}
5831
5832
5833void
5834MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5835#ifdef DEBUG_BESTLANES
5836 if (DEBUG_COND) {
5837 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5838 }
5839#endif
5840 if (startLane == nullptr) {
5841 startLane = myLane;
5842 }
5843 assert(startLane != 0);
5845 // depending on the calling context, startLane might be the forward lane
5846 // or the reverse-direction lane. In the latter case we need to
5847 // transform it to the forward lane.
5848 if (isOppositeLane(startLane)) {
5849 // use leftmost lane of forward edge
5850 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5851 assert(startLane != 0);
5852#ifdef DEBUG_BESTLANES
5853 if (DEBUG_COND) {
5854 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5855 }
5856#endif
5857 }
5858 }
5859 if (forceRebuild) {
5860 myLastBestLanesEdge = nullptr;
5862 }
5863 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5865#ifdef DEBUG_BESTLANES
5866 if (DEBUG_COND) {
5867 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5868 }
5869#endif
5870 return;
5871 }
5872 if (startLane->getEdge().isInternal()) {
5873 if (myBestLanes.size() == 0 || forceRebuild) {
5874 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5875 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5876 }
5877 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5878#ifdef DEBUG_BESTLANES
5879 if (DEBUG_COND) {
5880 std::cout << " nothing to do on internal\n";
5881 }
5882#endif
5883 return;
5884 }
5885 // adapt best lanes to fit the current internal edge:
5886 // keep the entries that are reachable from this edge
5887 const MSEdge* nextEdge = startLane->getNextNormal();
5888 assert(!nextEdge->isInternal());
5889 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5890 std::vector<LaneQ>& lanes = *it;
5891 assert(lanes.size() > 0);
5892 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5893 // keep those lanes which are successors of internal lanes from the edge of startLane
5894 std::vector<LaneQ> oldLanes = lanes;
5895 lanes.clear();
5896 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
5897 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
5898 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
5899 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
5900 lanes.push_back(*it_lane);
5901 break;
5902 }
5903 }
5904 }
5905 assert(lanes.size() == startLane->getEdge().getLanes().size());
5906 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
5907 for (int i = 0; i < (int)lanes.size(); ++i) {
5908 if (i + lanes[i].bestLaneOffset < 0) {
5909 lanes[i].bestLaneOffset = -i;
5910 }
5911 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
5912 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
5913 }
5914 assert(i + lanes[i].bestLaneOffset >= 0);
5915 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
5916 if (lanes[i].bestContinuations[0] != 0) {
5917 // patch length of bestContinuation to match expectations (only once)
5918 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
5919 }
5920 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
5921 myCurrentLaneInBestLanes = lanes.begin() + i;
5922 }
5923 assert(&(lanes[i].lane->getEdge()) == nextEdge);
5924 }
5925 myLastBestLanesInternalLane = startLane;
5927#ifdef DEBUG_BESTLANES
5928 if (DEBUG_COND) {
5929 std::cout << " updated for internal\n";
5930 }
5931#endif
5932 return;
5933 } else {
5934 // remove passed edges
5935 it = myBestLanes.erase(it);
5936 }
5937 }
5938 assert(false); // should always find the next edge
5939 }
5940 // start rebuilding
5942 myLastBestLanesEdge = &startLane->getEdge();
5944
5945 // get information about the next stop
5946 MSRouteIterator nextStopEdge = myRoute->end();
5947 const MSLane* nextStopLane = nullptr;
5948 double nextStopPos = 0;
5949 bool nextStopIsWaypoint = false;
5950 if (!myStops.empty()) {
5951 const MSStop& nextStop = myStops.front();
5952 nextStopLane = nextStop.lane;
5953 if (nextStop.isOpposite) {
5954 // target leftmost lane in forward direction
5955 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
5956 }
5957 nextStopEdge = nextStop.edge;
5958 nextStopPos = nextStop.pars.startPos;
5959 nextStopIsWaypoint = nextStop.getSpeed() > 0;
5960 }
5961 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
5962 if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
5963 nextStopEdge = (myRoute->end() - 1);
5964 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
5965 nextStopPos = myArrivalPos;
5966 }
5967 if (nextStopEdge != myRoute->end()) {
5968 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
5969 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
5970 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
5971 if (nextStopLane->isInternal()) {
5972 // switch to the correct lane before entering the intersection
5973 nextStopPos = (*nextStopEdge)->getLength();
5974 }
5975 }
5976
5977 // go forward along the next lanes;
5978 // trains do not have to deal with lane-changing for stops but their best
5979 // lanes lookahead is needed for rail signal control
5980 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
5981 int seen = 0;
5982 double seenLength = 0;
5983 bool progress = true;
5984 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
5985 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
5986 const double lookahead = getLaneChangeModel().getStrategicLookahead();
5987 for (MSRouteIterator ce = myCurrEdge; progress;) {
5988 std::vector<LaneQ> currentLanes;
5989 const std::vector<MSLane*>* allowed = nullptr;
5990 const MSEdge* nextEdge = nullptr;
5991 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
5992 nextEdge = *(ce + 1);
5993 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
5994 }
5995 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
5996 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
5997 LaneQ q;
5998 MSLane* cl = *i;
5999 q.lane = cl;
6000 q.bestContinuations.push_back(cl);
6001 q.bestLaneOffset = 0;
6002 q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
6003 q.currentLength = q.length;
6004 // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
6005 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
6006 q.occupation = 0;
6007 q.nextOccupation = 0;
6008 currentLanes.push_back(q);
6009 }
6010 //
6011 if (nextStopEdge == ce
6012 // already past the stop edge
6013 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
6014 if (!nextStopLane->isInternal() && !continueAfterStop) {
6015 progress = false;
6016 }
6017 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
6018 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
6019 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
6020 (*q).allowsContinuation = false;
6021 (*q).length = nextStopPos;
6022 (*q).currentLength = (*q).length;
6023 }
6024 }
6025 }
6026
6027 myBestLanes.push_back(currentLanes);
6028 ++seen;
6029 seenLength += currentLanes[0].lane->getLength();
6030 ++ce;
6031 if (lookahead >= 0) {
6032 progress &= (seen <= 2 || seenLength < lookahead); // custom (but we need to look at least one edge ahead)
6033 } else {
6034 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
6035 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
6036 }
6037 progress &= ce != myRoute->end();
6038 /*
6039 if(progress) {
6040 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
6041 }
6042 */
6043 }
6044
6045 // we are examining the last lane explicitly
6046 if (myBestLanes.size() != 0) {
6047 double bestLength = -1;
6048 // minimum and maximum lane index with best length
6049 int bestThisIndex = 0;
6050 int bestThisMaxIndex = 0;
6051 int index = 0;
6052 std::vector<LaneQ>& last = myBestLanes.back();
6053 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6054 if ((*j).length > bestLength) {
6055 bestLength = (*j).length;
6056 bestThisIndex = index;
6057 bestThisMaxIndex = index;
6058 } else if ((*j).length == bestLength) {
6059 bestThisMaxIndex = index;
6060 }
6061 }
6062 index = 0;
6063 bool requiredChangeRightForbidden = false;
6064 int requireChangeToLeftForbidden = -1;
6065 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6066 if ((*j).length < bestLength) {
6067 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6068 (*j).bestLaneOffset = bestThisIndex - index;
6069 } else {
6070 (*j).bestLaneOffset = bestThisMaxIndex - index;
6071 }
6072 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6073 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6074 || requiredChangeRightForbidden)) {
6075 // this lane and all further lanes to the left cannot be used
6076 requiredChangeRightForbidden = true;
6077 (*j).length = 0;
6078 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6079 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6080 // this lane and all previous lanes to the right cannot be used
6081 requireChangeToLeftForbidden = (*j).lane->getIndex();
6082 }
6083 }
6084 }
6085 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
6086 last[i].length = 0;
6087 }
6088#ifdef DEBUG_BESTLANES
6089 if (DEBUG_COND) {
6090 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6091 std::vector<LaneQ>& laneQs = myBestLanes.back();
6092 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6093 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
6094 }
6095 }
6096#endif
6097 }
6098 // go backward through the lanes
6099 // track back best lane and compute the best prior lane(s)
6100 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
6101 std::vector<LaneQ>& nextLanes = (*(i - 1));
6102 std::vector<LaneQ>& clanes = (*i);
6103 MSEdge* const cE = &clanes[0].lane->getEdge();
6104 int index = 0;
6105 double bestConnectedLength = -1;
6106 double bestLength = -1;
6107 for (const LaneQ& j : nextLanes) {
6108 if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
6109 bestConnectedLength = j.length;
6110 }
6111 if (bestLength < j.length) {
6112 bestLength = j.length;
6113 }
6114 }
6115 // compute index of the best lane (highest length and least offset from the best next lane)
6116 int bestThisIndex = 0;
6117 int bestThisMaxIndex = 0;
6118 if (bestConnectedLength > 0) {
6119 index = 0;
6120 for (LaneQ& j : clanes) {
6121 const LaneQ* bestConnectedNext = nullptr;
6122 if (j.allowsContinuation) {
6123 for (const LaneQ& m : nextLanes) {
6124 if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
6125 && m.lane->isApproachedFrom(cE, j.lane)) {
6126 if (betterContinuation(bestConnectedNext, m)) {
6127 bestConnectedNext = &m;
6128 }
6129 }
6130 }
6131 if (bestConnectedNext != nullptr) {
6132 if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
6133 j.length += bestLength;
6134 } else {
6135 j.length += bestConnectedNext->length;
6136 }
6137 j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
6138 }
6139 }
6140 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
6141 copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
6142 } else {
6143 j.allowsContinuation = false;
6144 }
6145 if (clanes[bestThisIndex].length < j.length
6146 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
6147 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
6148 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
6149 ) {
6150 bestThisIndex = index;
6151 bestThisMaxIndex = index;
6152 } else if (clanes[bestThisIndex].length == j.length
6153 && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
6154 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
6155 bestThisMaxIndex = index;
6156 }
6157 index++;
6158 }
6159
6160 //vehicle with elecHybrid device prefers running under an overhead wire
6161 if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
6162 index = 0;
6163 for (const LaneQ& j : clanes) {
6164 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6165 if (overheadWireSegmentID != "") {
6166 bestThisIndex = index;
6167 bestThisMaxIndex = index;
6168 }
6169 index++;
6170 }
6171 }
6172
6173 } else {
6174 // only needed in case of disconnected routes
6175 int bestNextIndex = 0;
6176 int bestDistToNeeded = (int) clanes.size();
6177 index = 0;
6178 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6179 if ((*j).allowsContinuation) {
6180 int nextIndex = 0;
6181 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
6182 if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
6183 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
6184 bestDistToNeeded = abs((*m).bestLaneOffset);
6185 bestThisIndex = index;
6186 bestThisMaxIndex = index;
6187 bestNextIndex = nextIndex;
6188 }
6189 }
6190 }
6191 }
6192 }
6193 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
6194 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
6195
6196 }
6197 // set bestLaneOffset for all lanes
6198 index = 0;
6199 bool requiredChangeRightForbidden = false;
6200 int requireChangeToLeftForbidden = -1;
6201 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6202 if ((*j).length < clanes[bestThisIndex].length
6203 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
6204 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
6205 ) {
6206 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6207 (*j).bestLaneOffset = bestThisIndex - index;
6208 } else {
6209 (*j).bestLaneOffset = bestThisMaxIndex - index;
6210 }
6211 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
6212 // try to move away from the lower-priority lane before it ends
6213 (*j).length = (*j).currentLength;
6214 }
6215 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6216 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6217 || requiredChangeRightForbidden)) {
6218 // this lane and all further lanes to the left cannot be used
6219 requiredChangeRightForbidden = true;
6220 if ((*j).length == (*j).currentLength) {
6221 (*j).length = 0;
6222 }
6223 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6224 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6225 // this lane and all previous lanes to the right cannot be used
6226 requireChangeToLeftForbidden = (*j).lane->getIndex();
6227 }
6228 } else {
6229 (*j).bestLaneOffset = 0;
6230 }
6231 }
6232 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
6233 if (clanes[idx].length == clanes[idx].currentLength) {
6234 clanes[idx].length = 0;
6235 };
6236 }
6237
6238 //vehicle with elecHybrid device prefers running under an overhead wire
6239 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
6240 index = 0;
6241 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6242 if (overheadWireID != "") {
6243 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6244 (*j).bestLaneOffset = bestThisIndex - index;
6245 }
6246 }
6247 }
6248
6249#ifdef DEBUG_BESTLANES
6250 if (DEBUG_COND) {
6251 std::cout << " edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6252 std::vector<LaneQ>& laneQs = clanes;
6253 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6254 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
6255 }
6256 }
6257#endif
6258
6259 }
6261#ifdef DEBUG_BESTLANES
6262 if (DEBUG_COND) {
6263 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
6264 }
6265#endif
6266}
6267
6268void
6270 if (myLane != nullptr) {
6272 }
6273}
6274
6275bool
6276MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
6277 if (bestConnectedNext == nullptr) {
6278 return true;
6279 } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
6280 return false;
6281 } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
6282 return true;
6283 } else if (bestConnectedNext->length < m.length) {
6284 return true;
6285 } else if (bestConnectedNext->length == m.length) {
6286 if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
6287 return true;
6288 }
6289 const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
6290 if (contRight < 1
6291 // if we don't check for adjacency, the rightmost line will get
6292 // multiple chances to be better which leads to an uninituitve distribution
6293 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
6294 && RandHelper::rand(getRNG()) > contRight) {
6295 return true;
6296 }
6297 }
6298 return false;
6299}
6300
6301
6302int
6303MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
6304 if (conts.size() < 2) {
6305 return -1;
6306 } else {
6307 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
6308 if (link != nullptr) {
6309 return link->havePriority() ? 1 : 0;
6310 } else {
6311 // disconnected route
6312 return -1;
6313 }
6314 }
6315}
6316
6317
6318void
6320 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
6321 std::vector<LaneQ>::iterator i;
6322 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
6323 double nextOccupation = 0;
6324 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
6325 nextOccupation += (*j)->getBruttoVehLenSum();
6326 }
6327 (*i).nextOccupation = nextOccupation;
6328#ifdef DEBUG_BESTLANES
6329 if (DEBUG_COND) {
6330 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
6331 }
6332#endif
6333 if ((*i).lane == startLane) {
6335 }
6336 }
6337}
6338
6339
6340const std::vector<MSLane*>&
6342 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6343 return myEmptyLaneVector;
6344 }
6345 return (*myCurrentLaneInBestLanes).bestContinuations;
6346}
6347
6348
6349const std::vector<MSLane*>&
6351 const MSLane* lane = l;
6352 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
6353 if (lane->getEdge().isInternal()) {
6354 // internal edges are not kept inside the bestLanes structure
6355 lane = lane->getLinkCont()[0]->getLane();
6356 }
6357 if (myBestLanes.size() == 0) {
6358 return myEmptyLaneVector;
6359 }
6360 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
6361 if ((*i).lane == lane) {
6362 return (*i).bestContinuations;
6363 }
6364 }
6365 return myEmptyLaneVector;
6366}
6367
6368const std::vector<const MSLane*>
6369MSVehicle::getUpcomingLanesUntil(double distance) const {
6370 std::vector<const MSLane*> lanes;
6371
6372 if (distance <= 0. || hasArrived()) {
6373 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
6374 return lanes;
6375 }
6376
6377 if (!myLaneChangeModel->isOpposite()) {
6378 distance += getPositionOnLane();
6379 } else {
6380 distance += myLane->getOppositePos(getPositionOnLane());
6381 }
6383 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6384 lanes.insert(lanes.end(), lane);
6385 distance -= lane->getLength();
6386 lane = lane->getLinkCont().front()->getViaLaneOrLane();
6387 }
6388
6389 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
6390 if (contLanes.empty()) {
6391 return lanes;
6392 }
6393 auto contLanesIt = contLanes.begin();
6394 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
6395 while (distance > 0.) {
6396 MSLane* l = nullptr;
6397 if (contLanesIt != contLanes.end()) {
6398 l = *contLanesIt;
6399 if (l != nullptr) {
6400 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
6401 }
6402 ++contLanesIt;
6403 if (l != nullptr || myLane->isInternal()) {
6404 ++routeIt;
6405 }
6406 if (l == nullptr) {
6407 continue;
6408 }
6409 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
6410 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6411 l = (*routeIt)->getLanes().back();
6412 ++routeIt;
6413 } else { // the search distance goes beyond our route
6414 break;
6415 }
6416
6417 assert(l != nullptr);
6418
6419 // insert internal lanes if applicable
6420 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
6421 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
6422 lanes.insert(lanes.end(), internalLane);
6423 distance -= internalLane->getLength();
6424 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6425 }
6426 if (distance <= 0.) {
6427 break;
6428 }
6429
6430 lanes.insert(lanes.end(), l);
6431 distance -= l->getLength();
6432 }
6433
6434 return lanes;
6435}
6436
6437const std::vector<const MSLane*>
6438MSVehicle::getPastLanesUntil(double distance) const {
6439 std::vector<const MSLane*> lanes;
6440
6441 if (distance <= 0.) {
6442 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
6443 return lanes;
6444 }
6445
6446 MSRouteIterator routeIt = myCurrEdge;
6447 if (!myLaneChangeModel->isOpposite()) {
6448 distance += myLane->getLength() - getPositionOnLane();
6449 } else {
6451 }
6453 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6454 lanes.insert(lanes.end(), lane);
6455 distance -= lane->getLength();
6456 lane = lane->getLogicalPredecessorLane();
6457 }
6458
6459 while (distance > 0.) {
6460 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6461 MSLane* l = (*routeIt)->getLanes().back();
6462
6463 // insert internal lanes if applicable
6464 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
6465 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
6466 std::vector<const MSLane*> internalLanes;
6467 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
6468 internalLanes.insert(internalLanes.begin(), internalLane);
6469 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6470 }
6471 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
6472 lanes.insert(lanes.end(), *it);
6473 distance -= (*it)->getLength();
6474 }
6475 if (distance <= 0.) {
6476 break;
6477 }
6478
6479 lanes.insert(lanes.end(), l);
6480 distance -= l->getLength();
6481
6482 // NOTE: we're going backwards with the (bi-directional) Iterator
6483 // TODO: consider make reverse_iterator() when moving on to C++14 or later
6484 if (routeIt != myRoute->begin()) {
6485 --routeIt;
6486 } else { // we went backwards to begin() and already processed the first and final element
6487 break;
6488 }
6489 }
6490
6491 return lanes;
6492}
6493
6494
6495const std::vector<MSLane*>
6497 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6498 std::vector<MSLane*> result;
6499 for (const MSLane* lane : routeLanes) {
6500 MSLane* opposite = lane->getOpposite();
6501 if (opposite != nullptr) {
6502 result.push_back(opposite);
6503 } else {
6504 break;
6505 }
6506 }
6507 return result;
6508}
6509
6510
6511int
6513 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6514 return 0;
6515 } else {
6516 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6517 }
6518}
6519
6520double
6522 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6523 return -1;
6524 } else {
6525 return (*myCurrentLaneInBestLanes).length;
6526 }
6527}
6528
6529
6530
6531void
6532MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6533 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6534 assert(laneIndex < (int)preb.size());
6535 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6536}
6537
6538
6539void
6545
6546std::pair<const MSLane*, double>
6547MSVehicle::getLanePosAfterDist(double distance) const {
6548 if (distance == 0) {
6549 return std::make_pair(myLane, getPositionOnLane());
6550 }
6551 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6552 distance += getPositionOnLane();
6553 for (const MSLane* lane : lanes) {
6554 if (lane->getLength() > distance) {
6555 return std::make_pair(lane, distance);
6556 }
6557 distance -= lane->getLength();
6558 }
6559 return std::make_pair(nullptr, -1);
6560}
6561
6562
6563double
6564MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
6565 if (isOnRoad() && destLane != nullptr) {
6566 return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
6567 }
6568 return std::numeric_limits<double>::max();
6569}
6570
6571
6572std::pair<const MSVehicle* const, double>
6573MSVehicle::getLeader(double dist) const {
6574 if (myLane == nullptr) {
6575 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6576 }
6577 if (dist == 0) {
6579 }
6580 const MSVehicle* lead = nullptr;
6581 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6582 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6583 // vehicle might be outside the road network
6584 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6585 if (it != vehs.end() && it + 1 != vehs.end()) {
6586 lead = *(it + 1);
6587 }
6588 if (lead != nullptr) {
6589 std::pair<const MSVehicle* const, double> result(
6590 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6591 lane->releaseVehicles();
6592 return result;
6593 }
6594 const double seen = myLane->getLength() - getPositionOnLane();
6595 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6596 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts);
6597 lane->releaseVehicles();
6598 return result;
6599}
6600
6601
6602std::pair<const MSVehicle* const, double>
6603MSVehicle::getFollower(double dist) const {
6604 if (myLane == nullptr) {
6605 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6606 }
6607 if (dist == 0) {
6608 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6609 }
6611}
6612
6613
6614double
6616 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6617 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6618 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6619 return -1;
6620 }
6621 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6622}
6623
6624
6625void
6627 MSBaseVehicle::addTransportable(transportable);
6628 if (myStops.size() > 0 && myStops.front().reached) {
6629 if (transportable->isPerson()) {
6630 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6631 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6632 }
6633 } else {
6634 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6635 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6636 }
6637 }
6638 }
6639}
6640
6641
6642void
6645 int state = myLaneChangeModel->getOwnState();
6646 // do not set blinker for sublane changes or when blocked from changing to the right
6647 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6648 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6652 // lane indices increase from left to right
6653 std::swap(left, right);
6654 }
6655 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6656 switchOnSignal(left);
6657 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6658 switchOnSignal(right);
6659 } else if (myLaneChangeModel->isChangingLanes()) {
6661 switchOnSignal(left);
6662 } else {
6663 switchOnSignal(right);
6664 }
6665 } else {
6666 const MSLane* lane = getLane();
6667 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6668 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6669 switch ((*link)->getDirection()) {
6674 break;
6678 break;
6679 default:
6680 break;
6681 }
6682 }
6683 }
6684 // stopping related signals
6685 if (hasStops()
6686 && (myStops.begin()->reached ||
6688 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6689 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6690 // not stopping on the right. Activate emergency blinkers
6692 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6693 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6695 }
6696 }
6697 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6699 myInfluencer->setSignals(-1); // overwrite computed signals only once
6700 }
6701}
6702
6703void
6705
6706 //TODO look if timestep ist SIMSTEP
6707 if (currentTime % 1000 == 0) {
6710 } else {
6712 }
6713 }
6714}
6715
6716
6717int
6719 return myLane == nullptr ? -1 : myLane->getIndex();
6720}
6721
6722
6723void
6724MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6725 myLane = lane;
6726 myState.myPos = pos;
6727 myState.myPosLat = posLat;
6729}
6730
6731
6732double
6734 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6735}
6736
6737
6738double
6740 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6741}
6742
6743
6744double
6746 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6747}
6748
6749
6750double
6752 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6753}
6754
6755
6756double
6758 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6759}
6760
6761
6762double
6764 return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
6765}
6766
6767
6768double
6770 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6772 } else if (lane == myLaneChangeModel->getShadowLane()) {
6773 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6774 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6775 }
6777 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6778 } else {
6779 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6780 }
6781 } else if (lane == myLane->getBidiLane()) {
6782 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6783 } else {
6784 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6785 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6786 if (myFurtherLanes[i] == lane) {
6787#ifdef DEBUG_FURTHER
6788 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
6789 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6790 << "\n";
6791#endif
6792 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6793 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6794#ifdef DEBUG_FURTHER
6795 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
6796 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6797 << "\n";
6798#endif
6799 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6800 }
6801 }
6802 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6803 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6804 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6805 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6806 if (shadowFurther[i] == lane) {
6807 assert(myLaneChangeModel->getShadowLane() != 0);
6808 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6810 }
6811 }
6812 assert(false);
6813 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6814 }
6815}
6816
6817
6818double
6820 assert(lane != 0);
6821 if (&lane->getEdge() == &myLane->getEdge()) {
6822 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6823 } else if (myLane->getParallelOpposite() == lane) {
6824 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6825 } else if (myLane->getBidiLane() == lane) {
6826 return -2 * getLateralPositionOnLane();
6827 } else {
6828 // Check whether the lane is a further lane for the vehicle
6829 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6830 if (myFurtherLanes[i] == lane) {
6831#ifdef DEBUG_FURTHER
6832 if (DEBUG_COND) {
6833 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6834 }
6835#endif
6837 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6838#ifdef DEBUG_FURTHER
6839 if (DEBUG_COND) {
6840 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
6841 }
6842#endif
6843 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
6844 }
6845 }
6846#ifdef DEBUG_FURTHER
6847 if (DEBUG_COND) {
6848 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6849 }
6850#endif
6851 // Check whether the lane is a "shadow further lane" for the vehicle
6852 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6853 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6854 if (shadowFurther[i] == lane) {
6855#ifdef DEBUG_FURTHER
6856 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6857 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6858 << " lane=" << lane->getID()
6859 << " i=" << i
6860 << " posLat=" << myState.myPosLat
6861 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6862 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6863 << "\n";
6864#endif
6866 }
6867 }
6868 // Check whether the vehicle issued a maneuverReservation on the lane.
6869 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6870 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6871 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6872 MSLane* targetLane = furtherTargets[i];
6873 if (targetLane == lane) {
6874 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6875 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
6876#ifdef DEBUG_TARGET_LANE
6877 if (DEBUG_COND) {
6878 std::cout << " getLatOffset veh=" << getID()
6879 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
6880 << "\n i=" << i
6881 << " posLat=" << myState.myPosLat
6882 << " furtherPosLat=" << myFurtherLanesPosLat[i]
6883 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
6884 << " targetDir=" << targetDir
6885 << " latOffset=" << latOffset
6886 << std::endl;
6887 }
6888#endif
6889 return latOffset;
6890 }
6891 }
6892 assert(false);
6893 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6894 }
6895}
6896
6897
6898double
6899MSVehicle::lateralDistanceToLane(const int offset) const {
6900 // compute the distance when changing to the neighboring lane
6901 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
6902 assert(offset == 0 || offset == 1 || offset == -1);
6903 assert(myLane != nullptr);
6904 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
6905 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
6906 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
6907 const double latPos = getLateralPositionOnLane();
6908 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
6909 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
6910 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
6911 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
6912 if (offset == 0) {
6913 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
6914 // correct overlapping left
6915 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
6916 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
6917 // correct overlapping right
6918 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
6919 }
6920 latLaneDist *= oppositeSign;
6921 } else if (offset == -1) {
6922 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
6923 } else if (offset == 1) {
6924 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
6925 }
6926#ifdef DEBUG_ACTIONSTEPS
6927 if (DEBUG_COND) {
6928 std::cout << SIMTIME
6929 << " veh=" << getID()
6930 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
6931 << " halfVehWidth=" << halfVehWidth
6932 << " latPos=" << latPos
6933 << " latLaneDist=" << latLaneDist
6934 << " leftLimit=" << leftLimit
6935 << " rightLimit=" << rightLimit
6936 << "\n";
6937 }
6938#endif
6939 return latLaneDist;
6940}
6941
6942
6943double
6944MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
6945 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
6946 - 0.5 * lane->getWidth());
6947}
6948
6949double
6953
6954double
6958
6959
6960void
6962 for (const DriveProcessItem& dpi : lfLinks) {
6963 if (dpi.myLink != nullptr) {
6964 dpi.myLink->removeApproaching(this);
6965 }
6966 }
6967 // unregister on all shadow links
6969}
6970
6971
6972bool
6974 // the following links are unsafe:
6975 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
6976 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
6977 double seen = myLane->getLength() - getPositionOnLane();
6978 const double dist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
6979 if (seen < dist) {
6980 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
6981 int view = 1;
6982 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
6983 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
6984 while (!lane->isLinkEnd(link) && seen <= dist) {
6985 if (!lane->getEdge().isInternal()
6986 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
6987 || !(*link)->havePriority())) {
6988 // find the drive item corresponding to this link
6989 bool found = false;
6990 while (di != myLFLinkLanes.end() && !found) {
6991 if ((*di).myLink != nullptr) {
6992 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
6993 if (diPredLane != nullptr) {
6994 if (&diPredLane->getEdge() == &lane->getEdge()) {
6995 found = true;
6996 }
6997 }
6998 }
6999 if (!found) {
7000 di++;
7001 }
7002 }
7003 if (found) {
7004 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
7005 (*di).getLeaveSpeed(), getVehicleType().getLength());
7006 if ((*link)->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
7007 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
7008 return true;
7009 }
7010 }
7011 // no drive item is found if the vehicle aborts its request within dist
7012 }
7013 lane = (*link)->getViaLaneOrLane();
7014 if (!lane->getEdge().isInternal()) {
7015 view++;
7016 }
7017 seen += lane->getLength();
7018 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7019 }
7020 }
7021 return false;
7022}
7023
7024
7026MSVehicle::getBoundingBox(double offset) const {
7027 PositionVector centerLine;
7028 Position pos = getPosition();
7029 centerLine.push_back(pos);
7030 switch (myType->getGuiShape()) {
7037 for (MSLane* lane : myFurtherLanes) {
7038 centerLine.push_back(lane->getShape().back());
7039 }
7040 break;
7041 }
7042 default:
7043 break;
7044 }
7045 double l = getLength();
7046 Position backPos = getBackPosition();
7047 if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
7048 // getBackPosition may not match the visual back in networks without internal lanes
7049 double a = getAngle() + M_PI; // angle pointing backwards
7050 backPos = pos + Position(l * cos(a), l * sin(a));
7051 }
7052 centerLine.push_back(backPos);
7053 if (offset != 0) {
7054 centerLine.extrapolate2D(offset);
7055 }
7056 PositionVector result = centerLine;
7057 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7058 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
7059 result.append(centerLine.reverse(), POSITION_EPS);
7060 return result;
7061}
7062
7063
7065MSVehicle::getBoundingPoly(double offset) const {
7066 switch (myType->getGuiShape()) {
7072 // box with corners cut off
7073 PositionVector result;
7074 PositionVector centerLine;
7075 centerLine.push_back(getPosition());
7076 centerLine.push_back(getBackPosition());
7077 if (offset != 0) {
7078 centerLine.extrapolate2D(offset);
7079 }
7080 PositionVector line1 = centerLine;
7081 PositionVector line2 = centerLine;
7082 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
7083 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7084 line2.scaleRelative(0.8);
7085 result.push_back(line1[0]);
7086 result.push_back(line2[0]);
7087 result.push_back(line2[1]);
7088 result.push_back(line1[1]);
7089 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
7090 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
7091 result.push_back(line1[1]);
7092 result.push_back(line2[1]);
7093 result.push_back(line2[0]);
7094 result.push_back(line1[0]);
7095 return result;
7096 }
7097 default:
7098 return getBoundingBox();
7099 }
7100}
7101
7102
7103bool
7105 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
7106 if (&(*i)->getEdge() == edge) {
7107 return true;
7108 }
7109 }
7110 return false;
7111}
7112
7113
7114bool
7115MSVehicle::isBidiOn(const MSLane* lane) const {
7116 return lane->getBidiLane() != nullptr && (
7117 myLane == lane->getBidiLane()
7118 || onFurtherEdge(&lane->getBidiLane()->getEdge()));
7119}
7120
7121
7122bool
7123MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
7124 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
7125 // consistency in the behaviour.
7126
7127 // get vehicle params
7128 MSParkingArea* destParkArea = getNextParkingArea();
7129 const MSRoute& route = getRoute();
7130 const MSEdge* lastEdge = route.getLastEdge();
7131
7132 if (destParkArea == nullptr) {
7133 // not driving towards a parking area
7134 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
7135 return false;
7136 }
7137
7138 // if the current route ends at the parking area, the new route will also and at the new area
7139 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
7140 && getArrivalPos() >= destParkArea->getBeginLanePosition()
7141 && getArrivalPos() <= destParkArea->getEndLanePosition());
7142
7143 // retrieve info on the new parking area
7145 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
7146
7147 if (newParkingArea == nullptr) {
7148 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
7149 return false;
7150 }
7151
7152 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
7154
7155 // Compute the route from the current edge to the parking area edge
7156 ConstMSEdgeVector edgesToPark;
7157 router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
7158
7159 // Compute the route from the parking area edge to the end of the route
7160 ConstMSEdgeVector edgesFromPark;
7161 if (!newDestination) {
7162 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
7163 } else {
7164 // adapt plans of any riders
7165 for (MSTransportable* p : getPersons()) {
7166 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
7167 }
7168 }
7169
7170 // we have a new destination, let's replace the vehicle route
7171 ConstMSEdgeVector edges = edgesToPark;
7172 if (edgesFromPark.size() > 0) {
7173 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
7174 }
7175
7176 if (newDestination) {
7177 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
7178 *newParameter = getParameter();
7180 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
7181 replaceParameter(newParameter);
7182 }
7183 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
7184 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
7185 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
7186 if (replaceParkingArea(newParkingArea, errorMsg)) {
7187 const bool onInit = myLane == nullptr;
7188 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
7189 } else {
7190 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
7191 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
7192 return false;
7193 }
7194 return true;
7195}
7196
7197
7198bool
7200 const int numStops = (int)myStops.size();
7201 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
7202 if (myLane != nullptr && numStops != (int)myStops.size()) {
7203 updateBestLanes(true);
7204 }
7205 return result;
7206}
7207
7208
7209bool
7210MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
7211 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
7212 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
7213 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
7214 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
7215 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
7216 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
7217 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
7218 // << " vNew=" << vNew
7219 // << "\n";
7220 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
7223 if (myState.myPos < myType->getLength()) {
7227 myAngle += M_PI;
7228 }
7229 }
7230 }
7231 }
7232 return true;
7233}
7234
7235
7236bool
7238 if (isStopped()) {
7242 }
7243 MSStop& stop = myStops.front();
7244 // we have waited long enough and fulfilled any passenger-requirements
7245 if (stop.busstop != nullptr) {
7246 // inform bus stop about leaving it
7247 stop.busstop->leaveFrom(this);
7248 }
7249 // we have waited long enough and fulfilled any container-requirements
7250 if (stop.containerstop != nullptr) {
7251 // inform container stop about leaving it
7252 stop.containerstop->leaveFrom(this);
7253 }
7254 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
7255 // inform parking area about leaving it
7256 stop.parkingarea->leaveFrom(this);
7257 }
7258 if (stop.chargingStation != nullptr) {
7259 // inform charging station about leaving it
7260 stop.chargingStation->leaveFrom(this);
7261 }
7262 // the current stop is no longer valid
7263 myLane->getEdge().removeWaiting(this);
7264 // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
7265 if (stop.pars.started == -1) {
7266 // waypoint edge was passed in a single step
7268 }
7269 if (MSStopOut::active()) {
7270 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
7271 }
7273 for (const auto& rem : myMoveReminders) {
7274 rem.first->notifyStopEnded();
7275 }
7277 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
7278 }
7280 // reset lateral position to default
7281 myState.myPosLat = 0;
7282 }
7283 myPastStops.push_back(stop.pars);
7284 myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
7285 myStops.pop_front();
7286 myStopDist = std::numeric_limits<double>::max();
7287 // do not count the stopping time towards gridlock time.
7288 // Other outputs use an independent counter and are not affected.
7289 myWaitingTime = 0;
7290 // maybe the next stop is on the same edge; let's rebuild best lanes
7291 updateBestLanes(true);
7292 // continue as wished...
7295 return true;
7296 }
7297 return false;
7298}
7299
7300
7303 if (myInfluencer == nullptr) {
7304 myInfluencer = new Influencer();
7305 }
7306 return *myInfluencer;
7307}
7308
7313
7314
7317 return myInfluencer;
7318}
7319
7322 return myInfluencer;
7323}
7324
7325
7326double
7328 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
7329 // influencer original speed is -1 on initialization
7331 }
7332 return myState.mySpeed;
7333}
7334
7335
7336int
7338 if (hasInfluencer()) {
7340 MSNet::getInstance()->getCurrentTimeStep(),
7341 myLane->getEdge(),
7342 getLaneIndex(),
7343 state);
7344 }
7345 return state;
7346}
7347
7348
7349void
7353
7354
7355bool
7359
7360
7361bool
7365
7366
7367bool
7368MSVehicle::keepClear(const MSLink* link) const {
7369 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
7370 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
7371 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
7372 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
7373 } else {
7374 return false;
7375 }
7376}
7377
7378
7379bool
7380MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
7381 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
7382 return true;
7383 }
7384 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
7385#ifdef DEBUG_IGNORE_RED
7386 if (DEBUG_COND) {
7387 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
7388 }
7389#endif
7390 if (ignoreRedTime < 0) {
7391 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
7392 if (ignoreYellowTime > 0 && link->haveYellow()) {
7393 assert(link->getTLLogic() != 0);
7394 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7395 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
7396 return !canBrake || ignoreYellowTime > yellowDuration;
7397 } else {
7398 return false;
7399 }
7400 } else if (link->haveYellow()) {
7401 // always drive at yellow when ignoring red
7402 return true;
7403 } else if (link->haveRed()) {
7404 assert(link->getTLLogic() != 0);
7405 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7406#ifdef DEBUG_IGNORE_RED
7407 if (DEBUG_COND) {
7408 std::cout
7409 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
7410 << " ignoreRedTime=" << ignoreRedTime
7411 << " spentRed=" << redDuration
7412 << " canBrake=" << canBrake << "\n";
7413 }
7414#endif
7415 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
7416 return !canBrake || ignoreRedTime > redDuration;
7417 } else {
7418 return false;
7419 }
7420}
7421
7422bool
7425 return false;
7426 }
7427 for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
7428 if (typeID == foe->getVehicleType().getID()) {
7429 return true;
7430 }
7431 }
7432 for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
7433 if (id == foe->getID()) {
7434 return true;
7435 }
7436 }
7437 return false;
7438}
7439
7440bool
7442 // either on an internal lane that was entered via minor link
7443 // or on approach to minor link below visibility distance
7444 if (myLane == nullptr) {
7445 return false;
7446 }
7447 if (myLane->getEdge().isInternal()) {
7448 return !myLane->getIncomingLanes().front().viaLink->havePriority();
7449 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
7450 MSLink* link = myLFLinkLanes.front().myLink;
7451 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
7452 }
7453 return false;
7454}
7455
7456bool
7457MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
7458 assert(link->fromInternalLane());
7459 if (veh == nullptr) {
7460 return false;
7461 }
7462 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
7463 // if this vehicle is not yet on the junction, every vehicle is a leader
7464 return true;
7465 }
7466 if (veh->getLaneChangeModel().hasBlueLight()) {
7467 // blue light device automatically gets right of way
7468 return true;
7469 }
7470 const MSLane* foeLane = veh->getLane();
7471 if (foeLane->isInternal()) {
7472 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
7474 SUMOTime foeET = veh->myJunctionEntryTime;
7475 // check relationship between link and foeLane
7477 // we are entering the junction from the same lane
7479 foeET = veh->myJunctionEntryTimeNeverYield;
7482 }
7483 } else {
7484 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
7485 const MSJunctionLogic* logic = link->getJunction()->getLogic();
7486 assert(logic != nullptr);
7487 // determine who has right of way
7488 bool response; // ego response to foe
7489 bool response2; // foe response to ego
7490 // attempt 1: tlLinkState
7491 const MSLink* entry = link->getCorrespondingEntryLink();
7492 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
7493 if (entry->haveRed() || foeEntry->haveRed()) {
7494 // ensure that vehicles which are stuck on the intersection may exit
7495 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
7496 // foe might be oncoming, don't drive unless foe can still brake safely
7497 const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
7498 const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
7499 foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
7500 // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
7501 // so the -2* makes it point in the right direction
7502 const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
7503#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7504 if (DEBUG_COND) {
7505 std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
7506
7507 }
7508#endif
7509 if (foeGap < foeBrakeGap) {
7510 response = true;
7511 response2 = false;
7512 } else {
7513 response = false;
7514 response2 = true;
7515 }
7516 } else {
7517 // brake for stuck foe
7518 response = foeEntry->haveRed();
7519 response2 = entry->haveRed();
7520 }
7521 } else if (entry->havePriority() != foeEntry->havePriority()) {
7522 response = !entry->havePriority();
7523 response2 = !foeEntry->havePriority();
7524 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
7525 // let the faster vehicle keep moving
7526 response = veh->getSpeed() >= getSpeed();
7527 response2 = getSpeed() >= veh->getSpeed();
7528 } else {
7529 // fallback if pedestrian crossings are involved
7530 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
7531 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
7532 }
7533#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7534 if (DEBUG_COND) {
7535 std::cout << SIMTIME
7536 << " foeLane=" << foeLane->getID()
7537 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
7538 << " linkIndex=" << link->getIndex()
7539 << " foeLinkIndex=" << foeLink->getIndex()
7540 << " entryState=" << toString(entry->getState())
7541 << " entryState2=" << toString(foeEntry->getState())
7542 << " response=" << response
7543 << " response2=" << response2
7544 << "\n";
7545 }
7546#endif
7547 if (!response) {
7548 // if we have right of way over the foe, entryTime does not matter
7549 foeET = veh->myJunctionConflictEntryTime;
7550 egoET = myJunctionEntryTime;
7551 } else if (response && response2) {
7552 // in a mutual conflict scenario, use entry time to avoid deadlock
7553 foeET = veh->myJunctionConflictEntryTime;
7555 }
7556 }
7557 if (egoET == foeET) {
7558 // try to use speed as tie braker
7559 if (getSpeed() == veh->getSpeed()) {
7560 // use ID as tie braker
7561#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7562 if (DEBUG_COND) {
7563 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7564 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7565 }
7566#endif
7567 return getID() < veh->getID();
7568 } else {
7569#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7570 if (DEBUG_COND) {
7571 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7572 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7573 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7574 << "\n";
7575 }
7576#endif
7577 return getSpeed() < veh->getSpeed();
7578 }
7579 } else {
7580 // leader was on the junction first
7581#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7582 if (DEBUG_COND) {
7583 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7584 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7585 }
7586#endif
7587 return egoET > foeET;
7588 }
7589 } else {
7590 // vehicle can only be partially on the junction. Must be a leader
7591 return true;
7592 }
7593 } else {
7594 // vehicle can only be partially on the junction. Must be a leader
7595 return true;
7596 }
7597}
7598
7599void
7602 // here starts the vehicle internal part (see loading)
7603 std::vector<std::string> internals;
7604 internals.push_back(toString(myParameter->parametersSet));
7605 internals.push_back(toString(myDeparture));
7606 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7607 internals.push_back(toString(myDepartPos));
7608 internals.push_back(toString(myWaitingTime));
7609 internals.push_back(toString(myTimeLoss));
7610 internals.push_back(toString(myLastActionTime));
7611 internals.push_back(toString(isStopped()));
7612 internals.push_back(toString(myPastStops.size()));
7613 out.writeAttr(SUMO_ATTR_STATE, internals);
7615 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7620 // save past stops
7622 stop.write(out, false);
7623 // do not write started and ended twice
7624 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7625 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7626 }
7627 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7628 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7629 }
7630 stop.writeParams(out);
7631 out.closeTag();
7632 }
7633 // save upcoming stops
7634 for (MSStop& stop : myStops) {
7635 stop.write(out);
7636 }
7637 // save parameters and device states
7639 for (MSVehicleDevice* const dev : myDevices) {
7640 dev->saveState(out);
7641 }
7642 out.closeTag();
7643}
7644
7645void
7647 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7648 throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
7649 }
7650 int routeOffset;
7651 bool stopped;
7652 int pastStops;
7653
7654 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7655 bis >> myParameter->parametersSet;
7656 bis >> myDeparture;
7657 bis >> routeOffset;
7658 bis >> myDepartPos;
7659 bis >> myWaitingTime;
7660 bis >> myTimeLoss;
7661 bis >> myLastActionTime;
7662 bis >> stopped;
7663 bis >> pastStops;
7664
7665 // load stops
7666 myStops.clear();
7668
7669 if (hasDeparted()) {
7670 myCurrEdge = myRoute->begin() + routeOffset;
7671 myDeparture -= offset;
7672 // fix stops
7673 while (pastStops > 0) {
7674 myPastStops.push_back(myStops.front().pars);
7675 myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
7676 myStops.pop_front();
7677 pastStops--;
7678 }
7679 // see MSBaseVehicle constructor
7682 }
7683 }
7686 WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
7687 }
7688 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7690 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7695 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7696 dis >> myOdometer >> myNumberReroutes;
7698 if (stopped) {
7699 myStops.front().startedFromState = true;
7700 myStopDist = 0;
7701 }
7703 // no need to reset myCachedPosition here since state loading happens directly after creation
7704}
7705
7706void
7708 SUMOTime arrivalTime, double arrivalSpeed,
7709 double arrivalSpeedBraking,
7710 double dist, double leaveSpeed) {
7711 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7712 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7713 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7714
7715}
7716
7717
7718std::shared_ptr<MSSimpleDriverState>
7722
7723
7724double
7726 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7727}
7728
7729
7730void
7731MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7732 myState.mySpeed = MAX2(0., prevSpeed);
7733 // also retcon acceleration
7734 if (prevAcceleration != std::numeric_limits<double>::min()) {
7735 myAcceleration = prevAcceleration;
7736 } else {
7738 }
7739}
7740
7741
7742double
7744 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7746}
7747
7748/****************************************************************************/
7749bool
7753
7754/* -------------------------------------------------------------------------
7755 * methods of MSVehicle::manoeuvre
7756 * ----------------------------------------------------------------------- */
7757
7758MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7759
7760
7762 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7763 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7764 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7765 myManoeuvreType = manoeuvre.myManoeuvreType;
7766 myGUIIncrement = manoeuvre.myGUIIncrement;
7767}
7768
7769
7772 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7773 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7774 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7775 myManoeuvreType = manoeuvre.myManoeuvreType;
7776 myGUIIncrement = manoeuvre.myGUIIncrement;
7777 return *this;
7778}
7779
7780
7781bool
7783 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7784 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7785 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7786 myManoeuvreType != manoeuvre.myManoeuvreType ||
7787 myGUIIncrement != manoeuvre.myGUIIncrement
7788 );
7789}
7790
7791
7792double
7794 return (myGUIIncrement);
7795}
7796
7797
7800 return (myManoeuvreType);
7801}
7802
7803
7808
7809
7810void
7814
7815
7816void
7818 myManoeuvreType = mType;
7819}
7820
7821
7822bool
7824 if (!veh->hasStops()) {
7825 return false; // should never happen - checked before call
7826 }
7827
7828 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7829 const MSStop& stop = veh->getNextStop();
7830
7831 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7832 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7833 if (abs(GUIAngle) < 0.1) {
7834 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7835 }
7836 myManoeuvreVehicleID = veh->getID();
7837 myManoeuvreStop = stop.parkingarea->getID();
7838 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7839 myManoeuvreStartTime = currentTime;
7840 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7841 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7842
7843#ifdef DEBUG_STOPS
7844 if (veh->isSelected()) {
7845 std::cout << "ENTRY manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " Rotation angle=" << RAD2DEG(GUIAngle) << " Road Angle" << RAD2DEG(veh->getAngle()) << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime <<
7846 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7847 }
7848#endif
7849
7850 return (true);
7851}
7852
7853
7854bool
7856 // At the moment we only want to set for parking areas
7857 if (!veh->hasStops()) {
7858 return true;
7859 }
7860 if (veh->getNextStop().parkingarea == nullptr) {
7861 return true;
7862 }
7863
7864 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
7865 return (false);
7866 }
7867
7868 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7869
7870 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
7871 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
7872 if (abs(GUIAngle) < 0.1) {
7873 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
7874 }
7875
7876 myManoeuvreVehicleID = veh->getID();
7877 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
7878 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
7879 myManoeuvreStartTime = currentTime;
7880 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
7881 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7882 if (veh->remainingStopDuration() > 0) {
7883 myManoeuvreCompleteTime += veh->remainingStopDuration();
7884 }
7885
7886#ifdef DEBUG_STOPS
7887 if (veh->isSelected()) {
7888 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
7889 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7890 }
7891#endif
7892
7893 return (true);
7894}
7895
7896
7897bool
7899 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
7900 if (!veh->hasStops()) {
7901 return (true);
7902 }
7903 MSStop* currentStop = &veh->myStops.front();
7904 if (currentStop->parkingarea == nullptr) {
7905 return true;
7906 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
7907 if (configureEntryManoeuvre(veh)) {
7909 return (false);
7910 } else { // cannot configure entry so stop trying
7911 return true;
7912 }
7913 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7914 return false;
7915 } else { // manoeuvre complete
7916 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
7917 return true;
7918 }
7919}
7920
7921
7922bool
7924 if (checkType != myManoeuvreType) {
7925 return true; // we're not maneuvering / wrong manoeuvre
7926 }
7927
7928 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7929 return false;
7930 } else {
7931 return true;
7932 }
7933}
7934
7935
7936bool
7938 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
7939}
7940
7941
7942bool
7946
7947
7948std::pair<double, double>
7950 if (hasStops()) {
7951 MSLane* lane = myLane;
7952 if (lane == nullptr) {
7953 // not in network
7954 lane = getEdge()->getLanes()[0];
7955 }
7956 const MSStop& stop = myStops.front();
7957 auto it = myCurrEdge + 1;
7958 // drive to end of current edge
7959 double dist = (lane->getLength() - getPositionOnLane());
7960 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
7961 // drive until stop edge
7962 while (it != myRoute->end() && it < stop.edge) {
7963 travelTime += (*it)->getMinimumTravelTime(this);
7964 dist += (*it)->getLength();
7965 it++;
7966 }
7967 // drive up to the stop position
7968 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
7969 dist += stopEdgeDist;
7970 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
7971 // estimate time loss due to acceleration and deceleration
7972 // maximum speed is limited by available distance:
7973 const double a = getCarFollowModel().getMaxAccel();
7974 const double b = getCarFollowModel().getMaxDecel();
7975 const double c = getSpeed();
7976 const double d = dist;
7977 const double len = getVehicleType().getLength();
7978 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
7979 // distAccel = (v - c)^2 / (2a)
7980 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
7981 // distAccel + distDecel < d
7982 const double maxVD = MAX2(c, ((sqrt(MAX2(0.0, pow(2 * c * b, 2) + (4 * ((b * ((a * (2 * d * (b + a) + (vs * vs) - (c * c))) - (b * (c * c))))
7983 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
7984 it = myCurrEdge;
7985 double v0 = c;
7986 bool v0Stable = getAcceleration() == 0 && v0 > 0;
7987 double timeLossAccel = 0;
7988 double timeLossDecel = 0;
7989 double timeLossLength = 0;
7990 while (it != myRoute->end() && it <= stop.edge) {
7991 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
7992 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
7993 if (edgeLength <= len && v0Stable && v0 < v) {
7994 const double lengthDist = MIN2(len, edgeLength);
7995 const double dTL = lengthDist / v0 - lengthDist / v;
7996 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
7997 timeLossLength += dTL;
7998 }
7999 if (edgeLength > len) {
8000 const double dv = v - v0;
8001 if (dv > 0) {
8002 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8003 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8004 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8005 timeLossAccel += dTA;
8006 // time loss from vehicle length
8007 } else if (dv < 0) {
8008 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8009 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8010 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8011 timeLossDecel += dTD;
8012 }
8013 v0 = v;
8014 v0Stable = true;
8015 }
8016 it++;
8017 }
8018 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
8019 double v = vs;
8020 const double dv = v - v0;
8021 if (dv > 0) {
8022 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8023 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8024 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8025 timeLossAccel += dTA;
8026 // time loss from vehicle length
8027 } else if (dv < 0) {
8028 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8029 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8030 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8031 timeLossDecel += dTD;
8032 }
8033 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
8034 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
8035 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
8036 return {MAX2(0.0, result), dist};
8037 } else {
8039 }
8040}
8041
8042
8043double
8045 if (hasStops() && myStops.front().pars.until >= 0) {
8046 const MSStop& stop = myStops.front();
8047 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
8048 if (stop.reached) {
8049 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
8050 }
8051 if (stop.pars.duration > 0) {
8052 estimatedDepart += stop.pars.duration;
8053 }
8054 estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
8055 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
8056 return result;
8057 } else {
8058 // vehicles cannot drive before 'until' so stop delay can never be
8059 // negative and we can use -1 to signal "undefined"
8060 return -1;
8061 }
8062}
8063
8064
8065double
8067 if (hasStops() && myStops.front().pars.arrival >= 0) {
8068 const MSStop& stop = myStops.front();
8069 if (stop.reached) {
8070 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
8071 } else {
8072 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
8073 }
8074 } else {
8075 // vehicles can arrival earlier than planned so arrival delay can be negative
8076 return INVALID_DOUBLE;
8077 }
8078}
8079
8080
8081const MSEdge*
8083 return myLane != nullptr ? &myLane->getEdge() : getEdge();
8084}
8085
8086
8087const MSEdge*
8089 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
8090 return nullptr;
8091 }
8092 if (myLane->isInternal()) {
8094 } else {
8095 const MSEdge* nextNormal = succEdge(1);
8096 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
8097 return nextInternal ? nextInternal : nextNormal;
8098 }
8099}
8100
8101
8102const MSLane*
8103MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
8104 if (furtherIndex < (int)myFurtherLanes.size()) {
8105 return myFurtherLanes[furtherIndex++];
8106 } else {
8107 // try to use route information
8108 int routeIndex = getRoutePosition();
8109 bool resultInternal;
8110 if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
8111 if (myLane->isInternal()) {
8112 if (furtherIndex % 2 == 0) {
8113 routeIndex -= (furtherIndex + 0) / 2;
8114 resultInternal = false;
8115 } else {
8116 routeIndex -= (furtherIndex + 1) / 2;
8117 resultInternal = false;
8118 }
8119 } else {
8120 if (furtherIndex % 2 != 0) {
8121 routeIndex -= (furtherIndex + 1) / 2;
8122 resultInternal = false;
8123 } else {
8124 routeIndex -= (furtherIndex + 2) / 2;
8125 resultInternal = true;
8126 }
8127 }
8128 } else {
8129 routeIndex -= furtherIndex;
8130 resultInternal = false;
8131 }
8132 furtherIndex++;
8133 if (routeIndex >= 0) {
8134 if (resultInternal) {
8135 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
8136 for (MSLane* cand : prevNormal->getLanes()) {
8137 for (MSLink* link : cand->getLinkCont()) {
8138 if (link->getLane() == current) {
8139 if (link->getViaLane() != nullptr) {
8140 return link->getViaLane();
8141 } else {
8142 return const_cast<MSLane*>(link->getLaneBefore());
8143 }
8144 }
8145 }
8146 }
8147 } else {
8148 return myRoute->getEdges()[routeIndex]->getLanes()[0];
8149 }
8150 }
8151 }
8152 return current;
8153}
8154
8157 // this vehicle currently has the highest priority on the allway_stop
8158 return link == myHaveStoppedFor ? SUMOTime_MAX : getWaitingTime();
8159}
8160
8161/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define RAD2DEG(x)
Definition GeomHelper.h:36
#define DEBUG_COND2(obj)
Definition MESegment.cpp:52
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
std::pair< const MSVehicle *, double > CLeaderDist
std::pair< const MSPerson *, double > PersonDist
Definition MSPModel.h:41
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition MSRoute.h:57
#define NUMERICAL_EPS_SPEED
#define STOPPING_PLACE_OFFSET
#define JUNCTION_BLOCKAGE_TIME
#define DIST_TO_STOPLINE_EXPECT_PRIORITY
#define CRLL_LOOK_AHEAD
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:296
#define WRITE_ERROR(msg)
Definition MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:315
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition Route.h:32
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMSTEP
Definition SUMOTime.h:61
#define ACCEL2SPEED(x)
Definition SUMOTime.h:51
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TS
Definition SUMOTime.h:42
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
#define DIST2SPEED(x)
Definition SUMOTime.h:47
#define SPEED2ACCEL(x)
Definition SUMOTime.h:53
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge.
@ RAIL_CARGO
render as a cargo train
@ RAIL
render as a rail
@ PASSENGER_VAN
render as a van
@ PASSENGER
render as a passenger vehicle
@ RAIL_CAR
render as a (city) rail without locomotive
@ PASSENGER_HATCHBACK
render as a hatchback passenger vehicle ("Fliessheck")
@ BUS_FLEXIBLE
render as a flexible city bus
@ TRUCK_1TRAILER
render as a transport vehicle with one trailer
@ PASSENGER_SEDAN
render as a sedan passenger vehicle ("Stufenheck")
@ PASSENGER_WAGON
render as a wagon passenger vehicle ("Combi")
@ TRUCK_SEMITRAILER
render as a semi-trailer transport vehicle ("Sattelschlepper")
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_EMERGENCY
public emergency vehicles
const long long int VEHPARS_FORCE_REROUTE
@ GIVEN
The lane is given.
@ GIVEN
The speed is given.
@ SPLIT_FRONT
depart position for a split vehicle is in front of the continuing vehicle
const long long int VEHPARS_CFMODEL_PARAMS_SET
@ GIVEN
The arrival lane is given.
@ GIVEN
The speed is given.
const int STOP_ENDED_SET
@ GIVEN
The arrival position is given.
const int STOP_STARTED_SET
@ SUMO_TAG_PARKING_AREA_REROUTE
entry for an alternative parking zone
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_OVERHEAD_WIRE_SEGMENT
An overhead wire segment.
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_ALLWAY_STOP
This is an uncontrolled, all-way stop link.
@ LINKSTATE_EQUAL
This is an uncontrolled, right-before-left link.
@ LINKSTATE_ZIPPER
This is an uncontrolled, zipper-merge link.
@ LCA_KEEPRIGHT
The action is due to the default of keeping right "Rechtsfahrgebot".
@ LCA_BLOCKED
blocked in all directions
@ LCA_URGENT
The action is urgent (to be defined by lc-model)
@ LCA_STAY
Needs to stay on the current lane.
@ LCA_SUBLANE
used by the sublane model
@ LCA_WANTS_LANECHANGE_OR_STAY
lane can change or stay
@ LCA_COOPERATIVE
The action is done to help someone else.
@ LCA_OVERLAPPING
The vehicle is blocked being overlapping.
@ LCA_LEFT
Wants go to the left.
@ LCA_STRATEGIC
The action is needed to follow the route (navigational lc)
@ LCA_TRACI
The action is due to a TraCI request.
@ LCA_SPEEDGAIN
The action is due to the wish to be faster (tactical lc)
@ LCA_RIGHT
Wants go to the right.
@ SUMO_ATTR_JM_STOPLINE_GAP_MINOR
@ SUMO_ATTR_JM_STOPLINE_CROSSING_GAP
@ SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_STARTED
@ SUMO_ATTR_MAXIMUMPOWER
Maximum Power.
@ SUMO_ATTR_WAITINGTIME
@ SUMO_ATTR_CF_IGNORE_IDS
@ SUMO_ATTR_JM_STOPLINE_GAP
@ SUMO_ATTR_POSITION_LAT
@ SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
@ SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
@ SUMO_ATTR_ENDED
@ SUMO_ATTR_LCA_CONTRIGHT
@ SUMO_ATTR_ANGLE
@ SUMO_ATTR_DISTANCE
@ SUMO_ATTR_CF_IGNORE_TYPES
@ SUMO_ATTR_FLEX_ARRIVAL
@ SUMO_ATTR_JM_IGNORE_JUNCTION_FOE_PROB
@ SUMO_ATTR_POSITION
@ SUMO_ATTR_STATE
The state of a link.
@ SUMO_ATTR_JM_DRIVE_RED_SPEED
int gPrecision
the precision for floating point outputs
Definition StdDefs.cpp:26
bool gDebugFlag1
global utility flags for debugging
Definition StdDefs.cpp:37
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:64
const double SUMO_const_laneWidth
Definition StdDefs.h:48
T MIN3(T a, T b, T c)
Definition StdDefs.h:89
T MIN2(T a, T b)
Definition StdDefs.h:76
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:58
T MAX2(T a, T b)
Definition StdDefs.h:82
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
#define SOFT_ASSERT(expr)
define SOFT_ASSERT raise an assertion in debug mode everywhere except on the windows test server
double getDoubleOptional(SumoXMLAttr attr, const double def) const
Returns the value for a given key with an optional default. SUMO_ATTR_MASS and SUMO_ATTR_FRONTSURFACE...
void setDynamicValues(const SUMOTime stopDuration, const bool parking, const SUMOTime waitingTime, const double angle)
Sets the values which change possibly in every simulation step and are relevant for emsssion calculat...
static double naviDegree(const double angle)
static double fromNaviDegree(const double angle)
Interface for lane-change models.
double getLaneChangeCompletion() const
Get the current lane change completion ratio.
const std::vector< double > & getShadowFurtherLanesPosLat() const
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model)
int getLaneChangeDirection() const
return the direction of the current lane change maneuver
void resetChanged()
reset the flag whether a vehicle already moved to false
MSLane * getShadowLane() const
Returns the lane the vehicle's shadow is on during continuous/sublane lane change.
virtual void saveState(OutputDevice &out) const
Save the state of the laneChangeModel.
void endLaneChangeManeuver(const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_LANE_CHANGE)
void setNoShadowPartialOccupator(MSLane *lane)
MSLane * getTargetLane() const
Returns the lane the vehicle has committed to enter during a sublane lane change.
SUMOTime remainingTime() const
Compute the remaining time until LC completion.
void setShadowApproachingInformation(MSLink *link) const
set approach information for the shadow vehicle
static MSAbstractLaneChangeModel * build(LaneChangeModel lcm, MSVehicle &vehicle)
Factory method for instantiating new lane changing models.
void changedToOpposite()
called when a vehicle changes between lanes in opposite directions
int getShadowDirection() const
return the direction in which the current shadow lane lies
virtual void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the laneChangeModel from the given attributes.
double calcAngleOffset()
return the angle offset during a continuous change maneuver
void setPreviousAngleOffset(const double angleOffset)
set the angle offset of the previous time step
const std::vector< MSLane * > & getFurtherTargetLanes() const
double getAngleOffset() const
return the angle offset resulting from lane change and sigma
const std::vector< MSLane * > & getShadowFurtherLanes() const
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
void setExtraImpatience(double value)
Sets routing behavior.
The base class for microscopic and mesoscopic vehicles.
double getMaxSpeed() const
Returns the maximum speed (the minimum of desired and technical maximum speed)
bool haveValidStopEdges(bool silent=false) const
check whether all stop.edge MSRouteIterators are valid and in order
virtual bool isSelected() const
whether this vehicle is selected in the GUI
std::list< MSStop > myStops
The vehicle's list of stops.
double getImpatience() const
Returns this vehicles impatience.
const std::vector< MSTransportable * > & getPersons() const
retrieve riding persons
virtual void initDevices()
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
void calculateArrivalParams(bool onInit)
(Re-)Calculates the arrival position and lane from the vehicle parameters
virtual double getArrivalPos() const
Returns this vehicle's desired arrivalPos for its current route (may change on reroute)
MSVehicleType * myType
This vehicle's type.
MoveReminderCont myMoveReminders
Currently relevant move reminders.
double myDepartPos
The real depart position.
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
void addReminder(MSMoveReminder *rem)
Adds a MoveReminder dynamically.
void replaceParameter(const SUMOVehicleParameter *newParameter)
replace the vehicle parameter (deleting the old one)
double getChosenSpeedFactor() const
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
std::vector< MSVehicleDevice * > myDevices
The devices this vehicle has.
virtual void addTransportable(MSTransportable *transportable)
Adds a person or container to this vehicle.
virtual bool replaceRoute(ConstMSRoutePtr route, const std::string &info, bool onInit=false, int offset=0, bool addRouteStops=true, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given one.
bool isRail() const
MSVehicleType & getSingularType()
Replaces the current vehicle type with a new one used by this vehicle only.
virtual void replaceVehicleType(MSVehicleType *type)
Replaces the current vehicle type by the one given.
double getLength() const
Returns the vehicle's length.
bool isParking() const
Returns whether the vehicle is parking.
MSParkingArea * getCurrentParkingArea()
get the current parking area stop or nullptr
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
int getPersonNumber() const
Returns the number of persons.
MSRouteIterator myCurrEdge
Iterator to current route-edge.
bool hasDeparted() const
Returns whether this vehicle has already departed.
MSStop & getNextStop()
ConstMSRoutePtr myRoute
This vehicle's route.
double getWidth() const
Returns the vehicle's width.
MSDevice_Transportable * myContainerDevice
The containers this vehicle may have.
const std::list< MSStop > & getStops() const
SumoRNG * getRNG() const
SUMOTime getDeparture() const
Returns this vehicle's real departure time.
EnergyParams * getEmissionParameters() const
retrieve parameters for the energy consumption model
MSDevice_Transportable * myPersonDevice
The passengers this vehicle may have.
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
@ ROUTE_START_INVALID_PERMISSIONS
void addStops(const bool ignoreStopErrors, MSRouteIterator *searchStart=nullptr, bool addRouteStops=true)
Adds stops to the built vehicle.
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
MSParkingArea * getNextParkingArea()
get the upcoming parking area stop or nullptr
int myArrivalLane
The destination lane where the vehicle stops.
SUMOTime myDeparture
The real departure time.
bool isStoppedTriggered() const
Returns whether the vehicle is on a triggered stop.
std::vector< SUMOVehicleParameter::Stop > myPastStops
The list of stops that the vehicle has already reached.
void onDepart()
Called when the vehicle is inserted into the network.
virtual bool addTraciStop(SUMOVehicleParameter::Stop stop, std::string &errorMsg)
const MSRoute & getRoute() const
Returns the current route.
int getRoutePosition() const
return index of edge within route
bool replaceParkingArea(MSParkingArea *parkingArea, std::string &errorMsg)
replace the current parking area stop with a new stop with merge duration
static const SUMOTime NOT_YET_DEPARTED
bool myAmRegisteredAsWaiting
Whether this vehicle is registered as waiting for a person or container (for deadlock-recognition)
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT() const
EnergyParams * myEnergyParams
The emission parameters this vehicle may have.
const SUMOVehicleParameter * myParameter
This vehicle's parameter.
int myRouteValidity
status of the current vehicle route
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
bool isStopped() const
Returns whether the vehicle is at a stop.
MSDevice * getDevice(const std::type_info &type) const
Returns a device of the given type if it exists, nullptr otherwise.
int myNumberReroutes
The number of reroutings.
double myArrivalPos
The position on the destination lane where the vehicle stops.
virtual void saveState(OutputDevice &out)
Saves the (common) state of a vehicle.
double myOdometer
A simple odometer to keep track of the length of the route already driven.
int getContainerNumber() const
Returns the number of containers.
bool replaceRouteEdges(ConstMSEdgeVector &edges, double cost, double savings, const std::string &info, bool onInit=false, bool check=false, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given edges.
The car-following model abstraction.
Definition MSCFModel.h:55
double estimateSpeedAfterDistance(const double dist, const double v, const double accel) const
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
virtual double minNextSpeedEmergency(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed after emergency braking, given the current speed (depends on the numerical ...
virtual VehicleVariables * createVehicleVariables() const
Returns model specific values which are stored inside a vehicle and must be used with casting.
Definition MSCFModel.h:247
double getEmergencyDecel() const
Get the vehicle type's maximal physically possible deceleration [m/s^2].
Definition MSCFModel.h:272
SUMOTime getStartupDelay() const
Get the vehicle type's startupDelay.
Definition MSCFModel.h:287
double getMinimalArrivalSpeed(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance.
virtual void setHeadwayTime(double headwayTime)
Sets a new value for desired headway [s].
Definition MSCFModel.h:574
virtual double freeSpeed(const MSVehicle *const veh, double speed, double seen, double maxSpeed, const bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed without a leader.
virtual double minNextSpeed(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed given the current speed (depends on the numerical update scheme and its ste...
virtual double insertionFollowSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0) const
Computes the vehicle's safe speed (no dawdling) This method is used during the insertion stage....
SUMOTime getMinimalArrivalTime(double dist, double currentSpeed, double arrivalSpeed) const
Computes the minimal time needed to cover a distance given the desired speed at arrival.
virtual double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences. Called at most once per simulation...
@ FUTURE
the return value is used for calculating future speeds
Definition MSCFModel.h:81
@ CURRENT_WAIT
the return value is used for calculating junction stop speeds
Definition MSCFModel.h:83
double getApparentDecel() const
Get the vehicle type's apparent deceleration [m/s^2] (the one regarded by its followers.
Definition MSCFModel.h:280
double getMaxAccel() const
Get the vehicle type's maximum acceleration [m/s^2].
Definition MSCFModel.h:256
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:380
virtual double maximumLaneSpeedCF(const MSVehicle *const veh, double maxSpeed, double maxSpeedLane) const
Returns the maximum velocity the CF-model wants to achieve in the next step.
Definition MSCFModel.h:224
double maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1, bool relaxEmergency=true) const
Returns the maximum next velocity for stopping within gap.
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:264
double getMinimalArrivalSpeedEuler(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance for Euler update.
virtual double followSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0, const CalcReason usage=CalcReason::CURRENT) const =0
Computes the vehicle's follow speed (no dawdling)
double stopSpeed(const MSVehicle *const veh, const double speed, double gap, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed for approaching a non-moving obstacle (no dawdling)
Definition MSCFModel.h:168
virtual double getHeadwayTime() const
Get the driver's desired headway [s].
Definition MSCFModel.h:311
The ToC Device controls transition of control between automated and manual driving.
std::shared_ptr< MSSimpleDriverState > getDriverState() const
return internal state
void update()
update internal state
A device which collects info on the vehicle trip (mainly on departure and arrival)
double consumption(SUMOVehicle &veh, double a, double newSpeed)
return energy consumption in Wh (power multiplied by TS)
void setConsum(const double consumption)
double acceleration(SUMOVehicle &veh, double power, double oldSpeed)
double getConsum() const
Get consum.
A device which collects info on current friction Coefficient on the road.
A device which collects info on the vehicle trip (mainly on departure and arrival)
A device which collects info on the vehicle trip (mainly on departure and arrival)
void cancelCurrentCustomers()
remove the persons the taxi is currently waiting for from reservations
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Checks whether the vehicle is at a stop and transportable action is needed.
bool anyLeavingAtStop(const MSStop &stop) const
void transferAtSplitOrJoin(MSBaseVehicle *otherVeh)
transfers transportables that want to continue in the other train part (without boarding/loading dela...
void checkCollisionForInactive(MSLane *l)
trigger collision checking for inactive lane
A road/street connecting two junctions.
Definition MSEdge.h:77
static void clear()
Clears the dictionary.
Definition MSEdge.cpp:1092
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition MSEdge.h:204
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
const MSEdge * getOppositeEdge() const
Returns the opposite direction edge if on exists else a nullptr.
Definition MSEdge.cpp:1340
bool isFringe() const
return whether this edge is at the fringe of the network
Definition MSEdge.h:761
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition MSEdge.cpp:947
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Get the allowed lanes to reach the destination-edge.
Definition MSEdge.cpp:479
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:282
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:263
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition MSEdge.cpp:1158
bool hasChangeProhibitions(SUMOVehicleClass svc, int index) const
return whether this edge prohibits changing for the given vClass when starting on the given lane inde...
Definition MSEdge.cpp:1362
const MSJunction * getToJunction() const
Definition MSEdge.h:418
const MSJunction * getFromJunction() const
Definition MSEdge.h:414
int getNumLanes() const
Definition MSEdge.h:172
double getMinimumTravelTime(const SUMOVehicle *const veh) const
returns the minimum travel time for the given vehicle
Definition MSEdge.h:476
bool isRoundabout() const
Definition MSEdge.h:721
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:656
bool isVaporizing() const
Returns whether vehicles on this edge shall be vaporized.
Definition MSEdge.h:434
void addWaiting(SUMOVehicle *vehicle) const
Adds a vehicle to the list of waiting vehicles.
Definition MSEdge.cpp:1451
const MSEdge * getInternalFollowingEdge(const MSEdge *followerAfterInternal, SUMOVehicleClass vClass) const
Definition MSEdge.cpp:900
void removeWaiting(const SUMOVehicle *vehicle) const
Removes a vehicle from the list of waiting vehicles.
Definition MSEdge.cpp:1460
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1258
static bool gModelParkingManoeuver
whether parking simulation includes manoeuver time and any associated lane blocking
Definition MSGlobals.h:162
static bool gUseMesoSim
Definition MSGlobals.h:106
static bool gUseStopStarted
Definition MSGlobals.h:134
static bool gCheckRoutes
Definition MSGlobals.h:91
static SUMOTime gStartupWaitThreshold
The minimum waiting time before applying startupDelay.
Definition MSGlobals.h:180
static double gTLSYellowMinDecel
The minimum deceleration at a yellow traffic light (only overruled by emergencyDecel)
Definition MSGlobals.h:171
static double gLateralResolution
Definition MSGlobals.h:100
static bool gSemiImplicitEulerUpdate
Definition MSGlobals.h:53
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition MSGlobals.h:174
static bool gSublane
whether sublane simulation is enabled (sublane model or continuous lanechanging)
Definition MSGlobals.h:165
static SUMOTime gLaneChangeDuration
Definition MSGlobals.h:97
static double gEmergencyDecelWarningThreshold
threshold for warning about strong deceleration
Definition MSGlobals.h:152
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition MSGlobals.h:81
void add(SUMOVehicle *veh)
Adds a single vehicle for departure.
virtual const MSJunctionLogic * getLogic() const
Definition MSJunction.h:141
virtual const MSLogicJunction::LinkBits & getResponseFor(int linkIndex) const
Returns the response for the given link.
Representation of a lane in the micro simulation.
Definition MSLane.h:84
std::vector< StopWatch< std::chrono::nanoseconds > > & getStopWatch()
Definition MSLane.h:1285
const std::vector< MSMoveReminder * > & getMoveReminders() const
Return the list of this lane's move reminders.
Definition MSLane.h:323
std::pair< MSVehicle *const, double > getFollower(const MSVehicle *ego, double egoPos, double dist, MinorLinkMode mLinkMode) const
Find follower vehicle for the given ego vehicle (which may be on the opposite direction lane)
Definition MSLane.cpp:4317
std::pair< const MSPerson *, double > nextBlocking(double minPos, double minRight, double maxLeft, double stopTime=0, bool bidi=false) const
This is just a wrapper around MSPModel::nextBlocking. You should always check using hasPedestrians be...
Definition MSLane.cpp:4491
MSLane * getParallelLane(int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to this one or 0 if it does not exist.
Definition MSLane.cpp:2774
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2756
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition MSLane.h:456
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition MSLane.cpp:2606
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2692
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition MSLane.h:464
double getBruttoVehLenSum() const
Returns the sum of lengths of vehicles, including their minGaps, which were on the lane during the la...
Definition MSLane.h:1158
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition MSLane.cpp:2620
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2359
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2669
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1349
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3701
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:592
std::vector< MSVehicle * > VehCont
Container for vehicles.
Definition MSLane.h:119
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2391
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:614
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:950
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3192
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
double getMaximumBrakeDist() const
compute maximum braking distance on this lane
Definition MSLane.cpp:2831
const MSLane * getInternalFollowingLane(const MSLane *const) const
returns the internal lane leading to the given lane or nullptr, if there is none
Definition MSLane.cpp:2681
const MSLeaderInfo getLastVehicleInformation(const MSVehicle *ego, double latOffset, double minPos=0, bool allowCached=true) const
Returns the last vehicles on the lane.
Definition MSLane.cpp:1410
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition MSLane.h:853
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:925
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition MSLane.cpp:374
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:574
double getRightSideOnEdge() const
Definition MSLane.h:1194
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4484
int getIndex() const
Returns the lane's index.
Definition MSLane.h:642
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3216
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4312
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3136
double getCenterOnEdge() const
Definition MSLane.h:1202
bool isNormal() const
Definition MSLane.cpp:2552
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2587
bool isInternal() const
Definition MSLane.cpp:2546
@ FOLLOW_NEVER
Definition MSLane.h:974
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition MSLane.cpp:393
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4300
virtual const VehCont & getVehiclesSecure() const
Returns the vehicles container; locks it for microsimulation.
Definition MSLane.h:483
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition MSLane.h:513
bool mustCheckJunctionCollisions() const
whether this lane must check for junction collisions
Definition MSLane.cpp:4571
double interpolateLanePosToGeometryPos(double lanePos) const
Definition MSLane.h:554
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4565
std::pair< MSVehicle *const, double > getLeaderOnConsecutive(double dist, double seen, double speed, const MSVehicle &veh, const std::vector< MSLane * > &bestLaneConts) const
Returns the immediate leader and the distance to him.
Definition MSLane.cpp:2915
@ COLLISION_ACTION_WARN
Definition MSLane.h:203
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4306
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
double getSpaceTillLastStanding(const MSVehicle *ego, bool &foundStopped) const
return the empty space up to the last standing vehicle or the empty space on the whole lane if no veh...
Definition MSLane.cpp:4580
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3161
MSLeaderDistanceInfo getFollowersOnConsecutive(const MSVehicle *ego, double backOffset, bool allSublanes, double searchDist=-1, MinorLinkMode mLinkMode=FOLLOW_ALWAYS) const
return the sublane followers with the largest missing rear gap among all predecessor lanes (within di...
Definition MSLane.cpp:3726
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
MSVehicle * getFirstFullVehicle() const
returns the first vehicle for which this lane is responsible or 0
Definition MSLane.cpp:2578
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition MSLane.h:560
static CollisionAction getCollisionAction()
Definition MSLane.h:1357
saves leader/follower vehicles and their distances relative to an ego vehicle
virtual std::string toString() const
print a debugging representation
void fixOppositeGaps(bool isFollower)
subtract vehicle length from all gaps if the leader vehicle is driving in the opposite direction
virtual int addLeader(const MSVehicle *veh, double gap, double latOffset=0, int sublane=-1)
void setSublaneOffset(int offset)
set number of sublanes by which to shift positions
void removeOpposite(const MSLane *lane)
remove vehicles that are driving in the opposite direction (fully or partially) on the given lane
int numSublanes() const
virtual int addLeader(const MSVehicle *veh, bool beyond, double latOffset=0.)
virtual std::string toString() const
print a debugging representation
virtual void clear()
discard all information
bool hasVehicles() const
int getSublaneOffset() const
void getSubLanes(const MSVehicle *veh, double latOffset, int &rightmost, int &leftmost) const
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_TELEPORT_ARRIVED
The vehicle was teleported out of the net.
@ NOTIFICATION_PARKING_REROUTE
The vehicle needs another parking area.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
@ NOTIFICATION_LANE_CHANGE
The vehicle changes lanes (micro only)
@ NOTIFICATION_VAPORIZED_VAPORIZER
The vehicle got vaporized with a vaporizer.
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
@ NOTIFICATION_PARKING
The vehicle starts or ends parking.
@ NOTIFICATION_VAPORIZED_COLLISION
The vehicle got removed by a collision.
@ NOTIFICATION_LOAD_STATE
The vehicle has been loaded from a state file.
@ NOTIFICATION_TELEPORT
The vehicle is being teleported.
@ NOTIFICATION_TELEPORT_CONTINUATION
The vehicle continues being teleported past an edge.
The simulated network and simulation perfomer.
Definition MSNet.h:89
void removeVehicleStateListener(VehicleStateListener *listener)
Removes a vehicle states listener.
Definition MSNet.cpp:1266
VehicleState
Definition of a vehicle state.
Definition MSNet.h:608
@ STARTING_STOP
The vehicles starts to stop.
@ STARTING_PARKING
The vehicles starts to park.
@ STARTING_TELEPORT
The vehicle started to teleport.
@ ENDING_STOP
The vehicle ends to stop.
@ ARRIVED
The vehicle arrived at his destination (is deleted)
@ EMERGENCYSTOP
The vehicle had to brake harder than permitted.
@ MANEUVERING
Vehicle maneuvering either entering or exiting a parking space.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:186
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition MSNet.cpp:1199
std::string getStoppingPlaceID(const MSLane *lane, const double pos, const SumoXMLTag category) const
Returns the stop of the given category close to the given position.
Definition MSNet.cpp:1402
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
static bool hasInstance()
Returns whether the network was already constructed.
Definition MSNet.h:152
MSStoppingPlace * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Returns the named stopping place of the given category.
Definition MSNet.cpp:1381
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1258
bool hasContainers() const
Returns whether containers are simulated.
Definition MSNet.h:411
void informVehicleStateListener(const SUMOVehicle *const vehicle, VehicleState to, const std::string &info="")
Informs all added listeners about a vehicle's state change.
Definition MSNet.cpp:1275
bool hasPersons() const
Returns whether persons are simulated.
Definition MSNet.h:395
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition MSNet.h:431
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:378
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1190
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:421
bool hasElevation() const
return whether the network contains elevation data
Definition MSNet.h:790
static const double SAFETY_GAP
Definition MSPModel.h:59
A lane area vehicles can halt at.
void leaveFrom(SUMOVehicle *what)
Called if a vehicle leaves this stop.
int getCapacity() const
Returns the area capacity.
void enter(SUMOVehicle *veh)
Called if a vehicle enters this stop.
int getLotIndex(const SUMOVehicle *veh) const
compute lot for this vehicle
int getLastFreeLotAngle() const
Return the angle of myLastFreeLot - the next parking lot only expected to be called after we have est...
bool parkOnRoad() const
whether vehicles park on the road
int getOccupancyIncludingBlocked() const
Returns the area occupancy.
double getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle &forVehicle, double brakePos)
Returns the last free position on this stop including reservations from the current lane and time ste...
double getLastFreeLotGUIAngle() const
Return the GUI angle of myLastFreeLot - the angle the GUI uses to rotate into the next parking lot as...
int getManoeuverAngle(const SUMOVehicle &forVehicle) const
Return the manoeuver angle of the lot where the vehicle is parked.
int getOccupancy() const
Returns the area occupancy.
double getGUIAngle(const SUMOVehicle &forVehicle) const
Return the GUI angle of the lot where the vehicle is parked.
void notifyApproach(const MSLink *link)
switch rail signal to active
static MSRailSignalControl & getInstance()
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:125
const MSEdge * getLastEdge() const
returns the destination edge
Definition MSRoute.cpp:91
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
const MSLane * lane
The lane to stop at (microsim only)
Definition MSStop.h:50
bool triggered
whether an arriving person lets the vehicle continue
Definition MSStop.h:69
bool containerTriggered
whether an arriving container lets the vehicle continue
Definition MSStop.h:71
SUMOTime timeToLoadNextContainer
The time at which the vehicle is able to load another container.
Definition MSStop.h:83
MSStoppingPlace * containerstop
(Optional) container stop if one is assigned to the stop
Definition MSStop.h:56
double getSpeed() const
return speed for passing waypoint / skipping on-demand stop
Definition MSStop.cpp:163
bool joinTriggered
whether coupling another vehicle (train) the vehicle continue
Definition MSStop.h:73
bool isOpposite
whether this an opposite-direction stop
Definition MSStop.h:87
SUMOTime getMinDuration(SUMOTime time) const
return minimum stop duration when starting stop at time
Definition MSStop.cpp:134
int numExpectedContainer
The number of still expected containers.
Definition MSStop.h:79
bool reached
Information whether the stop has been reached.
Definition MSStop.h:75
MSRouteIterator edge
The edge in the route to stop at.
Definition MSStop.h:48
SUMOTime timeToBoardNextPerson
The time at which the vehicle is able to board another person.
Definition MSStop.h:81
bool skipOnDemand
whether the decision to skip this stop has been made
Definition MSStop.h:89
const MSEdge * getEdge() const
Definition MSStop.cpp:54
double getReachedThreshold() const
return startPos taking into account opposite stopping
Definition MSStop.cpp:64
SUMOTime endBoarding
the maximum time at which persons may board this vehicle
Definition MSStop.h:85
double getEndPos(const SUMOVehicle &veh) const
return halting position for upcoming stop;
Definition MSStop.cpp:35
int numExpectedPerson
The number of still expected persons.
Definition MSStop.h:77
MSParkingArea * parkingarea
(Optional) parkingArea if one is assigned to the stop
Definition MSStop.h:58
bool startedFromState
whether the 'started' value was loaded from simulaton state
Definition MSStop.h:91
MSStoppingPlace * chargingStation
(Optional) charging station if one is assigned to the stop
Definition MSStop.h:60
SUMOTime duration
The stopping duration.
Definition MSStop.h:67
SUMOTime getUntil() const
return until / ended time
Definition MSStop.cpp:151
const SUMOVehicleParameter::Stop pars
The stop parameter.
Definition MSStop.h:65
MSStoppingPlace * busstop
(Optional) bus stop if one is assigned to the stop
Definition MSStop.h:54
static bool active()
Definition MSStopOut.h:54
void stopStarted(const SUMOVehicle *veh, int numPersons, int numContainers, SUMOTime time)
Definition MSStopOut.cpp:66
void stopEnded(const SUMOVehicle *veh, const SUMOVehicleParameter::Stop &stop, const std::string &laneOrEdgeID, bool simEnd=false)
static MSStopOut * getInstance()
Definition MSStopOut.h:60
double getBeginLanePosition() const
Returns the begin position of this stop.
bool fits(double pos, const SUMOVehicle &veh) const
return whether the given vehicle fits at the given position
double getEndLanePosition() const
Returns the end position of this stop.
void enter(SUMOVehicle *veh, bool parking)
Called if a vehicle enters this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
void leaveFrom(SUMOVehicle *what)
Called if a vehicle leaves this stop.
bool hasAnyWaiting(const MSEdge *edge, SUMOVehicle *vehicle) const
check whether any transportables are waiting for the given vehicle
bool loadAnyWaiting(const MSEdge *edge, SUMOVehicle *vehicle, SUMOTime &timeToLoadNext, SUMOTime &stopDuration, MSTransportable *const force=nullptr)
load any applicable transportables Loads any person / container that is waiting on that edge for the ...
bool isPerson() const
Whether it is a person.
A static instance of this class in GapControlState deactivates gap control for vehicles whose referen...
Definition MSVehicle.h:1353
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to, const std::string &info="")
Called if a vehicle changes its state.
Changes the wished vehicle speed / lanes.
Definition MSVehicle.h:1348
void setLaneChangeMode(int value)
Sets lane changing behavior.
TraciLaneChangePriority myTraciLaneChangePriority
flags for determining the priority of traci lane change requests
Definition MSVehicle.h:1661
bool getEmergencyBrakeRedLight() const
Returns whether red lights shall be a reason to brake.
Definition MSVehicle.h:1518
SUMOTime getLaneTimeLineEnd()
void adaptLaneTimeLine(int indexShift)
Adapts lane timeline when moving to a new lane and the lane index changes.
void setRemoteControlled(Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector &route, SUMOTime t)
bool isRemoteAffected(SUMOTime t) const
int getSpeedMode() const
return the current speed mode
void deactivateGapController()
Deactivates the gap control.
Influencer()
Constructor.
void setSpeedMode(int speedMode)
Sets speed-constraining behaviors.
std::shared_ptr< GapControlState > myGapControlState
The gap control state.
Definition MSVehicle.h:1609
bool considerSafeVelocity() const
Returns whether safe velocities shall be considered.
Definition MSVehicle.h:1532
int getSignals() const
Definition MSVehicle.h:1580
bool myConsiderMaxDeceleration
Whether the maximum deceleration shall be regarded.
Definition MSVehicle.h:1627
void setLaneTimeLine(const std::vector< std::pair< SUMOTime, int > > &laneTimeLine)
Sets a new lane timeline.
bool myRespectJunctionLeaderPriority
Whether the junction priority rules are respected (within)
Definition MSVehicle.h:1636
void setOriginalSpeed(double speed)
Stores the originally longitudinal speed.
double myOriginalSpeed
The velocity before influence.
Definition MSVehicle.h:1612
double implicitDeltaPosRemote(const MSVehicle *veh)
return the change in longitudinal position that is implicit in the new remote position
double implicitSpeedRemote(const MSVehicle *veh, double oldSpeed)
return the speed that is implicit in the new remote position
void postProcessRemoteControl(MSVehicle *v)
update position from remote control
double gapControlSpeed(SUMOTime currentTime, const SUMOVehicle *veh, double speed, double vSafe, double vMin, double vMax)
Applies gap control logic on the speed.
void setSublaneChange(double latDist)
Sets a new sublane-change request.
double getOriginalSpeed() const
Returns the originally longitudinal speed to use.
SUMOTime myLastRemoteAccess
Definition MSVehicle.h:1645
bool getRespectJunctionLeaderPriority() const
Returns whether junction priority rules within the junction shall be respected (concerns vehicles wit...
Definition MSVehicle.h:1526
LaneChangeMode myStrategicLC
lane changing which is necessary to follow the current route
Definition MSVehicle.h:1650
LaneChangeMode mySpeedGainLC
lane changing to travel with higher speed
Definition MSVehicle.h:1654
void init()
Static initalization.
LaneChangeMode mySublaneLC
changing to the prefered lateral alignment
Definition MSVehicle.h:1658
bool getRespectJunctionPriority() const
Returns whether junction priority rules shall be respected (concerns approaching vehicles outside the...
Definition MSVehicle.h:1510
static void cleanup()
Static cleanup.
int getLaneChangeMode() const
return the current lane change mode
SUMOTime getLaneTimeLineDuration()
double influenceSpeed(SUMOTime currentTime, double speed, double vSafe, double vMin, double vMax)
Applies stored velocity information on the speed to use.
double changeRequestRemainingSeconds(const SUMOTime currentTime) const
Return the remaining number of seconds of the current laneTimeLine assuming one exists.
bool myConsiderSafeVelocity
Whether the safe velocity shall be regarded.
Definition MSVehicle.h:1621
bool mySpeedAdaptationStarted
Whether influencing the speed has already started.
Definition MSVehicle.h:1618
~Influencer()
Destructor.
void setSignals(int signals)
Definition MSVehicle.h:1576
double myLatDist
The requested lateral change.
Definition MSVehicle.h:1615
bool myEmergencyBrakeRedLight
Whether red lights are a reason to brake.
Definition MSVehicle.h:1633
LaneChangeMode myRightDriveLC
changing to the rightmost lane
Definition MSVehicle.h:1656
void setSpeedTimeLine(const std::vector< std::pair< SUMOTime, double > > &speedTimeLine)
Sets a new velocity timeline.
void updateRemoteControlRoute(MSVehicle *v)
update route if provided by remote control
SUMOTime getLastAccessTimeStep() const
Definition MSVehicle.h:1556
bool myConsiderMaxAcceleration
Whether the maximum acceleration shall be regarded.
Definition MSVehicle.h:1624
LaneChangeMode myCooperativeLC
lane changing with the intent to help other vehicles
Definition MSVehicle.h:1652
bool isRemoteControlled() const
bool myRespectJunctionPriority
Whether the junction priority rules are respected (approaching)
Definition MSVehicle.h:1630
int influenceChangeDecision(const SUMOTime currentTime, const MSEdge &currentEdge, const int currentLaneIndex, int state)
Applies stored LaneChangeMode information and laneTimeLine.
void activateGapController(double originalTau, double newTimeHeadway, double newSpaceHeadway, double duration, double changeRate, double maxDecel, MSVehicle *refVeh=nullptr)
Activates the gap control with the given parameters,.
Container for manouevering time associated with stopping.
Definition MSVehicle.h:1272
SUMOTime myManoeuvreCompleteTime
Time at which this manoeuvre should complete.
Definition MSVehicle.h:1324
MSVehicle::ManoeuvreType getManoeuvreType() const
Accessor (get) for manoeuvre type.
std::string myManoeuvreStop
The name of the stop associated with the Manoeuvre - for debug output.
Definition MSVehicle.h:1318
bool manoeuvreIsComplete() const
Check if any manoeuver is ongoing and whether the completion time is beyond currentTime.
bool configureExitManoeuvre(MSVehicle *veh)
Setup the myManoeuvre for exiting (Sets completion time and manoeuvre type)
void setManoeuvreType(const MSVehicle::ManoeuvreType mType)
Accessor (set) for manoeuvre type.
Manoeuvre & operator=(const Manoeuvre &manoeuvre)
Assignment operator.
Manoeuvre()
Constructor.
ManoeuvreType myManoeuvreType
Manoeuvre type - currently entry, exit or none.
Definition MSVehicle.h:1327
double getGUIIncrement() const
Accessor for GUI rotation step when parking (radians)
SUMOTime myManoeuvreStartTime
Time at which the Manoeuvre for this stop started.
Definition MSVehicle.h:1321
bool operator!=(const Manoeuvre &manoeuvre)
Operator !=.
bool entryManoeuvreIsComplete(MSVehicle *veh)
Configure an entry manoeuvre if nothing is configured - otherwise check if complete.
bool manoeuvreIsComplete(const ManoeuvreType checkType) const
Check if specific manoeuver is ongoing and whether the completion time is beyond currentTime.
bool configureEntryManoeuvre(MSVehicle *veh)
Setup the entry manoeuvre for this vehicle (Sets completion time and manoeuvre type)
Container that holds the vehicles driving state (position+speed).
Definition MSVehicle.h:87
double myPosLat
the stored lateral position
Definition MSVehicle.h:140
State(double pos, double speed, double posLat, double backPos, double previousSpeed)
Constructor.
double myPreviousSpeed
the speed at the begin of the previous time step
Definition MSVehicle.h:148
double myPos
the stored position
Definition MSVehicle.h:134
bool operator!=(const State &state)
Operator !=.
double myLastCoveredDist
Definition MSVehicle.h:154
double mySpeed
the stored speed (should be >=0 at any time)
Definition MSVehicle.h:137
State & operator=(const State &state)
Assignment operator.
double pos() const
Position of this state.
Definition MSVehicle.h:107
double myBackPos
the stored back position
Definition MSVehicle.h:145
void passTime(SUMOTime dt, bool waiting)
const std::string getState() const
SUMOTime cumulatedWaitingTime(SUMOTime memory=-1) const
void setState(const std::string &state)
WaitingTimeCollector(SUMOTime memory=MSGlobals::gWaitingTimeMemory)
Constructor.
void registerEmergencyStop()
register emergency stop
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
void registerStopEnded()
register emergency stop
void registerEmergencyBraking()
register emergency stop
void removeVType(const MSVehicleType *vehType)
void registerOneWaiting()
increases the count of vehicles waiting for a transport to allow recognition of person / container re...
void unregisterOneWaiting()
decreases the count of vehicles waiting for a transport to allow recognition of person / container re...
void registerStopStarted()
register emergency stop
Abstract in-vehicle device.
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
void setManoeuvreType(const MSVehicle::ManoeuvreType mType)
accessor function to myManoeuvre equivalent
TraciLaneChangePriority
modes for prioritizing traci lane change requests
Definition MSVehicle.h:1150
@ LCP_OPPORTUNISTIC
Definition MSVehicle.h:1154
double getRightSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
bool wasRemoteControlled(SUMOTime lookBack=DELTA_T) const
Returns the information whether the vehicle is fully controlled via TraCI within the lookBack time.
void processLinkApproaches(double &vSafe, double &vSafeMin, double &vSafeMinDist)
This method iterates through the driveprocess items for the vehicle and adapts the given in/out param...
const MSLane * getPreviousLane(const MSLane *current, int &furtherIndex) const
void checkLinkLeader(const MSLink *link, const MSLane *lane, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass, double &vLinkWait, bool &setRequest, bool isShadowLink=false) const
checks for link leaders on the given link
void checkRewindLinkLanes(const double lengthsInFront, DriveItemVector &lfLinks) const
runs heuristic for keeping the intersection clear in case of downstream jamming
bool willStop() const
Returns whether the vehicle will stop on the current edge.
bool hasDriverState() const
Whether this vehicle is equipped with a MSDriverState.
Definition MSVehicle.h:996
static int nextLinkPriority(const std::vector< MSLane * > &conts)
get a numerical value for the priority of the upcoming link
double getTimeGapOnLane() const
Returns the time gap in seconds to the leader of the vehicle on the same lane.
void updateBestLanes(bool forceRebuild=false, const MSLane *startLane=0)
computes the best lanes to use in order to continue the route
bool myAmIdling
Whether the vehicle is trying to enter the network (eg after parking so engine is running)
Definition MSVehicle.h:1920
SUMOTime myWaitingTime
The time the vehicle waits (is not faster than 0.1m/s) in seconds.
Definition MSVehicle.h:1856
double getStopDelay() const
Returns the public transport stop delay in seconds.
double computeAngle() const
compute the current vehicle angle
double myTimeLoss
the time loss in seconds due to driving with less than maximum speed
Definition MSVehicle.h:1860
SUMOTime myLastActionTime
Action offset (actions are taken at time myActionOffset + N*getActionStepLength()) Initialized to 0,...
Definition MSVehicle.h:1875
ConstMSEdgeVector::const_iterator getRerouteOrigin() const
Returns the starting point for reroutes (usually the current edge)
bool hasArrivedInternal(bool oppositeTransformed=true) const
Returns whether this vehicle has already arived (reached the arrivalPosition on its final edge) metho...
double getFriction() const
Returns the current friction on the road as perceived by the friction device.
bool ignoreFoe(const SUMOTrafficObject *foe) const
decide whether a given foe object may be ignored
void boardTransportables(MSStop &stop)
board persons and load transportables at the given stop
const std::vector< const MSLane * > getUpcomingLanesUntil(double distance) const
Returns the upcoming (best followed by default 0) sequence of lanes to continue the route starting at...
bool isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
Definition MSVehicle.h:605
void adaptLaneEntering2MoveReminder(const MSLane &enteredLane)
Adapts the vehicle's entering of a new lane.
void addTransportable(MSTransportable *transportable)
Adds a person or container to this vehicle.
SUMOTime myJunctionConflictEntryTime
Definition MSVehicle.h:1938
double getLeftSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
PositionVector getBoundingPoly(double offset=0) const
get bounding polygon
void setTentativeLaneAndPosition(MSLane *lane, double pos, double posLat=0)
set tentative lane and position during insertion to ensure that all cfmodels work (some of them requi...
bool brakeForOverlap(const MSLink *link, const MSLane *lane) const
handle with transitions
void workOnMoveReminders(double oldPos, double newPos, double newSpeed)
Processes active move reminder.
bool isStoppedOnLane() const
double getDistanceToPosition(double destPos, const MSLane *destLane) const
bool brokeDown() const
Returns how long the vehicle has been stopped already due to lack of energy.
double myAcceleration
The current acceleration after dawdling in m/s.
Definition MSVehicle.h:1902
void registerInsertionApproach(MSLink *link, double dist)
register approach on insertion
void cleanupFurtherLanes()
remove vehicle from further lanes (on leaving the network)
void adaptToLeaders(const MSLeaderInfo &ahead, double latOffset, const double seen, DriveProcessItem *const lastLink, const MSLane *const lane, double &v, double &vLinkPass) const
const MSLane * getBackLane() const
Returns the lane the where the rear of the object is currently at.
void enterLaneAtInsertion(MSLane *enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification)
Update when the vehicle enters a new lane in the emit step.
double getBackPositionOnLane() const
Get the vehicle's position relative to its current lane.
Definition MSVehicle.h:405
void setPreviousSpeed(double prevSpeed, double prevAcceleration)
Sets the influenced previous speed.
SUMOTime getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const
double getAccumulatedWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s) within the last millisecs.
Definition MSVehicle.h:714
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
bool isFrontOnLane(const MSLane *lane) const
Returns the information whether the front of the vehicle is on the given lane.
virtual ~MSVehicle()
Destructor.
void processLaneAdvances(std::vector< MSLane * > &passedLanes, std::string &emergencyReason)
This method checks if the vehicle has advanced over one or several lanes along its route and triggers...
MSAbstractLaneChangeModel & getLaneChangeModel()
void setEmergencyBlueLight(SUMOTime currentTime)
sets the blue flashing light for emergency vehicles
bool isActionStep(SUMOTime t) const
Returns whether the next simulation step will be an action point for the vehicle.
Definition MSVehicle.h:635
MSAbstractLaneChangeModel * myLaneChangeModel
Definition MSVehicle.h:1882
Position getPositionAlongBestLanes(double offset) const
Return the (x,y)-position, which the vehicle would reach if it continued along its best continuation ...
bool hasValidRouteStart(std::string &msg)
checks wether the vehicle can depart on the first edge
double getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
std::vector< MSLane * > myFurtherLanes
The information into which lanes the vehicle laps into.
Definition MSVehicle.h:1909
bool signalSet(int which) const
Returns whether the given signal is on.
Definition MSVehicle.h:1186
MSCFModel::VehicleVariables * myCFVariables
The per vehicle variables of the car following model.
Definition MSVehicle.h:2147
bool betterContinuation(const LaneQ *bestConnectedNext, const LaneQ &m) const
comparison between different continuations from the same lane
bool addTraciStop(SUMOVehicleParameter::Stop stop, std::string &errorMsg)
void checkLinkLeaderCurrentAndParallel(const MSLink *link, const MSLane *lane, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass, double &vLinkWait, bool &setRequest) const
checks for link leaders of the current link as well as the parallel link (if there is one)
void planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector &lfLinks, double &myStopDist, std::pair< double, const MSLink * > &myNextTurn) const
std::pair< double, const MSLink * > myNextTurn
the upcoming turn for the vehicle
Definition MSVehicle.h:1906
double getDistanceToLeaveJunction() const
get the distance from the start of this lane to the start of the next normal lane (or 0 if this lane ...
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
double getMaxSpeedOnLane() const
Returns the maximal speed for the vehicle on its current lane (including speed factor and deviation,...
bool isRemoteControlled() const
Returns the information whether the vehicle is fully controlled via TraCI.
bool myAmOnNet
Whether the vehicle is on the network (not parking, teleported, vaporized, or arrived)
Definition MSVehicle.h:1917
void enterLaneAtMove(MSLane *enteredLane, bool onTeleporting=false)
Update when the vehicle enters a new lane in the move step.
void adaptBestLanesOccupation(int laneIndex, double density)
update occupation from MSLaneChanger
std::pair< double, double > estimateTimeToNextStop() const
return time (s) and distance to the next stop
double accelThresholdForWaiting() const
maximum acceleration to consider a vehicle as 'waiting' at low speed
Definition MSVehicle.h:2064
void setAngle(double angle, bool straightenFurther=false)
Set a custom vehicle angle in rad, optionally updates furtherLanePosLat.
std::vector< LaneQ >::iterator myCurrentLaneInBestLanes
Definition MSVehicle.h:1897
double getDeltaPos(const double accel) const
calculates the distance covered in the next integration step given an acceleration and assuming the c...
const MSLane * myLastBestLanesInternalLane
Definition MSVehicle.h:1885
void updateOccupancyAndCurrentBestLane(const MSLane *startLane)
updates LaneQ::nextOccupation and myCurrentLaneInBestLanes
const std::vector< MSLane * > getUpstreamOppositeLanes() const
Returns the sequence of opposite lanes corresponding to past lanes.
WaitingTimeCollector myWaitingTimeCollector
Definition MSVehicle.h:1857
void setRemoteState(Position xyPos)
sets position outside the road network
void fixPosition()
repair errors in vehicle position after changing between internal edges
double getAcceleration() const
Returns the vehicle's acceleration in m/s (this is computed as the last step's mean acceleration in c...
Definition MSVehicle.h:514
double getSpeedWithoutTraciInfluence() const
Returns the uninfluenced velocity.
PositionVector getBoundingBox(double offset=0) const
get bounding rectangle
ManoeuvreType
flag identifying which, if any, manoeuvre is in progress
Definition MSVehicle.h:1245
@ MANOEUVRE_ENTRY
Manoeuvre into stopping place.
Definition MSVehicle.h:1247
@ MANOEUVRE_NONE
not manouevring
Definition MSVehicle.h:1251
@ MANOEUVRE_EXIT
Manoeuvre out of stopping place.
Definition MSVehicle.h:1249
const MSEdge * getNextEdgePtr() const
returns the next edge (possibly an internal edge)
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
void setBrakingSignals(double vNext)
sets the braking lights on/off
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
const MSEdge * myLastBestLanesEdge
Definition MSVehicle.h:1884
bool ignoreCollision() const
whether this vehicle is except from collision checks
Influencer * myInfluencer
An instance of a velocity/lane influencing instance; built in "getInfluencer".
Definition MSVehicle.h:2150
void saveState(OutputDevice &out)
Saves the states of a vehicle.
void onRemovalFromNet(const MSMoveReminder::Notification reason)
Called when the vehicle is removed from the network.
void planMove(const SUMOTime t, const MSLeaderInfo &ahead, const double lengthsInFront)
Compute safe velocities for the upcoming lanes based on positions and speeds from the last time step....
bool resumeFromStopping()
int getBestLaneOffset() const
void adaptToJunctionLeader(const std::pair< const MSVehicle *, double > leaderInfo, const double seen, DriveProcessItem *const lastLink, const MSLane *const lane, double &v, double &vLinkPass, double distToCrossing=-1) const
double lateralDistanceToLane(const int offset) const
Get the minimal lateral distance required to move fully onto the lane at given offset.
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
void leaveLaneBack(const MSMoveReminder::Notification reason, const MSLane *leftLane)
Update of reminders if vehicle back leaves a lane during (during forward movement.
void resetActionOffset(const SUMOTime timeUntilNextAction=0)
Resets the action offset for the vehicle.
std::vector< DriveProcessItem > DriveItemVector
Container for used Links/visited Lanes during planMove() and executeMove.
Definition MSVehicle.h:2007
void interpolateLateralZ(Position &pos, double offset, double posLat) const
perform lateral z interpolation in elevated networks
void setBlinkerInformation()
sets the blue flashing light for emergency vehicles
const MSEdge * getCurrentEdge() const
Returns the edge the vehicle is currently at (possibly an internal edge or nullptr)
void adaptToLeaderDistance(const MSLeaderDistanceInfo &ahead, double latOffset, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
DriveItemVector::iterator myNextDriveItem
iterator pointing to the next item in myLFLinkLanes
Definition MSVehicle.h:2020
void leaveLane(const MSMoveReminder::Notification reason, const MSLane *approachedLane=0)
Update of members if vehicle leaves a new lane in the lane change step or at arrival.
const MSLink * myHaveStoppedFor
Definition MSVehicle.h:1942
bool isIdling() const
Returns whether a sim vehicle is waiting to enter a lane (after parking has completed)
Definition MSVehicle.h:621
std::shared_ptr< MSSimpleDriverState > getDriverState() const
Returns the vehicle driver's state.
void removeApproachingInformation(const DriveItemVector &lfLinks) const
unregister approach from all upcoming links
void replaceVehicleType(MSVehicleType *type)
Replaces the current vehicle type by the one given.
SUMOTime myJunctionEntryTimeNeverYield
Definition MSVehicle.h:1937
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
bool rerouteParkingArea(const std::string &parkingAreaID, std::string &errorMsg)
bool hasArrived() const
Returns whether this vehicle has already arived (reached the arrivalPosition on its final edge)
void switchOffSignal(int signal)
Switches the given signal off.
Definition MSVehicle.h:1169
void updateState(double vNext)
updates the vehicles state, given a next value for its speed. This value can be negative in case of t...
double getStopArrivalDelay() const
Returns the estimated public transport stop arrival delay in seconds.
int mySignals
State of things of the vehicle that can be on or off.
Definition MSVehicle.h:1914
bool setExitManoeuvre()
accessor function to myManoeuvre equivalent
bool isOppositeLane(const MSLane *lane) const
whether the give lane is reverse direction of the current route or not
double myStopDist
distance to the next stop or doubleMax if there is none
Definition MSVehicle.h:1928
Signalling
Some boolean values which describe the state of some vehicle parts.
Definition MSVehicle.h:1104
@ VEH_SIGNAL_BLINKER_RIGHT
Right blinker lights are switched on.
Definition MSVehicle.h:1108
@ VEH_SIGNAL_BRAKELIGHT
The brake lights are on.
Definition MSVehicle.h:1114
@ VEH_SIGNAL_EMERGENCY_BLUE
A blue emergency light is on.
Definition MSVehicle.h:1130
@ VEH_SIGNAL_BLINKER_LEFT
Left blinker lights are switched on.
Definition MSVehicle.h:1110
SUMOTime getActionStepLength() const
Returns the vehicle's action step length in millisecs, i.e. the interval between two action points.
Definition MSVehicle.h:525
bool myHaveToWaitOnNextLink
Definition MSVehicle.h:1922
SUMOTime collisionStopTime() const
Returns the remaining time a vehicle needs to stop due to a collision. A negative value indicates tha...
const std::vector< const MSLane * > getPastLanesUntil(double distance) const
Returns the sequence of past lanes (right-most on edge) based on the route starting at the current la...
double getBestLaneDist() const
returns the distance that can be driven without lane change
std::pair< const MSVehicle *const, double > getLeader(double dist=0) const
Returns the leader of the vehicle looking for a fixed distance.
double slowDownForSchedule(double vMinComfortable) const
optionally return an upper bound on speed to stay within the schedule
bool executeMove()
Executes planned vehicle movements with regards to right-of-way.
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
std::pair< const MSVehicle *const, double > getFollower(double dist=0) const
Returns the follower of the vehicle looking for a fixed distance.
SUMOTime getWaitingTimeFor(const MSLink *link) const
getWaitingTime, but taking into account having stopped for a stop-link
ChangeRequest
Requests set via TraCI.
Definition MSVehicle.h:191
@ REQUEST_HOLD
vehicle want's to keep the current lane
Definition MSVehicle.h:199
@ REQUEST_LEFT
vehicle want's to change to left lane
Definition MSVehicle.h:195
@ REQUEST_NONE
vehicle doesn't want to change
Definition MSVehicle.h:193
@ REQUEST_RIGHT
vehicle want's to change to right lane
Definition MSVehicle.h:197
bool isLeader(const MSLink *link, const MSVehicle *veh, const double gap) const
whether the given vehicle must be followed at the given junction
void computeFurtherLanes(MSLane *enteredLane, double pos, bool collision=false)
updates myFurtherLanes on lane insertion or after collision
MSLane * getMutableLane() const
Returns the lane the vehicle is on Non const version indicates that something volatile is going on.
Definition MSVehicle.h:589
std::pair< const MSLane *, double > getLanePosAfterDist(double distance) const
return lane and position along bestlanes at the given distance
SUMOTime myCollisionImmunity
amount of time for which the vehicle is immune from collisions
Definition MSVehicle.h:1931
bool passingMinor() const
decide whether the vehicle is passing a minor link or has comitted to do so
void updateWaitingTime(double vNext)
Updates the vehicle's waiting time counters (accumulated and consecutive)
void enterLaneAtLaneChange(MSLane *enteredLane)
Update when the vehicle enters a new lane in the laneChange step.
BaseInfluencer & getBaseInfluencer()
Returns the velocity/lane influencer.
Influencer & getInfluencer()
bool isBidiOn(const MSLane *lane) const
whether this vehicle is driving against lane
double getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
bool unsafeLinkAhead(const MSLane *lane) const
whether the vehicle may safely move to the given lane with regard to upcoming links
double getCurrentApparentDecel() const
get apparent deceleration based on vType parameters and current acceleration
double updateFurtherLanes(std::vector< MSLane * > &furtherLanes, std::vector< double > &furtherLanesPosLat, const std::vector< MSLane * > &passedLanes)
update a vector of further lanes and return the new backPos
DriveItemVector myLFLinkLanesPrev
planned speeds from the previous step for un-registering from junctions after the new container is fi...
Definition MSVehicle.h:2013
std::vector< std::vector< LaneQ > > myBestLanes
Definition MSVehicle.h:1892
void setActionStepLength(double actionStepLength, bool resetActionOffset=true)
Sets the action steplength of the vehicle.
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
double getSlope() const
Returns the slope of the road at vehicle's position in degrees.
bool myActionStep
The flag myActionStep indicates whether the current time step is an action point for the vehicle.
Definition MSVehicle.h:1872
const Position getBackPosition() const
bool congested() const
void loadState(const SUMOSAXAttributes &attrs, const SUMOTime offset)
Loads the state of this vehicle from the given description.
SUMOTime myTimeSinceStartup
duration of driving (speed > SUMO_const_haltingSpeed) after the last halting episode
Definition MSVehicle.h:1941
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
void setApproachingForAllLinks(const SUMOTime t)
Register junction approaches for all link items in the current plan.
SUMOTime remainingStopDuration() const
Returns the remaining stop duration for a stopped vehicle or 0.
bool keepStopping(bool afterProcessing=false) const
Returns whether the vehicle is stopped and must continue to do so.
void workOnIdleReminders()
cycle through vehicle devices invoking notifyIdle
static std::vector< MSLane * > myEmptyLaneVector
Definition MSVehicle.h:1899
Position myCachedPosition
Definition MSVehicle.h:1933
bool replaceRoute(ConstMSRoutePtr route, const std::string &info, bool onInit=false, int offset=0, bool addStops=true, bool removeStops=true, std::string *msgReturn=nullptr)
Replaces the current route by the given one.
MSVehicle::ManoeuvreType getManoeuvreType() const
accessor function to myManoeuvre equivalent
double checkReversal(bool &canReverse, double speedThreshold=SUMO_const_haltingSpeed, double seen=0) const
void updateLaneBruttoSum()
Update the lane brutto occupancy after a change in minGap.
void removePassedDriveItems()
Erase passed drive items from myLFLinkLanes (and unregister approaching information for corresponding...
const std::vector< MSLane * > & getFurtherLanes() const
Definition MSVehicle.h:835
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
std::vector< double > myFurtherLanesPosLat
lateral positions on further lanes
Definition MSVehicle.h:1911
bool checkActionStep(const SUMOTime t)
Returns whether the vehicle is supposed to take action in the current simulation step Updates myActio...
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:969
Position validatePosition(Position result, double offset=0) const
ensure that a vehicle-relative position is not invalid
void loadPreviousApproaching(MSLink *link, bool setRequest, SUMOTime arrivalTime, double arrivalSpeed, double arrivalSpeedBraking, double dist, double leaveSpeed)
bool keepClear(const MSLink *link) const
decide whether the given link must be kept clear
bool manoeuvreIsComplete() const
accessor function to myManoeuvre equivalent
double processNextStop(double currentVelocity)
Processes stops, returns the velocity needed to reach the stop.
double myAngle
the angle in radians (
Definition MSVehicle.h:1925
bool ignoreRed(const MSLink *link, bool canBrake) const
decide whether a red (or yellow light) may be ignored
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
void updateTimeLoss(double vNext)
Updates the vehicle's time loss.
MSDevice_DriverState * myDriverState
This vehicle's driver state.
Definition MSVehicle.h:1866
bool joinTrainPart(MSVehicle *veh)
try joining the given vehicle to the rear of this one (to resolve joinTriggered)
MSLane * myLane
The lane the vehicle is on.
Definition MSVehicle.h:1880
bool onFurtherEdge(const MSEdge *edge) const
whether this vehicle has its back (and no its front) on the given edge
double processTraCISpeedControl(double vSafe, double vNext)
Check for speed advices from the traci client and adjust the speed vNext in the current (euler) / aft...
Manoeuvre myManoeuvre
Definition MSVehicle.h:1334
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it's primary lane
double getAngle() const
Returns the vehicle's direction in radians.
Definition MSVehicle.h:735
bool handleCollisionStop(MSStop &stop, const double distToStop)
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition MSVehicle.h:1680
MSDevice_Friction * myFrictionDevice
This vehicle's friction perception.
Definition MSVehicle.h:1869
double getPreviousSpeed() const
Returns the vehicle's speed before the previous time step.
Definition MSVehicle.h:498
MSVehicle()
invalidated default constructor
bool joinTrainPartFront(MSVehicle *veh)
try joining the given vehicle to the front of this one (to resolve joinTriggered)
void updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength)
Process an updated action step length value (only affects the vehicle's action offset,...
double getBrakeGap(bool delayed=false) const
get distance for coming to a stop (used for rerouting checks)
void executeFractionalMove(double dist)
move vehicle forward by the given distance during insertion
LaneChangeMode
modes for resolving conflicts between external control (traci) and vehicle control over lane changing...
Definition MSVehicle.h:1142
virtual void drawOutsideNetwork(bool)
register vehicle for drawing while outside the network
Definition MSVehicle.h:1831
void initDevices()
void adaptToOncomingLeader(const std::pair< const MSVehicle *, double > leaderInfo, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
State myState
This Vehicles driving state (pos and speed)
Definition MSVehicle.h:1863
double getCenterOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
void adaptToLeader(const std::pair< const MSVehicle *, double > leaderInfo, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
void switchOnSignal(int signal)
Switches the given signal on.
Definition MSVehicle.h:1161
static bool overlap(const MSVehicle *veh1, const MSVehicle *veh2)
Definition MSVehicle.h:763
int getLaneIndex() const
void updateParkingState()
update state while parking
DriveItemVector myLFLinkLanes
container for the planned speeds in the current step
Definition MSVehicle.h:2010
void updateDriveItems()
Check whether the drive items (myLFLinkLanes) are up to date, and update them if required.
SUMOTime myJunctionEntryTime
time at which the current junction was entered
Definition MSVehicle.h:1936
static MSVehicleTransfer * getInstance()
Returns the instance of this object.
void remove(MSVehicle *veh)
Remove a vehicle from this transfer object.
The car-following model and parameter.
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
double getMaxSpeed() const
Get vehicle's (technical) maximum speed [m/s].
const std::string & getID() const
Returns the name of the vehicle type.
double getMinGap() const
Get the free space in front of vehicles of this class.
LaneChangeModel getLaneChangeModel() const
void setLength(const double &length)
Set a new value for this type's length.
SUMOTime getExitManoeuvreTime(const int angle) const
Accessor function for parameter equivalent returning exit time for a specific manoeuver angle.
const MSCFModel & getCarFollowModel() const
Returns the vehicle type's car following model definition (const version)
bool isVehicleSpecific() const
Returns whether this type belongs to a single vehicle only (was modified)
void setActionStepLength(const SUMOTime actionStepLength, bool resetActionOffset)
Set a new value for this type's action step length.
double getLength() const
Get vehicle's length [m].
SUMOVehicleShape getGuiShape() const
Get this vehicle type's shape.
SUMOTime getEntryManoeuvreTime(const int angle) const
Accessor function for parameter equivalent returning entry time for a specific manoeuver angle.
const SUMOVTypeParameter & getParameter() const
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:67
const std::string & getID() const
Returns the id.
Definition Named.h:74
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
void writeParams(OutputDevice &device) const
write Params in the given outputdevice
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double slopeTo2D(const Position &other) const
returns the slope of the vector pointing from here to the other position (in radians between -M_PI an...
Definition Position.h:291
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:322
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:276
void setz(double z)
set position z
Definition Position.h:80
double z() const
Returns the z-position.
Definition Position.h:65
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition Position.h:286
A list of positions.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
double slopeDegreeAtOffset(double pos) const
Returns the slope at the given length.
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void scaleRelative(double factor)
enlarges/shrinks the polygon by a factor based at the centroid
PositionVector reverse() const
reverse position vector
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
Encapsulated SAX-Attributes.
virtual std::string getString(int id, bool *isPresent=nullptr) const =0
Returns the string-value of the named (by its enum-value) attribute.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
double getFloat(int id) const
Returns the double-value of the named (by its enum-value) attribute.
Representation of a vehicle, person, or container.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual double getSpeed() const =0
Returns the object's current speed.
double speedFactorPremature
the possible speed reduction when a train is ahead of schedule
double getLCParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.
double getJMParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.
Representation of a vehicle.
Definition SUMOVehicle.h:62
Definition of vehicle stop (position and duration)
SUMOTime started
the time at which this stop was reached
ParkingType parking
whether the vehicle is removed from the net while stopping
SUMOTime extension
The maximum time extension for boarding / loading.
std::string split
the id of the vehicle (train portion) that splits of upon reaching this stop
double startPos
The stopping position start.
std::string line
the new line id of the trip within a cyclical public transport route
double posLat
the lateral offset when stopping
bool onDemand
whether the stop may be skipped
std::string join
the id of the vehicle (train portion) to which this vehicle shall be joined
SUMOTime until
The time at which the vehicle may continue its journey.
SUMOTime ended
the time at which this stop was ended
double endPos
The stopping position end.
SUMOTime waitUntil
The earliest pickup time for a taxi stop.
std::string tripId
id of the trip within a cyclical public transport route
bool collision
Whether this stop was triggered by a collision.
SUMOTime arrival
The (expected) time at which the vehicle reaches the stop.
SUMOTime duration
The stopping duration.
Structure representing possible vehicle parameter.
int departLane
(optional) The lane the vehicle shall depart from (index in edge)
ArrivalSpeedDefinition arrivalSpeedProcedure
Information how the vehicle's end speed shall be chosen.
double departSpeed
(optional) The initial speed of the vehicle
std::vector< std::string > via
List of the via-edges the vehicle must visit.
ArrivalLaneDefinition arrivalLaneProcedure
Information how the vehicle shall choose the lane to arrive on.
long long int parametersSet
Information for the router which parameter were set, TraCI may modify this (when changing color)
DepartLaneDefinition departLaneProcedure
Information how the vehicle shall choose the lane to depart from.
bool wasSet(long long int what) const
Returns whether the given parameter was set.
DepartSpeedDefinition departSpeedProcedure
Information how the vehicle's initial speed shall be chosen.
double arrivalPos
(optional) The position the vehicle shall arrive on
ArrivalPosDefinition arrivalPosProcedure
Information how the vehicle shall choose the arrival position.
double arrivalSpeed
(optional) The final speed of the vehicle (not used yet)
int arrivalEdge
(optional) The final edge within the route of the vehicle
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
static SUMOTime processActionStepLength(double given)
Checks and converts given value for the action step length from seconds to miliseconds assuring it be...
std::vector< std::string > getVector()
return vector of strings
#define DEBUG_COND
Definition json.hpp:4471
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
#define M_PI
Definition odrSpiral.cpp:45
Drive process items represent bounds on the safe velocity corresponding to the upcoming links.
Definition MSVehicle.h:1949
void adaptStopSpeed(const double v)
Definition MSVehicle.h:1996
double getLeaveSpeed() const
Definition MSVehicle.h:2000
void adaptLeaveSpeed(const double v)
Definition MSVehicle.h:1988
static std::map< const MSVehicle *, GapControlState * > refVehMap
stores reference vehicles currently in use by a gapController
Definition MSVehicle.h:1407
static GapControlVehStateListener * myVehStateListener
Definition MSVehicle.h:1410
void activate(double tauOriginal, double tauTarget, double additionalGap, double duration, double changeRate, double maxDecel, const MSVehicle *refVeh)
Start gap control with given params.
static void cleanup()
Static cleanup (removes vehicle state listener)
void deactivate()
Stop gap control.
static void init()
Static initalization (adds vehicle state listener)
A structure representing the best lanes for continuing the current route starting at 'lane'.
Definition MSVehicle.h:857
double length
The overall length which may be driven when using this lane without a lane change.
Definition MSVehicle.h:861
bool allowsContinuation
Whether this lane allows to continue the drive.
Definition MSVehicle.h:871
double nextOccupation
As occupation, but without the first lane.
Definition MSVehicle.h:867
std::vector< MSLane * > bestContinuations
Definition MSVehicle.h:877
MSLane * lane
The described lane.
Definition MSVehicle.h:859
double currentLength
The length which may be driven on this lane.
Definition MSVehicle.h:863
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive.
Definition MSVehicle.h:869
double occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition MSVehicle.h:865