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 myInfluencer(nullptr) {
1015}
1016
1017
1027
1028
1029void
1031 for (MSLane* further : myFurtherLanes) {
1032 further->resetPartialOccupation(this);
1033 if (further->getBidiLane() != nullptr
1034 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
1035 further->getBidiLane()->resetPartialOccupation(this);
1036 }
1037 }
1038 if (myLaneChangeModel != nullptr) {
1042 // still needed when calling resetPartialOccupation (getShadowLane) and when removing
1043 // approach information from parallel links
1044 }
1045 myFurtherLanes.clear();
1046 myFurtherLanesPosLat.clear();
1047}
1048
1049
1050void
1052#ifdef DEBUG_ACTIONSTEPS
1053 if (DEBUG_COND) {
1054 std::cout << SIMTIME << " Removing vehicle '" << getID() << "' (reason: " << toString(reason) << ")" << std::endl;
1055 }
1056#endif
1059 leaveLane(reason);
1062 }
1063}
1064
1065
1066void
1073
1074
1075// ------------ interaction with the route
1076bool
1078 // note: not a const method because getDepartLane may call updateBestLanes
1079 if (!(*myCurrEdge)->isTazConnector()) {
1081 if ((*myCurrEdge)->getDepartLane(*this) == nullptr) {
1082 msg = "Invalid departlane definition for vehicle '" + getID() + "'.";
1083 if (myParameter->departLane >= (int)(*myCurrEdge)->getLanes().size()) {
1085 } else {
1087 }
1088 return false;
1089 }
1090 } else {
1091 if ((*myCurrEdge)->allowedLanes(getVClass()) == nullptr) {
1092 msg = "Vehicle '" + getID() + "' is not allowed to depart on any lane of edge '" + (*myCurrEdge)->getID() + "'.";
1094 return false;
1095 }
1096 }
1098 msg = "Departure speed for vehicle '" + getID() + "' is too high for the vehicle type '" + myType->getID() + "'.";
1100 return false;
1101 }
1102 }
1104 return true;
1105}
1106
1107
1108bool
1110 return hasArrivedInternal(false);
1111}
1112
1113
1114bool
1115MSVehicle::hasArrivedInternal(bool oppositeTransformed) const {
1116 return ((myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge))
1117 && (myStops.empty() || myStops.front().edge != myCurrEdge || myStops.front().getSpeed() > 0)
1118 && ((myLaneChangeModel->isOpposite() && !oppositeTransformed) ? myLane->getLength() - myState.myPos : myState.myPos) > myArrivalPos - POSITION_EPS
1119 && !isRemoteControlled());
1120}
1121
1122
1123bool
1124MSVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
1125 if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
1126 // update best lanes (after stops were added)
1127 myLastBestLanesEdge = nullptr;
1129 updateBestLanes(true, onInit ? (*myCurrEdge)->getLanes().front() : 0);
1130 assert(!removeStops || haveValidStopEdges());
1131 if (myStops.size() == 0) {
1132 myStopDist = std::numeric_limits<double>::max();
1133 }
1134 return true;
1135 }
1136 return false;
1137}
1138
1139
1140// ------------ Interaction with move reminders
1141void
1142MSVehicle::workOnMoveReminders(double oldPos, double newPos, double newSpeed) {
1143 // This erasure-idiom works for all stl-sequence-containers
1144 // See Meyers: Effective STL, Item 9
1145 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
1146 // XXX: calling notifyMove with newSpeed seems not the best choice. For the ballistic update, the average speed is calculated and used
1147 // although a higher order quadrature-formula might be more adequate.
1148 // For the euler case (where the speed is considered constant for each time step) it is conceivable that
1149 // the current calculations may lead to systematic errors for large time steps (compared to reality). Refs. #2579
1150 if (!rem->first->notifyMove(*this, oldPos + rem->second, newPos + rem->second, MAX2(0., newSpeed))) {
1151#ifdef _DEBUG
1152 if (myTraceMoveReminders) {
1153 traceMoveReminder("notifyMove", rem->first, rem->second, false);
1154 }
1155#endif
1156 rem = myMoveReminders.erase(rem);
1157 } else {
1158#ifdef _DEBUG
1159 if (myTraceMoveReminders) {
1160 traceMoveReminder("notifyMove", rem->first, rem->second, true);
1161 }
1162#endif
1163 ++rem;
1164 }
1165 }
1166 if (myEnergyParams != nullptr) {
1167 // TODO make the vehicle energy params a derived class which is a move reminder
1168 const double duration = myEnergyParams->getDouble(SUMO_ATTR_DURATION);
1169 if (isStopped()) {
1170 if (duration < 0) {
1173 }
1174 } else {
1175 if (duration >= 0) {
1177 }
1178 }
1180 }
1181}
1182
1183
1184void
1186 updateWaitingTime(0.); // cf issue 2233
1187
1188 // vehicle move reminders
1189 for (const auto& rem : myMoveReminders) {
1190 rem.first->notifyIdle(*this);
1191 }
1192
1193 // lane move reminders - for aggregated values
1194 for (MSMoveReminder* rem : getLane()->getMoveReminders()) {
1195 rem->notifyIdle(*this);
1196 }
1197}
1198
1199// XXX: consider renaming...
1200void
1202 // save the old work reminders, patching the position information
1203 // add the information about the new offset to the old lane reminders
1204 const double oldLaneLength = myLane->getLength();
1205 for (auto& rem : myMoveReminders) {
1206 rem.second += oldLaneLength;
1207#ifdef _DEBUG
1208// if (rem->first==0) std::cout << "Null reminder (?!)" << std::endl;
1209// std::cout << "Adapted MoveReminder on lane " << ((rem->first->getLane()==0) ? "NULL" : rem->first->getLane()->getID()) <<" position to " << rem->second << std::endl;
1210 if (myTraceMoveReminders) {
1211 traceMoveReminder("adaptedPos", rem.first, rem.second, true);
1212 }
1213#endif
1214 }
1215 for (MSMoveReminder* const rem : enteredLane.getMoveReminders()) {
1216 addReminder(rem);
1217 }
1218}
1219
1220
1221// ------------ Other getter methods
1222double
1224 if (isParking() && getStops().begin()->parkingarea != nullptr) {
1225 return getStops().begin()->parkingarea->getVehicleSlope(*this);
1226 }
1227 if (myLane == nullptr) {
1228 return 0;
1229 }
1230 const double posLat = myState.myPosLat; // @todo get rid of the '-'
1231 Position p1 = getPosition();
1233 if (p2 == Position::INVALID) {
1234 // Handle special case of vehicle's back reaching out of the network
1235 if (myFurtherLanes.size() > 0) {
1236 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1237 if (p2 == Position::INVALID) {
1238 // unsuitable lane geometry
1239 p2 = myLane->geometryPositionAtOffset(0, posLat);
1240 }
1241 } else {
1242 p2 = myLane->geometryPositionAtOffset(0, posLat);
1243 }
1244 }
1246}
1247
1248
1250MSVehicle::getPosition(const double offset) const {
1251 if (myLane == nullptr) {
1252 // when called in the context of GUI-Drawing, the simulation step is already incremented
1254 return myCachedPosition;
1255 } else {
1256 return Position::INVALID;
1257 }
1258 }
1259 if (isParking()) {
1260 if (myStops.begin()->parkingarea != nullptr) {
1261 return myStops.begin()->parkingarea->getVehiclePosition(*this);
1262 } else {
1263 // position beside the road
1264 PositionVector shp = myLane->getEdge().getLanes()[0]->getShape();
1267 }
1268 }
1269 const bool changingLanes = myLaneChangeModel->isChangingLanes();
1270 const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
1271 if (offset == 0. && !changingLanes) {
1274 if (MSNet::getInstance()->hasElevation() && MSGlobals::gSublane) {
1276 }
1277 }
1278 return myCachedPosition;
1279 }
1280 Position result = validatePosition(myLane->geometryPositionAtOffset(getPositionOnLane() + offset, posLat), offset);
1281 interpolateLateralZ(result, getPositionOnLane() + offset, posLat);
1282 return result;
1283}
1284
1285
1286void
1287MSVehicle::interpolateLateralZ(Position& pos, double offset, double posLat) const {
1288 const MSLane* shadow = myLaneChangeModel->getShadowLane();
1289 if (shadow != nullptr && pos != Position::INVALID) {
1290 // ignore negative offset
1291 const Position shadowPos = shadow->geometryPositionAtOffset(MAX2(0.0, offset));
1292 if (shadowPos != Position::INVALID && pos.z() != shadowPos.z()) {
1293 const double centerDist = (myLane->getWidth() + shadow->getWidth()) * 0.5;
1294 double relOffset = fabs(posLat) / centerDist;
1295 double newZ = (1 - relOffset) * pos.z() + relOffset * shadowPos.z();
1296 pos.setz(newZ);
1297 }
1298 }
1299}
1300
1301
1302double
1304 double result = getLength() - getPositionOnLane();
1305 if (myLane->isNormal()) {
1306 return MAX2(0.0, result);
1307 }
1308 const MSLane* lane = myLane;
1309 while (lane->isInternal()) {
1310 result += lane->getLength();
1311 lane = lane->getCanonicalSuccessorLane();
1312 }
1313 return result;
1314}
1315
1316
1320 if (!isOnRoad()) {
1321 return Position::INVALID;
1322 }
1323 const std::vector<MSLane*>& bestLanes = getBestLanesContinuation();
1324 auto nextBestLane = bestLanes.begin();
1325 const bool opposite = myLaneChangeModel->isOpposite();
1326 double pos = opposite ? myLane->getLength() - myState.myPos : myState.myPos;
1327 const MSLane* lane = opposite ? myLane->getParallelOpposite() : getLane();
1328 assert(lane != 0);
1329 bool success = true;
1330
1331 while (offset > 0) {
1332 // take into account lengths along internal lanes
1333 while (lane->isInternal() && offset > 0) {
1334 if (offset > lane->getLength() - pos) {
1335 offset -= lane->getLength() - pos;
1336 lane = lane->getLinkCont()[0]->getViaLaneOrLane();
1337 pos = 0.;
1338 if (lane == nullptr) {
1339 success = false;
1340 offset = 0.;
1341 }
1342 } else {
1343 pos += offset;
1344 offset = 0;
1345 }
1346 }
1347 // set nextBestLane to next non-internal lane
1348 while (nextBestLane != bestLanes.end() && *nextBestLane == nullptr) {
1349 ++nextBestLane;
1350 }
1351 if (offset > 0) {
1352 assert(!lane->isInternal());
1353 assert(lane == *nextBestLane);
1354 if (offset > lane->getLength() - pos) {
1355 offset -= lane->getLength() - pos;
1356 ++nextBestLane;
1357 assert(nextBestLane == bestLanes.end() || *nextBestLane != 0);
1358 if (nextBestLane == bestLanes.end()) {
1359 success = false;
1360 offset = 0.;
1361 } else {
1362 const MSLink* link = lane->getLinkTo(*nextBestLane);
1363 assert(link != nullptr);
1364 lane = link->getViaLaneOrLane();
1365 pos = 0.;
1366 }
1367 } else {
1368 pos += offset;
1369 offset = 0;
1370 }
1371 }
1372
1373 }
1374
1375 if (success) {
1377 } else {
1378 return Position::INVALID;
1379 }
1380}
1381
1382
1383double
1385 if (myLane != nullptr) {
1386 return myLane->getVehicleMaxSpeed(this);
1387 }
1388 return myType->getMaxSpeed();
1389}
1390
1391
1393MSVehicle::validatePosition(Position result, double offset) const {
1394 int furtherIndex = 0;
1395 double lastLength = getPositionOnLane();
1396 while (result == Position::INVALID) {
1397 if (furtherIndex >= (int)myFurtherLanes.size()) {
1398 //WRITE_WARNINGF(TL("Could not compute position for vehicle '%', time=%."), getID(), time2string(MSNet::getInstance()->getCurrentTimeStep()));
1399 break;
1400 }
1401 //std::cout << SIMTIME << " veh=" << getID() << " lane=" << myLane->getID() << " pos=" << getPositionOnLane() << " posLat=" << getLateralPositionOnLane() << " offset=" << offset << " result=" << result << " i=" << furtherIndex << " further=" << myFurtherLanes.size() << "\n";
1402 MSLane* further = myFurtherLanes[furtherIndex];
1403 offset += lastLength;
1404 result = further->geometryPositionAtOffset(further->getLength() + offset, -getLateralPositionOnLane());
1405 lastLength = further->getLength();
1406 furtherIndex++;
1407 //std::cout << SIMTIME << " newResult=" << result << "\n";
1408 }
1409 return result;
1410}
1411
1412
1413ConstMSEdgeVector::const_iterator
1415 // too close to the next junction, so avoid an emergency brake here
1416 if (myLane != nullptr && (myCurrEdge + 1) != myRoute->end()) {
1417 if (myLane->isInternal()) {
1418 return myCurrEdge + 1;
1419 }
1420 if (myState.myPos > myLane->getLength() - getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)) {
1421 return myCurrEdge + 1;
1422 }
1424 return myCurrEdge + 1;
1425 }
1426 }
1427 return myCurrEdge;
1428}
1429
1430void
1431MSVehicle::setAngle(double angle, bool straightenFurther) {
1432#ifdef DEBUG_FURTHER
1433 if (DEBUG_COND) {
1434 std::cout << SIMTIME << " veh '" << getID() << " setAngle(" << angle << ") straightenFurther=" << straightenFurther << std::endl;
1435 }
1436#endif
1437 myAngle = angle;
1438 MSLane* next = myLane;
1439 if (straightenFurther && myFurtherLanesPosLat.size() > 0) {
1440 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
1441 MSLane* further = myFurtherLanes[i];
1442 const MSLink* link = further->getLinkTo(next);
1443 if (link != nullptr) {
1445 next = further;
1446 } else {
1447 break;
1448 }
1449 }
1450 }
1451}
1452
1453
1454void
1455MSVehicle::setActionStepLength(double actionStepLength, bool resetOffset) {
1456 SUMOTime actionStepLengthMillisecs = SUMOVehicleParserHelper::processActionStepLength(actionStepLength);
1457 SUMOTime previousActionStepLength = getActionStepLength();
1458 const bool newActionStepLength = actionStepLengthMillisecs != previousActionStepLength;
1459 if (newActionStepLength) {
1460 getSingularType().setActionStepLength(actionStepLengthMillisecs, resetOffset);
1461 if (!resetOffset) {
1462 updateActionOffset(previousActionStepLength, actionStepLengthMillisecs);
1463 }
1464 }
1465 if (resetOffset) {
1467 }
1468}
1469
1470
1471bool
1473 return myState.mySpeed < (60.0 / 3.6) || myLane->getSpeedLimit() < (60.1 / 3.6);
1474}
1475
1476
1477double
1479 Position p1;
1480 const double posLat = -myState.myPosLat; // @todo get rid of the '-'
1481 const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
1482
1483 // if parking manoeuvre is happening then rotate vehicle on each step
1486 }
1487
1488 if (isParking()) {
1489 if (myStops.begin()->parkingarea != nullptr) {
1490 return myStops.begin()->parkingarea->getVehicleAngle(*this);
1491 } else {
1493 }
1494 }
1496 // cannot use getPosition() because it already includes the offset to the side and thus messes up the angle
1497 p1 = myLane->geometryPositionAtOffset(myState.myPos, lefthandSign * posLat);
1498 if (p1 == Position::INVALID && myLane->getShape().length2D() == 0. && myLane->isInternal()) {
1499 // workaround: extrapolate the preceding lane shape
1500 MSLane* predecessorLane = myLane->getCanonicalPredecessorLane();
1501 p1 = predecessorLane->geometryPositionAtOffset(predecessorLane->getLength() + myState.myPos, lefthandSign * posLat);
1502 }
1503 } else {
1504 p1 = getPosition();
1505 }
1506
1507 Position p2;
1508 if (getVehicleType().getParameter().locomotiveLength > 0) {
1509 // articulated vehicle should use the heading of the first part
1510 const double locoLength = MIN2(getVehicleType().getParameter().locomotiveLength, getLength());
1511 p2 = getPosition(-locoLength);
1512 } else {
1513 p2 = getBackPosition();
1514 }
1515 if (p2 == Position::INVALID) {
1516 // Handle special case of vehicle's back reaching out of the network
1517 if (myFurtherLanes.size() > 0) {
1518 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1519 if (p2 == Position::INVALID) {
1520 // unsuitable lane geometry
1521 p2 = myLane->geometryPositionAtOffset(0, posLat);
1522 }
1523 } else {
1524 p2 = myLane->geometryPositionAtOffset(0, posLat);
1525 }
1526 }
1527 double result = (p1 != p2 ? p2.angleTo2D(p1) :
1529
1530 result += lefthandSign * myLaneChangeModel->calcAngleOffset();
1531
1532#ifdef DEBUG_FURTHER
1533 if (DEBUG_COND) {
1534 std::cout << SIMTIME << " computeAngle veh=" << getID() << " p1=" << p1 << " p2=" << p2 << " angle=" << RAD2DEG(result) << " naviDegree=" << GeomHelper::naviDegree(result) << "\n";
1535 }
1536#endif
1537 return result;
1538}
1539
1540
1541const Position
1543 const double posLat = MSGlobals::gLefthand ? myState.myPosLat : -myState.myPosLat;
1544 Position result;
1545 if (myState.myPos >= myType->getLength()) {
1546 // vehicle is fully on the new lane
1548 } else {
1550 // special case where the target lane has no predecessor
1551#ifdef DEBUG_FURTHER
1552 if (DEBUG_COND) {
1553 std::cout << " getBackPosition veh=" << getID() << " specialCase using myLane=" << myLane->getID() << " pos=0 posLat=" << myState.myPosLat << " result=" << myLane->geometryPositionAtOffset(0, posLat) << "\n";
1554 }
1555#endif
1556 result = myLane->geometryPositionAtOffset(0, posLat);
1557 } else {
1558#ifdef DEBUG_FURTHER
1559 if (DEBUG_COND) {
1560 std::cout << " getBackPosition veh=" << getID() << " myLane=" << myLane->getID() << " further=" << toString(myFurtherLanes) << " myFurtherLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
1561 }
1562#endif
1563 if (myFurtherLanes.size() > 0 && !myLaneChangeModel->isChangingLanes()) {
1564 // truncate to 0 if vehicle starts on an edge that is shorter than its length
1565 const double backPos = MAX2(0.0, getBackPositionOnLane(myFurtherLanes.back()));
1566 result = myFurtherLanes.back()->geometryPositionAtOffset(backPos, -myFurtherLanesPosLat.back() * (MSGlobals::gLefthand ? -1 : 1));
1567 } else {
1568 result = myLane->geometryPositionAtOffset(0, posLat);
1569 }
1570 }
1571 }
1573 interpolateLateralZ(result, myState.myPos - myType->getLength(), posLat);
1574 }
1575 return result;
1576}
1577
1578
1579bool
1581 return !isStopped() && !myStops.empty() && myLane != nullptr && &myStops.front().lane->getEdge() == &myLane->getEdge();
1582}
1583
1584bool
1586 return isStopped() && myStops.front().lane == myLane;
1587}
1588
1589bool
1590MSVehicle::keepStopping(bool afterProcessing) const {
1591 if (isStopped()) {
1592 // when coming out of vehicleTransfer we must shift the time forward
1593 return (myStops.front().duration - (afterProcessing ? DELTA_T : 0) > 0 || isStoppedTriggered() || myStops.front().pars.collision
1594 || myStops.front().pars.breakDown || (myStops.front().getSpeed() > 0
1595 && (myState.myPos < MIN2(myStops.front().pars.endPos, myStops.front().lane->getLength() - POSITION_EPS))
1596 && (myStops.front().pars.parking == ParkingType::ONROAD || getSpeed() >= SUMO_const_haltingSpeed)));
1597 } else {
1598 return false;
1599 }
1600}
1601
1602
1605 if (isStopped()) {
1606 return myStops.front().duration;
1607 }
1608 return 0;
1609}
1610
1611
1614 return (myStops.empty() || !myStops.front().pars.collision) ? myCollisionImmunity : MAX2((SUMOTime)0, myStops.front().duration);
1615}
1616
1617
1618bool
1620 return isStopped() && !myStops.empty() && myStops.front().pars.breakDown;
1621}
1622
1623
1624bool
1626 return myCollisionImmunity > 0;
1627}
1628
1629
1630double
1631MSVehicle::processNextStop(double currentVelocity) {
1632 if (myStops.empty()) {
1633 // no stops; pass
1634 return currentVelocity;
1635 }
1636
1637#ifdef DEBUG_STOPS
1638 if (DEBUG_COND) {
1639 std::cout << "\nPROCESS_NEXT_STOP\n" << SIMTIME << " vehicle '" << getID() << "'" << std::endl;
1640 }
1641#endif
1642
1643 MSStop& stop = myStops.front();
1645 if (stop.reached) {
1646 stop.duration -= getActionStepLength();
1647
1648#ifdef DEBUG_STOPS
1649 if (DEBUG_COND) {
1650 std::cout << SIMTIME << " vehicle '" << getID() << "' reached stop.\n"
1651 << "Remaining duration: " << STEPS2TIME(stop.duration) << std::endl;
1652 if (stop.getSpeed() > 0) {
1653 std::cout << " waypointSpeed=" << stop.getSpeed() << " vehPos=" << myState.myPos << " endPos=" << stop.pars.endPos << "\n";
1654 }
1655 }
1656#endif
1657 if (stop.duration <= 0 && stop.pars.join != "") {
1658 // join this train (part) to another one
1659 MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
1660 if (joinVeh && joinVeh->hasDeparted() && (joinVeh->joinTrainPart(this) || joinVeh->joinTrainPartFront(this))) {
1661 stop.joinTriggered = false;
1665 }
1666 // avoid collision warning before this vehicle is removed (joinVeh was already made longer)
1668 // mark this vehicle as arrived
1670 const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = getRoutePosition();
1671 // handle transportables that want to continue in the other vehicle
1672 if (myPersonDevice != nullptr) {
1674 }
1675 if (myContainerDevice != nullptr) {
1677 }
1678 }
1679 }
1680 boardTransportables(stop);
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 (isRailway(getVClass())
1689 && hasStops()) {
1690 // stay on the current lane in case of a double stop
1691 const MSStop& nextStop = getNextStop();
1692 if (nextStop.edge == myCurrEdge) {
1693 const double stopSpeed = getCarFollowModel().stopSpeed(this, getSpeed(), nextStop.pars.endPos - myState.myPos);
1694 //std::cout << SIMTIME << " veh=" << getID() << " resumedFromStopping currentVelocity=" << currentVelocity << " stopSpeed=" << stopSpeed << "\n";
1695 return stopSpeed;
1696 }
1697 }
1698 } else {
1699 if (stop.triggered) {
1700 if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
1701 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1702 stop.triggered = false;
1703 } else if (!myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1704 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1707#ifdef DEBUG_STOPS
1708 if (DEBUG_COND) {
1709 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for person." << std::endl;
1710 }
1711#endif
1712 }
1713 }
1714 if (stop.containerTriggered) {
1715 if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
1716 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1717 stop.containerTriggered = false;
1718 } else if (stop.containerTriggered && !myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1719 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1722#ifdef DEBUG_STOPS
1723 if (DEBUG_COND) {
1724 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for container." << std::endl;
1725 }
1726#endif
1727 }
1728 }
1729 // joining only takes place after stop duration is over
1731 && stop.duration <= (stop.pars.extension >= 0 ? -stop.pars.extension : 0)) {
1732 if (stop.pars.extension >= 0) {
1733 WRITE_WARNINGF(TL("Vehicle '%' aborts joining after extension of %s at time %."), getID(), STEPS2TIME(stop.pars.extension), time2string(SIMSTEP));
1734 stop.joinTriggered = false;
1735 } else {
1736 // keep stopping indefinitely but ensure that simulation terminates
1739 }
1740 }
1741 if (stop.getSpeed() > 0) {
1742 //waypoint mode
1743 if (stop.duration == 0) {
1744 return stop.getSpeed();
1745 } else {
1746 // stop for 'until' (computed in planMove)
1747 return currentVelocity;
1748 }
1749 } else {
1750 // brake
1752 return 0;
1753 } else {
1754 // ballistic:
1755 return getSpeed() - getCarFollowModel().getMaxDecel();
1756 }
1757 }
1758 }
1759 } else {
1760
1761#ifdef DEBUG_STOPS
1762 if (DEBUG_COND) {
1763 std::cout << SIMTIME << " vehicle '" << getID() << "' hasn't reached next stop." << std::endl;
1764 }
1765#endif
1766 //std::cout << SIMTIME << " myStopDist=" << myStopDist << " bGap=" << getBrakeGap(myLane->getVehicleMaxSpeed(this)) << "\n";
1767 if (stop.pars.onDemand && !stop.skipOnDemand && myStopDist <= getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this))) {
1768 MSNet* const net = MSNet::getInstance();
1769 const bool noExits = ((myPersonDevice == nullptr || !myPersonDevice->anyLeavingAtStop(stop))
1770 && (myContainerDevice == nullptr || !myContainerDevice->anyLeavingAtStop(stop)));
1771 const bool noEntries = ((!net->hasPersons() || !net->getPersonControl().hasAnyWaiting(stop.getEdge(), this))
1772 && (!net->hasContainers() || !net->getContainerControl().hasAnyWaiting(stop.getEdge(), this)));
1773 if (noExits && noEntries) {
1774 //std::cout << " skipOnDemand\n";
1775 stop.skipOnDemand = true;
1776 }
1777 }
1778 // is the next stop on the current lane?
1779 if (stop.edge == myCurrEdge) {
1780 // get the stopping position
1781 bool useStoppingPlace = stop.busstop != nullptr || stop.containerstop != nullptr || stop.parkingarea != nullptr;
1782 bool fitsOnStoppingPlace = true;
1783 if (!stop.skipOnDemand) { // no need to check available space if we skip it anyway
1784 if (stop.busstop != nullptr) {
1785 fitsOnStoppingPlace &= stop.busstop->fits(myState.myPos, *this);
1786 }
1787 if (stop.containerstop != nullptr) {
1788 fitsOnStoppingPlace &= stop.containerstop->fits(myState.myPos, *this);
1789 }
1790 // if the stop is a parking area we check if there is a free position on the area
1791 if (stop.parkingarea != nullptr) {
1792 fitsOnStoppingPlace &= myState.myPos > stop.parkingarea->getBeginLanePosition();
1793 if (stop.parkingarea->getOccupancy() >= stop.parkingarea->getCapacity()) {
1794 fitsOnStoppingPlace = false;
1795 // trigger potential parkingZoneReroute
1796 MSParkingArea* oldParkingArea = stop.parkingarea;
1797 for (MSMoveReminder* rem : myLane->getMoveReminders()) {
1798 if (rem->isParkingRerouter()) {
1799 rem->notifyEnter(*this, MSMoveReminder::NOTIFICATION_PARKING_REROUTE, myLane);
1800 }
1801 }
1802 if (myStops.empty() || myStops.front().parkingarea != oldParkingArea) {
1803 // rerouted, keep driving
1804 return currentVelocity;
1805 }
1806 } else if (stop.parkingarea->getOccupancyIncludingBlocked() >= stop.parkingarea->getCapacity()) {
1807 fitsOnStoppingPlace = false;
1808 } else if (stop.parkingarea->parkOnRoad() && stop.parkingarea->getLotIndex(this) < 0) {
1809 fitsOnStoppingPlace = false;
1810 }
1811 }
1812 }
1813 const double targetPos = myState.myPos + myStopDist + (stop.getSpeed() > 0 ? (stop.pars.startPos - stop.pars.endPos) : 0);
1814 const double reachedThreshold = (useStoppingPlace ? targetPos - STOPPING_PLACE_OFFSET : stop.getReachedThreshold()) - NUMERICAL_EPS;
1815#ifdef DEBUG_STOPS
1816 if (DEBUG_COND) {
1817 std::cout << " pos=" << myState.pos() << " speed=" << currentVelocity << " targetPos=" << targetPos << " fits=" << fitsOnStoppingPlace
1818 << " reachedThresh=" << reachedThreshold
1819 << " myLane=" << Named::getIDSecure(myLane)
1820 << " stopLane=" << Named::getIDSecure(stop.lane)
1821 << "\n";
1822 }
1823#endif
1824 if (myState.pos() >= reachedThreshold && fitsOnStoppingPlace && currentVelocity <= stop.getSpeed() + SUMO_const_haltingSpeed && myLane == stop.lane
1826 // ok, we may stop (have reached the stop) and either we are not modelling maneuvering or have completed entry
1827 stop.reached = true;
1828 if (!stop.startedFromState) {
1829 stop.pars.started = time;
1830 }
1831#ifdef DEBUG_STOPS
1832 if (DEBUG_COND) {
1833 std::cout << SIMTIME << " vehicle '" << getID() << "' reached next stop." << std::endl;
1834 }
1835#endif
1836 if (MSStopOut::active()) {
1838 }
1839 myLane->getEdge().addWaiting(this);
1842 // compute stopping time
1843 stop.duration = stop.getMinDuration(time);
1844 stop.endBoarding = stop.pars.extension >= 0 ? time + stop.duration + stop.pars.extension : SUMOTime_MAX;
1845 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1846 if (taxiDevice != nullptr && stop.pars.extension >= 0) {
1847 // earliestPickupTime is set with waitUntil
1848 stop.endBoarding = MAX2(time, stop.pars.waitUntil) + stop.pars.extension;
1849 }
1850 if (stop.getSpeed() > 0) {
1851 // ignore duration parameter in waypoint mode unless 'until' or 'ended' are set
1852 if (stop.getUntil() > time) {
1853 stop.duration = stop.getUntil() - time;
1854 } else {
1855 stop.duration = 0;
1856 }
1857 }
1858 if (stop.busstop != nullptr) {
1859 // let the bus stop know the vehicle
1860 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
1861 }
1862 if (stop.containerstop != nullptr) {
1863 // let the container stop know the vehicle
1865 }
1866 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
1867 // let the parking area know the vehicle
1868 stop.parkingarea->enter(this);
1869 }
1870 if (stop.chargingStation != nullptr) {
1871 // let the container stop know the vehicle
1873 }
1874
1875 if (stop.pars.tripId != "") {
1876 ((SUMOVehicleParameter&)getParameter()).setParameter("tripId", stop.pars.tripId);
1877 }
1878 if (stop.pars.line != "") {
1879 ((SUMOVehicleParameter&)getParameter()).line = stop.pars.line;
1880 }
1881 if (stop.pars.split != "") {
1882 // split the train
1883 MSVehicle* splitVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.split));
1884 if (splitVeh == nullptr) {
1885 WRITE_WARNINGF(TL("Vehicle '%' to split from vehicle '%' is not known. time=%."), stop.pars.split, getID(), SIMTIME)
1886 } else {
1888 splitVeh->getRoute().getEdges()[0]->removeWaiting(splitVeh);
1890 const double newLength = MAX2(myType->getLength() - splitVeh->getVehicleType().getLength(),
1892 getSingularType().setLength(newLength);
1893 // handle transportables that want to continue in the split part
1894 if (myPersonDevice != nullptr) {
1896 }
1897 if (myContainerDevice != nullptr) {
1899 }
1901 const double backShift = splitVeh->getLength() + getVehicleType().getMinGap();
1902 myState.myPos -= backShift;
1903 myState.myBackPos -= backShift;
1904 }
1905 }
1906 }
1907
1908 boardTransportables(stop);
1909 if (stop.pars.posLat != INVALID_DOUBLE) {
1910 myState.myPosLat = stop.pars.posLat;
1911 }
1912 }
1913 }
1914 }
1915 return currentVelocity;
1916}
1917
1918
1919void
1921 if (stop.skipOnDemand) {
1922 return;
1923 }
1924 // we have reached the stop
1925 // any waiting persons may board now
1927 MSNet* const net = MSNet::getInstance();
1928 const bool boarded = (time <= stop.endBoarding
1929 && net->hasPersons()
1931 && stop.numExpectedPerson == 0);
1932 // load containers
1933 const bool loaded = (time <= stop.endBoarding
1934 && net->hasContainers()
1936 && stop.numExpectedContainer == 0);
1937
1938 bool unregister = false;
1939 if (time > stop.endBoarding) {
1940 // for taxi: cancel customers
1941 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1942 if (taxiDevice != nullptr) {
1943 taxiDevice->cancelCurrentCustomers();
1944 }
1945
1946 stop.triggered = false;
1947 stop.containerTriggered = false;
1949 unregister = true;
1951 }
1952 }
1953 if (boarded) {
1954 // the triggering condition has been fulfilled. Maybe we want to wait a bit longer for additional riders (car pooling)
1956 unregister = true;
1957 }
1958 stop.triggered = false;
1960 }
1961 if (loaded) {
1962 // the triggering condition has been fulfilled
1964 unregister = true;
1965 }
1966 stop.containerTriggered = false;
1968 }
1969
1970 if (unregister) {
1972#ifdef DEBUG_STOPS
1973 if (DEBUG_COND) {
1974 std::cout << SIMTIME << " vehicle '" << getID() << "' unregisters as waiting for transportable." << std::endl;
1975 }
1976#endif
1977 }
1978}
1979
1980bool
1982 // check if veh is close enough to be joined to the rear of this vehicle
1983 MSLane* backLane = myFurtherLanes.size() == 0 ? myLane : myFurtherLanes.back();
1984 double gap = getBackPositionOnLane() - veh->getPositionOnLane();
1985 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == veh->getLane()
1986 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
1987 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
1988 getSingularType().setLength(newLength);
1989 myStops.begin()->joinTriggered = false;
1993 }
1994 return true;
1995 } else {
1996 return false;
1997 }
1998}
1999
2000
2001bool
2003 // check if veh is close enough to be joined to the front of this vehicle
2004 MSLane* backLane = veh->myFurtherLanes.size() == 0 ? veh->myLane : veh->myFurtherLanes.back();
2005 double gap = veh->getBackPositionOnLane(backLane) - getPositionOnLane();
2006 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == getLane()
2007 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
2008 double skippedLaneLengths = 0;
2009 if (veh->myFurtherLanes.size() > 0) {
2010 skippedLaneLengths += getLane()->getLength();
2011 // this vehicle must be moved to the lane of veh
2012 // ensure that lane and furtherLanes of veh match our route
2013 int routeIndex = getRoutePosition();
2014 if (myLane->isInternal()) {
2015 routeIndex++;
2016 }
2017 for (int i = (int)veh->myFurtherLanes.size() - 1; i >= 0; i--) {
2018 MSEdge* edge = &veh->myFurtherLanes[i]->getEdge();
2019 if (edge->isInternal()) {
2020 continue;
2021 }
2022 if (!edge->isInternal() && edge != 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 routeIndex++;
2028 }
2029 if (veh->getCurrentEdge()->getNormalSuccessor() != myRoute->getEdges()[routeIndex]) {
2030 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
2031 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
2032 return false;
2033 }
2034 for (int i = (int)veh->myFurtherLanes.size() - 2; i >= 0; i--) {
2035 skippedLaneLengths += veh->myFurtherLanes[i]->getLength();
2036 }
2037 }
2038
2039 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
2040 getSingularType().setLength(newLength);
2041 // lane will be advanced just as for regular movement
2042 myState.myPos = skippedLaneLengths + veh->getPositionOnLane();
2043 myStops.begin()->joinTriggered = false;
2047 }
2048 return true;
2049 } else {
2050 return false;
2051 }
2052}
2053
2054double
2055MSVehicle::getBrakeGap(bool delayed) const {
2056 return getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), delayed ? getCarFollowModel().getHeadwayTime() : 0);
2057}
2058
2059
2060bool
2063 if (myActionStep) {
2064 myLastActionTime = t;
2065 }
2066 return myActionStep;
2067}
2068
2069
2070void
2071MSVehicle::resetActionOffset(const SUMOTime timeUntilNextAction) {
2072 myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + timeUntilNextAction;
2073}
2074
2075
2076void
2077MSVehicle::updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength) {
2079 SUMOTime timeSinceLastAction = now - myLastActionTime;
2080 if (timeSinceLastAction == 0) {
2081 // Action was scheduled now, may be delayed be new action step length
2082 timeSinceLastAction = oldActionStepLength;
2083 }
2084 if (timeSinceLastAction >= newActionStepLength) {
2085 // Action point required in this step
2086 myLastActionTime = now;
2087 } else {
2088 SUMOTime timeUntilNextAction = newActionStepLength - timeSinceLastAction;
2089 resetActionOffset(timeUntilNextAction);
2090 }
2091}
2092
2093
2094
2095void
2096MSVehicle::planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront) {
2097#ifdef DEBUG_PLAN_MOVE
2098 if (DEBUG_COND) {
2099 std::cout
2100 << "\nPLAN_MOVE\n"
2101 << SIMTIME
2102 << std::setprecision(gPrecision)
2103 << " veh=" << getID()
2104 << " lane=" << myLane->getID()
2105 << " pos=" << getPositionOnLane()
2106 << " posLat=" << getLateralPositionOnLane()
2107 << " speed=" << getSpeed()
2108 << "\n";
2109 }
2110#endif
2111 // Update the driver state
2112 if (hasDriverState()) {
2114 setActionStepLength(myDriverState->getDriverState()->getActionStepLength(), false);
2115 }
2116
2117 if (!checkActionStep(t)) {
2118#ifdef DEBUG_ACTIONSTEPS
2119 if (DEBUG_COND) {
2120 std::cout << STEPS2TIME(t) << " vehicle '" << getID() << "' skips action." << std::endl;
2121 }
2122#endif
2123 // During non-action passed drive items still need to be removed
2124 // @todo rather work with updating myCurrentDriveItem (refs #3714)
2126 return;
2127 } else {
2128#ifdef DEBUG_ACTIONSTEPS
2129 if (DEBUG_COND) {
2130 std::cout << STEPS2TIME(t) << " vehicle = '" << getID() << "' takes action." << std::endl;
2131 }
2132#endif
2134 if (myInfluencer != nullptr) {
2136 }
2138#ifdef DEBUG_PLAN_MOVE
2139 if (DEBUG_COND) {
2140 DriveItemVector::iterator i;
2141 for (i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
2142 std::cout
2143 << " vPass=" << (*i).myVLinkPass
2144 << " vWait=" << (*i).myVLinkWait
2145 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
2146 << " request=" << (*i).mySetRequest
2147 << "\n";
2148 }
2149 }
2150#endif
2151 checkRewindLinkLanes(lengthsInFront, myLFLinkLanes);
2153 // ideally would only do this with the call inside planMoveInternal - but that needs a const method
2154 // so this is a kludge here - nuisance as it adds an extra check in a busy loop
2158 }
2159 }
2160 }
2162}
2163
2164
2165bool
2166MSVehicle::brakeForOverlap(const MSLink* link, const MSLane* lane) const {
2167 // @review needed
2168 //const double futurePosLat = getLateralPositionOnLane() + link->getLateralShift();
2169 //const double overlap = getLateralOverlap(futurePosLat, link->getViaLaneOrLane());
2170 //const double edgeWidth = link->getViaLaneOrLane()->getEdge().getWidth();
2171 const double futurePosLat = getLateralPositionOnLane() + (
2172 lane != myLane && lane->isInternal() ? lane->getIncomingLanes()[0].viaLink->getLateralShift() : 0);
2173 const double overlap = getLateralOverlap(futurePosLat, lane);
2174 const double edgeWidth = lane->getEdge().getWidth();
2175 const bool result = (overlap > POSITION_EPS
2176 // do not get stuck on narrow edges
2177 && getVehicleType().getWidth() <= edgeWidth
2178 && link->getViaLane() == nullptr
2179 // this is the exit link of a junction. The normal edge should support the shadow
2180 && ((myLaneChangeModel->getShadowLane(link->getLane()) == nullptr)
2181 // the internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
2182 || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
2183 // ignore situations where the shadow lane is part of a double-connection with the current lane
2184 && (myLaneChangeModel->getShadowLane() == nullptr
2185 || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
2186 || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != link->getLane()));
2187
2188#ifdef DEBUG_PLAN_MOVE
2189 if (DEBUG_COND) {
2190 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getDescription() << " lane=" << lane->getID()
2191 << " shift=" << link->getLateralShift()
2192 << " fpLat=" << futurePosLat << " overlap=" << overlap << " w=" << getVehicleType().getWidth() << " result=" << result << "\n";
2193 }
2194#endif
2195 return result;
2196}
2197
2198
2199
2200void
2201MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, std::pair<double, const MSLink*>& nextTurn) const {
2202 lfLinks.clear();
2203 newStopDist = std::numeric_limits<double>::max();
2204 //
2205 const MSCFModel& cfModel = getCarFollowModel();
2206 const double vehicleLength = getVehicleType().getLength();
2207 const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
2208 const bool opposite = myLaneChangeModel->isOpposite();
2209 double laneMaxV = myLane->getVehicleMaxSpeed(this);
2210 const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
2211 double lateralShift = 0;
2212 if (isRailway((SVCPermissions)getVehicleType().getVehicleClass())) {
2213 // speed limits must hold for the whole length of the train
2214 for (MSLane* l : myFurtherLanes) {
2215 laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this));
2216#ifdef DEBUG_PLAN_MOVE
2217 if (DEBUG_COND) {
2218 std::cout << " laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
2219 }
2220#endif
2221 }
2222 }
2223 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2224 laneMaxV = MAX2(laneMaxV, vMinComfortable);
2226 laneMaxV = std::numeric_limits<double>::max();
2227 }
2228 // v is the initial maximum velocity of this vehicle in this step
2229 double v = cfModel.maximumLaneSpeedCF(this, maxV, laneMaxV);
2230 // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
2231 // in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
2234 }
2235
2236 if (myInfluencer != nullptr) {
2237 const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
2238#ifdef DEBUG_TRACI
2239 if (DEBUG_COND) {
2240 std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
2241 }
2242#endif
2243 v = myInfluencer->influenceSpeed(t, v, v, vMin, maxV);
2244#ifdef DEBUG_TRACI
2245 if (DEBUG_COND) {
2246 std::cout << " influencedSpeed=" << v;
2247 }
2248#endif
2249 v = myInfluencer->gapControlSpeed(t, this, v, v, vMin, maxV);
2250#ifdef DEBUG_TRACI
2251 if (DEBUG_COND) {
2252 std::cout << " gapControlSpeed=" << v << "\n";
2253 }
2254#endif
2255 }
2256 // all links within dist are taken into account (potentially)
2257 const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
2258
2259 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
2260#ifdef DEBUG_PLAN_MOVE
2261 if (DEBUG_COND) {
2262 std::cout << " dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
2263 << "\n maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
2264 }
2265#endif
2266 assert(bestLaneConts.size() > 0);
2267 bool hadNonInternal = false;
2268 // the distance already "seen"; in the following always up to the end of the current "lane"
2269 double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
2270 nextTurn.first = seen;
2271 nextTurn.second = nullptr;
2272 bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
2273 double seenNonInternal = 0;
2274 double seenInternal = myLane->isInternal() ? seen : 0;
2275 double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2276 int view = 0;
2277 DriveProcessItem* lastLink = nullptr;
2278 bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
2279 double mustSeeBeforeReversal = 0;
2280 // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
2281 const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
2282 assert(lane != 0);
2283 const MSLane* leaderLane = myLane;
2284 bool foundRailSignal = !isRailway(getVClass());
2285 bool planningToStop = false;
2286#ifdef PARALLEL_STOPWATCH
2287 myLane->getStopWatch()[0].start();
2288#endif
2289
2290 // optionally slow down to match arrival time
2291 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2292 if (v > vMinComfortable && hasStops() && myStops.front().pars.arrival >= 0 && sfp > 0
2293 && v > myLane->getSpeedLimit() * sfp
2294 && !myStops.front().reached) {
2295 const double vSlowDown = slowDownForSchedule(vMinComfortable);
2296 v = MIN2(v, vSlowDown);
2297 }
2298 auto stopIt = myStops.begin();
2299 while (true) {
2300 // check leader on lane
2301 // leader is given for the first edge only
2302 if (opposite &&
2303 (leaderLane->getVehicleNumberWithPartials() > 1
2304 || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
2305 ahead.clear();
2306 // find opposite-driving leader that must be respected on the currently looked at lane
2307 // (only looking at one lane at a time)
2308 const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
2309 const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
2310 const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
2311 MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
2312 const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 * myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
2313 for (int i = 0; i < cands.numSublanes(); i++) {
2314 CLeaderDist cand = cands[i];
2315 if (cand.first != 0) {
2316 if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
2317 || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
2318 // respect leaders that also drive in the opposite direction (fully or with some overlap)
2319 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
2320 } else {
2321 // avoid frontal collision
2322 const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
2323 const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
2324 if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
2325 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
2326 }
2327 }
2328 }
2329 }
2330#ifdef DEBUG_PLAN_MOVE
2331 if (DEBUG_COND) {
2332 std::cout << " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
2333 << " cands=" << cands.toString() << " oppositeLeaders=" << oppositeLeaders.toString() << "\n";
2334 }
2335#endif
2336 adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
2337 } else {
2339 const double rightOL = getRightSideOnLane(lane) + lateralShift;
2340 const double leftOL = getLeftSideOnLane(lane) + lateralShift;
2341 const bool outsideLeft = leftOL > lane->getWidth();
2342#ifdef DEBUG_PLAN_MOVE
2343 if (DEBUG_COND) {
2344 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
2345 }
2346#endif
2347 if (rightOL < 0 || outsideLeft) {
2348 MSLeaderInfo outsideLeaders(lane->getWidth());
2349 // if ego is driving outside lane bounds we must consider
2350 // potential leaders that are also outside bounds
2351 int sublaneOffset = 0;
2352 if (outsideLeft) {
2353 sublaneOffset = MIN2(-1, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution));
2354 } else {
2355 sublaneOffset = MAX2(1, (int)ceil(-rightOL / MSGlobals::gLateralResolution));
2356 }
2357 outsideLeaders.setSublaneOffset(sublaneOffset);
2358#ifdef DEBUG_PLAN_MOVE
2359 if (DEBUG_COND) {
2360 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
2361 }
2362#endif
2363 for (const MSVehicle* cand : lane->getVehiclesSecure()) {
2364 if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
2365 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
2366 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
2367 outsideLeaders.addLeader(cand, true);
2368#ifdef DEBUG_PLAN_MOVE
2369 if (DEBUG_COND) {
2370 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << outsideLeaders.toString() << "\n";
2371 }
2372#endif
2373 }
2374 }
2375 lane->releaseVehicles();
2376 if (outsideLeaders.hasVehicles()) {
2377 adaptToLeaders(outsideLeaders, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2378 }
2379 }
2380 }
2381 adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2382 }
2383 if (lastLink != nullptr) {
2384 lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
2385 }
2386#ifdef DEBUG_PLAN_MOVE
2387 if (DEBUG_COND) {
2388 std::cout << "\nv = " << v << "\n";
2389
2390 }
2391#endif
2392 // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
2393 if (myLaneChangeModel->getShadowLane() != nullptr) {
2394 // also slow down for leaders on the shadowLane relative to the current lane
2395 const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
2396 if (shadowLane != nullptr
2397 && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
2398 // continous lane change cannot be stopped so we must adapt to the leader on the target lane
2400 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
2403 // ego posLat is added when retrieving sublanes but it
2404 // should be negated (subtract twice to compensate)
2405 latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
2406 - 2 * getLateralPositionOnLane());
2407
2408 }
2409 MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
2410#ifdef DEBUG_PLAN_MOVE
2412 std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2413 }
2414#endif
2416 // ignore oncoming vehicles on the shadow lane
2417 shadowLeaders.removeOpposite(shadowLane);
2418 }
2419 const double turningDifference = MAX2(0.0, leaderLane->getLength() - shadowLane->getLength());
2420 adaptToLeaders(shadowLeaders, latOffset, seen - turningDifference, lastLink, shadowLane, v, vLinkPass);
2421 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
2422 // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
2423 // (and thus in the same direction as ego)
2424 MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
2425 const double latOffset = 0;
2426#ifdef DEBUG_PLAN_MOVE
2427 if (DEBUG_COND) {
2428 std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
2429 << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2430 }
2431#endif
2432 shadowLeaders.fixOppositeGaps(true);
2433#ifdef DEBUG_PLAN_MOVE
2434 if (DEBUG_COND) {
2435 std::cout << " shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
2436 }
2437#endif
2438 adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
2439 }
2440 }
2441 }
2442 // adapt to pedestrians on the same lane
2443 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2444 const double relativePos = lane->getLength() - seen;
2445#ifdef DEBUG_PLAN_MOVE
2446 if (DEBUG_COND) {
2447 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2448 }
2449#endif
2450 const double stopTime = MAX2(1.0, ceil(getSpeed() / cfModel.getMaxDecel()));
2451 PersonDist leader = lane->nextBlocking(relativePos,
2452 getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
2453 if (leader.first != 0) {
2454 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2455 v = MIN2(v, stopSpeed);
2456#ifdef DEBUG_PLAN_MOVE
2457 if (DEBUG_COND) {
2458 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2459 }
2460#endif
2461 }
2462 }
2463 if (lane->getBidiLane() != nullptr) {
2464 // adapt to pedestrians on the bidi lane
2465 const MSLane* bidiLane = lane->getBidiLane();
2466 if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
2467 const double relativePos = seen;
2468#ifdef DEBUG_PLAN_MOVE
2469 if (DEBUG_COND) {
2470 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2471 }
2472#endif
2473 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2474 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
2475 PersonDist leader = bidiLane->nextBlocking(relativePos,
2476 leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
2477 if (leader.first != 0) {
2478 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2479 v = MIN2(v, stopSpeed);
2480#ifdef DEBUG_PLAN_MOVE
2481 if (DEBUG_COND) {
2482 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2483 }
2484#endif
2485 }
2486 }
2487 }
2488
2489 // process all stops and waypoints on the current edge
2490 bool foundRealStop = false;
2491 while (stopIt != myStops.end()
2492 && ((&stopIt->lane->getEdge() == &lane->getEdge())
2493 || (stopIt->isOpposite && stopIt->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
2494 // ignore stops that occur later in a looped route
2495 && stopIt->edge == myCurrEdge + view) {
2496 double stopDist = std::numeric_limits<double>::max();
2497 const MSStop& stop = *stopIt;
2498 const bool isFirstStop = stopIt == myStops.begin();
2499 stopIt++;
2500 if (!stop.reached || (stop.getSpeed() > 0 && keepStopping())) {
2501 // we are approaching a stop on the edge; must not drive further
2502 bool isWaypoint = stop.getSpeed() > 0;
2503 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
2504 if (stop.parkingarea != nullptr) {
2505 // leave enough space so parking vehicles can exit
2506 const double brakePos = getBrakeGap() + lane->getLength() - seen;
2507 endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
2508 } else if (isWaypoint && !stop.reached) {
2509 endPos = stop.pars.startPos;
2510 }
2511 stopDist = seen + endPos - lane->getLength();
2512#ifdef DEBUG_STOPS
2513 if (DEBUG_COND) {
2514 std::cout << SIMTIME << " veh=" << getID() << " stopDist=" << stopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
2515 }
2516#endif
2517 // regular stops are not emergencies
2518 double stopSpeed = laneMaxV;
2519 if (isWaypoint) {
2520 bool waypointWithStop = false;
2521 if (stop.getUntil() > t) {
2522 // check if we have to slow down or even stop
2523 SUMOTime time2end = 0;
2524 if (stop.reached) {
2525 time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
2526 } else {
2527 time2end = TIME2STEPS(
2528 // time to reach waypoint start
2529 stopDist / ((getSpeed() + stop.getSpeed()) / 2)
2530 // time to reach waypoint end
2531 + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
2532 }
2533 if (stop.getUntil() > t + time2end) {
2534 // we need to stop
2535 double distToEnd = stopDist;
2536 if (!stop.reached) {
2537 distToEnd += stop.pars.endPos - stop.pars.startPos;
2538 }
2539 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
2540 waypointWithStop = true;
2541 }
2542 }
2543 if (stop.reached) {
2544 stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
2545 if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
2546 stopDist = std::numeric_limits<double>::max();
2547 }
2548 } else {
2549 stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), stopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
2550 if (!stop.reached) {
2551 stopDist += stop.pars.endPos - stop.pars.startPos;
2552 }
2553 if (lastLink != nullptr) {
2554 lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
2555 }
2556 }
2557 } else {
2558 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), stopDist), vMinComfortable);
2559 if (lastLink != nullptr) {
2560 lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
2561 }
2562 }
2563 v = MIN2(v, stopSpeed);
2564 if (lane->isInternal()) {
2565 std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2566 assert(!lane->isLinkEnd(exitLink));
2567 bool dummySetRequest;
2568 double dummyVLinkWait;
2569 checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
2570 }
2571
2572#ifdef DEBUG_PLAN_MOVE
2573 if (DEBUG_COND) {
2574 std::cout << "\n" << SIMTIME << " next stop: distance = " << stopDist << " requires stopSpeed = " << stopSpeed << "\n";
2575
2576 }
2577#endif
2578 if (isFirstStop) {
2579 newStopDist = stopDist;
2580 // if the vehicle is going to stop we don't need to look further
2581 // (except for trains that make use of further link-approach registration for safety purposes)
2582 if (!isWaypoint) {
2583 planningToStop = true;
2584 if (!isRailway(getVClass())) {
2585 lfLinks.emplace_back(v, stopDist);
2586 foundRealStop = true;
2587 break;
2588 }
2589 }
2590 }
2591 }
2592 }
2593 if (foundRealStop) {
2594 break;
2595 }
2596
2597 // move to next lane
2598 // get the next link used
2599 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2600
2601 // Check whether this is a turn (to save info about the next upcoming turn)
2602 if (!encounteredTurn) {
2603 if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
2604 LinkDirection linkDir = (*link)->getDirection();
2605 switch (linkDir) {
2608 break;
2609 default:
2610 nextTurn.first = seen;
2611 nextTurn.second = *link;
2612 encounteredTurn = true;
2613#ifdef DEBUG_NEXT_TURN
2614 if (DEBUG_COND) {
2615 std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(linkDir)
2616 << " at " << nextTurn.first << "m." << std::endl;
2617 }
2618#endif
2619 }
2620 }
2621 }
2622
2623 // check whether the vehicle is on its final edge
2624 if (myCurrEdge + view + 1 == myRoute->end()
2625 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
2626 const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
2627 myParameter->arrivalSpeed : laneMaxV);
2628 // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
2629 // XXX: This does not work for ballistic update refs #2579
2630 const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
2631 const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
2632 v = MIN2(v, va);
2633 if (lastLink != nullptr) {
2634 lastLink->adaptLeaveSpeed(va);
2635 }
2636 lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
2637 break;
2638 }
2639 // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
2640 if (lane->isLinkEnd(link)
2641 || (MSGlobals::gSublane && brakeForOverlap(*link, lane))
2642 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
2644 double va = cfModel.stopSpeed(this, getSpeed(), seen);
2645 if (lastLink != nullptr) {
2646 lastLink->adaptLeaveSpeed(va);
2647 }
2650 } else {
2651 v = MIN2(va, v);
2652 }
2653#ifdef DEBUG_PLAN_MOVE
2654 if (DEBUG_COND) {
2655 std::cout << " braking for link end lane=" << lane->getID() << " seen=" << seen
2656 << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
2657
2658 }
2659#endif
2660 if (lane->isLinkEnd(link)) {
2661 lfLinks.emplace_back(v, seen);
2662 break;
2663 }
2664 }
2665 lateralShift += (*link)->getLateralShift();
2666 const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
2667 // We distinguish 3 cases when determining the point at which a vehicle stops:
2668 // - links that require stopping: here the vehicle needs to stop close to the stop line
2669 // to ensure it gets onto the junction in the next step. Otherwise the vehicle would 'forget'
2670 // that it already stopped and need to stop again. This is necessary pending implementation of #999
2671 // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
2672 // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
2673 // to minimize the time window for passing the junction. If the
2674 // vehicle 'decides' to accelerate and cannot enter the junction in
2675 // the next step, new foes may appear and cause a collision (see #1096)
2676 // - major links: stopping point is irrelevant
2677 double laneStopOffset;
2678 const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
2679 // override low desired decel at yellow and red
2680 const double stopDecel = yellowOrRed && !isRailway(getVClass()) ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
2681 const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
2682 const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
2683 const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
2684 if (yellowOrRed) {
2685 // Wait at red traffic light with full distance if possible
2686 laneStopOffset = majorStopOffset;
2687 } else if ((*link)->havePriority()) {
2688 // On priority link, we should never stop below visibility distance
2689 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
2690 } else {
2691 // On minor link, we should likewise never stop below visibility distance
2692 const double minorStopOffset = MAX2(lane->getVehicleStopOffset(this),
2693 getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
2694 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
2695 }
2696#ifdef DEBUG_PLAN_MOVE
2697 if (DEBUG_COND) {
2698 std::cout << SIMTIME << " veh=" << getID() << " desired stopOffset on lane '" << lane->getID() << "' is " << laneStopOffset << "\n";
2699 }
2700#endif
2701 if (canBrakeBeforeLaneEnd) {
2702 // avoid emergency braking if possible
2703 laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
2704 }
2705 laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
2706 double stopDist = MAX2(0., seen - laneStopOffset);
2707 if (yellowOrRed && getDevice(typeid(MSDevice_GLOSA)) != nullptr
2708 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->getOverrideSafety()
2709 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->isSpeedAdviceActive()) {
2710 stopDist = std::numeric_limits<double>::max();
2711 }
2712 if (newStopDist != std::numeric_limits<double>::max()) {
2713 stopDist = MAX2(stopDist, newStopDist);
2714 }
2715#ifdef DEBUG_PLAN_MOVE
2716 if (DEBUG_COND) {
2717 std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
2718 << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
2719 }
2720#endif
2721 if (isRailway(getVClass())
2722 && !lane->isInternal()) {
2723 // check for train direction reversal
2724 if (lane->getBidiLane() != nullptr
2725 && (*link)->getLane()->getBidiLane() == lane) {
2726 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
2727 if (seen < 1) {
2728 mustSeeBeforeReversal = 2 * seen + getLength();
2729 }
2730 v = MIN2(v, vMustReverse);
2731 }
2732 // signal that is passed in the current step does not count
2733 foundRailSignal |= ((*link)->getTLLogic() != nullptr
2734 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
2735 && seen > SPEED2DIST(v));
2736 }
2737
2738 bool canReverseEventually = false;
2739 const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
2740 v = MIN2(v, vReverse);
2741#ifdef DEBUG_PLAN_MOVE
2742 if (DEBUG_COND) {
2743 std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
2744 }
2745#endif
2746
2747 // check whether we need to slow down in order to finish a continuous lane change
2749 if ( // slow down to finish lane change before a turn lane
2750 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
2751 // slow down to finish lane change before the shadow lane ends
2752 (myLaneChangeModel->getShadowLane() != nullptr &&
2753 (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
2754 // XXX maybe this is too harsh. Vehicles could cut some corners here
2755 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
2756 assert(timeRemaining != 0);
2757 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
2758 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
2759 (seen - POSITION_EPS) / timeRemaining);
2760#ifdef DEBUG_PLAN_MOVE
2761 if (DEBUG_COND) {
2762 std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
2763 << " link=" << (*link)->getViaLaneOrLane()->getID()
2764 << " timeRemaining=" << timeRemaining
2765 << " v=" << v
2766 << " va=" << va
2767 << std::endl;
2768 }
2769#endif
2770 v = MIN2(va, v);
2771 }
2772 }
2773
2774 // - always issue a request to leave the intersection we are currently on
2775 const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
2776 // - do not issue a request to enter an intersection after we already slowed down for an earlier one
2777 const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
2778 // - even if red, if we cannot break we should issue a request
2779 bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
2780
2781 double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
2782 double vLinkWait = MIN2(v, stopSpeed);
2783#ifdef DEBUG_PLAN_MOVE
2784 if (DEBUG_COND) {
2785 std::cout
2786 << " stopDist=" << stopDist
2787 << " stopDecel=" << stopDecel
2788 << " vLinkWait=" << vLinkWait
2789 << " brakeDist=" << brakeDist
2790 << " seen=" << seen
2791 << " leaveIntersection=" << leavingCurrentIntersection
2792 << " setRequest=" << setRequest
2793 //<< std::setprecision(16)
2794 //<< " v=" << v
2795 //<< " speedEps=" << NUMERICAL_EPS_SPEED
2796 //<< std::setprecision(gPrecision)
2797 << "\n";
2798 }
2799#endif
2800
2801 if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
2802 if (lane->isInternal()) {
2803 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2804 }
2805 // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
2806 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
2807 // the vehicle is able to brake in front of a yellow/red traffic light
2808 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
2809 //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
2810 break;
2811 }
2812
2813 const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
2814 if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
2815 // restrict speed when ignoring a red light
2816 const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
2817 const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
2818 v = MIN2(va, v);
2819#ifdef DEBUG_PLAN_MOVE
2820 if (DEBUG_COND) std::cout
2821 << " ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
2822 << " redSpeed=" << redSpeed
2823 << " va=" << va
2824 << " v=" << v
2825 << "\n";
2826#endif
2827 }
2828
2829 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2830
2831 if (lastLink != nullptr) {
2832 lastLink->adaptLeaveSpeed(laneMaxV);
2833 }
2834 double arrivalSpeed = vLinkPass;
2835 // vehicles should decelerate when approaching a minor link
2836 // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
2837 // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
2838
2839 // whether the vehicle/driver is close enough to the link to see all possible foes #2123
2840 const double visibilityDistance = (*link)->getFoeVisibilityDistance();
2841 const double determinedFoePresence = seen <= visibilityDistance;
2842// // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
2843// double foeRecognitionTime = 0.0;
2844// double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
2845
2846#ifdef DEBUG_PLAN_MOVE
2847 if (DEBUG_COND) {
2848 std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
2849 }
2850#endif
2851
2852 const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
2853 if (couldBrakeForMinor && !determinedFoePresence) {
2854 // vehicle decelerates just enough to be able to stop if necessary and then accelerates
2855 double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0., false);
2856 // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
2857 double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
2858 arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
2859 slowedDownForMinor = true;
2860#ifdef DEBUG_PLAN_MOVE
2861 if (DEBUG_COND) {
2862 std::cout << " slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
2863 }
2864#endif
2865 } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
2866 // check for deadlock (circular yielding)
2867 //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
2868 std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
2869 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2870 int n = 100;
2871 while (blocker.second != nullptr && blocker.second != *link && n > 0) {
2872 blocker = blocker.second->getFirstApproachingFoe(*link);
2873 n--;
2874 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2875 }
2876 if (n == 0) {
2877 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
2878 }
2879 //std::cout << " blockerLink=" << blocker.second << " link=" << *link << "\n";
2880 if (blocker.second == *link) {
2881 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
2882 if (RandHelper::rand(getRNG()) < threshold) {
2883 //std::cout << " abort request, threshold=" << threshold << "\n";
2884 setRequest = false;
2885 }
2886 }
2887 }
2888
2889 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
2890 if (couldBrakeForMinor && determinedFoePresence && (*link)->getLane()->getEdge().isRoundabout()) {
2891 const bool wasOpened = (*link)->opened(arrivalTime, arrivalSpeed, arrivalSpeed,
2893 getCarFollowModel().getMaxDecel(),
2895 nullptr, false, this);
2896 if (!wasOpened) {
2897 slowedDownForMinor = true;
2898 }
2899#ifdef DEBUG_PLAN_MOVE
2900 if (DEBUG_COND) {
2901 std::cout << " slowedDownForMinor at roundabout=" << (!wasOpened) << "\n";
2902 }
2903#endif
2904 }
2905
2906 // compute arrival speed and arrival time if vehicle starts braking now
2907 // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
2908 double arrivalSpeedBraking = 0;
2909 const double bGap = cfModel.brakeGap(v);
2910 if (seen < bGap && !isStopped() && !planningToStop) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
2911 // vehicle cannot come to a complete stop in time
2913 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
2914 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
2915 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
2916 } else {
2917 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
2918 }
2919 }
2920
2921 // estimate leave speed for passing time computation
2922 // l=linkLength, a=accel, t=continuousTime, v=vLeave
2923 // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
2924 const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this),
2925 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
2926 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
2927 arrivalTime, arrivalSpeed,
2928 arrivalSpeedBraking,
2929 seen, estimatedLeaveSpeed));
2930 if ((*link)->getViaLane() == nullptr) {
2931 hadNonInternal = true;
2932 ++view;
2933 }
2934#ifdef DEBUG_PLAN_MOVE
2935 if (DEBUG_COND) {
2936 std::cout << " checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
2937 << " seenNonInternal=" << seenNonInternal
2938 << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
2939 }
2940#endif
2941 // we need to look ahead far enough to see available space for checkRewindLinkLanes
2942 if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
2943 break;
2944 }
2945 // get the following lane
2946 lane = (*link)->getViaLaneOrLane();
2947 laneMaxV = lane->getVehicleMaxSpeed(this);
2949 laneMaxV = std::numeric_limits<double>::max();
2950 }
2951 // the link was passed
2952 // compute the velocity to use when the link is not blocked by other vehicles
2953 // the vehicle shall be not faster when reaching the next lane than allowed
2954 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2955 const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable);
2956 v = MIN2(va, v);
2957#ifdef DEBUG_PLAN_MOVE
2958 if (DEBUG_COND) {
2959 std::cout << " laneMaxV=" << laneMaxV << " freeSpeed=" << va << " v=" << v << "\n";
2960 }
2961#endif
2962 if (lane->getEdge().isInternal()) {
2963 seenInternal += lane->getLength();
2964 } else {
2965 seenNonInternal += lane->getLength();
2966 }
2967 // do not restrict results to the current vehicle to allow caching for the current time step
2968 leaderLane = opposite ? lane->getParallelOpposite() : lane;
2969 if (leaderLane == nullptr) {
2970
2971 break;
2972 }
2973 ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
2974 seen += lane->getLength();
2975 vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2976 lastLink = &lfLinks.back();
2977 }
2978
2979//#ifdef DEBUG_PLAN_MOVE
2980// if(DEBUG_COND){
2981// std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
2982// }
2983//#endif
2984
2985#ifdef PARALLEL_STOPWATCH
2986 myLane->getStopWatch()[0].stop();
2987#endif
2988}
2989
2990
2991double
2992MSVehicle::slowDownForSchedule(double vMinComfortable) const {
2993 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2994 const MSStop& stop = myStops.front();
2995 std::pair<double, double> timeDist = estimateTimeToNextStop();
2996 double arrivalDelay = SIMTIME + timeDist.first - STEPS2TIME(stop.pars.arrival);
2997 double t = STEPS2TIME(stop.pars.arrival - SIMSTEP);
3000 arrivalDelay += STEPS2TIME(stop.pars.arrival - flexStart);
3001 t = STEPS2TIME(flexStart - SIMSTEP);
3002 } else if (stop.pars.started >= 0 && MSGlobals::gUseStopStarted) {
3003 arrivalDelay += STEPS2TIME(stop.pars.arrival - stop.pars.started);
3004 t = STEPS2TIME(stop.pars.started - SIMSTEP);
3005 }
3006 if (arrivalDelay < 0 && sfp < getChosenSpeedFactor()) {
3007 // we can slow down to better match the schedule (and increase energy efficiency)
3008 const double vSlowDownMin = MAX2(myLane->getSpeedLimit() * sfp, vMinComfortable);
3009 const double s = timeDist.second;
3010 const double b = getCarFollowModel().getMaxDecel();
3011 // x = speed for arriving in t seconds
3012 // u = time at full speed
3013 // u * x + (t - u) * 0.5 * x = s
3014 // t - u = x / b
3015 // eliminate u, solve x
3016 const double radicand = 4 * t * t * b * b - 8 * s * b;
3017 const double x = radicand >= 0 ? t * b - sqrt(radicand) * 0.5 : vSlowDownMin;
3018 double vSlowDown = x < vSlowDownMin ? vSlowDownMin : x;
3019#ifdef DEBUG_PLAN_MOVE
3020 if (DEBUG_COND) {
3021 std::cout << SIMTIME << " veh=" << getID() << " ad=" << arrivalDelay << " t=" << t << " vsm=" << vSlowDownMin
3022 << " r=" << radicand << " vs=" << vSlowDown << "\n";
3023 }
3024#endif
3025 return vSlowDown;
3026 } else if (arrivalDelay > 0 && sfp > getChosenSpeedFactor()) {
3027 // in principle we could up to catch up with the schedule
3028 // but at this point we can only lower the speed, the
3029 // information would have to be used when computing getVehicleMaxSpeed
3030 }
3031 return getMaxSpeed();
3032}
3033
3035MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
3036 const MSCFModel& cfModel = getCarFollowModel();
3037 SUMOTime arrivalTime;
3039 // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
3040 // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
3041 // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
3042 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
3043 } else {
3044 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
3045 }
3046 if (isStopped()) {
3047 arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
3048 }
3049 return arrivalTime;
3050}
3051
3052
3053void
3054MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
3055 const double seen, DriveProcessItem* const lastLink,
3056 const MSLane* const lane, double& v, double& vLinkPass) const {
3057 int rightmost;
3058 int leftmost;
3059 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3060#ifdef DEBUG_PLAN_MOVE
3061 if (DEBUG_COND) std::cout << SIMTIME
3062 << "\nADAPT_TO_LEADERS\nveh=" << getID()
3063 << " lane=" << lane->getID()
3064 << " latOffset=" << latOffset
3065 << " rm=" << rightmost
3066 << " lm=" << leftmost
3067 << " shift=" << ahead.getSublaneOffset()
3068 << " ahead=" << ahead.toString()
3069 << "\n";
3070#endif
3071 /*
3072 if (myLaneChangeModel->getCommittedSpeed() > 0) {
3073 v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
3074 vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
3075 #ifdef DEBUG_PLAN_MOVE
3076 if (DEBUG_COND) std::cout << " hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
3077 #endif
3078 return;
3079 }
3080 */
3081 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3082 const MSVehicle* pred = ahead[sublane];
3083 if (pred != nullptr && pred != this) {
3084 // @todo avoid multiple adaptations to the same leader
3085 const double predBack = pred->getBackPositionOnLane(lane);
3086 double gap = (lastLink == nullptr
3087 ? predBack - myState.myPos - getVehicleType().getMinGap()
3088 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3089 bool oncoming = false;
3091 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
3092 // ego might and leader are driving against lane
3093 gap = (lastLink == nullptr
3094 ? myState.myPos - predBack - getVehicleType().getMinGap()
3095 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3096 } else {
3097 // ego and leader are driving in the same direction as lane (shadowlane for ego)
3098 gap = (lastLink == nullptr
3099 ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
3100 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3101 }
3102 } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
3103 // must react to stopped / dangerous oncoming vehicles
3104 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
3105 // try to avoid collision in the next second
3106 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
3107#ifdef DEBUG_PLAN_MOVE
3108 if (DEBUG_COND) {
3109 std::cout << " fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
3110 }
3111#endif
3112 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
3113 gap -= predMaxDist;
3114 }
3115 } else if (pred->getLane() == lane->getBidiLane()) {
3116 gap -= pred->getVehicleType().getLengthWithGap();
3117 oncoming = true;
3118 }
3119#ifdef DEBUG_PLAN_MOVE
3120 if (DEBUG_COND) {
3121 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";
3122 }
3123#endif
3124 if (oncoming && gap >= 0) {
3125 adaptToOncomingLeader(std::make_pair(pred, gap), lastLink, v, vLinkPass);
3126 } else {
3127 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
3128 }
3129 }
3130 }
3131}
3132
3133void
3135 double seen,
3136 DriveProcessItem* const lastLink,
3137 double& v, double& vLinkPass) const {
3138 int rightmost;
3139 int leftmost;
3140 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3141#ifdef DEBUG_PLAN_MOVE
3142 if (DEBUG_COND) std::cout << SIMTIME
3143 << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
3144 << " latOffset=" << latOffset
3145 << " rm=" << rightmost
3146 << " lm=" << leftmost
3147 << " ahead=" << ahead.toString()
3148 << "\n";
3149#endif
3150 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3151 CLeaderDist predDist = ahead[sublane];
3152 const MSVehicle* pred = predDist.first;
3153 if (pred != nullptr && pred != this) {
3154#ifdef DEBUG_PLAN_MOVE
3155 if (DEBUG_COND) {
3156 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
3157 }
3158#endif
3159 adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
3160 }
3161 }
3162}
3163
3164
3165void
3166MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3167 double seen,
3168 DriveProcessItem* const lastLink,
3169 double& v, double& vLinkPass) const {
3170 if (leaderInfo.first != 0) {
3171 if (ignoreFoe(leaderInfo.first)) {
3172#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3173 if (DEBUG_COND) {
3174 std::cout << " foe ignored\n";
3175 }
3176#endif
3177 return;
3178 }
3179 const MSCFModel& cfModel = getCarFollowModel();
3180 double vsafeLeader = 0;
3182 vsafeLeader = -std::numeric_limits<double>::max();
3183 }
3184 bool backOnRoute = true;
3185 if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
3186 backOnRoute = false;
3187 // this can either be
3188 // a) a merging situation (leader back is is not our route) or
3189 // b) a minGap violation / collision
3190 MSLane* current = lastLink->myLink->getViaLaneOrLane();
3191 if (leaderInfo.first->getBackLane() == current) {
3192 backOnRoute = true;
3193 } else {
3194 for (MSLane* lane : getBestLanesContinuation()) {
3195 if (lane == current) {
3196 break;
3197 }
3198 if (leaderInfo.first->getBackLane() == lane) {
3199 backOnRoute = true;
3200 }
3201 }
3202 }
3203#ifdef DEBUG_PLAN_MOVE
3204 if (DEBUG_COND) {
3205 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
3206 }
3207#endif
3208 if (!backOnRoute) {
3209 double stopDist = seen - current->getLength() - POSITION_EPS;
3210 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
3211 // do not drive onto the junction conflict area
3212 stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
3213 }
3214 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
3215 }
3216 }
3217 if (backOnRoute) {
3218 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3219 }
3220 if (lastLink != nullptr) {
3221 const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
3222 lastLink->adaptLeaveSpeed(futureVSafe);
3223#ifdef DEBUG_PLAN_MOVE
3224 if (DEBUG_COND) {
3225 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3226 }
3227#endif
3228 }
3229 v = MIN2(v, vsafeLeader);
3230 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3231#ifdef DEBUG_PLAN_MOVE
3232 if (DEBUG_COND) std::cout
3233 << SIMTIME
3234 //std::cout << std::setprecision(10);
3235 << " veh=" << getID()
3236 << " lead=" << leaderInfo.first->getID()
3237 << " leadSpeed=" << leaderInfo.first->getSpeed()
3238 << " gap=" << leaderInfo.second
3239 << " leadLane=" << leaderInfo.first->getLane()->getID()
3240 << " predPos=" << leaderInfo.first->getPositionOnLane()
3241 << " myLane=" << myLane->getID()
3242 << " v=" << v
3243 << " vSafeLeader=" << vsafeLeader
3244 << " vLinkPass=" << vLinkPass
3245 << "\n";
3246#endif
3247 }
3248}
3249
3250
3251void
3252MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3253 const double seen, DriveProcessItem* const lastLink,
3254 const MSLane* const lane, double& v, double& vLinkPass,
3255 double distToCrossing) const {
3256 if (leaderInfo.first != 0) {
3257 if (ignoreFoe(leaderInfo.first)) {
3258#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3259 if (DEBUG_COND) {
3260 std::cout << " junction foe ignored\n";
3261 }
3262#endif
3263 return;
3264 }
3265 const MSCFModel& cfModel = getCarFollowModel();
3266 double vsafeLeader = 0;
3268 vsafeLeader = -std::numeric_limits<double>::max();
3269 }
3270 if (leaderInfo.second >= 0) {
3271 if (hasDeparted()) {
3272 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3273 } else {
3274 // called in the context of MSLane::isInsertionSuccess
3275 vsafeLeader = cfModel.insertionFollowSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3276 }
3277 } else if (leaderInfo.first != this) {
3278 // the leading, in-lapping vehicle is occupying the complete next lane
3279 // stop before entering this lane
3280 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
3281#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3282 if (DEBUG_COND) {
3283 std::cout << SIMTIME << " veh=" << getID() << " stopping before junction: lane=" << lane->getID() << " seen=" << seen
3284 << " laneLength=" << lane->getLength()
3285 << " stopDist=" << seen - lane->getLength() - POSITION_EPS
3286 << " vsafeLeader=" << vsafeLeader
3287 << " distToCrossing=" << distToCrossing
3288 << "\n";
3289 }
3290#endif
3291 }
3292 if (distToCrossing >= 0) {
3293 // can the leader still stop in the way?
3294 const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
3295 if (leaderInfo.first == this) {
3296 // braking for pedestrian
3297 const double vStopCrossing = cfModel.stopSpeed(this, getSpeed(), distToCrossing);
3298 vsafeLeader = vStopCrossing;
3299#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3300 if (DEBUG_COND) {
3301 std::cout << " breaking for pedestrian distToCrossing=" << distToCrossing << " vStopCrossing=" << vStopCrossing << "\n";
3302 }
3303#endif
3304 if (lastLink != nullptr) {
3305 lastLink->adaptStopSpeed(vsafeLeader);
3306 }
3307 } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
3308 // drive up to the crossing point and stop
3309#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3310 if (DEBUG_COND) {
3311 std::cout << " stop at crossing point for critical leader vStop=" << vStop << "\n";
3312 };
3313#endif
3314 vsafeLeader = MAX2(vsafeLeader, vStop);
3315 } else {
3316 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
3317 // estimate the time at which the leader has gone past the crossing point
3318 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
3319 // reach distToCrossing after that time
3320 // avgSpeed * leaderPastCPTime = distToCrossing
3321 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
3322 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
3323 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
3324 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
3325#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3326 if (DEBUG_COND) {
3327 std::cout << " driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
3328 << " leaderPastCPTime=" << leaderPastCPTime
3329 << " vFinal=" << vFinal
3330 << " v2=" << v2
3331 << " vStop=" << vStop
3332 << " vsafeLeader=" << vsafeLeader << "\n";
3333 }
3334#endif
3335 }
3336 }
3337 if (lastLink != nullptr) {
3338 lastLink->adaptLeaveSpeed(vsafeLeader);
3339 }
3340 v = MIN2(v, vsafeLeader);
3341 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3342#ifdef DEBUG_PLAN_MOVE
3343 if (DEBUG_COND) std::cout
3344 << SIMTIME
3345 //std::cout << std::setprecision(10);
3346 << " veh=" << getID()
3347 << " lead=" << leaderInfo.first->getID()
3348 << " leadSpeed=" << leaderInfo.first->getSpeed()
3349 << " gap=" << leaderInfo.second
3350 << " leadLane=" << leaderInfo.first->getLane()->getID()
3351 << " predPos=" << leaderInfo.first->getPositionOnLane()
3352 << " seen=" << seen
3353 << " lane=" << lane->getID()
3354 << " myLane=" << myLane->getID()
3355 << " dTC=" << distToCrossing
3356 << " v=" << v
3357 << " vSafeLeader=" << vsafeLeader
3358 << " vLinkPass=" << vLinkPass
3359 << "\n";
3360#endif
3361 }
3362}
3363
3364
3365void
3366MSVehicle::adaptToOncomingLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3367 DriveProcessItem* const lastLink,
3368 double& v, double& vLinkPass) const {
3369 if (leaderInfo.first != 0) {
3370 if (ignoreFoe(leaderInfo.first)) {
3371#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3372 if (DEBUG_COND) {
3373 std::cout << " oncoming foe ignored\n";
3374 }
3375#endif
3376 return;
3377 }
3378 const MSCFModel& cfModel = getCarFollowModel();
3379 const MSVehicle* lead = leaderInfo.first;
3380 const MSCFModel& cfModelL = lead->getCarFollowModel();
3381 // assume the leader reacts symmetrically (neither stopping instantly nor ignoring ego)
3382 const double leaderBrakeGap = cfModelL.brakeGap(lead->getSpeed(), cfModelL.getMaxDecel(), 0);
3383 const double egoBrakeGap = cfModel.brakeGap(getSpeed(), cfModel.getMaxDecel(), 0);
3384 const double gapSum = leaderBrakeGap + egoBrakeGap;
3385 // ensure that both vehicles can leave an intersection if they are currently on it
3386 double egoExit = getDistanceToLeaveJunction();
3387 const double leaderExit = lead->getDistanceToLeaveJunction();
3388 double gap = leaderInfo.second;
3389 if (egoExit + leaderExit < gap) {
3390 gap -= egoExit + leaderExit;
3391 } else {
3392 egoExit = 0;
3393 }
3394 // split any distance in excess of brakeGaps evenly
3395 const double freeGap = MAX2(0.0, gap - gapSum);
3396 const double splitGap = MIN2(gap, gapSum);
3397 // assume remaining distance is allocated in proportion to braking distance
3398 const double gapRatio = gapSum > 0 ? egoBrakeGap / gapSum : 0.5;
3399 const double vsafeLeader = cfModel.stopSpeed(this, getSpeed(), splitGap * gapRatio + egoExit + 0.5 * freeGap);
3400 if (lastLink != nullptr) {
3401 const double futureVSafe = cfModel.stopSpeed(this, lastLink->accelV, leaderInfo.second, MSCFModel::CalcReason::FUTURE);
3402 lastLink->adaptLeaveSpeed(futureVSafe);
3403#ifdef DEBUG_PLAN_MOVE
3404 if (DEBUG_COND) {
3405 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3406 }
3407#endif
3408 }
3409 v = MIN2(v, vsafeLeader);
3410 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3411#ifdef DEBUG_PLAN_MOVE
3412 if (DEBUG_COND) std::cout
3413 << SIMTIME
3414 //std::cout << std::setprecision(10);
3415 << " veh=" << getID()
3416 << " oncomingLead=" << lead->getID()
3417 << " leadSpeed=" << lead->getSpeed()
3418 << " gap=" << leaderInfo.second
3419 << " gap2=" << gap
3420 << " gapRatio=" << gapRatio
3421 << " leadLane=" << lead->getLane()->getID()
3422 << " predPos=" << lead->getPositionOnLane()
3423 << " myLane=" << myLane->getID()
3424 << " v=" << v
3425 << " vSafeLeader=" << vsafeLeader
3426 << " vLinkPass=" << vLinkPass
3427 << "\n";
3428#endif
3429 }
3430}
3431
3432
3433void
3434MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
3435 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
3437 // we want to pass the link but need to check for foes on internal lanes
3438 checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
3439 if (myLaneChangeModel->getShadowLane() != nullptr) {
3440 const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
3441 if (parallelLink != nullptr) {
3442 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
3443 }
3444 }
3445 }
3446
3447}
3448
3449void
3450MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
3451 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
3452 bool isShadowLink) const {
3453#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3454 if (DEBUG_COND) {
3455 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3456 }
3457#endif
3458 const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
3459#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3460 if (DEBUG_COND) {
3461 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3462 }
3463#endif
3464 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3465 // the vehicle to enter the junction first has priority
3466 const MSVehicle* leader = (*it).vehAndGap.first;
3467 if (leader == nullptr) {
3468 // leader is a pedestrian. Passing 'this' as a dummy.
3469#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3470 if (DEBUG_COND) {
3471 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
3472 }
3473#endif
3476#ifdef DEBUG_PLAN_MOVE
3477 if (DEBUG_COND) {
3478 std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
3479 }
3480#endif
3481 continue;
3482 }
3483 adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3484 // if blocked by a pedestrian for too long we must yield our request
3486 setRequest = false;
3487#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3488 if (DEBUG_COND) {
3489 std::cout << " aborting request\n";
3490 }
3491#endif
3492 }
3493 } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay()) {
3496#ifdef DEBUG_PLAN_MOVE
3497 if (DEBUG_COND) {
3498 std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
3499 }
3500#endif
3501 continue;
3502 }
3504 // sibling link (XXX: could also be partial occupator where this check fails)
3505 &leader->getLane()->getEdge() == &lane->getEdge()) {
3506 // check for sublane obstruction (trivial for sibling link leaders)
3507 const MSLane* conflictLane = link->getInternalLaneBefore();
3508 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
3509 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
3510 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
3511 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
3512 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
3513#ifdef DEBUG_PLAN_MOVE
3514 if (DEBUG_COND) {
3515 std::cout << SIMTIME << " veh=" << getID()
3516 << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
3517 << " isShadowLink=" << isShadowLink
3518 << " lane=" << lane->getID()
3519 << " foe=" << leader->getID()
3520 << " foeLane=" << leader->getLane()->getID()
3521 << " latOffset=" << latOffset
3522 << " latOffsetFoe=" << leader->getLatOffset(lane)
3523 << " linkLeadersAhead=" << linkLeadersAhead.toString()
3524 << "\n";
3525 }
3526#endif
3527 } else {
3528#ifdef DEBUG_PLAN_MOVE
3529 if (DEBUG_COND) {
3530 std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
3531 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3532 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3533 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3534 << "\n";
3535 }
3536#endif
3537 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3538 }
3539 if (lastLink != nullptr) {
3540 // we are not yet on the junction with this linkLeader.
3541 // at least we can drive up to the previous link and stop there
3542 v = MAX2(v, lastLink->myVLinkWait);
3543 }
3544 // if blocked by a leader from the same or next lane we must yield our request
3545 // also, if blocked by a stopped or blocked leader
3547 //&& leader->getSpeed() < SUMO_const_haltingSpeed
3549 || leader->getLane()->getLogicalPredecessorLane() == myLane
3550 || leader->isStopped()
3552 setRequest = false;
3553#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3554 if (DEBUG_COND) {
3555 std::cout << " aborting request\n";
3556 }
3557#endif
3558 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
3559 // we are not yet on the junction so must abort that request as well
3560 // (or maybe we are already on the junction and the leader is a partial occupator beyond)
3561 lastLink->mySetRequest = false;
3562#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3563 if (DEBUG_COND) {
3564 std::cout << " aborting previous request\n";
3565 }
3566#endif
3567 }
3568 }
3569 }
3570#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3571 else {
3572 if (DEBUG_COND) {
3573 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
3574 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3575 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3576 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3577 << "\n";
3578 }
3579 }
3580#endif
3581 }
3582 // if this is the link between two internal lanes we may have to slow down for pedestrians
3583 vLinkWait = MIN2(vLinkWait, v);
3584}
3585
3586
3587double
3588MSVehicle::getDeltaPos(const double accel) const {
3589 double vNext = myState.mySpeed + ACCEL2SPEED(accel);
3591 // apply implicit Euler positional update
3592 return SPEED2DIST(MAX2(vNext, 0.));
3593 } else {
3594 // apply ballistic update
3595 if (vNext >= 0) {
3596 // assume constant acceleration during this time step
3597 return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
3598 } else {
3599 // negative vNext indicates a stop within the middle of time step
3600 // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
3601 // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
3602 // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
3603 // until the vehicle stops.
3604 return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
3605 }
3606 }
3607}
3608
3609void
3610MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
3611
3612 // Speed limit due to zipper merging
3613 double vSafeZipper = std::numeric_limits<double>::max();
3614
3615 myHaveToWaitOnNextLink = false;
3616 bool canBrakeVSafeMin = false;
3617
3618 // Get safe velocities from DriveProcessItems.
3619 assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
3620 for (const DriveProcessItem& dpi : myLFLinkLanes) {
3621 MSLink* const link = dpi.myLink;
3622
3623#ifdef DEBUG_EXEC_MOVE
3624 if (DEBUG_COND) {
3625 std::cout
3626 << SIMTIME
3627 << " veh=" << getID()
3628 << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
3629 << " req=" << dpi.mySetRequest
3630 << " vP=" << dpi.myVLinkPass
3631 << " vW=" << dpi.myVLinkWait
3632 << " d=" << dpi.myDistance
3633 << "\n";
3634 gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
3635 }
3636#endif
3637
3638 // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
3639 if (link != nullptr && dpi.mySetRequest) {
3640
3641 const LinkState ls = link->getState();
3642 // vehicles should brake when running onto a yellow light if the distance allows to halt in front
3643 const bool yellow = link->haveYellow();
3644 const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
3646 assert(link->getLaneBefore() != nullptr);
3647 const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
3648 const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
3649 if (yellow && canBrake && !ignoreRedLink) {
3650 vSafe = dpi.myVLinkWait;
3652#ifdef DEBUG_CHECKREWINDLINKLANES
3653 if (DEBUG_COND) {
3654 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
3655 }
3656#endif
3657 break;
3658 }
3659 const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
3660 MSLink::BlockingFoes collectFoes;
3661 bool opened = (yellow || influencerPrio
3662 || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3664 canBrake ? getImpatience() : 1,
3667 ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
3668 ignoreRedLink, this, dpi.myDistance));
3669 if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
3670 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
3671 if (parallelLink != nullptr) {
3672 const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
3674 opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3677 getWaitingTime(), shadowLatPos, nullptr,
3678 ignoreRedLink, this, dpi.myDistance));
3679#ifdef DEBUG_EXEC_MOVE
3680 if (DEBUG_COND) {
3681 std::cout << SIMTIME
3682 << " veh=" << getID()
3683 << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
3684 << " shadowDir=" << myLaneChangeModel->getShadowDirection()
3685 << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
3686 << " opened=" << opened
3687 << "\n";
3688 }
3689#endif
3690 }
3691 }
3692 // vehicles should decelerate when approaching a minor link
3693#ifdef DEBUG_EXEC_MOVE
3694 if (DEBUG_COND) {
3695 std::cout << SIMTIME
3696 << " opened=" << opened
3697 << " influencerPrio=" << influencerPrio
3698 << " linkPrio=" << link->havePriority()
3699 << " lastContMajor=" << link->lastWasContMajor()
3700 << " isCont=" << link->isCont()
3701 << " ignoreRed=" << ignoreRedLink
3702 << "\n";
3703 }
3704#endif
3705 if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
3706 double visibilityDistance = link->getFoeVisibilityDistance();
3707 double determinedFoePresence = dpi.myDistance <= visibilityDistance;
3708 if (!determinedFoePresence && (canBrake || !yellow)) {
3709 vSafe = dpi.myVLinkWait;
3711#ifdef DEBUG_CHECKREWINDLINKLANES
3712 if (DEBUG_COND) {
3713 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
3714 }
3715#endif
3716 break;
3717 } else {
3718 // past the point of no return. we need to drive fast enough
3719 // to make it across the link. However, minor slowdowns
3720 // should be permissible to follow leading traffic safely
3721 // basically, this code prevents dawdling
3722 // (it's harder to do this later using
3723 // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
3724 // vehicle is already too close to stop at that part of the code)
3725 //
3726 // XXX: There is a problem in subsecond simulation: If we cannot
3727 // make it across the minor link in one step, new traffic
3728 // could appear on a major foe link and cause a collision. Refs. #1845, #2123
3729 vSafeMinDist = dpi.myDistance; // distance that must be covered
3731 vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3732 } else {
3733 vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3734 }
3735 canBrakeVSafeMin = canBrake;
3736#ifdef DEBUG_EXEC_MOVE
3737 if (DEBUG_COND) {
3738 std::cout << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
3739 }
3740#endif
3741 }
3742 }
3743 // have waited; may pass if opened...
3744 if (opened) {
3745 vSafe = dpi.myVLinkPass;
3746 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
3747 // this vehicle is probably not gonna drive across the next junction (heuristic)
3749#ifdef DEBUG_CHECKREWINDLINKLANES
3750 if (DEBUG_COND) {
3751 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
3752 }
3753#endif
3754 }
3755 } else if (link->getState() == LINKSTATE_ZIPPER) {
3756 vSafeZipper = MIN2(vSafeZipper,
3757 link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
3758 } else if (!canBrake
3759 // always brake hard for traffic lights (since an emergency stop is necessary anyway)
3760 && link->getTLLogic() == nullptr
3761 // cannot brake even with emergency deceleration
3762 && dpi.myDistance < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0.)) {
3763#ifdef DEBUG_EXEC_MOVE
3764 if (DEBUG_COND) {
3765 std::cout << SIMTIME << " too fast to brake for closed link\n";
3766 }
3767#endif
3768 vSafe = dpi.myVLinkPass;
3769 } else {
3770 vSafe = dpi.myVLinkWait;
3772#ifdef DEBUG_CHECKREWINDLINKLANES
3773 if (DEBUG_COND) {
3774 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
3775 }
3776#endif
3777#ifdef DEBUG_EXEC_MOVE
3778 if (DEBUG_COND) {
3779 std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
3780 }
3781#endif
3782 break;
3783 }
3784 } else {
3785 if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
3786 // blocked on the junction. yield request so other vehicles may
3787 // become junction leader
3788#ifdef DEBUG_EXEC_MOVE
3789 if (DEBUG_COND) {
3790 std::cout << SIMTIME << " resetting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
3791 }
3792#endif
3795 }
3796 // we have: i->link == 0 || !i->setRequest
3797 vSafe = dpi.myVLinkWait;
3798 if (vSafe < getSpeed()) {
3800#ifdef DEBUG_CHECKREWINDLINKLANES
3801 if (DEBUG_COND) {
3802 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
3803 }
3804#endif
3805 } else if (vSafe < SUMO_const_haltingSpeed) {
3807#ifdef DEBUG_CHECKREWINDLINKLANES
3808 if (DEBUG_COND) {
3809 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
3810 }
3811#endif
3812 }
3813 if (link == nullptr && myLFLinkLanes.size() == 1
3814 && getBestLanesContinuation().size() > 1
3815 && getBestLanesContinuation()[1]->hadPermissionChanges()
3816 && myLane->getFirstAnyVehicle() == this) {
3817 // temporal lane closing without notification, visible to the
3818 // vehicle at the front of the queue
3819 updateBestLanes(true);
3820 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
3821 }
3822 break;
3823 }
3824 }
3825
3826//#ifdef DEBUG_EXEC_MOVE
3827// if (DEBUG_COND) {
3828// std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
3829// std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
3830// std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
3831// std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
3832//
3833// double gap = getLeader().second;
3834// std::cout << "gap = " << toString(gap, 24) << std::endl;
3835// std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
3836// << "\n" << std::endl;
3837// }
3838//#endif
3839
3840 if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
3841 || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
3842 // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
3843 // 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
3844#ifdef DEBUG_EXEC_MOVE
3845 if (DEBUG_COND) {
3846 std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
3847 }
3848#endif
3849 if (canBrakeVSafeMin && vSafe < getSpeed()) {
3850 // cannot drive across a link so we need to stop before it
3851 vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
3852 getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
3853 vSafeMin = 0;
3855#ifdef DEBUG_CHECKREWINDLINKLANES
3856 if (DEBUG_COND) {
3857 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
3858 }
3859#endif
3860 } else {
3861 // if the link is yellow or visibility distance is large
3862 // then we might not make it across the link in one step anyway..
3863 // Possibly, the lane after the intersection has a lower speed limit so
3864 // we really need to drive slower already
3865 // -> keep driving without dawdling
3866 vSafeMin = vSafe;
3867 }
3868 }
3869
3870 // vehicles inside a roundabout should maintain their requests
3871 if (myLane->getEdge().isRoundabout()) {
3872 myHaveToWaitOnNextLink = false;
3873 }
3874
3875 vSafe = MIN2(vSafe, vSafeZipper);
3876}
3877
3878
3879double
3880MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
3881 if (myInfluencer != nullptr) {
3883#ifdef DEBUG_TRACI
3884 if DEBUG_COND2(this) {
3885 std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
3886 << " vSafe=" << vSafe << " (init)vNext=" << vNext << " keepStopping=" << keepStopping();
3887 }
3888#endif
3891 }
3892 const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
3895 vMin = MAX2(0., vMin);
3896 }
3897 vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
3898 if (keepStopping() && myStops.front().getSpeed() == 0) {
3899 // avoid driving while stopped (unless it's actually a waypoint
3900 vNext = myInfluencer->getOriginalSpeed();
3901 }
3902#ifdef DEBUG_TRACI
3903 if DEBUG_COND2(this) {
3904 std::cout << " (processed)vNext=" << vNext << std::endl;
3905 }
3906#endif
3907 }
3908 return vNext;
3909}
3910
3911
3912void
3914#ifdef DEBUG_ACTIONSTEPS
3915 if (DEBUG_COND) {
3916 std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
3917 << " Current items: ";
3918 for (auto& j : myLFLinkLanes) {
3919 if (j.myLink == 0) {
3920 std::cout << "\n Stop at distance " << j.myDistance;
3921 } else {
3922 const MSLane* to = j.myLink->getViaLaneOrLane();
3923 const MSLane* from = j.myLink->getLaneBefore();
3924 std::cout << "\n Link at distance " << j.myDistance << ": '"
3925 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3926 }
3927 }
3928 std::cout << "\n myNextDriveItem: ";
3929 if (myLFLinkLanes.size() != 0) {
3930 if (myNextDriveItem->myLink == 0) {
3931 std::cout << "\n Stop at distance " << myNextDriveItem->myDistance;
3932 } else {
3933 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
3934 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
3935 std::cout << "\n Link at distance " << myNextDriveItem->myDistance << ": '"
3936 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3937 }
3938 }
3939 std::cout << std::endl;
3940 }
3941#endif
3942 for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
3943#ifdef DEBUG_ACTIONSTEPS
3944 if (DEBUG_COND) {
3945 std::cout << " Removing item: ";
3946 if (j->myLink == 0) {
3947 std::cout << "Stop at distance " << j->myDistance;
3948 } else {
3949 const MSLane* to = j->myLink->getViaLaneOrLane();
3950 const MSLane* from = j->myLink->getLaneBefore();
3951 std::cout << "Link at distance " << j->myDistance << ": '"
3952 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3953 }
3954 std::cout << std::endl;
3955 }
3956#endif
3957 if (j->myLink != nullptr) {
3958 j->myLink->removeApproaching(this);
3959 }
3960 }
3963}
3964
3965
3966void
3968#ifdef DEBUG_ACTIONSTEPS
3969 if (DEBUG_COND) {
3970 std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
3971 for (const auto& dpi : myLFLinkLanes) {
3972 std::cout
3973 << " vPass=" << dpi.myVLinkPass
3974 << " vWait=" << dpi.myVLinkWait
3975 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
3976 << " request=" << dpi.mySetRequest
3977 << "\n";
3978 }
3979 std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
3980 }
3981#endif
3982 if (myLFLinkLanes.size() == 0) {
3983 // nothing to update
3984 return;
3985 }
3986 const MSLink* nextPlannedLink = nullptr;
3987// auto i = myLFLinkLanes.begin();
3988 auto i = myNextDriveItem;
3989 while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
3990 nextPlannedLink = i->myLink;
3991 ++i;
3992 }
3993
3994 if (nextPlannedLink == nullptr) {
3995 // No link for upcoming item -> no need for an update
3996#ifdef DEBUG_ACTIONSTEPS
3997 if (DEBUG_COND) {
3998 std::cout << "Found no link-related drive item." << std::endl;
3999 }
4000#endif
4001 return;
4002 }
4003
4004 if (getLane() == nextPlannedLink->getLaneBefore()) {
4005 // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
4006#ifdef DEBUG_ACTIONSTEPS
4007 if (DEBUG_COND) {
4008 std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
4009 }
4010#endif
4011 return;
4012 }
4013 // Lane must have been changed, determine the change direction
4014 const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
4015 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4016 // lcDir = 1;
4017 } else {
4018 parallelLink = nextPlannedLink->getParallelLink(-1);
4019 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4020 // lcDir = -1;
4021 } else {
4022 // If the vehicle's current lane is not the approaching lane for the next
4023 // drive process item's link, it is expected to lead to a parallel link,
4024 // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
4025 // Then a stop item should be scheduled! -> TODO!
4026 //assert(false);
4027 return;
4028 }
4029 }
4030#ifdef DEBUG_ACTIONSTEPS
4031 if (DEBUG_COND) {
4032 std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
4033 }
4034#endif
4035 // Trace link sequence along current best lanes and transfer drive items to the corresponding links
4036// DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
4037 DriveItemVector::iterator driveItemIt = myNextDriveItem;
4038 // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
4039 const MSLane* lane = myLane;
4040 assert(myLane == parallelLink->getLaneBefore());
4041 // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
4042 std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
4043 // Pointer to the new link for the current drive process item
4044 MSLink* newLink = nullptr;
4045 while (driveItemIt != myLFLinkLanes.end()) {
4046 if (driveItemIt->myLink == nullptr) {
4047 // Items not related to a specific link are not updated
4048 // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
4049 // the update necessary, this may slow down the vehicle's continuation on the new lane...)
4050 ++driveItemIt;
4051 continue;
4052 }
4053 // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
4054 // We just remove the leftover link-items, as they cannot be mapped to new links.
4055 if (bestLaneIt == getBestLanesContinuation().end()) {
4056#ifdef DEBUG_ACTIONSTEPS
4057 if (DEBUG_COND) {
4058 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
4059 }
4060#endif
4061 while (driveItemIt != myLFLinkLanes.end()) {
4062 if (driveItemIt->myLink == nullptr) {
4063 ++driveItemIt;
4064 continue;
4065 } else {
4066 driveItemIt->myLink->removeApproaching(this);
4067 driveItemIt = myLFLinkLanes.erase(driveItemIt);
4068 }
4069 }
4070 break;
4071 }
4072 // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
4073 const MSLane* const target = *bestLaneIt;
4074 assert(!target->isInternal());
4075 newLink = nullptr;
4076 for (MSLink* const link : lane->getLinkCont()) {
4077 if (link->getLane() == target) {
4078 newLink = link;
4079 break;
4080 }
4081 }
4082
4083 if (newLink == driveItemIt->myLink) {
4084 // new continuation merged into previous - stop update
4085#ifdef DEBUG_ACTIONSTEPS
4086 if (DEBUG_COND) {
4087 std::cout << "Old and new continuation sequences merge at link\n"
4088 << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
4089 << "\nNo update beyond merge required." << std::endl;
4090 }
4091#endif
4092 break;
4093 }
4094
4095#ifdef DEBUG_ACTIONSTEPS
4096 if (DEBUG_COND) {
4097 std::cout << "lane=" << lane->getID() << "\nUpdating link\n '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
4098 << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
4099 }
4100#endif
4101 newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
4102 driveItemIt->myLink->removeApproaching(this);
4103 driveItemIt->myLink = newLink;
4104 lane = newLink->getViaLaneOrLane();
4105 ++driveItemIt;
4106 if (!lane->isInternal()) {
4107 ++bestLaneIt;
4108 }
4109 }
4110#ifdef DEBUG_ACTIONSTEPS
4111 if (DEBUG_COND) {
4112 std::cout << "Updated drive items:" << std::endl;
4113 for (const auto& dpi : myLFLinkLanes) {
4114 std::cout
4115 << " vPass=" << dpi.myVLinkPass
4116 << " vWait=" << dpi.myVLinkWait
4117 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4118 << " request=" << dpi.mySetRequest
4119 << "\n";
4120 }
4121 }
4122#endif
4123}
4124
4125
4126void
4128 // To avoid casual blinking brake lights at high speeds due to dawdling of the
4129 // leading vehicle, we don't show brake lights when the deceleration could be caused
4130 // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
4131 double pseudoFriction = (0.05 + 0.005 * getSpeed()) * getSpeed();
4132 bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
4133
4134 if (vNext <= SUMO_const_haltingSpeed) {
4135 brakelightsOn = true;
4136 }
4137 if (brakelightsOn && !isStopped()) {
4139 } else {
4141 }
4142}
4143
4144
4145void
4150 } else {
4151 myWaitingTime = 0;
4153 if (hasInfluencer()) {
4155 }
4156 }
4157}
4158
4159
4160void
4162 // update time loss (depends on the updated edge)
4163 if (!isStopped()) {
4164 const double vmax = myLane->getVehicleMaxSpeed(this);
4165 if (vmax > 0) {
4166 myTimeLoss += TS * (vmax - vNext) / vmax;
4167 }
4168 }
4169}
4170
4171
4172double
4173MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
4174 const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
4175 || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
4176#ifdef DEBUG_REVERSE_BIDI
4177 if (DEBUG_COND) std::cout << SIMTIME << " checkReversal lane=" << myLane->getID()
4178 << " pos=" << myState.myPos
4179 << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
4180 << " speedThreshold=" << speedThreshold
4181 << " seen=" << seen
4182 << " isRail=" << ((getVClass() & SVC_RAIL_CLASSES) != 0)
4183 << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
4184 << " posOK=" << (myState.myPos <= myLane->getLength())
4185 << " normal=" << !myLane->isInternal()
4186 << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
4187 << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
4188 << " stopOk=" << stopOk
4189 << "\n";
4190#endif
4191 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4192 && getPreviousSpeed() <= speedThreshold
4193 && myState.myPos <= myLane->getLength()
4194 && !myLane->isInternal()
4195 && (myCurrEdge + 1) != myRoute->end()
4196 && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
4197 // ensure there are no further stops on this edge
4198 && stopOk
4199 ) {
4200 //if (isSelected()) std::cout << " check1 passed\n";
4201
4202 // ensure that the vehicle is fully on bidi edges that allow reversal
4203 const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
4204 ? myFurtherLanes.size()
4205 : ceil((double)myFurtherLanes.size() / 2.0));
4206 const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
4207 if (remainingRoute < neededFutureRoute) {
4208#ifdef DEBUG_REVERSE_BIDI
4209 if (DEBUG_COND) {
4210 std::cout << " fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
4211 }
4212#endif
4213 return getMaxSpeed();
4214 }
4215 //if (isSelected()) std::cout << " check2 passed\n";
4216
4217 // ensure that the turn-around connection exists from the current edge to its bidi-edge
4218 const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
4219 if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
4220#ifdef DEBUG_REVERSE_BIDI
4221 if (DEBUG_COND) {
4222 std::cout << " noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
4223 }
4224#endif
4225 return getMaxSpeed();
4226 }
4227 //if (isSelected()) std::cout << " check3 passed\n";
4228
4229 // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
4230 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
4231 const double stopPos = myStops.front().getEndPos(*this);
4232 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4233 const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
4234 if (newPos > stopPos) {
4235#ifdef DEBUG_REVERSE_BIDI
4236 if (DEBUG_COND) {
4237 std::cout << " reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
4238 }
4239#endif
4240 if (seen > MAX2(brakeDist, 1.0)) {
4241 return getMaxSpeed();
4242 } else {
4243#ifdef DEBUG_REVERSE_BIDI
4244 if (DEBUG_COND) {
4245 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4246 }
4247#endif
4248 }
4249 }
4250 }
4251 //if (isSelected()) std::cout << " check4 passed\n";
4252
4253 // ensure that bidi-edges exist for all further edges
4254 // and that no stops will be skipped when reversing
4255 // and that the train will not be on top of a red rail signal after reversal
4256 const MSLane* bidi = myLane->getBidiLane();
4257 int view = 2;
4258 for (MSLane* further : myFurtherLanes) {
4259 if (!further->getEdge().isInternal()) {
4260 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
4261#ifdef DEBUG_REVERSE_BIDI
4262 if (DEBUG_COND) {
4263 std::cout << " noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
4264 }
4265#endif
4266 return getMaxSpeed();
4267 }
4268 const MSLane* nextBidi = further->getBidiLane();
4269 const MSLink* toNext = bidi->getLinkTo(nextBidi);
4270 if (toNext == nullptr) {
4271 // can only happen if the route is invalid
4272 return getMaxSpeed();
4273 }
4274 if (toNext->haveRed()) {
4275#ifdef DEBUG_REVERSE_BIDI
4276 if (DEBUG_COND) {
4277 std::cout << " do not reverse on a red signal\n";
4278 }
4279#endif
4280 return getMaxSpeed();
4281 }
4282 bidi = nextBidi;
4283 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
4284 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4285 const double stopPos = myStops.front().getEndPos(*this);
4286 const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
4287 if (newPos > stopPos) {
4288#ifdef DEBUG_REVERSE_BIDI
4289 if (DEBUG_COND) {
4290 std::cout << " reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
4291 }
4292#endif
4293 if (seen > MAX2(brakeDist, 1.0)) {
4294 canReverse = false;
4295 return getMaxSpeed();
4296 } else {
4297#ifdef DEBUG_REVERSE_BIDI
4298 if (DEBUG_COND) {
4299 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4300 }
4301#endif
4302 }
4303 }
4304 }
4305 view++;
4306 }
4307 }
4308 // reverse as soon as comfortably possible
4309 const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
4310#ifdef DEBUG_REVERSE_BIDI
4311 if (DEBUG_COND) {
4312 std::cout << SIMTIME << " seen=" << seen << " vReverseOK=" << vMinComfortable << "\n";
4313 }
4314#endif
4315 canReverse = true;
4316 return vMinComfortable;
4317 }
4318 return getMaxSpeed();
4319}
4320
4321
4322void
4323MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
4324 for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
4325 passedLanes.push_back(*i);
4326 }
4327 if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
4328 passedLanes.push_back(myLane);
4329 }
4330 // let trains reverse direction
4331 bool reverseTrain = false;
4332 checkReversal(reverseTrain);
4333 if (reverseTrain) {
4334 // Train is 'reversing' so toggle the logical state
4336 // add some slack to ensure that the back of train does appear looped
4337 myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
4338 myState.mySpeed = 0;
4339#ifdef DEBUG_REVERSE_BIDI
4340 if (DEBUG_COND) {
4341 std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
4342 }
4343#endif
4344 }
4345 // move on lane(s)
4346 if (myState.myPos > myLane->getLength()) {
4347 // The vehicle has moved at least to the next lane (maybe it passed even more than one)
4348 if (myCurrEdge != myRoute->end() - 1) {
4349 MSLane* approachedLane = myLane;
4350 // move the vehicle forward
4352 while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
4353 const MSLink* link = myNextDriveItem->myLink;
4354 const double linkDist = myNextDriveItem->myDistance;
4356 // check whether the vehicle was allowed to enter lane
4357 // otherwise it is decelerated and we do not need to test for it's
4358 // approach on the following lanes when a lane changing is performed
4359 // proceed to the next lane
4360 if (approachedLane->mustCheckJunctionCollisions()) {
4361 // vehicle moves past approachedLane within a single step, collision checking must still be done
4363 }
4364 if (link != nullptr) {
4365 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4366 && !myLane->isInternal()
4367 && myLane->getBidiLane() != nullptr
4368 && link->getLane()->getBidiLane() == myLane
4369 && !reverseTrain) {
4370 emergencyReason = " because it must reverse direction";
4371 approachedLane = nullptr;
4372 break;
4373 }
4374 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4375 && myState.myPos < myLane->getLength() + NUMERICAL_EPS
4376 && hasStops() && getNextStop().edge == myCurrEdge) {
4377 // avoid skipping stop due to numerical instability
4378 // this is a special case for rail vehicles because they
4379 // continue myLFLinkLanes past stops
4380 approachedLane = myLane;
4382 break;
4383 }
4384 approachedLane = link->getViaLaneOrLane();
4386 bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
4387 if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
4388 emergencyReason = " because of a red traffic light";
4389 break;
4390 }
4391 }
4392 if (reverseTrain && approachedLane->isInternal()) {
4393 // avoid getting stuck on a slow turn-around internal lane
4394 myState.myPos += approachedLane->getLength();
4395 }
4396 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4397 // avoid warning due to numerical instability
4398 approachedLane = myLane;
4400 } else if (reverseTrain) {
4401 approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
4402 link = myLane->getLinkTo(approachedLane);
4403 assert(link != 0);
4404 while (link->getViaLane() != nullptr) {
4405 link = link->getViaLane()->getLinkCont()[0];
4406 }
4408 } else {
4409 emergencyReason = " because there is no connection to the next edge";
4410 approachedLane = nullptr;
4411 break;
4412 }
4413 if (approachedLane != myLane && approachedLane != nullptr) {
4416 assert(myState.myPos > 0);
4417 enterLaneAtMove(approachedLane);
4418 if (link->isEntryLink()) {
4421 }
4422 if (link->isConflictEntryLink()) {
4424 // renew yielded request
4426 }
4427 if (link->isExitLink()) {
4428 // passed junction, reset for approaching the next one
4432 }
4433#ifdef DEBUG_PLAN_MOVE_LEADERINFO
4434 if (DEBUG_COND) {
4435 std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
4436 << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
4437 << " ET=" << myJunctionEntryTime
4438 << " ETN=" << myJunctionEntryTimeNeverYield
4439 << " CET=" << myJunctionConflictEntryTime
4440 << "\n";
4441 }
4442#endif
4443 if (hasArrivedInternal()) {
4444 break;
4445 }
4448 // abort lane change
4449 WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
4450 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4452 }
4453 }
4454 if (approachedLane->getEdge().isVaporizing()) {
4456 break;
4457 }
4458 passedLanes.push_back(approachedLane);
4459 }
4460 }
4461 // NOTE: Passed drive items will be erased in the next simstep's planMove()
4462
4463#ifdef DEBUG_ACTIONSTEPS
4464 if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
4465 std::cout << "Updated drive items:" << std::endl;
4466 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
4467 std::cout
4468 << " vPass=" << (*i).myVLinkPass
4469 << " vWait=" << (*i).myVLinkWait
4470 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
4471 << " request=" << (*i).mySetRequest
4472 << "\n";
4473 }
4474 }
4475#endif
4476 } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4477 // avoid warning due to numerical instability when stopping at the end of the route
4479 }
4480
4481 }
4482}
4483
4484
4485
4486bool
4488#ifdef DEBUG_EXEC_MOVE
4489 if (DEBUG_COND) {
4490 std::cout << "\nEXECUTE_MOVE\n"
4491 << SIMTIME
4492 << " veh=" << getID()
4493 << " speed=" << getSpeed() // toString(getSpeed(), 24)
4494 << std::endl;
4495 }
4496#endif
4497
4498
4499 // Maximum safe velocity
4500 double vSafe = std::numeric_limits<double>::max();
4501 // Minimum safe velocity (lower bound).
4502 double vSafeMin = -std::numeric_limits<double>::max();
4503 // The distance to a link, which should either be crossed this step
4504 // or in front of which we need to stop.
4505 double vSafeMinDist = 0;
4506
4507 if (myActionStep) {
4508 // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
4509 processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
4510#ifdef DEBUG_ACTIONSTEPS
4511 if (DEBUG_COND) {
4512 std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
4513 " vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
4514 }
4515#endif
4516 } else {
4517 // Continue with current acceleration
4518 vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
4519#ifdef DEBUG_ACTIONSTEPS
4520 if (DEBUG_COND) {
4521 std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
4522 " continues with constant accel " << myAcceleration << "...\n"
4523 << "speed: " << getSpeed() << " -> " << vSafe << std::endl;
4524 }
4525#endif
4526 }
4527
4528
4529//#ifdef DEBUG_EXEC_MOVE
4530// if (DEBUG_COND) {
4531// std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
4532// }
4533//#endif
4534
4535 // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
4536 // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
4537 double vNext = vSafe;
4538 const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
4539 if (vNext <= SUMO_const_haltingSpeed * TS && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting() && myActionStep) {
4541 } else if (isStopped()) {
4542 // do not apply startupDelay for waypoints
4543 if (getCarFollowModel().startupDelayStopped() && getNextStop().pars.speed <= 0) {
4545 } else {
4546 // do not apply startupDelay but signal that a stop has taken place
4548 }
4549 } else {
4550 // identify potential startup (before other effects reduce the speed again)
4552 }
4553 if (myActionStep) {
4554 vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
4555 if (vNext > 0) {
4556 vNext = MAX2(vNext, vSafeMin);
4557 }
4558 }
4559 // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
4560 // (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
4561 // (Jakob) We also need to make sure to reach a stop at the start of the next edge
4562 if (fabs(vNext) < NUMERICAL_EPS_SPEED && myStopDist > POSITION_EPS) {
4563 vNext = 0.;
4564 }
4565#ifdef DEBUG_EXEC_MOVE
4566 if (DEBUG_COND) {
4567 std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
4568 << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
4569 }
4570#endif
4571
4572 // vNext may be higher than vSafe without implying a bug:
4573 // - when approaching a green light that suddenly switches to yellow
4574 // - when using unregulated junctions
4575 // - when using tau < step-size
4576 // - when using unsafe car following models
4577 // - when using TraCI and some speedMode / laneChangeMode settings
4578 //if (vNext > vSafe + NUMERICAL_EPS) {
4579 // WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
4580 // + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
4581 // + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4582 //}
4583
4585 vNext = MAX2(vNext, 0.);
4586 } else {
4587 // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
4588 }
4589
4590 // Check for speed advices from the traci client
4591 vNext = processTraCISpeedControl(vSafe, vNext);
4592
4593 // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
4594 MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
4595 if (elecHybridOfVehicle != nullptr) {
4596 // this is the consumption given by the car following model-computed acceleration
4597 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4598 // but the maximum power of the electric motor may be lower
4599 // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
4600 double maxPower = elecHybridOfVehicle->getParameterDouble(toString(SUMO_ATTR_MAXIMUMPOWER)) / 3600;
4601 if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
4602 // no, we cannot accelerate that fast, recompute the maximum possible acceleration
4603 double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
4604 // and update the speed of the vehicle
4605 vNext = MIN2(vNext, this->getSpeed() + accel * TS);
4606 vNext = MAX2(vNext, 0.);
4607 // and set the vehicle consumption to reflect this
4608 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4609 }
4610 }
4611
4612 setBrakingSignals(vNext);
4613
4614 // update position and speed
4615 int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
4616 const MSLane* oldLaneMaybeOpposite = myLane;
4618 // transform to the forward-direction lane, move and then transform back
4621 }
4622 updateState(vNext);
4623 updateWaitingTime(vNext);
4624
4625 // Lanes, which the vehicle touched at some moment of the executed simstep
4626 std::vector<MSLane*> passedLanes;
4627 // remember previous lane (myLane is updated in processLaneAdvances)
4628 const MSLane* oldLane = myLane;
4629 // Reason for a possible emergency stop
4630 std::string emergencyReason;
4631 processLaneAdvances(passedLanes, emergencyReason);
4632
4633 updateTimeLoss(vNext);
4635
4637 if (myState.myPos > myLane->getLength()) {
4638 if (emergencyReason == "") {
4639 emergencyReason = TL(" for unknown reasons");
4640 }
4641 WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
4642 getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
4647 myState.mySpeed = 0;
4648 myAcceleration = 0;
4649 }
4650 const MSLane* oldBackLane = getBackLane();
4652 passedLanes.clear(); // ignore back occupation
4653 }
4654#ifdef DEBUG_ACTIONSTEPS
4655 if (DEBUG_COND) {
4656 std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
4657 }
4658#endif
4660 if (passedLanes.size() > 1 && isRailway(getVClass())) {
4661 for (auto pi = passedLanes.rbegin(); pi != passedLanes.rend(); ++pi) {
4662 MSLane* pLane = *pi;
4663 if (pLane != myLane && std::find(myFurtherLanes.begin(), myFurtherLanes.end(), pLane) == myFurtherLanes.end()) {
4665 }
4666 }
4667 }
4668 // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
4670 if (myLane != oldLane || oldBackLane != getBackLane()) {
4671 if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
4672 // shadow lane must be updated if the front or back lane changed
4673 // either if we already have a shadowLane or if there is lateral overlap
4675 }
4677 // The vehicles target lane must be also be updated if the front or back lane changed
4679 }
4680 }
4681 setBlinkerInformation(); // needs updated bestLanes
4682 //change the blue light only for emergency vehicles SUMOVehicleClass
4684 setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
4685 }
4686 // must be done before angle computation
4687 // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
4688 if (myActionStep) {
4689 // check (#2681): Can this be skipped?
4691 } else {
4693#ifdef DEBUG_ACTIONSTEPS
4694 if (DEBUG_COND) {
4695 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
4696 }
4697#endif
4698 }
4701 }
4702
4703#ifdef DEBUG_EXEC_MOVE
4704 if (DEBUG_COND) {
4705 std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
4706 gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
4707 }
4708#endif
4710 // transform back to the opposite-direction lane
4711 MSLane* newOpposite = nullptr;
4712 const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
4713 if (newOppositeEdge != nullptr) {
4714 newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
4715#ifdef DEBUG_EXEC_MOVE
4716 if (DEBUG_COND) {
4717 std::cout << SIMTIME << " newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
4718 }
4719#endif
4720 }
4721 if (newOpposite == nullptr) {
4723 // unusual overtaking at junctions is ok for emergency vehicles
4724 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
4726 }
4728 if (myState.myPos < getLength()) {
4729 // further lanes is always cleared during opposite driving
4730 MSLane* oldOpposite = oldLane->getOpposite();
4731 if (oldOpposite != nullptr) {
4732 myFurtherLanes.push_back(oldOpposite);
4733 myFurtherLanesPosLat.push_back(0);
4734 // small value since the lane is going in the other direction
4737 } else {
4738 SOFT_ASSERT(false);
4739 }
4740 }
4741 } else {
4743 myLane = newOpposite;
4744 oldLane = oldLaneMaybeOpposite;
4745 //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
4748 }
4749 }
4751 // Return whether the vehicle did move to another lane
4752 return myLane != oldLane;
4753}
4754
4755void
4757 myState.myPos += dist;
4760
4761 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
4763 for (int i = 0; i < (int)lanes.size(); i++) {
4764 MSLink* link = nullptr;
4765 if (i + 1 < (int)lanes.size()) {
4766 const MSLane* const to = lanes[i + 1];
4767 const bool internal = to->isInternal();
4768 for (MSLink* const l : lanes[i]->getLinkCont()) {
4769 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
4770 link = l;
4771 break;
4772 }
4773 }
4774 }
4775 myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
4776 }
4777 // minimum execute move:
4778 std::vector<MSLane*> passedLanes;
4779 // Reason for a possible emergency stop
4780 if (lanes.size() > 1) {
4782 }
4783 std::string emergencyReason;
4784 processLaneAdvances(passedLanes, emergencyReason);
4785#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
4786 if (DEBUG_COND) {
4787 std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
4788 << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
4789 << " finalPos=" << myState.myPos
4790 << " speed=" << getSpeed()
4791 << " myFurtherLanes=" << toString(myFurtherLanes)
4792 << "\n";
4793 }
4794#endif
4796 if (lanes.size() > 1) {
4797 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
4798#ifdef DEBUG_FURTHER
4799 if (DEBUG_COND) {
4800 std::cout << SIMTIME << " leaveLane \n";
4801 }
4802#endif
4803 (*i)->resetPartialOccupation(this);
4804 }
4805 myFurtherLanes.clear();
4806 myFurtherLanesPosLat.clear();
4808 }
4809}
4810
4811
4812void
4814 // update position and speed
4815 double deltaPos; // positional change
4817 // euler
4818 deltaPos = SPEED2DIST(vNext);
4819 } else {
4820 // ballistic
4821 deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
4822 }
4823
4824 // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
4825 // NOTE: for the ballistic update vNext may be negative, indicating a stop.
4827
4828#ifdef DEBUG_EXEC_MOVE
4829 if (DEBUG_COND) {
4830 std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
4831 << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
4832 }
4833#endif
4834 double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
4835 if (decelPlus > 0) {
4836 const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
4837 if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
4838 // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
4839 decelPlus += 2 * NUMERICAL_EPS;
4840 const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
4841 if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
4842 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
4843 //+ " decelPlus=" + toString(decelPlus)
4844 //+ " prevAccel=" + toString(previousAcceleration)
4845 //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
4846 getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
4848 }
4849 }
4850 }
4851
4853 myState.mySpeed = MAX2(vNext, 0.);
4854
4855 if (isRemoteControlled()) {
4856 deltaPos = myInfluencer->implicitDeltaPosRemote(this);
4857 }
4858
4859 myState.myPos += deltaPos;
4860 myState.myLastCoveredDist = deltaPos;
4861 myNextTurn.first -= deltaPos;
4862
4864}
4865
4866void
4868 updateState(0);
4869 // deboard while parked
4870 if (myPersonDevice != nullptr) {
4872 }
4873 if (myContainerDevice != nullptr) {
4875 }
4876 for (MSVehicleDevice* const dev : myDevices) {
4877 dev->notifyParking();
4878 }
4879}
4880
4881
4882void
4888
4889
4890const MSLane*
4892 if (myFurtherLanes.size() > 0) {
4893 return myFurtherLanes.back();
4894 } else {
4895 return myLane;
4896 }
4897}
4898
4899
4900double
4901MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
4902 const std::vector<MSLane*>& passedLanes) {
4903#ifdef DEBUG_SETFURTHER
4904 if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
4905 << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
4906 << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
4907 << " passed=" << toString(passedLanes)
4908 << "\n";
4909#endif
4910 for (MSLane* further : furtherLanes) {
4911 further->resetPartialOccupation(this);
4912 if (further->getBidiLane() != nullptr
4913 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4914 further->getBidiLane()->resetPartialOccupation(this);
4915 }
4916 }
4917
4918 std::vector<MSLane*> newFurther;
4919 std::vector<double> newFurtherPosLat;
4920 double backPosOnPreviousLane = myState.myPos - getLength();
4921 bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
4922 if (passedLanes.size() > 1) {
4923 // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
4924 std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
4925 std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
4926 for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
4927 // As long as vehicle back reaches into passed lane, add it to the further lanes
4928 MSLane* further = *pi;
4929 newFurther.push_back(further);
4930 backPosOnPreviousLane += further->setPartialOccupation(this);
4931 if (further->getBidiLane() != nullptr
4932 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4933 further->getBidiLane()->setPartialOccupation(this);
4934 }
4935 if (fi != furtherLanes.end() && further == *fi) {
4936 // Lateral position on this lane is already known. Assume constant and use old value.
4937 newFurtherPosLat.push_back(*fpi);
4938 ++fi;
4939 ++fpi;
4940 } else {
4941 // The lane *pi was not in furtherLanes before.
4942 // If it is downstream, we assume as lateral position the current position
4943 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
4944 // we assign the last known lateral position.
4945 if (newFurtherPosLat.size() == 0) {
4946 if (widthShift) {
4947 newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
4948 } else {
4949 newFurtherPosLat.push_back(myState.myPosLat);
4950 }
4951 } else {
4952 newFurtherPosLat.push_back(newFurtherPosLat.back());
4953 }
4954 }
4955#ifdef DEBUG_SETFURTHER
4956 if (DEBUG_COND) {
4957 std::cout << SIMTIME << " updateFurtherLanes \n"
4958 << " further lane '" << further->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
4959 << std::endl;
4960 }
4961#endif
4962 }
4963 furtherLanes = newFurther;
4964 furtherLanesPosLat = newFurtherPosLat;
4965 } else {
4966 furtherLanes.clear();
4967 furtherLanesPosLat.clear();
4968 }
4969#ifdef DEBUG_SETFURTHER
4970 if (DEBUG_COND) std::cout
4971 << " newFurther=" << toString(furtherLanes)
4972 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
4973 << " newBackPos=" << backPosOnPreviousLane
4974 << "\n";
4975#endif
4976 return backPosOnPreviousLane;
4977}
4978
4979
4980double
4981MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
4982#ifdef DEBUG_FURTHER
4983 if (DEBUG_COND) {
4984 std::cout << SIMTIME
4985 << " getBackPositionOnLane veh=" << getID()
4986 << " lane=" << Named::getIDSecure(lane)
4987 << " cbgP=" << calledByGetPosition
4988 << " pos=" << myState.myPos
4989 << " backPos=" << myState.myBackPos
4990 << " myLane=" << myLane->getID()
4991 << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
4992 << " further=" << toString(myFurtherLanes)
4993 << " furtherPosLat=" << toString(myFurtherLanesPosLat)
4994 << "\n shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
4995 << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
4996 << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
4997 << "\n targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
4998 << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
4999 << std::endl;
5000 }
5001#endif
5002 if (lane == myLane
5003 || lane == myLaneChangeModel->getShadowLane()
5004 || lane == myLaneChangeModel->getTargetLane()) {
5006 if (lane == myLaneChangeModel->getShadowLane()) {
5007 return lane->getLength() - myState.myPos - myType->getLength();
5008 } else {
5009 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5010 }
5011 } else if (&lane->getEdge() != &myLane->getEdge()) {
5012 return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5013 } else {
5014 // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
5015 return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
5016 }
5017 } else if (lane == myLane->getBidiLane()) {
5018 return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
5019 } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
5020 return myState.myBackPos;
5021 } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
5022 || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
5023 assert(myFurtherLanes.size() > 0);
5024 if (lane->getLength() == myFurtherLanes.back()->getLength()) {
5025 return myState.myBackPos;
5026 } else {
5027 // interpolate
5028 //if (DEBUG_COND) {
5029 //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
5030 // std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
5031 // << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
5032 // << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
5033 //}
5034 return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
5035 }
5036 } else {
5037 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
5038 double leftLength = myType->getLength() - myState.myPos;
5039
5040 std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
5041 while (leftLength > 0 && i != myFurtherLanes.end()) {
5042 leftLength -= (*i)->getLength();
5043 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5044 if (*i == lane) {
5045 return -leftLength;
5046 } else if (*i == lane->getBidiLane()) {
5047 return lane->getLength() + leftLength - (calledByGetPosition ? 2 * myType->getLength() : 0);
5048 }
5049 ++i;
5050 }
5051 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
5052 leftLength = myType->getLength() - myState.myPos;
5054 while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
5055 leftLength -= (*i)->getLength();
5056 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5057 if (*i == lane) {
5058 return -leftLength;
5059 }
5060 ++i;
5061 }
5062 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
5063 leftLength = myType->getLength() - myState.myPos;
5064 i = getFurtherLanes().begin();
5065 const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
5066 auto j = furtherTargetLanes.begin();
5067 while (leftLength > 0 && j != furtherTargetLanes.end()) {
5068 leftLength -= (*i)->getLength();
5069 // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5070 if (*j == lane) {
5071 return -leftLength;
5072 }
5073 ++i;
5074 ++j;
5075 }
5076 WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
5077 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
5078 SOFT_ASSERT(false);
5079 return myState.myBackPos;
5080 }
5081}
5082
5083
5084double
5086 return getBackPositionOnLane(lane, true) + myType->getLength();
5087}
5088
5089
5090bool
5092 return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
5093}
5094
5095
5096void
5097MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
5099 double seenSpace = -lengthsInFront;
5100#ifdef DEBUG_CHECKREWINDLINKLANES
5101 if (DEBUG_COND) {
5102 std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
5103 };
5104#endif
5105 bool foundStopped = false;
5106 // compute available space until a stopped vehicle is found
5107 // this is the sum of non-interal lane length minus in-between vehicle lengths
5108 for (int i = 0; i < (int)lfLinks.size(); ++i) {
5109 // skip unset links
5110 DriveProcessItem& item = lfLinks[i];
5111#ifdef DEBUG_CHECKREWINDLINKLANES
5112 if (DEBUG_COND) std::cout << SIMTIME
5113 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5114 << " foundStopped=" << foundStopped;
5115#endif
5116 if (item.myLink == nullptr || foundStopped) {
5117 if (!foundStopped) {
5118 item.availableSpace += seenSpace;
5119 } else {
5120 item.availableSpace = seenSpace;
5121 }
5122#ifdef DEBUG_CHECKREWINDLINKLANES
5123 if (DEBUG_COND) {
5124 std::cout << " avail=" << item.availableSpace << "\n";
5125 }
5126#endif
5127 continue;
5128 }
5129 // get the next lane, determine whether it is an internal lane
5130 const MSLane* approachedLane = item.myLink->getViaLane();
5131 if (approachedLane != nullptr) {
5132 if (keepClear(item.myLink)) {
5133 seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
5134 if (approachedLane == myLane) {
5135 seenSpace += getVehicleType().getLengthWithGap();
5136 }
5137 } else {
5138 seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
5139 }
5140 item.availableSpace = seenSpace;
5141#ifdef DEBUG_CHECKREWINDLINKLANES
5142 if (DEBUG_COND) std::cout
5143 << " approached=" << approachedLane->getID()
5144 << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
5145 << " avail=" << item.availableSpace
5146 << " seenSpace=" << seenSpace
5147 << " hadStoppedVehicle=" << item.hadStoppedVehicle
5148 << " lengthsInFront=" << lengthsInFront
5149 << "\n";
5150#endif
5151 continue;
5152 }
5153 approachedLane = item.myLink->getLane();
5154 const MSVehicle* last = approachedLane->getLastAnyVehicle();
5155 if (last == nullptr || last == this) {
5156 if (approachedLane->getLength() > getVehicleType().getLength()
5157 || keepClear(item.myLink)) {
5158 seenSpace += approachedLane->getLength();
5159 }
5160 item.availableSpace = seenSpace;
5161#ifdef DEBUG_CHECKREWINDLINKLANES
5162 if (DEBUG_COND) {
5163 std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
5164 }
5165#endif
5166 } else {
5167 bool foundStopped2 = false;
5168 double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
5169 if (approachedLane->getBidiLane() != nullptr) {
5170 const MSVehicle* oncomingVeh = approachedLane->getBidiLane()->getFirstFullVehicle();
5171 if (oncomingVeh) {
5172 const double oncomingGap = approachedLane->getLength() - oncomingVeh->getPositionOnLane();
5173 const double oncomingBGap = oncomingVeh->getBrakeGap(true);
5174 // oncoming movement until ego enters the junction
5175 const double oncomingMove = STEPS2TIME(item.myArrivalTime - SIMSTEP) * oncomingVeh->getSpeed();
5176 const double spaceTillOncoming = oncomingGap - oncomingBGap - oncomingMove;
5177 spaceTillLastStanding = MIN2(spaceTillLastStanding, spaceTillOncoming);
5178 if (spaceTillOncoming <= getVehicleType().getLengthWithGap()) {
5179 foundStopped = true;
5180 }
5181#ifdef DEBUG_CHECKREWINDLINKLANES
5182 if (DEBUG_COND) {
5183 std::cout << " oVeh=" << oncomingVeh->getID()
5184 << " oGap=" << oncomingGap
5185 << " bGap=" << oncomingBGap
5186 << " mGap=" << oncomingMove
5187 << " sto=" << spaceTillOncoming;
5188 }
5189#endif
5190 }
5191 }
5192 seenSpace += spaceTillLastStanding;
5193 if (foundStopped2) {
5194 foundStopped = true;
5195 item.hadStoppedVehicle = true;
5196 }
5197 item.availableSpace = seenSpace;
5198 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
5199 foundStopped = true;
5200 item.hadStoppedVehicle = true;
5201 }
5202#ifdef DEBUG_CHECKREWINDLINKLANES
5203 if (DEBUG_COND) std::cout
5204 << " approached=" << approachedLane->getID()
5205 << " last=" << last->getID()
5206 << " lastHasToWait=" << last->myHaveToWaitOnNextLink
5207 << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
5208 << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
5209 << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
5210 // gap of last up to the next intersection
5211 - last->getVehicleType().getMinGap())
5212 << " stls=" << spaceTillLastStanding
5213 << " avail=" << item.availableSpace
5214 << " seenSpace=" << seenSpace
5215 << " foundStopped=" << foundStopped
5216 << " foundStopped2=" << foundStopped2
5217 << "\n";
5218#endif
5219 }
5220 }
5221
5222 // check which links allow continuation and add pass available to the previous item
5223 for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
5224 DriveProcessItem& item = lfLinks[i - 1];
5225 DriveProcessItem& nextItem = lfLinks[i];
5226 const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
5227 const bool opened = (item.myLink != nullptr
5228 && (canLeaveJunction || (
5229 // indirect bicycle turn
5230 nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
5231 && (
5232 item.myLink->havePriority()
5233 || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
5235 || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
5238 bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
5239#ifdef DEBUG_CHECKREWINDLINKLANES
5240 if (DEBUG_COND) std::cout
5241 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5242 << " canLeave=" << canLeaveJunction
5243 << " opened=" << opened
5244 << " allowsContinuation=" << allowsContinuation
5245 << " foundStopped=" << foundStopped
5246 << "\n";
5247#endif
5248 if (!opened && item.myLink != nullptr) {
5249 foundStopped = true;
5250 if (i > 1) {
5251 DriveProcessItem& item2 = lfLinks[i - 2];
5252 if (item2.myLink != nullptr && item2.myLink->isCont()) {
5253 allowsContinuation = true;
5254 }
5255 }
5256 }
5257 if (allowsContinuation) {
5258 item.availableSpace = nextItem.availableSpace;
5259#ifdef DEBUG_CHECKREWINDLINKLANES
5260 if (DEBUG_COND) std::cout
5261 << " link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5262 << " copy nextAvail=" << nextItem.availableSpace
5263 << "\n";
5264#endif
5265 }
5266 }
5267
5268 // find removalBegin
5269 int removalBegin = -1;
5270 for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
5271 // skip unset links
5272 const DriveProcessItem& item = lfLinks[i];
5273 if (item.myLink == nullptr) {
5274 continue;
5275 }
5276 /*
5277 double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
5278 if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
5279 removalBegin = lastLinkToInternal;
5280 }
5281 */
5282
5283 const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
5284#ifdef DEBUG_CHECKREWINDLINKLANES
5285 if (DEBUG_COND) std::cout
5286 << SIMTIME
5287 << " veh=" << getID()
5288 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5289 << " avail=" << item.availableSpace
5290 << " leftSpace=" << leftSpace
5291 << "\n";
5292#endif
5293 if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
5294 double impatienceCorrection = 0;
5295 /*
5296 if(item.myLink->getState()==LINKSTATE_MINOR) {
5297 impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
5298 }
5299 */
5300 // may ignore keepClear rules
5301 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
5302 removalBegin = i;
5303 }
5304 //removalBegin = i;
5305 }
5306 }
5307 // abort requests
5308 if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
5309 const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
5310 while (removalBegin < (int)(lfLinks.size())) {
5311 DriveProcessItem& dpi = lfLinks[removalBegin];
5312 if (dpi.myLink == nullptr) {
5313 break;
5314 }
5315 dpi.myVLinkPass = dpi.myVLinkWait;
5316#ifdef DEBUG_CHECKREWINDLINKLANES
5317 if (DEBUG_COND) {
5318 std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
5319 }
5320#endif
5321 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
5322 // always leave junctions after requesting to enter
5323 if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
5324 dpi.mySetRequest = false;
5325 }
5326 }
5327 ++removalBegin;
5328 }
5329 }
5330 }
5331}
5332
5333
5334void
5336 if (!checkActionStep(t)) {
5337 return;
5338 }
5340 for (DriveProcessItem& dpi : myLFLinkLanes) {
5341 if (dpi.myLink != nullptr) {
5342 if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
5343 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
5344 }
5345 dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5346 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance, getLateralPositionOnLane());
5347 }
5348 }
5349 if (isRailway(getVClass())) {
5350 for (DriveProcessItem& dpi : myLFLinkLanes) {
5351 if (dpi.myLink != nullptr && dpi.myLink->getTLLogic() != nullptr && dpi.myLink->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
5353 }
5354 }
5355 }
5356 if (myLaneChangeModel->getShadowLane() != nullptr) {
5357 // register on all shadow links
5358 for (const DriveProcessItem& dpi : myLFLinkLanes) {
5359 if (dpi.myLink != nullptr) {
5360 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
5361 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
5362 // register on opposite direction entry link to warn foes at minor side road
5363 parallelLink = dpi.myLink->getOppositeDirectionLink();
5364 }
5365 if (parallelLink != nullptr) {
5366 const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
5367 parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5368 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance,
5369 latOffset);
5371 }
5372 }
5373 }
5374 }
5375#ifdef DEBUG_PLAN_MOVE
5376 if (DEBUG_COND) {
5377 std::cout << SIMTIME
5378 << " veh=" << getID()
5379 << " after checkRewindLinkLanes\n";
5380 for (DriveProcessItem& dpi : myLFLinkLanes) {
5381 std::cout
5382 << " vPass=" << dpi.myVLinkPass
5383 << " vWait=" << dpi.myVLinkWait
5384 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
5385 << " request=" << dpi.mySetRequest
5386 << " atime=" << dpi.myArrivalTime
5387 << "\n";
5388 }
5389 }
5390#endif
5391}
5392
5393
5394void
5396 DriveProcessItem dpi(0, dist);
5397 dpi.myLink = link;
5398 const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
5399 link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
5400 // ensure cleanup in the next step
5401 myLFLinkLanes.push_back(dpi);
5403}
5404
5405
5406void
5407MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
5408 myAmOnNet = !onTeleporting;
5409 // vaporizing edge?
5410 /*
5411 if (enteredLane->getEdge().isVaporizing()) {
5412 // yep, let's do the vaporization...
5413 myLane = enteredLane;
5414 return true;
5415 }
5416 */
5417 // Adjust MoveReminder offset to the next lane
5418 adaptLaneEntering2MoveReminder(*enteredLane);
5419 // set the entered lane as the current lane
5420 MSLane* oldLane = myLane;
5421 myLane = enteredLane;
5422 myLastBestLanesEdge = nullptr;
5423
5424 // internal edges are not a part of the route...
5425 if (!enteredLane->getEdge().isInternal()) {
5426 ++myCurrEdge;
5428 }
5429 if (myInfluencer != nullptr) {
5431 }
5432 if (!onTeleporting) {
5435 // transform lateral position when the lane width changes
5436 assert(oldLane != nullptr);
5437 const MSLink* const link = oldLane->getLinkTo(myLane);
5438 if (link != nullptr) {
5440 myState.myPosLat += link->getLateralShift();
5441 }
5442 } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
5443 const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
5444 const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5445 const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5446 myState.myPosLat *= range2 / range;
5447 }
5448 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5449 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5450 // (unless the lane is shared with cars)
5452 }
5453 } else {
5454 // normal move() isn't called so reset position here. must be done
5455 // before calling reminders
5456 myState.myPos = 0;
5459 }
5460 // update via
5461 if (myParameter->via.size() > 0 && myLane->getEdge().getID() == myParameter->via.front()) {
5462 myParameter->via.erase(myParameter->via.begin());
5463 }
5464}
5465
5466
5467void
5469 myAmOnNet = true;
5470 myLane = enteredLane;
5472 // need to update myCurrentLaneInBestLanes
5474 // switch to and activate the new lane's reminders
5475 // keep OldLaneReminders
5476 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5477 addReminder(*rem);
5478 }
5480 MSLane* lane = myLane;
5481 double leftLength = getVehicleType().getLength() - myState.myPos;
5482 int deleteFurther = 0;
5483#ifdef DEBUG_SETFURTHER
5484 if (DEBUG_COND) {
5485 std::cout << SIMTIME << " enterLaneAtLaneChange entered=" << Named::getIDSecure(enteredLane) << " oldFurther=" << toString(myFurtherLanes) << "\n";
5486 }
5487#endif
5488 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5489 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5490 // (unless the lane is shared with cars)
5492 }
5493 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
5494 if (lane != nullptr) {
5496 }
5497#ifdef DEBUG_SETFURTHER
5498 if (DEBUG_COND) {
5499 std::cout << " enterLaneAtLaneChange i=" << i << " lane=" << Named::getIDSecure(lane) << " leftLength=" << leftLength << "\n";
5500 }
5501#endif
5502 if (leftLength > 0) {
5503 if (lane != nullptr) {
5505 if (myFurtherLanes[i]->getBidiLane() != nullptr
5506 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5507 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5508 }
5509 // lane changing onto longer lanes may reduce the number of
5510 // remaining further lanes
5511 myFurtherLanes[i] = lane;
5513 leftLength -= lane->setPartialOccupation(this);
5514 if (lane->getBidiLane() != nullptr
5515 && (!isRailway(getVClass()) || (lane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5516 lane->getBidiLane()->setPartialOccupation(this);
5517 }
5518 myState.myBackPos = -leftLength;
5519#ifdef DEBUG_SETFURTHER
5520 if (DEBUG_COND) {
5521 std::cout << SIMTIME << " newBackPos=" << myState.myBackPos << "\n";
5522 }
5523#endif
5524 } else {
5525 // keep the old values, but ensure there is no shadow
5528 }
5529 if (myState.myBackPos < 0) {
5530 myState.myBackPos += myFurtherLanes[i]->getLength();
5531 }
5532#ifdef DEBUG_SETFURTHER
5533 if (DEBUG_COND) {
5534 std::cout << SIMTIME << " i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
5535 }
5536#endif
5537 }
5538 } else {
5539 myFurtherLanes[i]->resetPartialOccupation(this);
5540 if (myFurtherLanes[i]->getBidiLane() != nullptr
5541 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5542 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5543 }
5544 deleteFurther++;
5545 }
5546 }
5547 if (deleteFurther > 0) {
5548#ifdef DEBUG_SETFURTHER
5549 if (DEBUG_COND) {
5550 std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
5551 }
5552#endif
5553 myFurtherLanes.erase(myFurtherLanes.end() - deleteFurther, myFurtherLanes.end());
5554 myFurtherLanesPosLat.erase(myFurtherLanesPosLat.end() - deleteFurther, myFurtherLanesPosLat.end());
5555 }
5556#ifdef DEBUG_SETFURTHER
5557 if (DEBUG_COND) {
5558 std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
5559 << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
5560 }
5561#endif
5563}
5564
5565
5566void
5567MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
5568 // build the list of lanes the vehicle is lapping into
5569 if (!myLaneChangeModel->isOpposite()) {
5570 double leftLength = myType->getLength() - pos;
5571 MSLane* clane = enteredLane;
5572 int routeIndex = getRoutePosition();
5573 while (leftLength > 0) {
5574 if (routeIndex > 0 && clane->getEdge().isNormal()) {
5575 // get predecessor lane that corresponds to prior route
5576 routeIndex--;
5577 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
5578 MSLane* target = clane;
5579 clane = nullptr;
5580 for (auto ili : target->getIncomingLanes()) {
5581 if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
5582 clane = ili.lane;
5583 break;
5584 }
5585 }
5586 } else {
5587 clane = clane->getLogicalPredecessorLane();
5588 }
5589 if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
5590 || (clane->isInternal() && (
5591 clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
5592 || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
5593 break;
5594 }
5595 if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
5596 myFurtherLanes.push_back(clane);
5598 clane->setPartialOccupation(this);
5599 if (clane->getBidiLane() != nullptr
5600 && (!isRailway(getVClass()) || (clane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5601 clane->getBidiLane()->setPartialOccupation(this);
5602 }
5603 }
5604 leftLength -= clane->getLength();
5605 }
5606 myState.myBackPos = -leftLength;
5607#ifdef DEBUG_SETFURTHER
5608 if (DEBUG_COND) {
5609 std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
5610 }
5611#endif
5612 } else {
5613 // clear partial occupation
5614 for (MSLane* further : myFurtherLanes) {
5615#ifdef DEBUG_SETFURTHER
5616 if (DEBUG_COND) {
5617 std::cout << SIMTIME << " opposite: resetPartialOccupation " << further->getID() << " \n";
5618 }
5619#endif
5620 further->resetPartialOccupation(this);
5621 if (further->getBidiLane() != nullptr
5622 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5623 further->getBidiLane()->resetPartialOccupation(this);
5624 }
5625 }
5626 myFurtherLanes.clear();
5627 myFurtherLanesPosLat.clear();
5628 }
5629}
5630
5631
5632void
5633MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
5634 myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
5636 onDepart();
5637 }
5639 assert(myState.myPos >= 0);
5640 assert(myState.mySpeed >= 0);
5641 myLane = enteredLane;
5642 myAmOnNet = true;
5643 // schedule action for the next timestep
5645 if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
5646 // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
5647 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5648 addReminder(*rem);
5649 }
5650 activateReminders(notification, enteredLane);
5651 } else {
5652 myLastBestLanesEdge = nullptr;
5655 }
5656 computeFurtherLanes(enteredLane, pos);
5660 } else if (MSGlobals::gLaneChangeDuration > 0) {
5662 }
5663 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5666 myAngle += M_PI;
5667 }
5668 }
5669}
5670
5671
5672void
5673MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5674 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5675 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5676#ifdef _DEBUG
5677 if (myTraceMoveReminders) {
5678 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5679 }
5680#endif
5681 ++rem;
5682 } else {
5683#ifdef _DEBUG
5684 if (myTraceMoveReminders) {
5685 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5686 }
5687#endif
5688 rem = myMoveReminders.erase(rem);
5689 }
5690 }
5694 && myLane != nullptr) {
5696 }
5697 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
5698 && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5700 }
5702 // @note. In case of lane change, myFurtherLanes and partial occupation
5703 // are handled in enterLaneAtLaneChange()
5704 for (MSLane* further : myFurtherLanes) {
5705#ifdef DEBUG_FURTHER
5706 if (DEBUG_COND) {
5707 std::cout << SIMTIME << " leaveLane \n";
5708 }
5709#endif
5710 further->resetPartialOccupation(this);
5711 if (further->getBidiLane() != nullptr
5712 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5713 further->getBidiLane()->resetPartialOccupation(this);
5714 }
5715 }
5716 myFurtherLanes.clear();
5717 myFurtherLanesPosLat.clear();
5718 }
5720 myAmOnNet = false;
5721 myWaitingTime = 0;
5722 }
5724 myStopDist = std::numeric_limits<double>::max();
5725 if (myPastStops.back().speed <= 0) {
5726 WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
5727 }
5728 }
5730 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5731 if (myStops.front().getSpeed() <= 0) {
5732 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5733 time2string(MSNet::getInstance()->getCurrentTimeStep()))
5734 myStops.pop_front();
5735 } else {
5736 MSStop& stop = myStops.front();
5737 // passed waypoint at the end of the lane
5738 if (!stop.reached) {
5739 if (MSStopOut::active()) {
5741 }
5742 stop.reached = true;
5743 // enter stopping place so leaveFrom works as expected
5744 if (stop.busstop != nullptr) {
5745 // let the bus stop know the vehicle
5746 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5747 }
5748 if (stop.containerstop != nullptr) {
5749 // let the container stop know the vehicle
5751 }
5752 // do not enter parkingarea!
5753 if (stop.chargingStation != nullptr) {
5754 // let the container stop know the vehicle
5756 }
5757 }
5759 }
5760 myStopDist = std::numeric_limits<double>::max();
5761 }
5762 }
5763}
5764
5765
5766void
5768 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5769 if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
5770#ifdef _DEBUG
5771 if (myTraceMoveReminders) {
5772 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
5773 }
5774#endif
5775 ++rem;
5776 } else {
5777#ifdef _DEBUG
5778 if (myTraceMoveReminders) {
5779 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
5780 }
5781#endif
5782 rem = myMoveReminders.erase(rem);
5783 }
5784 }
5785#ifdef DEBUG_MOVEREMINDERS
5786 if (DEBUG_COND) {
5787 std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
5788 for (auto rem : myMoveReminders) {
5789 std::cout << rem.first->getDescription() << " ";
5790 }
5791 std::cout << "\n";
5792 }
5793#endif
5794}
5795
5796
5801
5802
5807
5808bool
5810 return (lane->isInternal()
5811 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5812 : &lane->getEdge() != *myCurrEdge);
5813}
5814
5815const std::vector<MSVehicle::LaneQ>&
5817 return *myBestLanes.begin();
5818}
5819
5820
5821void
5822MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5823#ifdef DEBUG_BESTLANES
5824 if (DEBUG_COND) {
5825 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5826 }
5827#endif
5828 if (startLane == nullptr) {
5829 startLane = myLane;
5830 }
5831 assert(startLane != 0);
5833 // depending on the calling context, startLane might be the forward lane
5834 // or the reverse-direction lane. In the latter case we need to
5835 // transform it to the forward lane.
5836 if (isOppositeLane(startLane)) {
5837 // use leftmost lane of forward edge
5838 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5839 assert(startLane != 0);
5840#ifdef DEBUG_BESTLANES
5841 if (DEBUG_COND) {
5842 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5843 }
5844#endif
5845 }
5846 }
5847 if (forceRebuild) {
5848 myLastBestLanesEdge = nullptr;
5850 }
5851 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5853#ifdef DEBUG_BESTLANES
5854 if (DEBUG_COND) {
5855 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5856 }
5857#endif
5858 return;
5859 }
5860 if (startLane->getEdge().isInternal()) {
5861 if (myBestLanes.size() == 0 || forceRebuild) {
5862 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5863 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5864 }
5865 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5866#ifdef DEBUG_BESTLANES
5867 if (DEBUG_COND) {
5868 std::cout << " nothing to do on internal\n";
5869 }
5870#endif
5871 return;
5872 }
5873 // adapt best lanes to fit the current internal edge:
5874 // keep the entries that are reachable from this edge
5875 const MSEdge* nextEdge = startLane->getNextNormal();
5876 assert(!nextEdge->isInternal());
5877 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5878 std::vector<LaneQ>& lanes = *it;
5879 assert(lanes.size() > 0);
5880 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5881 // keep those lanes which are successors of internal lanes from the edge of startLane
5882 std::vector<LaneQ> oldLanes = lanes;
5883 lanes.clear();
5884 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
5885 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
5886 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
5887 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
5888 lanes.push_back(*it_lane);
5889 break;
5890 }
5891 }
5892 }
5893 assert(lanes.size() == startLane->getEdge().getLanes().size());
5894 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
5895 for (int i = 0; i < (int)lanes.size(); ++i) {
5896 if (i + lanes[i].bestLaneOffset < 0) {
5897 lanes[i].bestLaneOffset = -i;
5898 }
5899 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
5900 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
5901 }
5902 assert(i + lanes[i].bestLaneOffset >= 0);
5903 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
5904 if (lanes[i].bestContinuations[0] != 0) {
5905 // patch length of bestContinuation to match expectations (only once)
5906 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
5907 }
5908 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
5909 myCurrentLaneInBestLanes = lanes.begin() + i;
5910 }
5911 assert(&(lanes[i].lane->getEdge()) == nextEdge);
5912 }
5913 myLastBestLanesInternalLane = startLane;
5915#ifdef DEBUG_BESTLANES
5916 if (DEBUG_COND) {
5917 std::cout << " updated for internal\n";
5918 }
5919#endif
5920 return;
5921 } else {
5922 // remove passed edges
5923 it = myBestLanes.erase(it);
5924 }
5925 }
5926 assert(false); // should always find the next edge
5927 }
5928 // start rebuilding
5930 myLastBestLanesEdge = &startLane->getEdge();
5932
5933 // get information about the next stop
5934 MSRouteIterator nextStopEdge = myRoute->end();
5935 const MSLane* nextStopLane = nullptr;
5936 double nextStopPos = 0;
5937 bool nextStopIsWaypoint = false;
5938 if (!myStops.empty()) {
5939 const MSStop& nextStop = myStops.front();
5940 nextStopLane = nextStop.lane;
5941 if (nextStop.isOpposite) {
5942 // target leftmost lane in forward direction
5943 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
5944 }
5945 nextStopEdge = nextStop.edge;
5946 nextStopPos = nextStop.pars.startPos;
5947 nextStopIsWaypoint = nextStop.getSpeed() > 0;
5948 }
5949 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
5950 if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
5951 nextStopEdge = (myRoute->end() - 1);
5952 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
5953 nextStopPos = myArrivalPos;
5954 }
5955 if (nextStopEdge != myRoute->end()) {
5956 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
5957 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
5958 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
5959 if (nextStopLane->isInternal()) {
5960 // switch to the correct lane before entering the intersection
5961 nextStopPos = (*nextStopEdge)->getLength();
5962 }
5963 }
5964
5965 // go forward along the next lanes;
5966 // trains do not have to deal with lane-changing for stops but their best
5967 // lanes lookahead is needed for rail signal control
5968 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
5969 int seen = 0;
5970 double seenLength = 0;
5971 bool progress = true;
5972 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
5973 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
5974 for (MSRouteIterator ce = myCurrEdge; progress;) {
5975 std::vector<LaneQ> currentLanes;
5976 const std::vector<MSLane*>* allowed = nullptr;
5977 const MSEdge* nextEdge = nullptr;
5978 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
5979 nextEdge = *(ce + 1);
5980 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
5981 }
5982 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
5983 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
5984 LaneQ q;
5985 MSLane* cl = *i;
5986 q.lane = cl;
5987 q.bestContinuations.push_back(cl);
5988 q.bestLaneOffset = 0;
5989 q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
5990 q.currentLength = q.length;
5991 // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
5992 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
5993 q.occupation = 0;
5994 q.nextOccupation = 0;
5995 currentLanes.push_back(q);
5996 }
5997 //
5998 if (nextStopEdge == ce
5999 // already past the stop edge
6000 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
6001 if (!nextStopLane->isInternal() && !continueAfterStop) {
6002 progress = false;
6003 }
6004 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
6005 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
6006 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
6007 (*q).allowsContinuation = false;
6008 (*q).length = nextStopPos;
6009 (*q).currentLength = (*q).length;
6010 }
6011 }
6012 }
6013
6014 myBestLanes.push_back(currentLanes);
6015 ++seen;
6016 seenLength += currentLanes[0].lane->getLength();
6017 ++ce;
6018 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
6019 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
6020 progress &= ce != myRoute->end();
6021 /*
6022 if(progress) {
6023 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
6024 }
6025 */
6026 }
6027
6028 // we are examining the last lane explicitly
6029 if (myBestLanes.size() != 0) {
6030 double bestLength = -1;
6031 // minimum and maximum lane index with best length
6032 int bestThisIndex = 0;
6033 int bestThisMaxIndex = 0;
6034 int index = 0;
6035 std::vector<LaneQ>& last = myBestLanes.back();
6036 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6037 if ((*j).length > bestLength) {
6038 bestLength = (*j).length;
6039 bestThisIndex = index;
6040 bestThisMaxIndex = index;
6041 } else if ((*j).length == bestLength) {
6042 bestThisMaxIndex = index;
6043 }
6044 }
6045 index = 0;
6046 bool requiredChangeRightForbidden = false;
6047 int requireChangeToLeftForbidden = -1;
6048 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6049 if ((*j).length < bestLength) {
6050 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6051 (*j).bestLaneOffset = bestThisIndex - index;
6052 } else {
6053 (*j).bestLaneOffset = bestThisMaxIndex - index;
6054 }
6055 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6056 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6057 || requiredChangeRightForbidden)) {
6058 // this lane and all further lanes to the left cannot be used
6059 requiredChangeRightForbidden = true;
6060 (*j).length = 0;
6061 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6062 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6063 // this lane and all previous lanes to the right cannot be used
6064 requireChangeToLeftForbidden = (*j).lane->getIndex();
6065 }
6066 }
6067 }
6068 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
6069 last[i].length = 0;
6070 }
6071#ifdef DEBUG_BESTLANES
6072 if (DEBUG_COND) {
6073 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6074 std::vector<LaneQ>& laneQs = myBestLanes.back();
6075 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6076 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
6077 }
6078 }
6079#endif
6080 }
6081 // go backward through the lanes
6082 // track back best lane and compute the best prior lane(s)
6083 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
6084 std::vector<LaneQ>& nextLanes = (*(i - 1));
6085 std::vector<LaneQ>& clanes = (*i);
6086 MSEdge* const cE = &clanes[0].lane->getEdge();
6087 int index = 0;
6088 double bestConnectedLength = -1;
6089 double bestLength = -1;
6090 for (const LaneQ& j : nextLanes) {
6091 if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
6092 bestConnectedLength = j.length;
6093 }
6094 if (bestLength < j.length) {
6095 bestLength = j.length;
6096 }
6097 }
6098 // compute index of the best lane (highest length and least offset from the best next lane)
6099 int bestThisIndex = 0;
6100 int bestThisMaxIndex = 0;
6101 if (bestConnectedLength > 0) {
6102 index = 0;
6103 for (LaneQ& j : clanes) {
6104 const LaneQ* bestConnectedNext = nullptr;
6105 if (j.allowsContinuation) {
6106 for (const LaneQ& m : nextLanes) {
6107 if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
6108 && m.lane->isApproachedFrom(cE, j.lane)) {
6109 if (betterContinuation(bestConnectedNext, m)) {
6110 bestConnectedNext = &m;
6111 }
6112 }
6113 }
6114 if (bestConnectedNext != nullptr) {
6115 if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
6116 j.length += bestLength;
6117 } else {
6118 j.length += bestConnectedNext->length;
6119 }
6120 j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
6121 }
6122 }
6123 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
6124 copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
6125 } else {
6126 j.allowsContinuation = false;
6127 }
6128 if (clanes[bestThisIndex].length < j.length
6129 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
6130 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
6131 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
6132 ) {
6133 bestThisIndex = index;
6134 bestThisMaxIndex = index;
6135 } else if (clanes[bestThisIndex].length == j.length
6136 && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
6137 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
6138 bestThisMaxIndex = index;
6139 }
6140 index++;
6141 }
6142
6143 //vehicle with elecHybrid device prefers running under an overhead wire
6144 if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
6145 index = 0;
6146 for (const LaneQ& j : clanes) {
6147 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6148 if (overheadWireSegmentID != "") {
6149 bestThisIndex = index;
6150 bestThisMaxIndex = index;
6151 }
6152 index++;
6153 }
6154 }
6155
6156 } else {
6157 // only needed in case of disconnected routes
6158 int bestNextIndex = 0;
6159 int bestDistToNeeded = (int) clanes.size();
6160 index = 0;
6161 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6162 if ((*j).allowsContinuation) {
6163 int nextIndex = 0;
6164 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
6165 if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
6166 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
6167 bestDistToNeeded = abs((*m).bestLaneOffset);
6168 bestThisIndex = index;
6169 bestThisMaxIndex = index;
6170 bestNextIndex = nextIndex;
6171 }
6172 }
6173 }
6174 }
6175 }
6176 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
6177 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
6178
6179 }
6180 // set bestLaneOffset for all lanes
6181 index = 0;
6182 bool requiredChangeRightForbidden = false;
6183 int requireChangeToLeftForbidden = -1;
6184 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6185 if ((*j).length < clanes[bestThisIndex].length
6186 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
6187 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
6188 ) {
6189 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6190 (*j).bestLaneOffset = bestThisIndex - index;
6191 } else {
6192 (*j).bestLaneOffset = bestThisMaxIndex - index;
6193 }
6194 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
6195 // try to move away from the lower-priority lane before it ends
6196 (*j).length = (*j).currentLength;
6197 }
6198 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6199 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6200 || requiredChangeRightForbidden)) {
6201 // this lane and all further lanes to the left cannot be used
6202 requiredChangeRightForbidden = true;
6203 if ((*j).length == (*j).currentLength) {
6204 (*j).length = 0;
6205 }
6206 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6207 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6208 // this lane and all previous lanes to the right cannot be used
6209 requireChangeToLeftForbidden = (*j).lane->getIndex();
6210 }
6211 } else {
6212 (*j).bestLaneOffset = 0;
6213 }
6214 }
6215 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
6216 if (clanes[idx].length == clanes[idx].currentLength) {
6217 clanes[idx].length = 0;
6218 };
6219 }
6220
6221 //vehicle with elecHybrid device prefers running under an overhead wire
6222 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
6223 index = 0;
6224 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6225 if (overheadWireID != "") {
6226 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6227 (*j).bestLaneOffset = bestThisIndex - index;
6228 }
6229 }
6230 }
6231
6232#ifdef DEBUG_BESTLANES
6233 if (DEBUG_COND) {
6234 std::cout << " edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6235 std::vector<LaneQ>& laneQs = clanes;
6236 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6237 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
6238 }
6239 }
6240#endif
6241
6242 }
6244#ifdef DEBUG_BESTLANES
6245 if (DEBUG_COND) {
6246 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
6247 }
6248#endif
6249}
6250
6251void
6253 if (myLane != nullptr) {
6255 }
6256}
6257
6258bool
6259MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
6260 if (bestConnectedNext == nullptr) {
6261 return true;
6262 } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
6263 return false;
6264 } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
6265 return true;
6266 } else if (bestConnectedNext->length < m.length) {
6267 return true;
6268 } else if (bestConnectedNext->length == m.length) {
6269 if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
6270 return true;
6271 }
6272 const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
6273 if (contRight < 1
6274 // if we don't check for adjacency, the rightmost line will get
6275 // multiple chances to be better which leads to an uninituitve distribution
6276 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
6277 && RandHelper::rand(getRNG()) > contRight) {
6278 return true;
6279 }
6280 }
6281 return false;
6282}
6283
6284
6285int
6286MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
6287 if (conts.size() < 2) {
6288 return -1;
6289 } else {
6290 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
6291 if (link != nullptr) {
6292 return link->havePriority() ? 1 : 0;
6293 } else {
6294 // disconnected route
6295 return -1;
6296 }
6297 }
6298}
6299
6300
6301void
6303 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
6304 std::vector<LaneQ>::iterator i;
6305 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
6306 double nextOccupation = 0;
6307 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
6308 nextOccupation += (*j)->getBruttoVehLenSum();
6309 }
6310 (*i).nextOccupation = nextOccupation;
6311#ifdef DEBUG_BESTLANES
6312 if (DEBUG_COND) {
6313 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
6314 }
6315#endif
6316 if ((*i).lane == startLane) {
6318 }
6319 }
6320}
6321
6322
6323const std::vector<MSLane*>&
6325 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6326 return myEmptyLaneVector;
6327 }
6328 return (*myCurrentLaneInBestLanes).bestContinuations;
6329}
6330
6331
6332const std::vector<MSLane*>&
6334 const MSLane* lane = l;
6335 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
6336 if (lane->getEdge().isInternal()) {
6337 // internal edges are not kept inside the bestLanes structure
6338 lane = lane->getLinkCont()[0]->getLane();
6339 }
6340 if (myBestLanes.size() == 0) {
6341 return myEmptyLaneVector;
6342 }
6343 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
6344 if ((*i).lane == lane) {
6345 return (*i).bestContinuations;
6346 }
6347 }
6348 return myEmptyLaneVector;
6349}
6350
6351const std::vector<const MSLane*>
6352MSVehicle::getUpcomingLanesUntil(double distance) const {
6353 std::vector<const MSLane*> lanes;
6354
6355 if (distance <= 0. || hasArrived()) {
6356 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
6357 return lanes;
6358 }
6359
6360 if (!myLaneChangeModel->isOpposite()) {
6361 distance += getPositionOnLane();
6362 } else {
6363 distance += myLane->getOppositePos(getPositionOnLane());
6364 }
6366 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6367 lanes.insert(lanes.end(), lane);
6368 distance -= lane->getLength();
6369 lane = lane->getLinkCont().front()->getViaLaneOrLane();
6370 }
6371
6372 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
6373 if (contLanes.empty()) {
6374 return lanes;
6375 }
6376 auto contLanesIt = contLanes.begin();
6377 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
6378 while (distance > 0.) {
6379 MSLane* l = nullptr;
6380 if (contLanesIt != contLanes.end()) {
6381 l = *contLanesIt;
6382 if (l != nullptr) {
6383 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
6384 }
6385 ++contLanesIt;
6386 if (l != nullptr || myLane->isInternal()) {
6387 ++routeIt;
6388 }
6389 if (l == nullptr) {
6390 continue;
6391 }
6392 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
6393 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6394 l = (*routeIt)->getLanes().back();
6395 ++routeIt;
6396 } else { // the search distance goes beyond our route
6397 break;
6398 }
6399
6400 assert(l != nullptr);
6401
6402 // insert internal lanes if applicable
6403 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
6404 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
6405 lanes.insert(lanes.end(), internalLane);
6406 distance -= internalLane->getLength();
6407 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6408 }
6409 if (distance <= 0.) {
6410 break;
6411 }
6412
6413 lanes.insert(lanes.end(), l);
6414 distance -= l->getLength();
6415 }
6416
6417 return lanes;
6418}
6419
6420const std::vector<const MSLane*>
6421MSVehicle::getPastLanesUntil(double distance) const {
6422 std::vector<const MSLane*> lanes;
6423
6424 if (distance <= 0.) {
6425 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
6426 return lanes;
6427 }
6428
6429 MSRouteIterator routeIt = myCurrEdge;
6430 if (!myLaneChangeModel->isOpposite()) {
6431 distance += myLane->getLength() - getPositionOnLane();
6432 } else {
6434 }
6436 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6437 lanes.insert(lanes.end(), lane);
6438 distance -= lane->getLength();
6439 lane = lane->getLogicalPredecessorLane();
6440 }
6441
6442 while (distance > 0.) {
6443 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6444 MSLane* l = (*routeIt)->getLanes().back();
6445
6446 // insert internal lanes if applicable
6447 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
6448 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
6449 std::vector<const MSLane*> internalLanes;
6450 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
6451 internalLanes.insert(internalLanes.begin(), internalLane);
6452 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6453 }
6454 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
6455 lanes.insert(lanes.end(), *it);
6456 distance -= (*it)->getLength();
6457 }
6458 if (distance <= 0.) {
6459 break;
6460 }
6461
6462 lanes.insert(lanes.end(), l);
6463 distance -= l->getLength();
6464
6465 // NOTE: we're going backwards with the (bi-directional) Iterator
6466 // TODO: consider make reverse_iterator() when moving on to C++14 or later
6467 if (routeIt != myRoute->begin()) {
6468 --routeIt;
6469 } else { // we went backwards to begin() and already processed the first and final element
6470 break;
6471 }
6472 }
6473
6474 return lanes;
6475}
6476
6477
6478const std::vector<MSLane*>
6480 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6481 std::vector<MSLane*> result;
6482 for (const MSLane* lane : routeLanes) {
6483 MSLane* opposite = lane->getOpposite();
6484 if (opposite != nullptr) {
6485 result.push_back(opposite);
6486 } else {
6487 break;
6488 }
6489 }
6490 return result;
6491}
6492
6493
6494int
6496 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6497 return 0;
6498 } else {
6499 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6500 }
6501}
6502
6503double
6505 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6506 return -1;
6507 } else {
6508 return (*myCurrentLaneInBestLanes).length;
6509 }
6510}
6511
6512
6513
6514void
6515MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6516 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6517 assert(laneIndex < (int)preb.size());
6518 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6519}
6520
6521
6522void
6528
6529std::pair<const MSLane*, double>
6530MSVehicle::getLanePosAfterDist(double distance) const {
6531 if (distance == 0) {
6532 return std::make_pair(myLane, getPositionOnLane());
6533 }
6534 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6535 distance += getPositionOnLane();
6536 for (const MSLane* lane : lanes) {
6537 if (lane->getLength() > distance) {
6538 return std::make_pair(lane, distance);
6539 }
6540 distance -= lane->getLength();
6541 }
6542 return std::make_pair(nullptr, -1);
6543}
6544
6545
6546double
6547MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
6548 if (isOnRoad() && destLane != nullptr) {
6549 return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
6550 }
6551 return std::numeric_limits<double>::max();
6552}
6553
6554
6555std::pair<const MSVehicle* const, double>
6556MSVehicle::getLeader(double dist) const {
6557 if (myLane == nullptr) {
6558 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6559 }
6560 if (dist == 0) {
6562 }
6563 const MSVehicle* lead = nullptr;
6564 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6565 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6566 // vehicle might be outside the road network
6567 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6568 if (it != vehs.end() && it + 1 != vehs.end()) {
6569 lead = *(it + 1);
6570 }
6571 if (lead != nullptr) {
6572 std::pair<const MSVehicle* const, double> result(
6573 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6574 lane->releaseVehicles();
6575 return result;
6576 }
6577 const double seen = myLane->getLength() - getPositionOnLane();
6578 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6579 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts);
6580 lane->releaseVehicles();
6581 return result;
6582}
6583
6584
6585std::pair<const MSVehicle* const, double>
6586MSVehicle::getFollower(double dist) const {
6587 if (myLane == nullptr) {
6588 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6589 }
6590 if (dist == 0) {
6591 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6592 }
6594}
6595
6596
6597double
6599 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6600 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6601 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6602 return -1;
6603 }
6604 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6605}
6606
6607
6608void
6610 MSBaseVehicle::addTransportable(transportable);
6611 if (myStops.size() > 0 && myStops.front().reached) {
6612 if (transportable->isPerson()) {
6613 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6614 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6615 }
6616 } else {
6617 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6618 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6619 }
6620 }
6621 }
6622}
6623
6624
6625void
6628 int state = myLaneChangeModel->getOwnState();
6629 // do not set blinker for sublane changes or when blocked from changing to the right
6630 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6631 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6635 // lane indices increase from left to right
6636 std::swap(left, right);
6637 }
6638 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6639 switchOnSignal(left);
6640 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6641 switchOnSignal(right);
6642 } else if (myLaneChangeModel->isChangingLanes()) {
6644 switchOnSignal(left);
6645 } else {
6646 switchOnSignal(right);
6647 }
6648 } else {
6649 const MSLane* lane = getLane();
6650 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6651 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6652 switch ((*link)->getDirection()) {
6657 break;
6661 break;
6662 default:
6663 break;
6664 }
6665 }
6666 }
6667 // stopping related signals
6668 if (hasStops()
6669 && (myStops.begin()->reached ||
6671 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6672 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6673 // not stopping on the right. Activate emergency blinkers
6675 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6676 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6678 }
6679 }
6680 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6682 myInfluencer->setSignals(-1); // overwrite computed signals only once
6683 }
6684}
6685
6686void
6688
6689 //TODO look if timestep ist SIMSTEP
6690 if (currentTime % 1000 == 0) {
6693 } else {
6695 }
6696 }
6697}
6698
6699
6700int
6702 return myLane == nullptr ? -1 : myLane->getIndex();
6703}
6704
6705
6706void
6707MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6708 myLane = lane;
6709 myState.myPos = pos;
6710 myState.myPosLat = posLat;
6712}
6713
6714
6715double
6717 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6718}
6719
6720
6721double
6723 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6724}
6725
6726
6727double
6729 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6730}
6731
6732
6733double
6735 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6736}
6737
6738
6739double
6741 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6742}
6743
6744
6745double
6747 return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
6748}
6749
6750
6751double
6753 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6755 } else if (lane == myLaneChangeModel->getShadowLane()) {
6756 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6757 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6758 }
6760 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6761 } else {
6762 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6763 }
6764 } else if (lane == myLane->getBidiLane()) {
6765 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6766 } else {
6767 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6768 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6769 if (myFurtherLanes[i] == lane) {
6770#ifdef DEBUG_FURTHER
6771 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
6772 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6773 << "\n";
6774#endif
6775 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6776 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6777#ifdef DEBUG_FURTHER
6778 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
6779 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6780 << "\n";
6781#endif
6782 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6783 }
6784 }
6785 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6786 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6787 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6788 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6789 if (shadowFurther[i] == lane) {
6790 assert(myLaneChangeModel->getShadowLane() != 0);
6791 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6793 }
6794 }
6795 assert(false);
6796 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6797 }
6798}
6799
6800
6801double
6803 assert(lane != 0);
6804 if (&lane->getEdge() == &myLane->getEdge()) {
6805 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6806 } else if (myLane->getParallelOpposite() == lane) {
6807 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6808 } else if (myLane->getBidiLane() == lane) {
6809 return -2 * getLateralPositionOnLane();
6810 } else {
6811 // Check whether the lane is a further lane for the vehicle
6812 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6813 if (myFurtherLanes[i] == lane) {
6814#ifdef DEBUG_FURTHER
6815 if (DEBUG_COND) {
6816 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6817 }
6818#endif
6820 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6821#ifdef DEBUG_FURTHER
6822 if (DEBUG_COND) {
6823 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
6824 }
6825#endif
6826 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
6827 }
6828 }
6829#ifdef DEBUG_FURTHER
6830 if (DEBUG_COND) {
6831 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6832 }
6833#endif
6834 // Check whether the lane is a "shadow further lane" for the vehicle
6835 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6836 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6837 if (shadowFurther[i] == lane) {
6838#ifdef DEBUG_FURTHER
6839 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6840 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6841 << " lane=" << lane->getID()
6842 << " i=" << i
6843 << " posLat=" << myState.myPosLat
6844 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6845 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6846 << "\n";
6847#endif
6849 }
6850 }
6851 // Check whether the vehicle issued a maneuverReservation on the lane.
6852 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6853 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6854 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6855 MSLane* targetLane = furtherTargets[i];
6856 if (targetLane == lane) {
6857 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6858 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
6859#ifdef DEBUG_TARGET_LANE
6860 if (DEBUG_COND) {
6861 std::cout << " getLatOffset veh=" << getID()
6862 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
6863 << "\n i=" << i
6864 << " posLat=" << myState.myPosLat
6865 << " furtherPosLat=" << myFurtherLanesPosLat[i]
6866 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
6867 << " targetDir=" << targetDir
6868 << " latOffset=" << latOffset
6869 << std::endl;
6870 }
6871#endif
6872 return latOffset;
6873 }
6874 }
6875 assert(false);
6876 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6877 }
6878}
6879
6880
6881double
6882MSVehicle::lateralDistanceToLane(const int offset) const {
6883 // compute the distance when changing to the neighboring lane
6884 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
6885 assert(offset == 0 || offset == 1 || offset == -1);
6886 assert(myLane != nullptr);
6887 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
6888 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
6889 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
6890 const double latPos = getLateralPositionOnLane();
6891 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
6892 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
6893 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
6894 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
6895 if (offset == 0) {
6896 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
6897 // correct overlapping left
6898 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
6899 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
6900 // correct overlapping right
6901 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
6902 }
6903 latLaneDist *= oppositeSign;
6904 } else if (offset == -1) {
6905 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
6906 } else if (offset == 1) {
6907 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
6908 }
6909#ifdef DEBUG_ACTIONSTEPS
6910 if (DEBUG_COND) {
6911 std::cout << SIMTIME
6912 << " veh=" << getID()
6913 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
6914 << " halfVehWidth=" << halfVehWidth
6915 << " latPos=" << latPos
6916 << " latLaneDist=" << latLaneDist
6917 << " leftLimit=" << leftLimit
6918 << " rightLimit=" << rightLimit
6919 << "\n";
6920 }
6921#endif
6922 return latLaneDist;
6923}
6924
6925
6926double
6927MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
6928 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
6929 - 0.5 * lane->getWidth());
6930}
6931
6932double
6936
6937double
6941
6942
6943void
6945 for (const DriveProcessItem& dpi : lfLinks) {
6946 if (dpi.myLink != nullptr) {
6947 dpi.myLink->removeApproaching(this);
6948 }
6949 }
6950 // unregister on all shadow links
6952}
6953
6954
6955bool
6957 // the following links are unsafe:
6958 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
6959 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
6960 double seen = myLane->getLength() - getPositionOnLane();
6961 const double dist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
6962 if (seen < dist) {
6963 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
6964 int view = 1;
6965 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
6966 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
6967 while (!lane->isLinkEnd(link) && seen <= dist) {
6968 if (!lane->getEdge().isInternal()
6969 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
6970 || !(*link)->havePriority())) {
6971 // find the drive item corresponding to this link
6972 bool found = false;
6973 while (di != myLFLinkLanes.end() && !found) {
6974 if ((*di).myLink != nullptr) {
6975 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
6976 if (diPredLane != nullptr) {
6977 if (&diPredLane->getEdge() == &lane->getEdge()) {
6978 found = true;
6979 }
6980 }
6981 }
6982 if (!found) {
6983 di++;
6984 }
6985 }
6986 if (found) {
6987 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
6988 (*di).getLeaveSpeed(), getVehicleType().getLength());
6989 if ((*link)->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
6990 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
6991 return true;
6992 }
6993 }
6994 // no drive item is found if the vehicle aborts its request within dist
6995 }
6996 lane = (*link)->getViaLaneOrLane();
6997 if (!lane->getEdge().isInternal()) {
6998 view++;
6999 }
7000 seen += lane->getLength();
7001 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7002 }
7003 }
7004 return false;
7005}
7006
7007
7009MSVehicle::getBoundingBox(double offset) const {
7010 PositionVector centerLine;
7011 Position pos = getPosition();
7012 centerLine.push_back(pos);
7013 switch (myType->getGuiShape()) {
7020 for (MSLane* lane : myFurtherLanes) {
7021 centerLine.push_back(lane->getShape().back());
7022 }
7023 break;
7024 }
7025 default:
7026 break;
7027 }
7028 double l = getLength();
7029 Position backPos = getBackPosition();
7030 if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
7031 // getBackPosition may not match the visual back in networks without internal lanes
7032 double a = getAngle() + M_PI; // angle pointing backwards
7033 backPos = pos + Position(l * cos(a), l * sin(a));
7034 }
7035 centerLine.push_back(backPos);
7036 if (offset != 0) {
7037 centerLine.extrapolate2D(offset);
7038 }
7039 PositionVector result = centerLine;
7040 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7041 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
7042 result.append(centerLine.reverse(), POSITION_EPS);
7043 return result;
7044}
7045
7046
7048MSVehicle::getBoundingPoly(double offset) const {
7049 switch (myType->getGuiShape()) {
7055 // box with corners cut off
7056 PositionVector result;
7057 PositionVector centerLine;
7058 centerLine.push_back(getPosition());
7059 centerLine.push_back(getBackPosition());
7060 if (offset != 0) {
7061 centerLine.extrapolate2D(offset);
7062 }
7063 PositionVector line1 = centerLine;
7064 PositionVector line2 = centerLine;
7065 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
7066 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7067 line2.scaleRelative(0.8);
7068 result.push_back(line1[0]);
7069 result.push_back(line2[0]);
7070 result.push_back(line2[1]);
7071 result.push_back(line1[1]);
7072 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
7073 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
7074 result.push_back(line1[1]);
7075 result.push_back(line2[1]);
7076 result.push_back(line2[0]);
7077 result.push_back(line1[0]);
7078 return result;
7079 }
7080 default:
7081 return getBoundingBox();
7082 }
7083}
7084
7085
7086bool
7088 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
7089 if (&(*i)->getEdge() == edge) {
7090 return true;
7091 }
7092 }
7093 return false;
7094}
7095
7096
7097bool
7098MSVehicle::isBidiOn(const MSLane* lane) const {
7099 return lane->getBidiLane() != nullptr && (
7100 myLane == lane->getBidiLane()
7101 || onFurtherEdge(&lane->getBidiLane()->getEdge()));
7102}
7103
7104
7105bool
7106MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
7107 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
7108 // consistency in the behaviour.
7109
7110 // get vehicle params
7111 MSParkingArea* destParkArea = getNextParkingArea();
7112 const MSRoute& route = getRoute();
7113 const MSEdge* lastEdge = route.getLastEdge();
7114
7115 if (destParkArea == nullptr) {
7116 // not driving towards a parking area
7117 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
7118 return false;
7119 }
7120
7121 // if the current route ends at the parking area, the new route will also and at the new area
7122 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
7123 && getArrivalPos() >= destParkArea->getBeginLanePosition()
7124 && getArrivalPos() <= destParkArea->getEndLanePosition());
7125
7126 // retrieve info on the new parking area
7128 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
7129
7130 if (newParkingArea == nullptr) {
7131 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
7132 return false;
7133 }
7134
7135 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
7137
7138 // Compute the route from the current edge to the parking area edge
7139 ConstMSEdgeVector edgesToPark;
7140 router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
7141
7142 // Compute the route from the parking area edge to the end of the route
7143 ConstMSEdgeVector edgesFromPark;
7144 if (!newDestination) {
7145 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
7146 } else {
7147 // adapt plans of any riders
7148 for (MSTransportable* p : getPersons()) {
7149 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
7150 }
7151 }
7152
7153 // we have a new destination, let's replace the vehicle route
7154 ConstMSEdgeVector edges = edgesToPark;
7155 if (edgesFromPark.size() > 0) {
7156 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
7157 }
7158
7159 if (newDestination) {
7160 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
7161 *newParameter = getParameter();
7163 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
7164 replaceParameter(newParameter);
7165 }
7166 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
7167 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
7168 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
7169 if (replaceParkingArea(newParkingArea, errorMsg)) {
7170 const bool onInit = myLane == nullptr;
7171 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
7172 } else {
7173 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
7174 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
7175 return false;
7176 }
7177 return true;
7178}
7179
7180
7181bool
7183 const int numStops = (int)myStops.size();
7184 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
7185 if (myLane != nullptr && numStops != (int)myStops.size()) {
7186 updateBestLanes(true);
7187 }
7188 return result;
7189}
7190
7191
7192bool
7193MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
7194 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
7195 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
7196 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
7197 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
7198 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
7199 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
7200 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
7201 // << " vNew=" << vNew
7202 // << "\n";
7203 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
7206 if (myState.myPos < myType->getLength()) {
7210 myAngle += M_PI;
7211 }
7212 }
7213 }
7214 }
7215 return true;
7216}
7217
7218
7219bool
7221 if (isStopped()) {
7225 }
7226 MSStop& stop = myStops.front();
7227 // we have waited long enough and fulfilled any passenger-requirements
7228 if (stop.busstop != nullptr) {
7229 // inform bus stop about leaving it
7230 stop.busstop->leaveFrom(this);
7231 }
7232 // we have waited long enough and fulfilled any container-requirements
7233 if (stop.containerstop != nullptr) {
7234 // inform container stop about leaving it
7235 stop.containerstop->leaveFrom(this);
7236 }
7237 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
7238 // inform parking area about leaving it
7239 stop.parkingarea->leaveFrom(this);
7240 }
7241 if (stop.chargingStation != nullptr) {
7242 // inform charging station about leaving it
7243 stop.chargingStation->leaveFrom(this);
7244 }
7245 // the current stop is no longer valid
7246 myLane->getEdge().removeWaiting(this);
7247 // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
7248 if (stop.pars.started == -1) {
7249 // waypoint edge was passed in a single step
7251 }
7252 if (MSStopOut::active()) {
7253 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
7254 }
7256 for (const auto& rem : myMoveReminders) {
7257 rem.first->notifyStopEnded();
7258 }
7260 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
7261 }
7263 // reset lateral position to default
7264 myState.myPosLat = 0;
7265 }
7266 myPastStops.push_back(stop.pars);
7267 myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
7268 myStops.pop_front();
7269 myStopDist = std::numeric_limits<double>::max();
7270 // do not count the stopping time towards gridlock time.
7271 // Other outputs use an independent counter and are not affected.
7272 myWaitingTime = 0;
7273 // maybe the next stop is on the same edge; let's rebuild best lanes
7274 updateBestLanes(true);
7275 // continue as wished...
7278 return true;
7279 }
7280 return false;
7281}
7282
7283
7286 if (myInfluencer == nullptr) {
7287 myInfluencer = new Influencer();
7288 }
7289 return *myInfluencer;
7290}
7291
7296
7297
7300 return myInfluencer;
7301}
7302
7305 return myInfluencer;
7306}
7307
7308
7309double
7311 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
7312 // influencer original speed is -1 on initialization
7314 }
7315 return myState.mySpeed;
7316}
7317
7318
7319int
7321 if (hasInfluencer()) {
7323 MSNet::getInstance()->getCurrentTimeStep(),
7324 myLane->getEdge(),
7325 getLaneIndex(),
7326 state);
7327 }
7328 return state;
7329}
7330
7331
7332void
7336
7337
7338bool
7342
7343
7344bool
7348
7349
7350bool
7351MSVehicle::keepClear(const MSLink* link) const {
7352 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
7353 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
7354 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
7355 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
7356 } else {
7357 return false;
7358 }
7359}
7360
7361
7362bool
7363MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
7364 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
7365 return true;
7366 }
7367 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
7368#ifdef DEBUG_IGNORE_RED
7369 if (DEBUG_COND) {
7370 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
7371 }
7372#endif
7373 if (ignoreRedTime < 0) {
7374 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
7375 if (ignoreYellowTime > 0 && link->haveYellow()) {
7376 assert(link->getTLLogic() != 0);
7377 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7378 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
7379 return !canBrake || ignoreYellowTime > yellowDuration;
7380 } else {
7381 return false;
7382 }
7383 } else if (link->haveYellow()) {
7384 // always drive at yellow when ignoring red
7385 return true;
7386 } else if (link->haveRed()) {
7387 assert(link->getTLLogic() != 0);
7388 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7389#ifdef DEBUG_IGNORE_RED
7390 if (DEBUG_COND) {
7391 std::cout
7392 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
7393 << " ignoreRedTime=" << ignoreRedTime
7394 << " spentRed=" << redDuration
7395 << " canBrake=" << canBrake << "\n";
7396 }
7397#endif
7398 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
7399 return !canBrake || ignoreRedTime > redDuration;
7400 } else {
7401 return false;
7402 }
7403}
7404
7405bool
7408 return false;
7409 }
7410 for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
7411 if (typeID == foe->getVehicleType().getID()) {
7412 return true;
7413 }
7414 }
7415 for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
7416 if (id == foe->getID()) {
7417 return true;
7418 }
7419 }
7420 return false;
7421}
7422
7423bool
7425 // either on an internal lane that was entered via minor link
7426 // or on approach to minor link below visibility distance
7427 if (myLane == nullptr) {
7428 return false;
7429 }
7430 if (myLane->getEdge().isInternal()) {
7431 return !myLane->getIncomingLanes().front().viaLink->havePriority();
7432 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
7433 MSLink* link = myLFLinkLanes.front().myLink;
7434 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
7435 }
7436 return false;
7437}
7438
7439bool
7440MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
7441 assert(link->fromInternalLane());
7442 if (veh == nullptr) {
7443 return false;
7444 }
7445 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
7446 // if this vehicle is not yet on the junction, every vehicle is a leader
7447 return true;
7448 }
7449 if (veh->getLaneChangeModel().hasBlueLight()) {
7450 // blue light device automatically gets right of way
7451 return true;
7452 }
7453 const MSLane* foeLane = veh->getLane();
7454 if (foeLane->isInternal()) {
7455 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
7457 SUMOTime foeET = veh->myJunctionEntryTime;
7458 // check relationship between link and foeLane
7460 // we are entering the junction from the same lane
7462 foeET = veh->myJunctionEntryTimeNeverYield;
7465 }
7466 } else {
7467 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
7468 const MSJunctionLogic* logic = link->getJunction()->getLogic();
7469 assert(logic != nullptr);
7470 // determine who has right of way
7471 bool response; // ego response to foe
7472 bool response2; // foe response to ego
7473 // attempt 1: tlLinkState
7474 const MSLink* entry = link->getCorrespondingEntryLink();
7475 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
7476 if (entry->haveRed() || foeEntry->haveRed()) {
7477 // ensure that vehicles which are stuck on the intersection may exit
7478 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
7479 // foe might be oncoming, don't drive unless foe can still brake safely
7480 const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
7481 const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
7482 foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
7483 // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
7484 // so the -2* makes it point in the right direction
7485 const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
7486#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7487 if (DEBUG_COND) {
7488 std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
7489
7490 }
7491#endif
7492 if (foeGap < foeBrakeGap) {
7493 response = true;
7494 response2 = false;
7495 } else {
7496 response = false;
7497 response2 = true;
7498 }
7499 } else {
7500 // brake for stuck foe
7501 response = foeEntry->haveRed();
7502 response2 = entry->haveRed();
7503 }
7504 } else if (entry->havePriority() != foeEntry->havePriority()) {
7505 response = !entry->havePriority();
7506 response2 = !foeEntry->havePriority();
7507 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
7508 // let the faster vehicle keep moving
7509 response = veh->getSpeed() >= getSpeed();
7510 response2 = getSpeed() >= veh->getSpeed();
7511 } else {
7512 // fallback if pedestrian crossings are involved
7513 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
7514 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
7515 }
7516#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7517 if (DEBUG_COND) {
7518 std::cout << SIMTIME
7519 << " foeLane=" << foeLane->getID()
7520 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
7521 << " linkIndex=" << link->getIndex()
7522 << " foeLinkIndex=" << foeLink->getIndex()
7523 << " entryState=" << toString(entry->getState())
7524 << " entryState2=" << toString(foeEntry->getState())
7525 << " response=" << response
7526 << " response2=" << response2
7527 << "\n";
7528 }
7529#endif
7530 if (!response) {
7531 // if we have right of way over the foe, entryTime does not matter
7532 foeET = veh->myJunctionConflictEntryTime;
7533 egoET = myJunctionEntryTime;
7534 } else if (response && response2) {
7535 // in a mutual conflict scenario, use entry time to avoid deadlock
7536 foeET = veh->myJunctionConflictEntryTime;
7538 }
7539 }
7540 if (egoET == foeET) {
7541 // try to use speed as tie braker
7542 if (getSpeed() == veh->getSpeed()) {
7543 // use ID as tie braker
7544#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7545 if (DEBUG_COND) {
7546 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7547 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7548 }
7549#endif
7550 return getID() < veh->getID();
7551 } else {
7552#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7553 if (DEBUG_COND) {
7554 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7555 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7556 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7557 << "\n";
7558 }
7559#endif
7560 return getSpeed() < veh->getSpeed();
7561 }
7562 } else {
7563 // leader was on the junction first
7564#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7565 if (DEBUG_COND) {
7566 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7567 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7568 }
7569#endif
7570 return egoET > foeET;
7571 }
7572 } else {
7573 // vehicle can only be partially on the junction. Must be a leader
7574 return true;
7575 }
7576 } else {
7577 // vehicle can only be partially on the junction. Must be a leader
7578 return true;
7579 }
7580}
7581
7582void
7585 // here starts the vehicle internal part (see loading)
7586 std::vector<std::string> internals;
7587 internals.push_back(toString(myParameter->parametersSet));
7588 internals.push_back(toString(myDeparture));
7589 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7590 internals.push_back(toString(myDepartPos));
7591 internals.push_back(toString(myWaitingTime));
7592 internals.push_back(toString(myTimeLoss));
7593 internals.push_back(toString(myLastActionTime));
7594 internals.push_back(toString(isStopped()));
7595 internals.push_back(toString(myPastStops.size()));
7596 out.writeAttr(SUMO_ATTR_STATE, internals);
7598 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7603 // save past stops
7605 stop.write(out, false);
7606 // do not write started and ended twice
7607 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7608 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7609 }
7610 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7611 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7612 }
7613 stop.writeParams(out);
7614 out.closeTag();
7615 }
7616 // save upcoming stops
7617 for (MSStop& stop : myStops) {
7618 stop.write(out);
7619 }
7620 // save parameters and device states
7622 for (MSVehicleDevice* const dev : myDevices) {
7623 dev->saveState(out);
7624 }
7625 out.closeTag();
7626}
7627
7628void
7630 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7631 throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
7632 }
7633 int routeOffset;
7634 bool stopped;
7635 int pastStops;
7636
7637 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7638 bis >> myParameter->parametersSet;
7639 bis >> myDeparture;
7640 bis >> routeOffset;
7641 bis >> myDepartPos;
7642 bis >> myWaitingTime;
7643 bis >> myTimeLoss;
7644 bis >> myLastActionTime;
7645 bis >> stopped;
7646 bis >> pastStops;
7647
7648 // load stops
7649 myStops.clear();
7651
7652 if (hasDeparted()) {
7653 myCurrEdge = myRoute->begin() + routeOffset;
7654 myDeparture -= offset;
7655 // fix stops
7656 while (pastStops > 0) {
7657 myPastStops.push_back(myStops.front().pars);
7658 myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
7659 myStops.pop_front();
7660 pastStops--;
7661 }
7662 // see MSBaseVehicle constructor
7665 }
7666 }
7669 WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
7670 }
7671 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7673 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7678 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7679 dis >> myOdometer >> myNumberReroutes;
7681 if (stopped) {
7682 myStops.front().startedFromState = true;
7683 myStopDist = 0;
7684 }
7686 // no need to reset myCachedPosition here since state loading happens directly after creation
7687}
7688
7689void
7691 SUMOTime arrivalTime, double arrivalSpeed,
7692 double arrivalSpeedBraking,
7693 double dist, double leaveSpeed) {
7694 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7695 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7696 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7697
7698}
7699
7700
7701std::shared_ptr<MSSimpleDriverState>
7705
7706
7707double
7709 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7710}
7711
7712
7713void
7714MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7715 myState.mySpeed = MAX2(0., prevSpeed);
7716 // also retcon acceleration
7717 if (prevAcceleration != std::numeric_limits<double>::min()) {
7718 myAcceleration = prevAcceleration;
7719 } else {
7721 }
7722}
7723
7724
7725double
7727 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7729}
7730
7731/****************************************************************************/
7732bool
7736
7737/* -------------------------------------------------------------------------
7738 * methods of MSVehicle::manoeuvre
7739 * ----------------------------------------------------------------------- */
7740
7741MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7742
7743
7745 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7746 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7747 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7748 myManoeuvreType = manoeuvre.myManoeuvreType;
7749 myGUIIncrement = manoeuvre.myGUIIncrement;
7750}
7751
7752
7755 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7756 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7757 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7758 myManoeuvreType = manoeuvre.myManoeuvreType;
7759 myGUIIncrement = manoeuvre.myGUIIncrement;
7760 return *this;
7761}
7762
7763
7764bool
7766 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7767 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7768 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7769 myManoeuvreType != manoeuvre.myManoeuvreType ||
7770 myGUIIncrement != manoeuvre.myGUIIncrement
7771 );
7772}
7773
7774
7775double
7777 return (myGUIIncrement);
7778}
7779
7780
7783 return (myManoeuvreType);
7784}
7785
7786
7791
7792
7793void
7797
7798
7799void
7801 myManoeuvreType = mType;
7802}
7803
7804
7805bool
7807 if (!veh->hasStops()) {
7808 return false; // should never happen - checked before call
7809 }
7810
7811 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7812 const MSStop& stop = veh->getNextStop();
7813
7814 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7815 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7816 if (abs(GUIAngle) < 0.1) {
7817 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7818 }
7819 myManoeuvreVehicleID = veh->getID();
7820 myManoeuvreStop = stop.parkingarea->getID();
7821 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7822 myManoeuvreStartTime = currentTime;
7823 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7824 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7825
7826#ifdef DEBUG_STOPS
7827 if (veh->isSelected()) {
7828 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 <<
7829 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7830 }
7831#endif
7832
7833 return (true);
7834}
7835
7836
7837bool
7839 // At the moment we only want to set for parking areas
7840 if (!veh->hasStops()) {
7841 return true;
7842 }
7843 if (veh->getNextStop().parkingarea == nullptr) {
7844 return true;
7845 }
7846
7847 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
7848 return (false);
7849 }
7850
7851 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7852
7853 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
7854 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
7855 if (abs(GUIAngle) < 0.1) {
7856 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
7857 }
7858
7859 myManoeuvreVehicleID = veh->getID();
7860 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
7861 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
7862 myManoeuvreStartTime = currentTime;
7863 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
7864 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7865 if (veh->remainingStopDuration() > 0) {
7866 myManoeuvreCompleteTime += veh->remainingStopDuration();
7867 }
7868
7869#ifdef DEBUG_STOPS
7870 if (veh->isSelected()) {
7871 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
7872 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7873 }
7874#endif
7875
7876 return (true);
7877}
7878
7879
7880bool
7882 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
7883 if (!veh->hasStops()) {
7884 return (true);
7885 }
7886 MSStop* currentStop = &veh->myStops.front();
7887 if (currentStop->parkingarea == nullptr) {
7888 return true;
7889 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
7890 if (configureEntryManoeuvre(veh)) {
7892 return (false);
7893 } else { // cannot configure entry so stop trying
7894 return true;
7895 }
7896 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7897 return false;
7898 } else { // manoeuvre complete
7899 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
7900 return true;
7901 }
7902}
7903
7904
7905bool
7907 if (checkType != myManoeuvreType) {
7908 return true; // we're not maneuvering / wrong manoeuvre
7909 }
7910
7911 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7912 return false;
7913 } else {
7914 return true;
7915 }
7916}
7917
7918
7919bool
7921 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
7922}
7923
7924
7925bool
7929
7930
7931std::pair<double, double>
7933 if (hasStops()) {
7934 MSLane* lane = myLane;
7935 if (lane == nullptr) {
7936 // not in network
7937 lane = getEdge()->getLanes()[0];
7938 }
7939 const MSStop& stop = myStops.front();
7940 auto it = myCurrEdge + 1;
7941 // drive to end of current edge
7942 double dist = (lane->getLength() - getPositionOnLane());
7943 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
7944 // drive until stop edge
7945 while (it != myRoute->end() && it < stop.edge) {
7946 travelTime += (*it)->getMinimumTravelTime(this);
7947 dist += (*it)->getLength();
7948 it++;
7949 }
7950 // drive up to the stop position
7951 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
7952 dist += stopEdgeDist;
7953 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
7954 // estimate time loss due to acceleration and deceleration
7955 // maximum speed is limited by available distance:
7956 const double a = getCarFollowModel().getMaxAccel();
7957 const double b = getCarFollowModel().getMaxDecel();
7958 const double c = getSpeed();
7959 const double d = dist;
7960 const double len = getVehicleType().getLength();
7961 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
7962 // distAccel = (v - c)^2 / (2a)
7963 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
7964 // distAccel + distDecel < d
7965 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))))
7966 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
7967 it = myCurrEdge;
7968 double v0 = c;
7969 bool v0Stable = getAcceleration() == 0 && v0 > 0;
7970 double timeLossAccel = 0;
7971 double timeLossDecel = 0;
7972 double timeLossLength = 0;
7973 while (it != myRoute->end() && it <= stop.edge) {
7974 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
7975 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
7976 if (edgeLength <= len && v0Stable && v0 < v) {
7977 const double lengthDist = MIN2(len, edgeLength);
7978 const double dTL = lengthDist / v0 - lengthDist / v;
7979 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
7980 timeLossLength += dTL;
7981 }
7982 if (edgeLength > len) {
7983 const double dv = v - v0;
7984 if (dv > 0) {
7985 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
7986 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
7987 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
7988 timeLossAccel += dTA;
7989 // time loss from vehicle length
7990 } else if (dv < 0) {
7991 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
7992 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
7993 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
7994 timeLossDecel += dTD;
7995 }
7996 v0 = v;
7997 v0Stable = true;
7998 }
7999 it++;
8000 }
8001 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
8002 double v = vs;
8003 const double dv = v - v0;
8004 if (dv > 0) {
8005 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8006 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8007 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8008 timeLossAccel += dTA;
8009 // time loss from vehicle length
8010 } else if (dv < 0) {
8011 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8012 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8013 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8014 timeLossDecel += dTD;
8015 }
8016 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
8017 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
8018 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
8019 return {MAX2(0.0, result), dist};
8020 } else {
8022 }
8023}
8024
8025
8026double
8028 if (hasStops() && myStops.front().pars.until >= 0) {
8029 const MSStop& stop = myStops.front();
8030 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
8031 if (stop.reached) {
8032 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
8033 }
8034 if (stop.pars.duration > 0) {
8035 estimatedDepart += stop.pars.duration;
8036 }
8037 estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
8038 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
8039 return result;
8040 } else {
8041 // vehicles cannot drive before 'until' so stop delay can never be
8042 // negative and we can use -1 to signal "undefined"
8043 return -1;
8044 }
8045}
8046
8047
8048double
8050 if (hasStops() && myStops.front().pars.arrival >= 0) {
8051 const MSStop& stop = myStops.front();
8052 if (stop.reached) {
8053 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
8054 } else {
8055 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
8056 }
8057 } else {
8058 // vehicles can arrival earlier than planned so arrival delay can be negative
8059 return INVALID_DOUBLE;
8060 }
8061}
8062
8063
8064const MSEdge*
8066 return myLane != nullptr ? &myLane->getEdge() : getEdge();
8067}
8068
8069
8070const MSEdge*
8072 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
8073 return nullptr;
8074 }
8075 if (myLane->isInternal()) {
8077 } else {
8078 const MSEdge* nextNormal = succEdge(1);
8079 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
8080 return nextInternal ? nextInternal : nextNormal;
8081 }
8082}
8083
8084
8085const MSLane*
8086MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
8087 if (furtherIndex < (int)myFurtherLanes.size()) {
8088 return myFurtherLanes[furtherIndex++];
8089 } else {
8090 // try to use route information
8091 int routeIndex = getRoutePosition();
8092 bool resultInternal;
8093 if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
8094 if (myLane->isInternal()) {
8095 if (furtherIndex % 2 == 0) {
8096 routeIndex -= (furtherIndex + 0) / 2;
8097 resultInternal = false;
8098 } else {
8099 routeIndex -= (furtherIndex + 1) / 2;
8100 resultInternal = false;
8101 }
8102 } else {
8103 if (furtherIndex % 2 != 0) {
8104 routeIndex -= (furtherIndex + 1) / 2;
8105 resultInternal = false;
8106 } else {
8107 routeIndex -= (furtherIndex + 2) / 2;
8108 resultInternal = true;
8109 }
8110 }
8111 } else {
8112 routeIndex -= furtherIndex;
8113 resultInternal = false;
8114 }
8115 furtherIndex++;
8116 if (routeIndex >= 0) {
8117 if (resultInternal) {
8118 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
8119 for (MSLane* cand : prevNormal->getLanes()) {
8120 for (MSLink* link : cand->getLinkCont()) {
8121 if (link->getLane() == current) {
8122 if (link->getViaLane() != nullptr) {
8123 return link->getViaLane();
8124 } else {
8125 return const_cast<MSLane*>(link->getLaneBefore());
8126 }
8127 }
8128 }
8129 }
8130 } else {
8131 return myRoute->getEdges()[routeIndex]->getLanes()[0];
8132 }
8133 }
8134 }
8135 return current;
8136}
8137
8138
8139/****************************************************************************/
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.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ 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_PARKING
@ 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_DURATION
@ 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 getDouble(SumoXMLAttr attr) const
void setDouble(SumoXMLAttr attr, double value)
Sets a parameter.
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.
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.
double getWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s)
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)
double getParameterDouble(const std::string &key) const
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:4316
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:4490
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:2773
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2755
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:2605
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2691
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:2619
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2358
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2668
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1348
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3700
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:2390
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:3191
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:2830
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:2680
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:1409
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:4483
int getIndex() const
Returns the lane's index.
Definition MSLane.h:642
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3215
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4311
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3135
double getCenterOnEdge() const
Definition MSLane.h:1202
bool isNormal() const
Definition MSLane.cpp:2551
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2586
bool isInternal() const
Definition MSLane.cpp:2545
@ 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:4299
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:4570
double interpolateLanePosToGeometryPos(double lanePos) const
Definition MSLane.h:554
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4564
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:2914
@ 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:4305
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:4579
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3160
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:3725
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:2577
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:1265
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:185
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition MSNet.cpp:1198
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:1401
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:1380
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1257
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:1274
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:1189
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:1349
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:1344
void setLaneChangeMode(int value)
Sets lane changing behavior.
TraciLaneChangePriority myTraciLaneChangePriority
flags for determining the priority of traci lane change requests
Definition MSVehicle.h:1657
bool getEmergencyBrakeRedLight() const
Returns whether red lights shall be a reason to brake.
Definition MSVehicle.h:1514
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:1605
bool considerSafeVelocity() const
Returns whether safe velocities shall be considered.
Definition MSVehicle.h:1528
int getSignals() const
Definition MSVehicle.h:1576
bool myConsiderMaxDeceleration
Whether the maximum deceleration shall be regarded.
Definition MSVehicle.h:1623
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:1632
void setOriginalSpeed(double speed)
Stores the originally longitudinal speed.
double myOriginalSpeed
The velocity before influence.
Definition MSVehicle.h:1608
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:1641
bool getRespectJunctionLeaderPriority() const
Returns whether junction priority rules within the junction shall be respected (concerns vehicles wit...
Definition MSVehicle.h:1522
LaneChangeMode myStrategicLC
lane changing which is necessary to follow the current route
Definition MSVehicle.h:1646
LaneChangeMode mySpeedGainLC
lane changing to travel with higher speed
Definition MSVehicle.h:1650
void init()
Static initalization.
LaneChangeMode mySublaneLC
changing to the prefered lateral alignment
Definition MSVehicle.h:1654
bool getRespectJunctionPriority() const
Returns whether junction priority rules shall be respected (concerns approaching vehicles outside the...
Definition MSVehicle.h:1506
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:1617
bool mySpeedAdaptationStarted
Whether influencing the speed has already started.
Definition MSVehicle.h:1614
~Influencer()
Destructor.
void setSignals(int signals)
Definition MSVehicle.h:1572
double myLatDist
The requested lateral change.
Definition MSVehicle.h:1611
bool myEmergencyBrakeRedLight
Whether red lights are a reason to brake.
Definition MSVehicle.h:1629
LaneChangeMode myRightDriveLC
changing to the rightmost lane
Definition MSVehicle.h:1652
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:1552
bool myConsiderMaxAcceleration
Whether the maximum acceleration shall be regarded.
Definition MSVehicle.h:1620
LaneChangeMode myCooperativeLC
lane changing with the intent to help other vehicles
Definition MSVehicle.h:1648
bool isRemoteControlled() const
bool myRespectJunctionPriority
Whether the junction priority rules are respected (approaching)
Definition MSVehicle.h:1626
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:1268
SUMOTime myManoeuvreCompleteTime
Time at which this manoeuvre should complete.
Definition MSVehicle.h:1320
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:1314
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:1323
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:1317
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:1146
@ LCP_OPPORTUNISTIC
Definition MSVehicle.h:1150
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:992
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:1916
SUMOTime myWaitingTime
The time the vehicle waits (is not faster than 0.1m/s) in seconds.
Definition MSVehicle.h:1852
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:1856
SUMOTime myLastActionTime
Action offset (actions are taken at time myActionOffset + N*getActionStepLength()) Initialized to 0,...
Definition MSVehicle.h:1871
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:1934
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:1898
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:710
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:1878
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:1905
bool signalSet(int which) const
Returns whether the given signal is on.
Definition MSVehicle.h:1182
MSCFModel::VehicleVariables * myCFVariables
The per vehicle variables of the car following model.
Definition MSVehicle.h:2142
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:1902
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:1913
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:2059
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:1893
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:1881
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:1853
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:1241
@ MANOEUVRE_ENTRY
Manoeuvre into stopping place.
Definition MSVehicle.h:1243
@ MANOEUVRE_NONE
not manouevring
Definition MSVehicle.h:1247
@ MANOEUVRE_EXIT
Manoeuvre out of stopping place.
Definition MSVehicle.h:1245
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:1880
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:2145
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:2002
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:2015
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.
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:1933
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:1165
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:1910
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:1924
Signalling
Some boolean values which describe the state of some vehicle parts.
Definition MSVehicle.h:1100
@ VEH_SIGNAL_BLINKER_RIGHT
Right blinker lights are switched on.
Definition MSVehicle.h:1104
@ VEH_SIGNAL_BRAKELIGHT
The brake lights are on.
Definition MSVehicle.h:1110
@ VEH_SIGNAL_EMERGENCY_BLUE
A blue emergency light is on.
Definition MSVehicle.h:1126
@ VEH_SIGNAL_BLINKER_LEFT
Left blinker lights are switched on.
Definition MSVehicle.h:1106
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:1918
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.
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:1927
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:2008
std::vector< std::vector< LaneQ > > myBestLanes
Definition MSVehicle.h:1888
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:1868
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:1937
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:1895
Position myCachedPosition
Definition MSVehicle.h:1929
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:831
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:1907
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:965
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:1921
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:1862
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:1876
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:1330
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:731
bool handleCollisionStop(MSStop &stop, const double distToStop)
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition MSVehicle.h:1676
MSDevice_Friction * myFrictionDevice
This vehicle's friction perception.
Definition MSVehicle.h:1865
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:1138
virtual void drawOutsideNetwork(bool)
register vehicle for drawing while outside the network
Definition MSVehicle.h:1827
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:1859
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:1157
static bool overlap(const MSVehicle *veh1, const MSVehicle *veh2)
Definition MSVehicle.h:759
int getLaneIndex() const
void updateParkingState()
update state while parking
DriveItemVector myLFLinkLanes
container for the planned speeds in the current step
Definition MSVehicle.h:2005
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:1932
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:1944
void adaptStopSpeed(const double v)
Definition MSVehicle.h:1991
double getLeaveSpeed() const
Definition MSVehicle.h:1995
void adaptLeaveSpeed(const double v)
Definition MSVehicle.h:1983
static std::map< const MSVehicle *, GapControlState * > refVehMap
stores reference vehicles currently in use by a gapController
Definition MSVehicle.h:1403
static GapControlVehStateListener * myVehStateListener
Definition MSVehicle.h:1406
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:853
double length
The overall length which may be driven when using this lane without a lane change.
Definition MSVehicle.h:857
bool allowsContinuation
Whether this lane allows to continue the drive.
Definition MSVehicle.h:867
double nextOccupation
As occupation, but without the first lane.
Definition MSVehicle.h:863
std::vector< MSLane * > bestContinuations
Definition MSVehicle.h:873
MSLane * lane
The described lane.
Definition MSVehicle.h:855
double currentLength
The length which may be driven on this lane.
Definition MSVehicle.h:859
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive.
Definition MSVehicle.h:865
double occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition MSVehicle.h:861