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