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