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