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