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