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-2025 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()) == 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);
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 internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
2190 || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
2191 // ignore situations where the shadow lane is part of a double-connection with the current lane
2192 && (myLaneChangeModel->getShadowLane() == nullptr
2193 || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
2194 || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != link->getLane())
2195 // emergency vehicles may do some crazy stuff
2197
2198#ifdef DEBUG_PLAN_MOVE
2199 if (DEBUG_COND) {
2200 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getDescription() << " lane=" << lane->getID()
2201 << " shift=" << link->getLateralShift()
2202 << " fpLat=" << futurePosLat << " overlap=" << overlap << " w=" << getVehicleType().getWidth() << " result=" << result << "\n";
2203 }
2204#endif
2205 return result;
2206}
2207
2208
2209
2210void
2211MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, std::pair<double, const MSLink*>& nextTurn) const {
2212 lfLinks.clear();
2213 newStopDist = std::numeric_limits<double>::max();
2214 //
2215 const MSCFModel& cfModel = getCarFollowModel();
2216 const double vehicleLength = getVehicleType().getLength();
2217 const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
2218 const double maxVD = MAX2(getMaxSpeed(), MIN2(maxV, getDesiredMaxSpeed()));
2219 const bool opposite = myLaneChangeModel->isOpposite();
2220 // maxVD is possibly higher than vType-maxSpeed and in this case laneMaxV may be higher as well
2221 double laneMaxV = myLane->getVehicleMaxSpeed(this, maxVD);
2222 const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
2223 double lateralShift = 0;
2224 if (isRail()) {
2225 // speed limits must hold for the whole length of the train
2226 for (MSLane* l : myFurtherLanes) {
2227 laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this, maxVD));
2228#ifdef DEBUG_PLAN_MOVE
2229 if (DEBUG_COND) {
2230 std::cout << " laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
2231 }
2232#endif
2233 }
2234 }
2235 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2236 laneMaxV = MAX2(laneMaxV, vMinComfortable);
2238 laneMaxV = std::numeric_limits<double>::max();
2239 }
2240 // v is the initial maximum velocity of this vehicle in this step
2241 double v = cfModel.maximumLaneSpeedCF(this, maxV, laneMaxV);
2242 // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
2243 // in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
2246 }
2247
2248 if (myInfluencer != nullptr) {
2249 const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
2250#ifdef DEBUG_TRACI
2251 if (DEBUG_COND) {
2252 std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
2253 }
2254#endif
2255 v = myInfluencer->influenceSpeed(t, v, v, vMin, maxV);
2256#ifdef DEBUG_TRACI
2257 if (DEBUG_COND) {
2258 std::cout << " influencedSpeed=" << v;
2259 }
2260#endif
2261 v = myInfluencer->gapControlSpeed(t, this, v, v, vMin, maxV);
2262#ifdef DEBUG_TRACI
2263 if (DEBUG_COND) {
2264 std::cout << " gapControlSpeed=" << v << "\n";
2265 }
2266#endif
2267 }
2268 // all links within dist are taken into account (potentially)
2269 const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
2270
2271 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
2272#ifdef DEBUG_PLAN_MOVE
2273 if (DEBUG_COND) {
2274 std::cout << " dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
2275 << "\n maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
2276 }
2277#endif
2278 assert(bestLaneConts.size() > 0);
2279 bool hadNonInternal = false;
2280 // the distance already "seen"; in the following always up to the end of the current "lane"
2281 double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
2282 nextTurn.first = seen;
2283 nextTurn.second = nullptr;
2284 bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
2285 double seenNonInternal = 0;
2286 double seenInternal = myLane->isInternal() ? seen : 0;
2287 double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2288 int view = 0;
2289 DriveProcessItem* lastLink = nullptr;
2290 bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
2291 double mustSeeBeforeReversal = 0;
2292 // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
2293 const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
2294 assert(lane != 0);
2295 const MSLane* leaderLane = myLane;
2296 bool foundRailSignal = !isRail();
2297 bool planningToStop = false;
2298#ifdef PARALLEL_STOPWATCH
2299 myLane->getStopWatch()[0].start();
2300#endif
2301
2302 // optionally slow down to match arrival time
2303 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2304 if (v > vMinComfortable && hasStops() && myStops.front().pars.arrival >= 0 && sfp > 0
2305 && v > myLane->getSpeedLimit() * sfp
2306 && !myStops.front().reached) {
2307 const double vSlowDown = slowDownForSchedule(vMinComfortable);
2308 v = MIN2(v, vSlowDown);
2309 }
2310 auto stopIt = myStops.begin();
2311 while (true) {
2312 // check leader on lane
2313 // leader is given for the first edge only
2314 if (opposite &&
2315 (leaderLane->getVehicleNumberWithPartials() > 1
2316 || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
2317 ahead.clear();
2318 // find opposite-driving leader that must be respected on the currently looked at lane
2319 // (only looking at one lane at a time)
2320 const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
2321 const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
2322 const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
2323 MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
2324 const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 * myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
2325 for (int i = 0; i < cands.numSublanes(); i++) {
2326 CLeaderDist cand = cands[i];
2327 if (cand.first != 0) {
2328 if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
2329 || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
2330 // respect leaders that also drive in the opposite direction (fully or with some overlap)
2331 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
2332 } else {
2333 // avoid frontal collision
2334 const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
2335 const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
2336 if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
2337 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
2338 }
2339 }
2340 }
2341 }
2342#ifdef DEBUG_PLAN_MOVE
2343 if (DEBUG_COND) {
2344 std::cout << " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
2345 << " cands=" << cands.toString() << " oppositeLeaders=" << oppositeLeaders.toString() << "\n";
2346 }
2347#endif
2348 adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
2349 } else {
2351 const double rightOL = getRightSideOnLane(lane) + lateralShift;
2352 const double leftOL = getLeftSideOnLane(lane) + lateralShift;
2353 const bool outsideLeft = leftOL > lane->getWidth();
2354#ifdef DEBUG_PLAN_MOVE
2355 if (DEBUG_COND) {
2356 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
2357 }
2358#endif
2359 if (rightOL < 0 || outsideLeft) {
2360 MSLeaderInfo outsideLeaders(lane->getWidth());
2361 // if ego is driving outside lane bounds we must consider
2362 // potential leaders that are also outside bounds
2363 int sublaneOffset = 0;
2364 if (outsideLeft) {
2365 sublaneOffset = MIN2(-1, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution));
2366 } else {
2367 sublaneOffset = MAX2(1, (int)ceil(-rightOL / MSGlobals::gLateralResolution));
2368 }
2369 outsideLeaders.setSublaneOffset(sublaneOffset);
2370#ifdef DEBUG_PLAN_MOVE
2371 if (DEBUG_COND) {
2372 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
2373 }
2374#endif
2375 for (const MSVehicle* cand : lane->getVehiclesSecure()) {
2376 if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
2377 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
2378 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
2379 outsideLeaders.addLeader(cand, true);
2380#ifdef DEBUG_PLAN_MOVE
2381 if (DEBUG_COND) {
2382 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << outsideLeaders.toString() << "\n";
2383 }
2384#endif
2385 }
2386 }
2387 lane->releaseVehicles();
2388 if (outsideLeaders.hasVehicles()) {
2389 adaptToLeaders(outsideLeaders, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2390 }
2391 }
2392 }
2393 adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2394 }
2395 if (lastLink != nullptr) {
2396 lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
2397 }
2398#ifdef DEBUG_PLAN_MOVE
2399 if (DEBUG_COND) {
2400 std::cout << "\nv = " << v << "\n";
2401
2402 }
2403#endif
2404 // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
2405 if (myLaneChangeModel->getShadowLane() != nullptr) {
2406 // also slow down for leaders on the shadowLane relative to the current lane
2407 const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
2408 if (shadowLane != nullptr
2409 && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
2410 // continous lane change cannot be stopped so we must adapt to the leader on the target lane
2412 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
2415 // ego posLat is added when retrieving sublanes but it
2416 // should be negated (subtract twice to compensate)
2417 latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
2418 - 2 * getLateralPositionOnLane());
2419
2420 }
2421 MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
2422#ifdef DEBUG_PLAN_MOVE
2424 std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2425 }
2426#endif
2428 // ignore oncoming vehicles on the shadow lane
2429 shadowLeaders.removeOpposite(shadowLane);
2430 }
2431 const double turningDifference = MAX2(0.0, leaderLane->getLength() - shadowLane->getLength());
2432 adaptToLeaders(shadowLeaders, latOffset, seen - turningDifference, lastLink, shadowLane, v, vLinkPass);
2433 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
2434 // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
2435 // (and thus in the same direction as ego)
2436 MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
2437 const double latOffset = 0;
2438#ifdef DEBUG_PLAN_MOVE
2439 if (DEBUG_COND) {
2440 std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
2441 << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2442 }
2443#endif
2444 shadowLeaders.fixOppositeGaps(true);
2445#ifdef DEBUG_PLAN_MOVE
2446 if (DEBUG_COND) {
2447 std::cout << " shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
2448 }
2449#endif
2450 adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
2451 }
2452 }
2453 }
2454 // adapt to pedestrians on the same lane
2455 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2456 const double relativePos = lane->getLength() - seen;
2457#ifdef DEBUG_PLAN_MOVE
2458 if (DEBUG_COND) {
2459 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2460 }
2461#endif
2462 const double stopTime = MAX2(1.0, ceil(getSpeed() / cfModel.getMaxDecel()));
2463 PersonDist leader = lane->nextBlocking(relativePos,
2464 getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
2465 if (leader.first != 0) {
2466 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2467 v = MIN2(v, stopSpeed);
2468#ifdef DEBUG_PLAN_MOVE
2469 if (DEBUG_COND) {
2470 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2471 }
2472#endif
2473 }
2474 }
2475 if (lane->getBidiLane() != nullptr) {
2476 // adapt to pedestrians on the bidi lane
2477 const MSLane* bidiLane = lane->getBidiLane();
2478 if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
2479 const double relativePos = seen;
2480#ifdef DEBUG_PLAN_MOVE
2481 if (DEBUG_COND) {
2482 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2483 }
2484#endif
2485 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2486 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
2487 PersonDist leader = bidiLane->nextBlocking(relativePos,
2488 leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
2489 if (leader.first != 0) {
2490 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2491 v = MIN2(v, stopSpeed);
2492#ifdef DEBUG_PLAN_MOVE
2493 if (DEBUG_COND) {
2494 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2495 }
2496#endif
2497 }
2498 }
2499 }
2500 // adapt to vehicles blocked from (urgent) lane-changing
2501 if (!opposite && lane->getEdge().hasLaneChanger()) {
2502 v = MIN2(v, myLaneChangeModel->getCooperativeHelpSpeed(lane, seen));
2503 }
2504
2505 // process all stops and waypoints on the current edge
2506 bool foundRealStop = false;
2507 while (stopIt != myStops.end()
2508 && ((&stopIt->lane->getEdge() == &lane->getEdge())
2509 || (stopIt->isOpposite && stopIt->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
2510 // ignore stops that occur later in a looped route
2511 && stopIt->edge == myCurrEdge + view) {
2512 double stopDist = std::numeric_limits<double>::max();
2513 const MSStop& stop = *stopIt;
2514 const bool isFirstStop = stopIt == myStops.begin();
2515 stopIt++;
2516 if (!stop.reached || (stop.getSpeed() > 0 && keepStopping())) {
2517 // we are approaching a stop on the edge; must not drive further
2518 bool isWaypoint = stop.getSpeed() > 0;
2519 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
2520 if (stop.parkingarea != nullptr) {
2521 // leave enough space so parking vehicles can exit
2522 const double brakePos = getBrakeGap() + lane->getLength() - seen;
2523 endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
2524 } else if (isWaypoint && !stop.reached) {
2525 endPos = stop.pars.startPos;
2526 }
2527 stopDist = seen + endPos - lane->getLength();
2528#ifdef DEBUG_STOPS
2529 if (DEBUG_COND) {
2530 std::cout << SIMTIME << " veh=" << getID() << " stopDist=" << stopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
2531 }
2532#endif
2533 // regular stops are not emergencies
2534 double stopSpeed = laneMaxV;
2535 if (isWaypoint) {
2536 bool waypointWithStop = false;
2537 if (stop.getUntil() > t) {
2538 // check if we have to slow down or even stop
2539 SUMOTime time2end = 0;
2540 if (stop.reached) {
2541 time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
2542 } else {
2543 time2end = TIME2STEPS(
2544 // time to reach waypoint start
2545 stopDist / ((getSpeed() + stop.getSpeed()) / 2)
2546 // time to reach waypoint end
2547 + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
2548 }
2549 if (stop.getUntil() > t + time2end) {
2550 // we need to stop
2551 double distToEnd = stopDist;
2552 if (!stop.reached) {
2553 distToEnd += stop.pars.endPos - stop.pars.startPos;
2554 }
2555 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
2556 waypointWithStop = true;
2557 }
2558 }
2559 if (stop.reached) {
2560 stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
2561 if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
2562 stopDist = std::numeric_limits<double>::max();
2563 }
2564 } else {
2565 stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), stopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
2566 if (!stop.reached) {
2567 stopDist += stop.pars.endPos - stop.pars.startPos;
2568 }
2569 if (lastLink != nullptr) {
2570 lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
2571 }
2572 }
2573 } else {
2574 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), stopDist), vMinComfortable);
2575 if (lastLink != nullptr) {
2576 lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
2577 }
2578 }
2579 v = MIN2(v, stopSpeed);
2580 if (lane->isInternal()) {
2581 std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2582 assert(!lane->isLinkEnd(exitLink));
2583 bool dummySetRequest;
2584 double dummyVLinkWait;
2585 checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
2586 }
2587
2588#ifdef DEBUG_PLAN_MOVE
2589 if (DEBUG_COND) {
2590 std::cout << "\n" << SIMTIME << " next stop: distance = " << stopDist << " requires stopSpeed = " << stopSpeed << "\n";
2591
2592 }
2593#endif
2594 if (isFirstStop) {
2595 newStopDist = stopDist;
2596 // if the vehicle is going to stop we don't need to look further
2597 // (except for trains that make use of further link-approach registration for safety purposes)
2598 if (!isWaypoint) {
2599 planningToStop = true;
2600 if (!isRail()) {
2601 lfLinks.emplace_back(v, stopDist);
2602 foundRealStop = true;
2603 break;
2604 }
2605 }
2606 }
2607 }
2608 }
2609 if (foundRealStop) {
2610 break;
2611 }
2612
2613 // move to next lane
2614 // get the next link used
2615 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2616 if (lane->isLinkEnd(link) && myLaneChangeModel->hasBlueLight() && myCurrEdge != myRoute->end() - 1) {
2617 // emergency vehicle is on the wrong lane. Obtain the link that it would use from the correct turning lane
2618 const int currentIndex = lane->getIndex();
2619 const MSLane* bestJump = nullptr;
2620 for (const LaneQ& preb : getBestLanes()) {
2621 if (preb.allowsContinuation &&
2622 (bestJump == nullptr
2623 || abs(currentIndex - preb.lane->getIndex()) < abs(currentIndex - bestJump->getIndex()))) {
2624 bestJump = preb.lane;
2625 }
2626 }
2627 if (bestJump != nullptr) {
2628 const MSEdge* nextEdge = *(myCurrEdge + 1);
2629 for (auto cand_it = bestJump->getLinkCont().begin(); cand_it != bestJump->getLinkCont().end(); cand_it++) {
2630 if (&(*cand_it)->getLane()->getEdge() == nextEdge) {
2631 link = cand_it;
2632 break;
2633 }
2634 }
2635 }
2636 }
2637
2638 // Check whether this is a turn (to save info about the next upcoming turn)
2639 if (!encounteredTurn) {
2640 if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
2641 LinkDirection linkDir = (*link)->getDirection();
2642 switch (linkDir) {
2645 break;
2646 default:
2647 nextTurn.first = seen;
2648 nextTurn.second = *link;
2649 encounteredTurn = true;
2650#ifdef DEBUG_NEXT_TURN
2651 if (DEBUG_COND) {
2652 std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(linkDir)
2653 << " at " << nextTurn.first << "m." << std::endl;
2654 }
2655#endif
2656 }
2657 }
2658 }
2659
2660 // check whether the vehicle is on its final edge
2661 if (myCurrEdge + view + 1 == myRoute->end()
2662 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
2663 const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
2664 myParameter->arrivalSpeed : laneMaxV);
2665 // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
2666 // XXX: This does not work for ballistic update refs #2579
2667 const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
2668 const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
2669 v = MIN2(v, va);
2670 if (lastLink != nullptr) {
2671 lastLink->adaptLeaveSpeed(va);
2672 }
2673 lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
2674 break;
2675 }
2676 // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
2677 if (lane->isLinkEnd(link)
2678 || (MSGlobals::gSublane && brakeForOverlap(*link, lane))
2679 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
2681 double va = cfModel.stopSpeed(this, getSpeed(), seen);
2682 if (lastLink != nullptr) {
2683 lastLink->adaptLeaveSpeed(va);
2684 }
2687 } else {
2688 v = MIN2(va, v);
2689 }
2690#ifdef DEBUG_PLAN_MOVE
2691 if (DEBUG_COND) {
2692 std::cout << " braking for link end lane=" << lane->getID() << " seen=" << seen
2693 << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
2694
2695 }
2696#endif
2697 if (lane->isLinkEnd(link)) {
2698 lfLinks.emplace_back(v, seen);
2699 break;
2700 }
2701 }
2702 lateralShift += (*link)->getLateralShift();
2703 const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
2704 // We distinguish 3 cases when determining the point at which a vehicle stops:
2705 // - allway_stop: the vehicle should stop close to the stop line but may stop at larger distance
2706 // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
2707 // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
2708 // to minimize the time window for passing the junction. If the
2709 // vehicle 'decides' to accelerate and cannot enter the junction in
2710 // the next step, new foes may appear and cause a collision (see #1096)
2711 // - major links: stopping point is irrelevant
2712 double laneStopOffset;
2713 const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
2714 // override low desired decel at yellow and red
2715 const double stopDecel = yellowOrRed && !isRail() ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
2716 const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
2717 const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
2718 const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
2719 if (yellowOrRed) {
2720 // Wait at red traffic light with full distance if possible
2721 laneStopOffset = majorStopOffset;
2722 } else if ((*link)->havePriority()) {
2723 // On priority link, we should never stop below visibility distance
2724 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
2725 } else {
2726 double minorStopOffset = MAX2(lane->getVehicleStopOffset(this),
2727 getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
2728#ifdef DEBUG_PLAN_MOVE
2729 if (DEBUG_COND) {
2730 std::cout << " minorStopOffset=" << minorStopOffset << " distToFoePedCrossing=" << (*link)->getDistToFoePedCrossing() << "\n";
2731 }
2732#endif
2733 if ((*link)->getState() == LINKSTATE_ALLWAY_STOP) {
2734 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, 0));
2735 } else {
2736 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP_MINOR, 0));
2737 }
2738 // On minor link, we should likewise never stop below visibility distance
2739 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
2740 }
2741#ifdef DEBUG_PLAN_MOVE
2742 if (DEBUG_COND) {
2743 std::cout << SIMTIME << " veh=" << getID() << " desired stopOffset on lane '" << lane->getID() << "' is " << laneStopOffset << "\n";
2744 }
2745#endif
2746 if (canBrakeBeforeLaneEnd) {
2747 // avoid emergency braking if possible
2748 laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
2749 }
2750 laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
2751 double stopDist = MAX2(0., seen - laneStopOffset);
2752 if (yellowOrRed && getDevice(typeid(MSDevice_GLOSA)) != nullptr
2753 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->getOverrideSafety()
2754 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->isSpeedAdviceActive()) {
2755 stopDist = std::numeric_limits<double>::max();
2756 }
2757 if (newStopDist != std::numeric_limits<double>::max()) {
2758 stopDist = MAX2(stopDist, newStopDist);
2759 }
2760#ifdef DEBUG_PLAN_MOVE
2761 if (DEBUG_COND) {
2762 std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
2763 << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
2764 }
2765#endif
2766 if (isRail()
2767 && !lane->isInternal()) {
2768 // check for train direction reversal
2769 if (lane->getBidiLane() != nullptr
2770 && (*link)->getLane()->getBidiLane() == lane) {
2771 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
2772 if (seen < 1) {
2773 mustSeeBeforeReversal = 2 * seen + getLength();
2774 }
2775 v = MIN2(v, vMustReverse);
2776 }
2777 // signal that is passed in the current step does not count
2778 foundRailSignal |= ((*link)->getTLLogic() != nullptr
2779 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
2780 && seen > SPEED2DIST(v));
2781 }
2782
2783 bool canReverseEventually = false;
2784 const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
2785 v = MIN2(v, vReverse);
2786#ifdef DEBUG_PLAN_MOVE
2787 if (DEBUG_COND) {
2788 std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
2789 }
2790#endif
2791
2792 // check whether we need to slow down in order to finish a continuous lane change
2794 if ( // slow down to finish lane change before a turn lane
2795 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
2796 // slow down to finish lane change before the shadow lane ends
2797 (myLaneChangeModel->getShadowLane() != nullptr &&
2798 (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
2799 // XXX maybe this is too harsh. Vehicles could cut some corners here
2800 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
2801 assert(timeRemaining != 0);
2802 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
2803 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
2804 (seen - POSITION_EPS) / timeRemaining);
2805#ifdef DEBUG_PLAN_MOVE
2806 if (DEBUG_COND) {
2807 std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
2808 << " link=" << (*link)->getViaLaneOrLane()->getID()
2809 << " timeRemaining=" << timeRemaining
2810 << " v=" << v
2811 << " va=" << va
2812 << std::endl;
2813 }
2814#endif
2815 v = MIN2(va, v);
2816 }
2817 }
2818
2819 // - always issue a request to leave the intersection we are currently on
2820 const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
2821 // - do not issue a request to enter an intersection after we already slowed down for an earlier one
2822 const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
2823 // - even if red, if we cannot break we should issue a request
2824 bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
2825
2826 double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
2827 double vLinkWait = MIN2(v, stopSpeed);
2828#ifdef DEBUG_PLAN_MOVE
2829 if (DEBUG_COND) {
2830 std::cout
2831 << " stopDist=" << stopDist
2832 << " stopDecel=" << stopDecel
2833 << " vLinkWait=" << vLinkWait
2834 << " brakeDist=" << brakeDist
2835 << " seen=" << seen
2836 << " leaveIntersection=" << leavingCurrentIntersection
2837 << " setRequest=" << setRequest
2838 //<< std::setprecision(16)
2839 //<< " v=" << v
2840 //<< " speedEps=" << NUMERICAL_EPS_SPEED
2841 //<< std::setprecision(gPrecision)
2842 << "\n";
2843 }
2844#endif
2845
2846 if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
2847 if (lane->isInternal()) {
2848 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2849 }
2850 // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
2851 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
2852 // the vehicle is able to brake in front of a yellow/red traffic light
2853 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
2854 //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
2855 break;
2856 }
2857
2858 const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
2859 if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
2860 // restrict speed when ignoring a red light
2861 const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
2862 const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
2863 v = MIN2(va, v);
2864#ifdef DEBUG_PLAN_MOVE
2865 if (DEBUG_COND) std::cout
2866 << " ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
2867 << " redSpeed=" << redSpeed
2868 << " va=" << va
2869 << " v=" << v
2870 << "\n";
2871#endif
2872 }
2873
2874 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2875
2876 if (lastLink != nullptr) {
2877 lastLink->adaptLeaveSpeed(laneMaxV);
2878 }
2879 double arrivalSpeed = vLinkPass;
2880 // vehicles should decelerate when approaching a minor link
2881 // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
2882 // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
2883
2884 // whether the vehicle/driver is close enough to the link to see all possible foes #2123
2885 const double visibilityDistance = (*link)->getFoeVisibilityDistance();
2886 const double determinedFoePresence = seen <= visibilityDistance;
2887// // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
2888// double foeRecognitionTime = 0.0;
2889// double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
2890
2891#ifdef DEBUG_PLAN_MOVE
2892 if (DEBUG_COND) {
2893 std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
2894 }
2895#endif
2896
2897 const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
2898 if (couldBrakeForMinor && !determinedFoePresence) {
2899 // vehicle decelerates just enough to be able to stop if necessary and then accelerates
2900 double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0., false);
2901 // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
2902 double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
2903 arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
2904 slowedDownForMinor = true;
2905#ifdef DEBUG_PLAN_MOVE
2906 if (DEBUG_COND) {
2907 std::cout << " slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
2908 }
2909#endif
2910 } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
2911 // check for deadlock (circular yielding)
2912 //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
2913 std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
2914 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2915 int n = 100;
2916 while (blocker.second != nullptr && blocker.second != *link && n > 0) {
2917 blocker = blocker.second->getFirstApproachingFoe(*link);
2918 n--;
2919 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2920 }
2921 if (n == 0) {
2922 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
2923 }
2924 //std::cout << " blockerLink=" << blocker.second << " link=" << *link << "\n";
2925 if (blocker.second == *link) {
2926 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
2927 if (RandHelper::rand(getRNG()) < threshold) {
2928 //std::cout << " abort request, threshold=" << threshold << "\n";
2929 setRequest = false;
2930 }
2931 }
2932 }
2933
2934 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
2935 if (couldBrakeForMinor && determinedFoePresence && (*link)->getLane()->getEdge().isRoundabout()) {
2936 const bool wasOpened = (*link)->opened(arrivalTime, arrivalSpeed, arrivalSpeed,
2938 getCarFollowModel().getMaxDecel(),
2940 nullptr, false, this);
2941 if (!wasOpened) {
2942 slowedDownForMinor = true;
2943 }
2944#ifdef DEBUG_PLAN_MOVE
2945 if (DEBUG_COND) {
2946 std::cout << " slowedDownForMinor at roundabout=" << (!wasOpened) << "\n";
2947 }
2948#endif
2949 }
2950
2951 // compute arrival speed and arrival time if vehicle starts braking now
2952 // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
2953 double arrivalSpeedBraking = 0;
2954 const double bGap = cfModel.brakeGap(v);
2955 if (seen < bGap && !isStopped() && !planningToStop) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
2956 // vehicle cannot come to a complete stop in time
2958 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
2959 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
2960 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
2961 } else {
2962 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
2963 }
2964 }
2965
2966 // estimate leave speed for passing time computation
2967 // l=linkLength, a=accel, t=continuousTime, v=vLeave
2968 // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
2969 const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this, maxVD),
2970 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
2971 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
2972 arrivalTime, arrivalSpeed,
2973 arrivalSpeedBraking,
2974 seen, estimatedLeaveSpeed));
2975 if ((*link)->getViaLane() == nullptr) {
2976 hadNonInternal = true;
2977 ++view;
2978 }
2979#ifdef DEBUG_PLAN_MOVE
2980 if (DEBUG_COND) {
2981 std::cout << " checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
2982 << " seenNonInternal=" << seenNonInternal
2983 << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
2984 }
2985#endif
2986 // we need to look ahead far enough to see available space for checkRewindLinkLanes
2987 if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
2988 break;
2989 }
2990 // get the following lane
2991 lane = (*link)->getViaLaneOrLane();
2992 laneMaxV = lane->getVehicleMaxSpeed(this, maxVD);
2994 laneMaxV = std::numeric_limits<double>::max();
2995 }
2996 // the link was passed
2997 // compute the velocity to use when the link is not blocked by other vehicles
2998 // the vehicle shall be not faster when reaching the next lane than allowed
2999 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
3000 const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable);
3001 v = MIN2(va, v);
3002#ifdef DEBUG_PLAN_MOVE
3003 if (DEBUG_COND) {
3004 std::cout << " laneMaxV=" << laneMaxV << " freeSpeed=" << va << " v=" << v << "\n";
3005 }
3006#endif
3007 if (lane->getEdge().isInternal()) {
3008 seenInternal += lane->getLength();
3009 } else {
3010 seenNonInternal += lane->getLength();
3011 }
3012 // do not restrict results to the current vehicle to allow caching for the current time step
3013 leaderLane = opposite ? lane->getParallelOpposite() : lane;
3014 if (leaderLane == nullptr) {
3015
3016 break;
3017 }
3018 ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
3019 seen += lane->getLength();
3020 vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
3021 lastLink = &lfLinks.back();
3022 }
3023
3024//#ifdef DEBUG_PLAN_MOVE
3025// if(DEBUG_COND){
3026// std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
3027// }
3028//#endif
3029
3030#ifdef PARALLEL_STOPWATCH
3031 myLane->getStopWatch()[0].stop();
3032#endif
3033}
3034
3035
3036double
3037MSVehicle::slowDownForSchedule(double vMinComfortable) const {
3038 const double sfp = getVehicleType().getParameter().speedFactorPremature;
3039 const MSStop& stop = myStops.front();
3040 std::pair<double, double> timeDist = estimateTimeToNextStop();
3041 double arrivalDelay = SIMTIME + timeDist.first - STEPS2TIME(stop.pars.arrival);
3042 double t = STEPS2TIME(stop.pars.arrival - SIMSTEP);
3045 arrivalDelay += STEPS2TIME(stop.pars.arrival - flexStart);
3046 t = STEPS2TIME(flexStart - SIMSTEP);
3047 } else if (stop.pars.started >= 0 && MSGlobals::gUseStopStarted) {
3048 arrivalDelay += STEPS2TIME(stop.pars.arrival - stop.pars.started);
3049 t = STEPS2TIME(stop.pars.started - SIMSTEP);
3050 }
3051 if (arrivalDelay < 0 && sfp < getChosenSpeedFactor()) {
3052 // we can slow down to better match the schedule (and increase energy efficiency)
3053 const double vSlowDownMin = MAX2(myLane->getSpeedLimit() * sfp, vMinComfortable);
3054 const double s = timeDist.second;
3055 const double b = getCarFollowModel().getMaxDecel();
3056 // x = speed for arriving in t seconds
3057 // u = time at full speed
3058 // u * x + (t - u) * 0.5 * x = s
3059 // t - u = x / b
3060 // eliminate u, solve x
3061 const double radicand = 4 * t * t * b * b - 8 * s * b;
3062 const double x = radicand >= 0 ? t * b - sqrt(radicand) * 0.5 : vSlowDownMin;
3063 double vSlowDown = x < vSlowDownMin ? vSlowDownMin : x;
3064#ifdef DEBUG_PLAN_MOVE
3065 if (DEBUG_COND) {
3066 std::cout << SIMTIME << " veh=" << getID() << " ad=" << arrivalDelay << " t=" << t << " vsm=" << vSlowDownMin
3067 << " r=" << radicand << " vs=" << vSlowDown << "\n";
3068 }
3069#endif
3070 return vSlowDown;
3071 } else if (arrivalDelay > 0 && sfp > getChosenSpeedFactor()) {
3072 // in principle we could up to catch up with the schedule
3073 // but at this point we can only lower the speed, the
3074 // information would have to be used when computing getVehicleMaxSpeed
3075 }
3076 return getMaxSpeed();
3077}
3078
3080MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
3081 const MSCFModel& cfModel = getCarFollowModel();
3082 SUMOTime arrivalTime;
3084 // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
3085 // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
3086 // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
3087 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
3088 } else {
3089 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
3090 }
3091 if (isStopped()) {
3092 arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
3093 }
3094 return arrivalTime;
3095}
3096
3097
3098void
3099MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
3100 const double seen, DriveProcessItem* const lastLink,
3101 const MSLane* const lane, double& v, double& vLinkPass) const {
3102 int rightmost;
3103 int leftmost;
3104 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3105#ifdef DEBUG_PLAN_MOVE
3106 if (DEBUG_COND) std::cout << SIMTIME
3107 << "\nADAPT_TO_LEADERS\nveh=" << getID()
3108 << " lane=" << lane->getID()
3109 << " latOffset=" << latOffset
3110 << " rm=" << rightmost
3111 << " lm=" << leftmost
3112 << " shift=" << ahead.getSublaneOffset()
3113 << " ahead=" << ahead.toString()
3114 << "\n";
3115#endif
3116 /*
3117 if (myLaneChangeModel->getCommittedSpeed() > 0) {
3118 v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
3119 vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
3120 #ifdef DEBUG_PLAN_MOVE
3121 if (DEBUG_COND) std::cout << " hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
3122 #endif
3123 return;
3124 }
3125 */
3126 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3127 const MSVehicle* pred = ahead[sublane];
3128 if (pred != nullptr && pred != this) {
3129 // @todo avoid multiple adaptations to the same leader
3130 const double predBack = pred->getBackPositionOnLane(lane);
3131 double gap = (lastLink == nullptr
3132 ? predBack - myState.myPos - getVehicleType().getMinGap()
3133 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3134 bool oncoming = false;
3136 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
3137 // ego might and leader are driving against lane
3138 gap = (lastLink == nullptr
3139 ? myState.myPos - predBack - getVehicleType().getMinGap()
3140 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3141 } else {
3142 // ego and leader are driving in the same direction as lane (shadowlane for ego)
3143 gap = (lastLink == nullptr
3144 ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
3145 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3146 }
3147 } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
3148 // must react to stopped / dangerous oncoming vehicles
3149 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
3150 // try to avoid collision in the next second
3151 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
3152#ifdef DEBUG_PLAN_MOVE
3153 if (DEBUG_COND) {
3154 std::cout << " fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
3155 }
3156#endif
3157 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
3158 gap -= predMaxDist;
3159 }
3160 } else if (pred->getLane() == lane->getBidiLane()) {
3161 gap -= pred->getVehicleType().getLengthWithGap();
3162 oncoming = true;
3163 }
3164#ifdef DEBUG_PLAN_MOVE
3165 if (DEBUG_COND) {
3166 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";
3167 }
3168#endif
3169 if (oncoming && gap >= 0) {
3170 adaptToOncomingLeader(std::make_pair(pred, gap), lastLink, v, vLinkPass);
3171 } else {
3172 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
3173 }
3174 }
3175 }
3176}
3177
3178void
3180 double seen,
3181 DriveProcessItem* const lastLink,
3182 double& v, double& vLinkPass) const {
3183 int rightmost;
3184 int leftmost;
3185 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3186#ifdef DEBUG_PLAN_MOVE
3187 if (DEBUG_COND) std::cout << SIMTIME
3188 << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
3189 << " latOffset=" << latOffset
3190 << " rm=" << rightmost
3191 << " lm=" << leftmost
3192 << " ahead=" << ahead.toString()
3193 << "\n";
3194#endif
3195 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3196 CLeaderDist predDist = ahead[sublane];
3197 const MSVehicle* pred = predDist.first;
3198 if (pred != nullptr && pred != this) {
3199#ifdef DEBUG_PLAN_MOVE
3200 if (DEBUG_COND) {
3201 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
3202 }
3203#endif
3204 adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
3205 }
3206 }
3207}
3208
3209
3210void
3211MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3212 double seen,
3213 DriveProcessItem* const lastLink,
3214 double& v, double& vLinkPass) const {
3215 if (leaderInfo.first != 0) {
3216 if (ignoreFoe(leaderInfo.first)) {
3217#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3218 if (DEBUG_COND) {
3219 std::cout << " foe ignored\n";
3220 }
3221#endif
3222 return;
3223 }
3224 const MSCFModel& cfModel = getCarFollowModel();
3225 double vsafeLeader = 0;
3227 vsafeLeader = -std::numeric_limits<double>::max();
3228 }
3229 bool backOnRoute = true;
3230 if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
3231 backOnRoute = false;
3232 // this can either be
3233 // a) a merging situation (leader back is is not our route) or
3234 // b) a minGap violation / collision
3235 MSLane* current = lastLink->myLink->getViaLaneOrLane();
3236 if (leaderInfo.first->getBackLane() == current) {
3237 backOnRoute = true;
3238 } else {
3239 for (MSLane* lane : getBestLanesContinuation()) {
3240 if (lane == current) {
3241 break;
3242 }
3243 if (leaderInfo.first->getBackLane() == lane) {
3244 backOnRoute = true;
3245 }
3246 }
3247 }
3248#ifdef DEBUG_PLAN_MOVE
3249 if (DEBUG_COND) {
3250 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
3251 }
3252#endif
3253 if (!backOnRoute) {
3254 double stopDist = seen - current->getLength() - POSITION_EPS;
3255 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
3256 // do not drive onto the junction conflict area
3257 stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
3258 }
3259 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
3260 }
3261 }
3262 if (backOnRoute) {
3263 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3264 }
3265 if (lastLink != nullptr) {
3266 const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
3267 lastLink->adaptLeaveSpeed(futureVSafe);
3268#ifdef DEBUG_PLAN_MOVE
3269 if (DEBUG_COND) {
3270 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3271 }
3272#endif
3273 }
3274 v = MIN2(v, vsafeLeader);
3275 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3276#ifdef DEBUG_PLAN_MOVE
3277 if (DEBUG_COND) std::cout
3278 << SIMTIME
3279 //std::cout << std::setprecision(10);
3280 << " veh=" << getID()
3281 << " lead=" << leaderInfo.first->getID()
3282 << " leadSpeed=" << leaderInfo.first->getSpeed()
3283 << " gap=" << leaderInfo.second
3284 << " leadLane=" << leaderInfo.first->getLane()->getID()
3285 << " predPos=" << leaderInfo.first->getPositionOnLane()
3286 << " myLane=" << myLane->getID()
3287 << " v=" << v
3288 << " vSafeLeader=" << vsafeLeader
3289 << " vLinkPass=" << vLinkPass
3290 << "\n";
3291#endif
3292 }
3293}
3294
3295
3296void
3297MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3298 const double seen, DriveProcessItem* const lastLink,
3299 const MSLane* const lane, double& v, double& vLinkPass,
3300 double distToCrossing) const {
3301 if (leaderInfo.first != 0) {
3302 if (ignoreFoe(leaderInfo.first)) {
3303#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3304 if (DEBUG_COND) {
3305 std::cout << " junction foe ignored\n";
3306 }
3307#endif
3308 return;
3309 }
3310 const MSCFModel& cfModel = getCarFollowModel();
3311 double vsafeLeader = 0;
3313 vsafeLeader = -std::numeric_limits<double>::max();
3314 }
3315 if (leaderInfo.second >= 0) {
3316 if (hasDeparted()) {
3317 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3318 } else {
3319 // called in the context of MSLane::isInsertionSuccess
3320 vsafeLeader = cfModel.insertionFollowSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3321 }
3322 } else if (leaderInfo.first != this) {
3323 // the leading, in-lapping vehicle is occupying the complete next lane
3324 // stop before entering this lane
3325 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
3326#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3327 if (DEBUG_COND) {
3328 std::cout << SIMTIME << " veh=" << getID() << " stopping before junction: lane=" << lane->getID() << " seen=" << seen
3329 << " laneLength=" << lane->getLength()
3330 << " stopDist=" << seen - lane->getLength() - POSITION_EPS
3331 << " vsafeLeader=" << vsafeLeader
3332 << " distToCrossing=" << distToCrossing
3333 << "\n";
3334 }
3335#endif
3336 }
3337 if (distToCrossing >= 0) {
3338 // can the leader still stop in the way?
3339 const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
3340 if (leaderInfo.first == this) {
3341 // braking for pedestrian
3342 const double vStopCrossing = cfModel.stopSpeed(this, getSpeed(), distToCrossing);
3343 vsafeLeader = vStopCrossing;
3344#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3345 if (DEBUG_COND) {
3346 std::cout << " breaking for pedestrian distToCrossing=" << distToCrossing << " vStopCrossing=" << vStopCrossing << "\n";
3347 }
3348#endif
3349 if (lastLink != nullptr) {
3350 lastLink->adaptStopSpeed(vsafeLeader);
3351 }
3352 } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
3353 // drive up to the crossing point and stop
3354#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3355 if (DEBUG_COND) {
3356 std::cout << " stop at crossing point for critical leader vStop=" << vStop << "\n";
3357 };
3358#endif
3359 vsafeLeader = MAX2(vsafeLeader, vStop);
3360 } else {
3361 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
3362 // estimate the time at which the leader has gone past the crossing point
3363 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
3364 // reach distToCrossing after that time
3365 // avgSpeed * leaderPastCPTime = distToCrossing
3366 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
3367 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
3368 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
3369 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
3370#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3371 if (DEBUG_COND) {
3372 std::cout << " driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
3373 << " leaderPastCPTime=" << leaderPastCPTime
3374 << " vFinal=" << vFinal
3375 << " v2=" << v2
3376 << " vStop=" << vStop
3377 << " vsafeLeader=" << vsafeLeader << "\n";
3378 }
3379#endif
3380 }
3381 }
3382 if (lastLink != nullptr) {
3383 lastLink->adaptLeaveSpeed(vsafeLeader);
3384 }
3385 v = MIN2(v, vsafeLeader);
3386 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3387#ifdef DEBUG_PLAN_MOVE
3388 if (DEBUG_COND) std::cout
3389 << SIMTIME
3390 //std::cout << std::setprecision(10);
3391 << " veh=" << getID()
3392 << " lead=" << leaderInfo.first->getID()
3393 << " leadSpeed=" << leaderInfo.first->getSpeed()
3394 << " gap=" << leaderInfo.second
3395 << " leadLane=" << leaderInfo.first->getLane()->getID()
3396 << " predPos=" << leaderInfo.first->getPositionOnLane()
3397 << " seen=" << seen
3398 << " lane=" << lane->getID()
3399 << " myLane=" << myLane->getID()
3400 << " dTC=" << distToCrossing
3401 << " v=" << v
3402 << " vSafeLeader=" << vsafeLeader
3403 << " vLinkPass=" << vLinkPass
3404 << "\n";
3405#endif
3406 }
3407}
3408
3409
3410void
3411MSVehicle::adaptToOncomingLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3412 DriveProcessItem* const lastLink,
3413 double& v, double& vLinkPass) const {
3414 if (leaderInfo.first != 0) {
3415 if (ignoreFoe(leaderInfo.first)) {
3416#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3417 if (DEBUG_COND) {
3418 std::cout << " oncoming foe ignored\n";
3419 }
3420#endif
3421 return;
3422 }
3423 const MSCFModel& cfModel = getCarFollowModel();
3424 const MSVehicle* lead = leaderInfo.first;
3425 const MSCFModel& cfModelL = lead->getCarFollowModel();
3426 // assume the leader reacts symmetrically (neither stopping instantly nor ignoring ego)
3427 const double leaderBrakeGap = cfModelL.brakeGap(lead->getSpeed(), cfModelL.getMaxDecel(), 0);
3428 const double egoBrakeGap = cfModel.brakeGap(getSpeed(), cfModel.getMaxDecel(), 0);
3429 const double gapSum = leaderBrakeGap + egoBrakeGap;
3430 // ensure that both vehicles can leave an intersection if they are currently on it
3431 double egoExit = getDistanceToLeaveJunction();
3432 const double leaderExit = lead->getDistanceToLeaveJunction();
3433 double gap = leaderInfo.second;
3434 if (egoExit + leaderExit < gap) {
3435 gap -= egoExit + leaderExit;
3436 } else {
3437 egoExit = 0;
3438 }
3439 // split any distance in excess of brakeGaps evenly
3440 const double freeGap = MAX2(0.0, gap - gapSum);
3441 const double splitGap = MIN2(gap, gapSum);
3442 // assume remaining distance is allocated in proportion to braking distance
3443 const double gapRatio = gapSum > 0 ? egoBrakeGap / gapSum : 0.5;
3444 const double vsafeLeader = cfModel.stopSpeed(this, getSpeed(), splitGap * gapRatio + egoExit + 0.5 * freeGap);
3445 if (lastLink != nullptr) {
3446 const double futureVSafe = cfModel.stopSpeed(this, lastLink->accelV, leaderInfo.second, MSCFModel::CalcReason::FUTURE);
3447 lastLink->adaptLeaveSpeed(futureVSafe);
3448#ifdef DEBUG_PLAN_MOVE
3449 if (DEBUG_COND) {
3450 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3451 }
3452#endif
3453 }
3454 v = MIN2(v, vsafeLeader);
3455 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3456#ifdef DEBUG_PLAN_MOVE
3457 if (DEBUG_COND) std::cout
3458 << SIMTIME
3459 //std::cout << std::setprecision(10);
3460 << " veh=" << getID()
3461 << " oncomingLead=" << lead->getID()
3462 << " leadSpeed=" << lead->getSpeed()
3463 << " gap=" << leaderInfo.second
3464 << " gap2=" << gap
3465 << " gapRatio=" << gapRatio
3466 << " leadLane=" << lead->getLane()->getID()
3467 << " predPos=" << lead->getPositionOnLane()
3468 << " myLane=" << myLane->getID()
3469 << " v=" << v
3470 << " vSafeLeader=" << vsafeLeader
3471 << " vLinkPass=" << vLinkPass
3472 << "\n";
3473#endif
3474 }
3475}
3476
3477
3478void
3479MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
3480 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
3482 // we want to pass the link but need to check for foes on internal lanes
3483 checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
3484 if (myLaneChangeModel->getShadowLane() != nullptr) {
3485 const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
3486 if (parallelLink != nullptr) {
3487 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
3488 }
3489 }
3490 }
3491
3492}
3493
3494void
3495MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
3496 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
3497 bool isShadowLink) const {
3498#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3499 if (DEBUG_COND) {
3500 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3501 }
3502#endif
3503 const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
3504#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3505 if (DEBUG_COND) {
3506 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3507 }
3508#endif
3509 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3510 // the vehicle to enter the junction first has priority
3511 const MSVehicle* leader = (*it).vehAndGap.first;
3512 if (leader == nullptr) {
3513 // leader is a pedestrian. Passing 'this' as a dummy.
3514#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3515 if (DEBUG_COND) {
3516 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
3517 }
3518#endif
3521#ifdef DEBUG_PLAN_MOVE
3522 if (DEBUG_COND) {
3523 std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
3524 }
3525#endif
3526 continue;
3527 }
3528 adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3529 // if blocked by a pedestrian for too long we must yield our request
3531 setRequest = false;
3532#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3533 if (DEBUG_COND) {
3534 std::cout << " aborting request\n";
3535 }
3536#endif
3537 }
3538 } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay()) {
3541#ifdef DEBUG_PLAN_MOVE
3542 if (DEBUG_COND) {
3543 std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
3544 }
3545#endif
3546 continue;
3547 }
3549 // sibling link (XXX: could also be partial occupator where this check fails)
3550 &leader->getLane()->getEdge() == &lane->getEdge()) {
3551 // check for sublane obstruction (trivial for sibling link leaders)
3552 const MSLane* conflictLane = link->getInternalLaneBefore();
3553 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
3554 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
3555 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
3556 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
3557 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
3558#ifdef DEBUG_PLAN_MOVE
3559 if (DEBUG_COND) {
3560 std::cout << SIMTIME << " veh=" << getID()
3561 << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
3562 << " isShadowLink=" << isShadowLink
3563 << " lane=" << lane->getID()
3564 << " foe=" << leader->getID()
3565 << " foeLane=" << leader->getLane()->getID()
3566 << " latOffset=" << latOffset
3567 << " latOffsetFoe=" << leader->getLatOffset(lane)
3568 << " linkLeadersAhead=" << linkLeadersAhead.toString()
3569 << "\n";
3570 }
3571#endif
3572 } else {
3573#ifdef DEBUG_PLAN_MOVE
3574 if (DEBUG_COND) {
3575 std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
3576 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3577 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3578 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3579 << "\n";
3580 }
3581#endif
3582 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3583 }
3584 if (lastLink != nullptr) {
3585 // we are not yet on the junction with this linkLeader.
3586 // at least we can drive up to the previous link and stop there
3587 v = MAX2(v, lastLink->myVLinkWait);
3588 }
3589 // if blocked by a leader from the same or next lane we must yield our request
3590 // also, if blocked by a stopped or blocked leader
3592 //&& leader->getSpeed() < SUMO_const_haltingSpeed
3594 || leader->getLane()->getLogicalPredecessorLane() == myLane
3595 || leader->isStopped()
3597 setRequest = false;
3598#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3599 if (DEBUG_COND) {
3600 std::cout << " aborting request\n";
3601 }
3602#endif
3603 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
3604 // we are not yet on the junction so must abort that request as well
3605 // (or maybe we are already on the junction and the leader is a partial occupator beyond)
3606 lastLink->mySetRequest = false;
3607#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3608 if (DEBUG_COND) {
3609 std::cout << " aborting previous request\n";
3610 }
3611#endif
3612 }
3613 }
3614 }
3615#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3616 else {
3617 if (DEBUG_COND) {
3618 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
3619 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3620 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3621 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3622 << "\n";
3623 }
3624 }
3625#endif
3626 }
3627 // if this is the link between two internal lanes we may have to slow down for pedestrians
3628 vLinkWait = MIN2(vLinkWait, v);
3629}
3630
3631
3632double
3633MSVehicle::getDeltaPos(const double accel) const {
3634 double vNext = myState.mySpeed + ACCEL2SPEED(accel);
3636 // apply implicit Euler positional update
3637 return SPEED2DIST(MAX2(vNext, 0.));
3638 } else {
3639 // apply ballistic update
3640 if (vNext >= 0) {
3641 // assume constant acceleration during this time step
3642 return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
3643 } else {
3644 // negative vNext indicates a stop within the middle of time step
3645 // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
3646 // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
3647 // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
3648 // until the vehicle stops.
3649 return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
3650 }
3651 }
3652}
3653
3654void
3655MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
3656
3657 // Speed limit due to zipper merging
3658 double vSafeZipper = std::numeric_limits<double>::max();
3659
3660 myHaveToWaitOnNextLink = false;
3661 bool canBrakeVSafeMin = false;
3662
3663 // Get safe velocities from DriveProcessItems.
3664 assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
3665 for (const DriveProcessItem& dpi : myLFLinkLanes) {
3666 MSLink* const link = dpi.myLink;
3667
3668#ifdef DEBUG_EXEC_MOVE
3669 if (DEBUG_COND) {
3670 std::cout
3671 << SIMTIME
3672 << " veh=" << getID()
3673 << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
3674 << " req=" << dpi.mySetRequest
3675 << " vP=" << dpi.myVLinkPass
3676 << " vW=" << dpi.myVLinkWait
3677 << " d=" << dpi.myDistance
3678 << "\n";
3679 gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
3680 }
3681#endif
3682
3683 // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
3684 if (link != nullptr && dpi.mySetRequest) {
3685
3686 const LinkState ls = link->getState();
3687 // vehicles should brake when running onto a yellow light if the distance allows to halt in front
3688 const bool yellow = link->haveYellow();
3689 const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
3691 assert(link->getLaneBefore() != nullptr);
3692 const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
3693 const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
3694 if (yellow && canBrake && !ignoreRedLink) {
3695 vSafe = dpi.myVLinkWait;
3697#ifdef DEBUG_CHECKREWINDLINKLANES
3698 if (DEBUG_COND) {
3699 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
3700 }
3701#endif
3702 break;
3703 }
3704 const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
3705 MSLink::BlockingFoes collectFoes;
3706 bool opened = (yellow || influencerPrio
3707 || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3709 canBrake ? getImpatience() : 1,
3712 ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
3713 ignoreRedLink, this, dpi.myDistance));
3714 if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
3715 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
3716 if (parallelLink != nullptr) {
3717 const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
3719 opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3722 getWaitingTimeFor(link), shadowLatPos, nullptr,
3723 ignoreRedLink, this, dpi.myDistance));
3724#ifdef DEBUG_EXEC_MOVE
3725 if (DEBUG_COND) {
3726 std::cout << SIMTIME
3727 << " veh=" << getID()
3728 << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
3729 << " shadowDir=" << myLaneChangeModel->getShadowDirection()
3730 << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
3731 << " opened=" << opened
3732 << "\n";
3733 }
3734#endif
3735 }
3736 }
3737 // vehicles should decelerate when approaching a minor link
3738#ifdef DEBUG_EXEC_MOVE
3739 if (DEBUG_COND) {
3740 std::cout << SIMTIME
3741 << " opened=" << opened
3742 << " influencerPrio=" << influencerPrio
3743 << " linkPrio=" << link->havePriority()
3744 << " lastContMajor=" << link->lastWasContMajor()
3745 << " isCont=" << link->isCont()
3746 << " ignoreRed=" << ignoreRedLink
3747 << "\n";
3748 }
3749#endif
3750 double visibilityDistance = link->getFoeVisibilityDistance();
3751 bool determinedFoePresence = dpi.myDistance <= visibilityDistance;
3752 if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
3753 if (!determinedFoePresence && (canBrake || !yellow)) {
3754 vSafe = dpi.myVLinkWait;
3756#ifdef DEBUG_CHECKREWINDLINKLANES
3757 if (DEBUG_COND) {
3758 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
3759 }
3760#endif
3761 break;
3762 } else {
3763 // past the point of no return. we need to drive fast enough
3764 // to make it across the link. However, minor slowdowns
3765 // should be permissible to follow leading traffic safely
3766 // basically, this code prevents dawdling
3767 // (it's harder to do this later using
3768 // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
3769 // vehicle is already too close to stop at that part of the code)
3770 //
3771 // XXX: There is a problem in subsecond simulation: If we cannot
3772 // make it across the minor link in one step, new traffic
3773 // could appear on a major foe link and cause a collision. Refs. #1845, #2123
3774 vSafeMinDist = dpi.myDistance; // distance that must be covered
3776 vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3777 } else {
3778 vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3779 }
3780 canBrakeVSafeMin = canBrake;
3781#ifdef DEBUG_EXEC_MOVE
3782 if (DEBUG_COND) {
3783 std::cout << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
3784 }
3785#endif
3786 }
3787 }
3788 // have waited; may pass if opened...
3789 if (opened) {
3790 vSafe = dpi.myVLinkPass;
3791 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
3792 // this vehicle is probably not gonna drive across the next junction (heuristic)
3794#ifdef DEBUG_CHECKREWINDLINKLANES
3795 if (DEBUG_COND) {
3796 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
3797 }
3798#endif
3799 }
3800 if (link->mustStop() && determinedFoePresence && myHaveStoppedFor == nullptr) {
3801 myHaveStoppedFor = link;
3802 }
3803 } else if (link->getState() == LINKSTATE_ZIPPER) {
3804 vSafeZipper = MIN2(vSafeZipper,
3805 link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
3806 } else if (!canBrake
3807 // always brake hard for traffic lights (since an emergency stop is necessary anyway)
3808 && link->getTLLogic() == nullptr
3809 // cannot brake even with emergency deceleration
3810 && dpi.myDistance < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0.)) {
3811#ifdef DEBUG_EXEC_MOVE
3812 if (DEBUG_COND) {
3813 std::cout << SIMTIME << " too fast to brake for closed link\n";
3814 }
3815#endif
3816 vSafe = dpi.myVLinkPass;
3817 } else {
3818 vSafe = dpi.myVLinkWait;
3820#ifdef DEBUG_CHECKREWINDLINKLANES
3821 if (DEBUG_COND) {
3822 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
3823 }
3824#endif
3825#ifdef DEBUG_EXEC_MOVE
3826 if (DEBUG_COND) {
3827 std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
3828 }
3829#endif
3830 break;
3831 }
3832 } else {
3833 if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
3834 // blocked on the junction. yield request so other vehicles may
3835 // become junction leader
3836#ifdef DEBUG_EXEC_MOVE
3837 if (DEBUG_COND) {
3838 std::cout << SIMTIME << " resetting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
3839 }
3840#endif
3843 }
3844 // we have: i->link == 0 || !i->setRequest
3845 vSafe = dpi.myVLinkWait;
3846 if (vSafe < getSpeed()) {
3848#ifdef DEBUG_CHECKREWINDLINKLANES
3849 if (DEBUG_COND) {
3850 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
3851 }
3852#endif
3853 } else if (vSafe < SUMO_const_haltingSpeed) {
3855#ifdef DEBUG_CHECKREWINDLINKLANES
3856 if (DEBUG_COND) {
3857 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
3858 }
3859#endif
3860 }
3861 if (link == nullptr && myLFLinkLanes.size() == 1
3862 && getBestLanesContinuation().size() > 1
3863 && getBestLanesContinuation()[1]->hadPermissionChanges()
3864 && myLane->getFirstAnyVehicle() == this) {
3865 // temporal lane closing without notification, visible to the
3866 // vehicle at the front of the queue
3867 updateBestLanes(true);
3868 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
3869 }
3870 break;
3871 }
3872 }
3873
3874//#ifdef DEBUG_EXEC_MOVE
3875// if (DEBUG_COND) {
3876// std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
3877// std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
3878// std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
3879// std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
3880//
3881// double gap = getLeader().second;
3882// std::cout << "gap = " << toString(gap, 24) << std::endl;
3883// std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
3884// << "\n" << std::endl;
3885// }
3886//#endif
3887
3888 if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
3889 || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
3890 // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
3891 // 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
3892#ifdef DEBUG_EXEC_MOVE
3893 if (DEBUG_COND) {
3894 std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
3895 }
3896#endif
3897 if (canBrakeVSafeMin && vSafe < getSpeed()) {
3898 // cannot drive across a link so we need to stop before it
3899 vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
3900 getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
3901 vSafeMin = 0;
3903#ifdef DEBUG_CHECKREWINDLINKLANES
3904 if (DEBUG_COND) {
3905 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
3906 }
3907#endif
3908 } else {
3909 // if the link is yellow or visibility distance is large
3910 // then we might not make it across the link in one step anyway..
3911 // Possibly, the lane after the intersection has a lower speed limit so
3912 // we really need to drive slower already
3913 // -> keep driving without dawdling
3914 vSafeMin = vSafe;
3915 }
3916 }
3917
3918 // vehicles inside a roundabout should maintain their requests
3919 if (myLane->getEdge().isRoundabout()) {
3920 myHaveToWaitOnNextLink = false;
3921 }
3922
3923 vSafe = MIN2(vSafe, vSafeZipper);
3924}
3925
3926
3927double
3928MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
3929 if (myInfluencer != nullptr) {
3931#ifdef DEBUG_TRACI
3932 if DEBUG_COND2(this) {
3933 std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
3934 << " vSafe=" << vSafe << " (init)vNext=" << vNext << " keepStopping=" << keepStopping();
3935 }
3936#endif
3939 }
3940 const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
3943 vMin = MAX2(0., vMin);
3944 }
3945 vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
3946 if (keepStopping() && myStops.front().getSpeed() == 0) {
3947 // avoid driving while stopped (unless it's actually a waypoint
3948 vNext = myInfluencer->getOriginalSpeed();
3949 }
3950#ifdef DEBUG_TRACI
3951 if DEBUG_COND2(this) {
3952 std::cout << " (processed)vNext=" << vNext << std::endl;
3953 }
3954#endif
3955 }
3956 return vNext;
3957}
3958
3959
3960void
3962#ifdef DEBUG_ACTIONSTEPS
3963 if (DEBUG_COND) {
3964 std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
3965 << " Current items: ";
3966 for (auto& j : myLFLinkLanes) {
3967 if (j.myLink == 0) {
3968 std::cout << "\n Stop at distance " << j.myDistance;
3969 } else {
3970 const MSLane* to = j.myLink->getViaLaneOrLane();
3971 const MSLane* from = j.myLink->getLaneBefore();
3972 std::cout << "\n Link at distance " << j.myDistance << ": '"
3973 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3974 }
3975 }
3976 std::cout << "\n myNextDriveItem: ";
3977 if (myLFLinkLanes.size() != 0) {
3978 if (myNextDriveItem->myLink == 0) {
3979 std::cout << "\n Stop at distance " << myNextDriveItem->myDistance;
3980 } else {
3981 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
3982 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
3983 std::cout << "\n Link at distance " << myNextDriveItem->myDistance << ": '"
3984 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3985 }
3986 }
3987 std::cout << std::endl;
3988 }
3989#endif
3990 for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
3991#ifdef DEBUG_ACTIONSTEPS
3992 if (DEBUG_COND) {
3993 std::cout << " Removing item: ";
3994 if (j->myLink == 0) {
3995 std::cout << "Stop at distance " << j->myDistance;
3996 } else {
3997 const MSLane* to = j->myLink->getViaLaneOrLane();
3998 const MSLane* from = j->myLink->getLaneBefore();
3999 std::cout << "Link at distance " << j->myDistance << ": '"
4000 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
4001 }
4002 std::cout << std::endl;
4003 }
4004#endif
4005 if (j->myLink != nullptr) {
4006 j->myLink->removeApproaching(this);
4007 }
4008 }
4011}
4012
4013
4014void
4016#ifdef DEBUG_ACTIONSTEPS
4017 if (DEBUG_COND) {
4018 std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
4019 for (const auto& dpi : myLFLinkLanes) {
4020 std::cout
4021 << " vPass=" << dpi.myVLinkPass
4022 << " vWait=" << dpi.myVLinkWait
4023 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4024 << " request=" << dpi.mySetRequest
4025 << "\n";
4026 }
4027 std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
4028 }
4029#endif
4030 if (myLFLinkLanes.size() == 0) {
4031 // nothing to update
4032 return;
4033 }
4034 const MSLink* nextPlannedLink = nullptr;
4035// auto i = myLFLinkLanes.begin();
4036 auto i = myNextDriveItem;
4037 while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
4038 nextPlannedLink = i->myLink;
4039 ++i;
4040 }
4041
4042 if (nextPlannedLink == nullptr) {
4043 // No link for upcoming item -> no need for an update
4044#ifdef DEBUG_ACTIONSTEPS
4045 if (DEBUG_COND) {
4046 std::cout << "Found no link-related drive item." << std::endl;
4047 }
4048#endif
4049 return;
4050 }
4051
4052 if (getLane() == nextPlannedLink->getLaneBefore()) {
4053 // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
4054#ifdef DEBUG_ACTIONSTEPS
4055 if (DEBUG_COND) {
4056 std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
4057 }
4058#endif
4059 return;
4060 }
4061 // Lane must have been changed, determine the change direction
4062 const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
4063 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4064 // lcDir = 1;
4065 } else {
4066 parallelLink = nextPlannedLink->getParallelLink(-1);
4067 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4068 // lcDir = -1;
4069 } else {
4070 // If the vehicle's current lane is not the approaching lane for the next
4071 // drive process item's link, it is expected to lead to a parallel link,
4072 // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
4073 // Then a stop item should be scheduled! -> TODO!
4074 //assert(false);
4075 return;
4076 }
4077 }
4078#ifdef DEBUG_ACTIONSTEPS
4079 if (DEBUG_COND) {
4080 std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
4081 }
4082#endif
4083 // Trace link sequence along current best lanes and transfer drive items to the corresponding links
4084// DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
4085 DriveItemVector::iterator driveItemIt = myNextDriveItem;
4086 // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
4087 const MSLane* lane = myLane;
4088 assert(myLane == parallelLink->getLaneBefore());
4089 // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
4090 std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
4091 // Pointer to the new link for the current drive process item
4092 MSLink* newLink = nullptr;
4093 while (driveItemIt != myLFLinkLanes.end()) {
4094 if (driveItemIt->myLink == nullptr) {
4095 // Items not related to a specific link are not updated
4096 // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
4097 // the update necessary, this may slow down the vehicle's continuation on the new lane...)
4098 ++driveItemIt;
4099 continue;
4100 }
4101 // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
4102 // We just remove the leftover link-items, as they cannot be mapped to new links.
4103 if (bestLaneIt == getBestLanesContinuation().end()) {
4104#ifdef DEBUG_ACTIONSTEPS
4105 if (DEBUG_COND) {
4106 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
4107 }
4108#endif
4109 while (driveItemIt != myLFLinkLanes.end()) {
4110 if (driveItemIt->myLink == nullptr) {
4111 ++driveItemIt;
4112 continue;
4113 } else {
4114 driveItemIt->myLink->removeApproaching(this);
4115 driveItemIt = myLFLinkLanes.erase(driveItemIt);
4116 }
4117 }
4118 break;
4119 }
4120 // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
4121 const MSLane* const target = *bestLaneIt;
4122 assert(!target->isInternal());
4123 newLink = nullptr;
4124 for (MSLink* const link : lane->getLinkCont()) {
4125 if (link->getLane() == target) {
4126 newLink = link;
4127 break;
4128 }
4129 }
4130
4131 if (newLink == driveItemIt->myLink) {
4132 // new continuation merged into previous - stop update
4133#ifdef DEBUG_ACTIONSTEPS
4134 if (DEBUG_COND) {
4135 std::cout << "Old and new continuation sequences merge at link\n"
4136 << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
4137 << "\nNo update beyond merge required." << std::endl;
4138 }
4139#endif
4140 break;
4141 }
4142
4143#ifdef DEBUG_ACTIONSTEPS
4144 if (DEBUG_COND) {
4145 std::cout << "lane=" << lane->getID() << "\nUpdating link\n '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
4146 << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
4147 }
4148#endif
4149 newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
4150 driveItemIt->myLink->removeApproaching(this);
4151 driveItemIt->myLink = newLink;
4152 lane = newLink->getViaLaneOrLane();
4153 ++driveItemIt;
4154 if (!lane->isInternal()) {
4155 ++bestLaneIt;
4156 }
4157 }
4158#ifdef DEBUG_ACTIONSTEPS
4159 if (DEBUG_COND) {
4160 std::cout << "Updated drive items:" << std::endl;
4161 for (const auto& dpi : myLFLinkLanes) {
4162 std::cout
4163 << " vPass=" << dpi.myVLinkPass
4164 << " vWait=" << dpi.myVLinkWait
4165 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4166 << " request=" << dpi.mySetRequest
4167 << "\n";
4168 }
4169 }
4170#endif
4171}
4172
4173
4174void
4176 // To avoid casual blinking brake lights at high speeds due to dawdling of the
4177 // leading vehicle, we don't show brake lights when the deceleration could be caused
4178 // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
4179 double pseudoFriction = (0.05 + 0.005 * getSpeed()) * getSpeed();
4180 bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
4181
4182 if (vNext <= SUMO_const_haltingSpeed) {
4183 brakelightsOn = true;
4184 }
4185 if (brakelightsOn && !isStopped()) {
4187 } else {
4189 }
4190}
4191
4192
4193void
4198 } else {
4199 myWaitingTime = 0;
4201 if (hasInfluencer()) {
4203 }
4204 }
4205}
4206
4207
4208void
4210 // update time loss (depends on the updated edge)
4211 if (!isStopped()) {
4212 const double vmax = myLane->getVehicleMaxSpeed(this);
4213 if (vmax > 0) {
4214 myTimeLoss += TS * (vmax - vNext) / vmax;
4215 }
4216 }
4217}
4218
4219
4220double
4221MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
4222 const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
4223 || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
4224#ifdef DEBUG_REVERSE_BIDI
4225 if (DEBUG_COND) std::cout << SIMTIME << " checkReversal lane=" << myLane->getID()
4226 << " pos=" << myState.myPos
4227 << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
4228 << " speedThreshold=" << speedThreshold
4229 << " seen=" << seen
4230 << " isRail=" << isRail()
4231 << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
4232 << " posOK=" << (myState.myPos <= myLane->getLength())
4233 << " normal=" << !myLane->isInternal()
4234 << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
4235 << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
4236 << " stopOk=" << stopOk
4237 << "\n";
4238#endif
4239 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4240 && getPreviousSpeed() <= speedThreshold
4241 && myState.myPos <= myLane->getLength()
4242 && !myLane->isInternal()
4243 && (myCurrEdge + 1) != myRoute->end()
4244 && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
4245 // ensure there are no further stops on this edge
4246 && stopOk
4247 ) {
4248 //if (isSelected()) std::cout << " check1 passed\n";
4249
4250 // ensure that the vehicle is fully on bidi edges that allow reversal
4251 const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
4252 ? myFurtherLanes.size()
4253 : ceil((double)myFurtherLanes.size() / 2.0));
4254 const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
4255 if (remainingRoute < neededFutureRoute) {
4256#ifdef DEBUG_REVERSE_BIDI
4257 if (DEBUG_COND) {
4258 std::cout << " fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
4259 }
4260#endif
4261 return getMaxSpeed();
4262 }
4263 //if (isSelected()) std::cout << " check2 passed\n";
4264
4265 // ensure that the turn-around connection exists from the current edge to its bidi-edge
4266 const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
4267 if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
4268#ifdef DEBUG_REVERSE_BIDI
4269 if (DEBUG_COND) {
4270 std::cout << " noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
4271 }
4272#endif
4273 return getMaxSpeed();
4274 }
4275 //if (isSelected()) std::cout << " check3 passed\n";
4276
4277 // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
4278 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
4279 const double stopPos = myStops.front().getEndPos(*this);
4280 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4281 const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
4282 if (newPos > stopPos) {
4283#ifdef DEBUG_REVERSE_BIDI
4284 if (DEBUG_COND) {
4285 std::cout << " reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
4286 }
4287#endif
4288 if (seen > MAX2(brakeDist, 1.0)) {
4289 return getMaxSpeed();
4290 } else {
4291#ifdef DEBUG_REVERSE_BIDI
4292 if (DEBUG_COND) {
4293 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4294 }
4295#endif
4296 }
4297 }
4298 }
4299 //if (isSelected()) std::cout << " check4 passed\n";
4300
4301 // ensure that bidi-edges exist for all further edges
4302 // and that no stops will be skipped when reversing
4303 // and that the train will not be on top of a red rail signal after reversal
4304 const MSLane* bidi = myLane->getBidiLane();
4305 int view = 2;
4306 for (MSLane* further : myFurtherLanes) {
4307 if (!further->getEdge().isInternal()) {
4308 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
4309#ifdef DEBUG_REVERSE_BIDI
4310 if (DEBUG_COND) {
4311 std::cout << " noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
4312 }
4313#endif
4314 return getMaxSpeed();
4315 }
4316 const MSLane* nextBidi = further->getBidiLane();
4317 const MSLink* toNext = bidi->getLinkTo(nextBidi);
4318 if (toNext == nullptr) {
4319 // can only happen if the route is invalid
4320 return getMaxSpeed();
4321 }
4322 if (toNext->haveRed()) {
4323#ifdef DEBUG_REVERSE_BIDI
4324 if (DEBUG_COND) {
4325 std::cout << " do not reverse on a red signal\n";
4326 }
4327#endif
4328 return getMaxSpeed();
4329 }
4330 bidi = nextBidi;
4331 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
4332 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4333 const double stopPos = myStops.front().getEndPos(*this);
4334 const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
4335 if (newPos > stopPos) {
4336#ifdef DEBUG_REVERSE_BIDI
4337 if (DEBUG_COND) {
4338 std::cout << " reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
4339 }
4340#endif
4341 if (seen > MAX2(brakeDist, 1.0)) {
4342 canReverse = false;
4343 return getMaxSpeed();
4344 } else {
4345#ifdef DEBUG_REVERSE_BIDI
4346 if (DEBUG_COND) {
4347 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4348 }
4349#endif
4350 }
4351 }
4352 }
4353 view++;
4354 }
4355 }
4356 // reverse as soon as comfortably possible
4357 const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
4358#ifdef DEBUG_REVERSE_BIDI
4359 if (DEBUG_COND) {
4360 std::cout << SIMTIME << " seen=" << seen << " vReverseOK=" << vMinComfortable << "\n";
4361 }
4362#endif
4363 canReverse = true;
4364 return vMinComfortable;
4365 }
4366 return getMaxSpeed();
4367}
4368
4369
4370void
4371MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
4372 for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
4373 passedLanes.push_back(*i);
4374 }
4375 if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
4376 passedLanes.push_back(myLane);
4377 }
4378 // let trains reverse direction
4379 bool reverseTrain = false;
4380 checkReversal(reverseTrain);
4381 if (reverseTrain) {
4382 // Train is 'reversing' so toggle the logical state
4384 // add some slack to ensure that the back of train does appear looped
4385 myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
4386 myState.mySpeed = 0;
4387#ifdef DEBUG_REVERSE_BIDI
4388 if (DEBUG_COND) {
4389 std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
4390 }
4391#endif
4392 }
4393 // move on lane(s)
4394 if (myState.myPos > myLane->getLength()) {
4395 // The vehicle has moved at least to the next lane (maybe it passed even more than one)
4396 if (myCurrEdge != myRoute->end() - 1) {
4397 MSLane* approachedLane = myLane;
4398 // move the vehicle forward
4400 while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
4401 const MSLink* link = myNextDriveItem->myLink;
4402 const double linkDist = myNextDriveItem->myDistance;
4404 // check whether the vehicle was allowed to enter lane
4405 // otherwise it is decelerated and we do not need to test for it's
4406 // approach on the following lanes when a lane changing is performed
4407 // proceed to the next lane
4408 if (approachedLane->mustCheckJunctionCollisions()) {
4409 // vehicle moves past approachedLane within a single step, collision checking must still be done
4411 }
4412 if (link != nullptr) {
4413 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4414 && !myLane->isInternal()
4415 && myLane->getBidiLane() != nullptr
4416 && link->getLane()->getBidiLane() == myLane
4417 && !reverseTrain) {
4418 emergencyReason = " because it must reverse direction";
4419 approachedLane = nullptr;
4420 break;
4421 }
4422 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4423 && myState.myPos < myLane->getLength() + NUMERICAL_EPS
4424 && hasStops() && getNextStop().edge == myCurrEdge) {
4425 // avoid skipping stop due to numerical instability
4426 // this is a special case for rail vehicles because they
4427 // continue myLFLinkLanes past stops
4428 approachedLane = myLane;
4430 break;
4431 }
4432 approachedLane = link->getViaLaneOrLane();
4434 bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
4435 if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
4436 emergencyReason = " because of a red traffic light";
4437 break;
4438 }
4439 }
4440 if (reverseTrain && approachedLane->isInternal()) {
4441 // avoid getting stuck on a slow turn-around internal lane
4442 myState.myPos += approachedLane->getLength();
4443 }
4444 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4445 // avoid warning due to numerical instability
4446 approachedLane = myLane;
4448 } else if (reverseTrain) {
4449 approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
4450 link = myLane->getLinkTo(approachedLane);
4451 assert(link != 0);
4452 while (link->getViaLane() != nullptr) {
4453 link = link->getViaLane()->getLinkCont()[0];
4454 }
4456 } else {
4457 emergencyReason = " because there is no connection to the next edge";
4458 approachedLane = nullptr;
4459 break;
4460 }
4461 if (approachedLane != myLane && approachedLane != nullptr) {
4464 assert(myState.myPos > 0);
4465 enterLaneAtMove(approachedLane);
4466 if (link->isEntryLink()) {
4469 myHaveStoppedFor = nullptr;
4470 }
4471 if (link->isConflictEntryLink()) {
4473 // renew yielded request
4475 }
4476 if (link->isExitLink()) {
4477 // passed junction, reset for approaching the next one
4481 }
4482#ifdef DEBUG_PLAN_MOVE_LEADERINFO
4483 if (DEBUG_COND) {
4484 std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
4485 << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
4486 << " ET=" << myJunctionEntryTime
4487 << " ETN=" << myJunctionEntryTimeNeverYield
4488 << " CET=" << myJunctionConflictEntryTime
4489 << "\n";
4490 }
4491#endif
4492 if (hasArrivedInternal()) {
4493 break;
4494 }
4497 // abort lane change
4498 WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
4499 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4501 }
4502 }
4503 if (approachedLane->getEdge().isVaporizing()) {
4505 break;
4506 }
4507 passedLanes.push_back(approachedLane);
4508 }
4509 }
4510 // NOTE: Passed drive items will be erased in the next simstep's planMove()
4511
4512#ifdef DEBUG_ACTIONSTEPS
4513 if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
4514 std::cout << "Updated drive items:" << std::endl;
4515 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
4516 std::cout
4517 << " vPass=" << (*i).myVLinkPass
4518 << " vWait=" << (*i).myVLinkWait
4519 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
4520 << " request=" << (*i).mySetRequest
4521 << "\n";
4522 }
4523 }
4524#endif
4525 } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4526 // avoid warning due to numerical instability when stopping at the end of the route
4528 }
4529
4530 }
4531}
4532
4533
4534
4535bool
4537#ifdef DEBUG_EXEC_MOVE
4538 if (DEBUG_COND) {
4539 std::cout << "\nEXECUTE_MOVE\n"
4540 << SIMTIME
4541 << " veh=" << getID()
4542 << " speed=" << getSpeed() // toString(getSpeed(), 24)
4543 << std::endl;
4544 }
4545#endif
4546
4547
4548 // Maximum safe velocity
4549 double vSafe = std::numeric_limits<double>::max();
4550 // Minimum safe velocity (lower bound).
4551 double vSafeMin = -std::numeric_limits<double>::max();
4552 // The distance to a link, which should either be crossed this step
4553 // or in front of which we need to stop.
4554 double vSafeMinDist = 0;
4555
4556 if (myActionStep) {
4557 // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
4558 processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
4559#ifdef DEBUG_ACTIONSTEPS
4560 if (DEBUG_COND) {
4561 std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
4562 " vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
4563 }
4564#endif
4565 } else {
4566 // Continue with current acceleration
4567 vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
4568#ifdef DEBUG_ACTIONSTEPS
4569 if (DEBUG_COND) {
4570 std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
4571 " continues with constant accel " << myAcceleration << "...\n"
4572 << "speed: " << getSpeed() << " -> " << vSafe << std::endl;
4573 }
4574#endif
4575 }
4576
4577
4578//#ifdef DEBUG_EXEC_MOVE
4579// if (DEBUG_COND) {
4580// std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
4581// }
4582//#endif
4583
4584 // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
4585 // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
4586 double vNext = vSafe;
4587 const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
4588 if (vNext <= SUMO_const_haltingSpeed * TS && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting() && myActionStep) {
4590 } else if (isStopped()) {
4591 // do not apply startupDelay for waypoints
4592 if (getCarFollowModel().startupDelayStopped() && getNextStop().pars.speed <= 0) {
4594 } else {
4595 // do not apply startupDelay but signal that a stop has taken place
4597 }
4598 } else {
4599 // identify potential startup (before other effects reduce the speed again)
4601 }
4602 if (myActionStep) {
4603 vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
4604 if (vNext > 0) {
4605 vNext = MAX2(vNext, vSafeMin);
4606 }
4607 }
4608 // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
4609 // (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
4610 // (Jakob) We also need to make sure to reach a stop at the start of the next edge
4611 if (fabs(vNext) < NUMERICAL_EPS_SPEED && (myStopDist > POSITION_EPS || (hasStops() && myCurrEdge == getNextStop().edge))) {
4612 vNext = 0.;
4613 }
4614#ifdef DEBUG_EXEC_MOVE
4615 if (DEBUG_COND) {
4616 std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
4617 << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
4618 }
4619#endif
4620
4621 // vNext may be higher than vSafe without implying a bug:
4622 // - when approaching a green light that suddenly switches to yellow
4623 // - when using unregulated junctions
4624 // - when using tau < step-size
4625 // - when using unsafe car following models
4626 // - when using TraCI and some speedMode / laneChangeMode settings
4627 //if (vNext > vSafe + NUMERICAL_EPS) {
4628 // WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
4629 // + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
4630 // + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4631 //}
4632
4634 vNext = MAX2(vNext, 0.);
4635 } else {
4636 // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
4637 }
4638
4639 // Check for speed advices from the traci client
4640 vNext = processTraCISpeedControl(vSafe, vNext);
4641
4642 // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
4643 MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
4644 if (elecHybridOfVehicle != nullptr) {
4645 // this is the consumption given by the car following model-computed acceleration
4646 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4647 // but the maximum power of the electric motor may be lower
4648 // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
4649 double maxPower = getEmissionParameters()->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 100000.) / 3600;
4650 if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
4651 // no, we cannot accelerate that fast, recompute the maximum possible acceleration
4652 double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
4653 // and update the speed of the vehicle
4654 vNext = MIN2(vNext, this->getSpeed() + accel * TS);
4655 vNext = MAX2(vNext, 0.);
4656 // and set the vehicle consumption to reflect this
4657 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4658 }
4659 }
4660
4661 setBrakingSignals(vNext);
4662
4663 // update position and speed
4664 int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
4665 const MSLane* oldLaneMaybeOpposite = myLane;
4667 // transform to the forward-direction lane, move and then transform back
4670 }
4671 updateState(vNext);
4672 updateWaitingTime(vNext);
4673
4674 // Lanes, which the vehicle touched at some moment of the executed simstep
4675 std::vector<MSLane*> passedLanes;
4676 // remember previous lane (myLane is updated in processLaneAdvances)
4677 const MSLane* oldLane = myLane;
4678 // Reason for a possible emergency stop
4679 std::string emergencyReason;
4680 processLaneAdvances(passedLanes, emergencyReason);
4681
4682 updateTimeLoss(vNext);
4684
4686 if (myState.myPos > myLane->getLength()) {
4687 if (emergencyReason == "") {
4688 emergencyReason = TL(" for unknown reasons");
4689 }
4690 WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
4691 getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
4696 myState.mySpeed = 0;
4697 myAcceleration = 0;
4698 }
4699 const MSLane* oldBackLane = getBackLane();
4701 passedLanes.clear(); // ignore back occupation
4702 }
4703#ifdef DEBUG_ACTIONSTEPS
4704 if (DEBUG_COND) {
4705 std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
4706 }
4707#endif
4709 if (passedLanes.size() > 1 && isRail()) {
4710 for (auto pi = passedLanes.rbegin(); pi != passedLanes.rend(); ++pi) {
4711 MSLane* pLane = *pi;
4712 if (pLane != myLane && std::find(myFurtherLanes.begin(), myFurtherLanes.end(), pLane) == myFurtherLanes.end()) {
4714 }
4715 }
4716 }
4717 // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
4719 if (myLane != oldLane || oldBackLane != getBackLane()) {
4720 if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
4721 // shadow lane must be updated if the front or back lane changed
4722 // either if we already have a shadowLane or if there is lateral overlap
4724 }
4726 // The vehicles target lane must be also be updated if the front or back lane changed
4728 }
4729 }
4730 setBlinkerInformation(); // needs updated bestLanes
4731 //change the blue light only for emergency vehicles SUMOVehicleClass
4733 setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
4734 }
4735 // must be done before angle computation
4736 // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
4737 if (myActionStep) {
4738 // check (#2681): Can this be skipped?
4740 } else {
4742#ifdef DEBUG_ACTIONSTEPS
4743 if (DEBUG_COND) {
4744 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
4745 }
4746#endif
4747 }
4750 }
4751
4752#ifdef DEBUG_EXEC_MOVE
4753 if (DEBUG_COND) {
4754 std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
4755 gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
4756 }
4757#endif
4759 // transform back to the opposite-direction lane
4760 MSLane* newOpposite = nullptr;
4761 const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
4762 if (newOppositeEdge != nullptr) {
4763 newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
4764#ifdef DEBUG_EXEC_MOVE
4765 if (DEBUG_COND) {
4766 std::cout << SIMTIME << " newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
4767 }
4768#endif
4769 }
4770 if (newOpposite == nullptr) {
4772 // unusual overtaking at junctions is ok for emergency vehicles
4773 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
4775 }
4777 if (myState.myPos < getLength()) {
4778 // further lanes is always cleared during opposite driving
4779 MSLane* oldOpposite = oldLane->getOpposite();
4780 if (oldOpposite != nullptr) {
4781 myFurtherLanes.push_back(oldOpposite);
4782 myFurtherLanesPosLat.push_back(0);
4783 // small value since the lane is going in the other direction
4786 } else {
4787 SOFT_ASSERT(false);
4788 }
4789 }
4790 } else {
4792 myLane = newOpposite;
4793 oldLane = oldLaneMaybeOpposite;
4794 //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
4797 }
4798 }
4800 // Return whether the vehicle did move to another lane
4801 return myLane != oldLane;
4802}
4803
4804void
4806 myState.myPos += dist;
4809
4810 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
4812 for (int i = 0; i < (int)lanes.size(); i++) {
4813 MSLink* link = nullptr;
4814 if (i + 1 < (int)lanes.size()) {
4815 const MSLane* const to = lanes[i + 1];
4816 const bool internal = to->isInternal();
4817 for (MSLink* const l : lanes[i]->getLinkCont()) {
4818 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
4819 link = l;
4820 break;
4821 }
4822 }
4823 }
4824 myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
4825 }
4826 // minimum execute move:
4827 std::vector<MSLane*> passedLanes;
4828 // Reason for a possible emergency stop
4829 if (lanes.size() > 1) {
4831 }
4832 std::string emergencyReason;
4833 processLaneAdvances(passedLanes, emergencyReason);
4834#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
4835 if (DEBUG_COND) {
4836 std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
4837 << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
4838 << " finalPos=" << myState.myPos
4839 << " speed=" << getSpeed()
4840 << " myFurtherLanes=" << toString(myFurtherLanes)
4841 << "\n";
4842 }
4843#endif
4845 if (lanes.size() > 1) {
4846 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
4847#ifdef DEBUG_FURTHER
4848 if (DEBUG_COND) {
4849 std::cout << SIMTIME << " leaveLane \n";
4850 }
4851#endif
4852 (*i)->resetPartialOccupation(this);
4853 }
4854 myFurtherLanes.clear();
4855 myFurtherLanesPosLat.clear();
4857 }
4858}
4859
4860
4861void
4862MSVehicle::updateState(double vNext, bool parking) {
4863 // update position and speed
4864 double deltaPos; // positional change
4866 // euler
4867 deltaPos = SPEED2DIST(vNext);
4868 } else {
4869 // ballistic
4870 deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
4871 }
4872
4873 // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
4874 // NOTE: for the ballistic update vNext may be negative, indicating a stop.
4876
4877#ifdef DEBUG_EXEC_MOVE
4878 if (DEBUG_COND) {
4879 std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
4880 << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
4881 }
4882#endif
4883 double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
4884 if (decelPlus > 0) {
4885 const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
4886 if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
4887 // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
4888 decelPlus += 2 * NUMERICAL_EPS;
4889 const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
4890 if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
4891 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
4892 //+ " decelPlus=" + toString(decelPlus)
4893 //+ " prevAccel=" + toString(previousAcceleration)
4894 //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
4895 getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
4897 }
4898 }
4899 }
4900
4902 myState.mySpeed = MAX2(vNext, 0.);
4903
4904 if (isRemoteControlled()) {
4905 deltaPos = myInfluencer->implicitDeltaPosRemote(this);
4906 }
4907
4908 myState.myPos += deltaPos;
4909 myState.myLastCoveredDist = deltaPos;
4910 myNextTurn.first -= deltaPos;
4911
4912 if (!parking) {
4914 }
4915}
4916
4917void
4919 updateState(0, true);
4920 // deboard while parked
4921 if (myPersonDevice != nullptr) {
4923 }
4924 if (myContainerDevice != nullptr) {
4926 }
4927 for (MSVehicleDevice* const dev : myDevices) {
4928 dev->notifyParking();
4929 }
4930}
4931
4932
4933void
4939
4940
4941const MSLane*
4943 if (myFurtherLanes.size() > 0) {
4944 return myFurtherLanes.back();
4945 } else {
4946 return myLane;
4947 }
4948}
4949
4950
4951double
4952MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
4953 const std::vector<MSLane*>& passedLanes) {
4954#ifdef DEBUG_SETFURTHER
4955 if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
4956 << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
4957 << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
4958 << " passed=" << toString(passedLanes)
4959 << "\n";
4960#endif
4961 for (MSLane* further : furtherLanes) {
4962 further->resetPartialOccupation(this);
4963 if (further->getBidiLane() != nullptr
4964 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4965 further->getBidiLane()->resetPartialOccupation(this);
4966 }
4967 }
4968
4969 std::vector<MSLane*> newFurther;
4970 std::vector<double> newFurtherPosLat;
4971 double backPosOnPreviousLane = myState.myPos - getLength();
4972 bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
4973 if (passedLanes.size() > 1) {
4974 // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
4975 std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
4976 std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
4977 for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
4978 // As long as vehicle back reaches into passed lane, add it to the further lanes
4979 MSLane* further = *pi;
4980 newFurther.push_back(further);
4981 backPosOnPreviousLane += further->setPartialOccupation(this);
4982 if (further->getBidiLane() != nullptr
4983 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
4984 further->getBidiLane()->setPartialOccupation(this);
4985 }
4986 if (fi != furtherLanes.end() && further == *fi) {
4987 // Lateral position on this lane is already known. Assume constant and use old value.
4988 newFurtherPosLat.push_back(*fpi);
4989 ++fi;
4990 ++fpi;
4991 } else {
4992 // The lane *pi was not in furtherLanes before.
4993 // If it is downstream, we assume as lateral position the current position
4994 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
4995 // we assign the last known lateral position.
4996 if (newFurtherPosLat.size() == 0) {
4997 if (widthShift) {
4998 newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
4999 } else {
5000 newFurtherPosLat.push_back(myState.myPosLat);
5001 }
5002 } else {
5003 newFurtherPosLat.push_back(newFurtherPosLat.back());
5004 }
5005 }
5006#ifdef DEBUG_SETFURTHER
5007 if (DEBUG_COND) {
5008 std::cout << SIMTIME << " updateFurtherLanes \n"
5009 << " further lane '" << further->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
5010 << std::endl;
5011 }
5012#endif
5013 }
5014 furtherLanes = newFurther;
5015 furtherLanesPosLat = newFurtherPosLat;
5016 } else {
5017 furtherLanes.clear();
5018 furtherLanesPosLat.clear();
5019 }
5020#ifdef DEBUG_SETFURTHER
5021 if (DEBUG_COND) std::cout
5022 << " newFurther=" << toString(furtherLanes)
5023 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
5024 << " newBackPos=" << backPosOnPreviousLane
5025 << "\n";
5026#endif
5027 return backPosOnPreviousLane;
5028}
5029
5030
5031double
5032MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
5033#ifdef DEBUG_FURTHER
5034 if (DEBUG_COND) {
5035 std::cout << SIMTIME
5036 << " getBackPositionOnLane veh=" << getID()
5037 << " lane=" << Named::getIDSecure(lane)
5038 << " cbgP=" << calledByGetPosition
5039 << " pos=" << myState.myPos
5040 << " backPos=" << myState.myBackPos
5041 << " myLane=" << myLane->getID()
5042 << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
5043 << " further=" << toString(myFurtherLanes)
5044 << " furtherPosLat=" << toString(myFurtherLanesPosLat)
5045 << "\n shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
5046 << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
5047 << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
5048 << "\n targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
5049 << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
5050 << std::endl;
5051 }
5052#endif
5053 if (lane == myLane
5054 || lane == myLaneChangeModel->getShadowLane()
5055 || lane == myLaneChangeModel->getTargetLane()) {
5057 if (lane == myLaneChangeModel->getShadowLane()) {
5058 return lane->getLength() - myState.myPos - myType->getLength();
5059 } else {
5060 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5061 }
5062 } else if (&lane->getEdge() != &myLane->getEdge()) {
5063 return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5064 } else {
5065 // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
5066 return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
5067 }
5068 } else if (lane == myLane->getBidiLane()) {
5069 return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
5070 } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
5071 return myState.myBackPos;
5072 } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
5073 || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
5074 assert(myFurtherLanes.size() > 0);
5075 if (lane->getLength() == myFurtherLanes.back()->getLength()) {
5076 return myState.myBackPos;
5077 } else {
5078 // interpolate
5079 //if (DEBUG_COND) {
5080 //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
5081 // std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
5082 // << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
5083 // << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
5084 //}
5085 return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
5086 }
5087 } else {
5088 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
5089 double leftLength = myType->getLength() - myState.myPos;
5090
5091 std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
5092 while (leftLength > 0 && i != myFurtherLanes.end()) {
5093 leftLength -= (*i)->getLength();
5094 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5095 if (*i == lane) {
5096 return -leftLength;
5097 } else if (*i == lane->getBidiLane()) {
5098 return lane->getLength() + leftLength - (calledByGetPosition ? 2 * myType->getLength() : 0);
5099 }
5100 ++i;
5101 }
5102 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
5103 leftLength = myType->getLength() - myState.myPos;
5105 while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
5106 leftLength -= (*i)->getLength();
5107 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5108 if (*i == lane) {
5109 return -leftLength;
5110 }
5111 ++i;
5112 }
5113 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
5114 leftLength = myType->getLength() - myState.myPos;
5115 i = getFurtherLanes().begin();
5116 const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
5117 auto j = furtherTargetLanes.begin();
5118 while (leftLength > 0 && j != furtherTargetLanes.end()) {
5119 leftLength -= (*i)->getLength();
5120 // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5121 if (*j == lane) {
5122 return -leftLength;
5123 }
5124 ++i;
5125 ++j;
5126 }
5127 WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
5128 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
5129 SOFT_ASSERT(false);
5130 return myState.myBackPos;
5131 }
5132}
5133
5134
5135double
5137 return getBackPositionOnLane(lane, true) + myType->getLength();
5138}
5139
5140
5141bool
5143 return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
5144}
5145
5146
5147void
5148MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
5150 double seenSpace = -lengthsInFront;
5151#ifdef DEBUG_CHECKREWINDLINKLANES
5152 if (DEBUG_COND) {
5153 std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
5154 };
5155#endif
5156 bool foundStopped = false;
5157 // compute available space until a stopped vehicle is found
5158 // this is the sum of non-interal lane length minus in-between vehicle lengths
5159 for (int i = 0; i < (int)lfLinks.size(); ++i) {
5160 // skip unset links
5161 DriveProcessItem& item = lfLinks[i];
5162#ifdef DEBUG_CHECKREWINDLINKLANES
5163 if (DEBUG_COND) std::cout << SIMTIME
5164 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5165 << " foundStopped=" << foundStopped;
5166#endif
5167 if (item.myLink == nullptr || foundStopped) {
5168 if (!foundStopped) {
5169 item.availableSpace += seenSpace;
5170 } else {
5171 item.availableSpace = seenSpace;
5172 }
5173#ifdef DEBUG_CHECKREWINDLINKLANES
5174 if (DEBUG_COND) {
5175 std::cout << " avail=" << item.availableSpace << "\n";
5176 }
5177#endif
5178 continue;
5179 }
5180 // get the next lane, determine whether it is an internal lane
5181 const MSLane* approachedLane = item.myLink->getViaLane();
5182 if (approachedLane != nullptr) {
5183 if (keepClear(item.myLink)) {
5184 seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
5185 if (approachedLane == myLane) {
5186 seenSpace += getVehicleType().getLengthWithGap();
5187 }
5188 } else {
5189 seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
5190 }
5191 item.availableSpace = seenSpace;
5192#ifdef DEBUG_CHECKREWINDLINKLANES
5193 if (DEBUG_COND) std::cout
5194 << " approached=" << approachedLane->getID()
5195 << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
5196 << " avail=" << item.availableSpace
5197 << " seenSpace=" << seenSpace
5198 << " hadStoppedVehicle=" << item.hadStoppedVehicle
5199 << " lengthsInFront=" << lengthsInFront
5200 << "\n";
5201#endif
5202 continue;
5203 }
5204 approachedLane = item.myLink->getLane();
5205 const MSVehicle* last = approachedLane->getLastAnyVehicle();
5206 if (last == nullptr || last == this) {
5207 if (approachedLane->getLength() > getVehicleType().getLength()
5208 || keepClear(item.myLink)) {
5209 seenSpace += approachedLane->getLength();
5210 }
5211 item.availableSpace = seenSpace;
5212#ifdef DEBUG_CHECKREWINDLINKLANES
5213 if (DEBUG_COND) {
5214 std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
5215 }
5216#endif
5217 } else {
5218 bool foundStopped2 = false;
5219 double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
5220 if (approachedLane->getBidiLane() != nullptr) {
5221 const MSVehicle* oncomingVeh = approachedLane->getBidiLane()->getFirstFullVehicle();
5222 if (oncomingVeh) {
5223 const double oncomingGap = approachedLane->getLength() - oncomingVeh->getPositionOnLane();
5224 const double oncomingBGap = oncomingVeh->getBrakeGap(true);
5225 // oncoming movement until ego enters the junction
5226 const double oncomingMove = STEPS2TIME(item.myArrivalTime - SIMSTEP) * oncomingVeh->getSpeed();
5227 const double spaceTillOncoming = oncomingGap - oncomingBGap - oncomingMove;
5228 spaceTillLastStanding = MIN2(spaceTillLastStanding, spaceTillOncoming);
5229 if (spaceTillOncoming <= getVehicleType().getLengthWithGap()) {
5230 foundStopped = true;
5231 }
5232#ifdef DEBUG_CHECKREWINDLINKLANES
5233 if (DEBUG_COND) {
5234 std::cout << " oVeh=" << oncomingVeh->getID()
5235 << " oGap=" << oncomingGap
5236 << " bGap=" << oncomingBGap
5237 << " mGap=" << oncomingMove
5238 << " sto=" << spaceTillOncoming;
5239 }
5240#endif
5241 }
5242 }
5243 seenSpace += spaceTillLastStanding;
5244 if (foundStopped2) {
5245 foundStopped = true;
5246 item.hadStoppedVehicle = true;
5247 }
5248 item.availableSpace = seenSpace;
5249 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
5250 foundStopped = true;
5251 item.hadStoppedVehicle = true;
5252 }
5253#ifdef DEBUG_CHECKREWINDLINKLANES
5254 if (DEBUG_COND) std::cout
5255 << " approached=" << approachedLane->getID()
5256 << " last=" << last->getID()
5257 << " lastHasToWait=" << last->myHaveToWaitOnNextLink
5258 << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
5259 << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
5260 << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
5261 // gap of last up to the next intersection
5262 - last->getVehicleType().getMinGap())
5263 << " stls=" << spaceTillLastStanding
5264 << " avail=" << item.availableSpace
5265 << " seenSpace=" << seenSpace
5266 << " foundStopped=" << foundStopped
5267 << " foundStopped2=" << foundStopped2
5268 << "\n";
5269#endif
5270 }
5271 }
5272
5273 // check which links allow continuation and add pass available to the previous item
5274 for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
5275 DriveProcessItem& item = lfLinks[i - 1];
5276 DriveProcessItem& nextItem = lfLinks[i];
5277 const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
5278 const bool opened = (item.myLink != nullptr
5279 && (canLeaveJunction || (
5280 // indirect bicycle turn
5281 nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
5282 && (
5283 item.myLink->havePriority()
5284 || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
5286 || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
5289 bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
5290#ifdef DEBUG_CHECKREWINDLINKLANES
5291 if (DEBUG_COND) std::cout
5292 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5293 << " canLeave=" << canLeaveJunction
5294 << " opened=" << opened
5295 << " allowsContinuation=" << allowsContinuation
5296 << " foundStopped=" << foundStopped
5297 << "\n";
5298#endif
5299 if (!opened && item.myLink != nullptr) {
5300 foundStopped = true;
5301 if (i > 1) {
5302 DriveProcessItem& item2 = lfLinks[i - 2];
5303 if (item2.myLink != nullptr && item2.myLink->isCont()) {
5304 allowsContinuation = true;
5305 }
5306 }
5307 }
5308 if (allowsContinuation) {
5309 item.availableSpace = nextItem.availableSpace;
5310#ifdef DEBUG_CHECKREWINDLINKLANES
5311 if (DEBUG_COND) std::cout
5312 << " link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5313 << " copy nextAvail=" << nextItem.availableSpace
5314 << "\n";
5315#endif
5316 }
5317 }
5318
5319 // find removalBegin
5320 int removalBegin = -1;
5321 for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
5322 // skip unset links
5323 const DriveProcessItem& item = lfLinks[i];
5324 if (item.myLink == nullptr) {
5325 continue;
5326 }
5327 /*
5328 double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
5329 if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
5330 removalBegin = lastLinkToInternal;
5331 }
5332 */
5333
5334 const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
5335#ifdef DEBUG_CHECKREWINDLINKLANES
5336 if (DEBUG_COND) std::cout
5337 << SIMTIME
5338 << " veh=" << getID()
5339 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5340 << " avail=" << item.availableSpace
5341 << " leftSpace=" << leftSpace
5342 << "\n";
5343#endif
5344 if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
5345 double impatienceCorrection = 0;
5346 /*
5347 if(item.myLink->getState()==LINKSTATE_MINOR) {
5348 impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
5349 }
5350 */
5351 // may ignore keepClear rules
5352 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
5353 removalBegin = i;
5354 }
5355 //removalBegin = i;
5356 }
5357 }
5358 // abort requests
5359 if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
5360 const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
5361 while (removalBegin < (int)(lfLinks.size())) {
5362 DriveProcessItem& dpi = lfLinks[removalBegin];
5363 if (dpi.myLink == nullptr) {
5364 break;
5365 }
5366 dpi.myVLinkPass = dpi.myVLinkWait;
5367#ifdef DEBUG_CHECKREWINDLINKLANES
5368 if (DEBUG_COND) {
5369 std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
5370 }
5371#endif
5372 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
5373 // always leave junctions after requesting to enter
5374 if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
5375 dpi.mySetRequest = false;
5376 }
5377 }
5378 ++removalBegin;
5379 }
5380 }
5381 }
5382}
5383
5384
5385void
5387 if (!myActionStep) {
5388 return;
5389 }
5391 for (DriveProcessItem& dpi : myLFLinkLanes) {
5392 if (dpi.myLink != nullptr) {
5393 if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
5394 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
5395 }
5396 dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5397 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance, getLateralPositionOnLane());
5398 }
5399 }
5400 if (isRail()) {
5401 for (DriveProcessItem& dpi : myLFLinkLanes) {
5402 if (dpi.myLink != nullptr && dpi.myLink->getTLLogic() != nullptr && dpi.myLink->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
5404 }
5405 }
5406 }
5407 if (myLaneChangeModel->getShadowLane() != nullptr) {
5408 // register on all shadow links
5409 for (const DriveProcessItem& dpi : myLFLinkLanes) {
5410 if (dpi.myLink != nullptr) {
5411 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
5412 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
5413 // register on opposite direction entry link to warn foes at minor side road
5414 parallelLink = dpi.myLink->getOppositeDirectionLink();
5415 }
5416 if (parallelLink != nullptr) {
5417 const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
5418 parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5419 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance,
5420 latOffset);
5422 }
5423 }
5424 }
5425 }
5426#ifdef DEBUG_PLAN_MOVE
5427 if (DEBUG_COND) {
5428 std::cout << SIMTIME
5429 << " veh=" << getID()
5430 << " after checkRewindLinkLanes\n";
5431 for (DriveProcessItem& dpi : myLFLinkLanes) {
5432 std::cout
5433 << " vPass=" << dpi.myVLinkPass
5434 << " vWait=" << dpi.myVLinkWait
5435 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
5436 << " request=" << dpi.mySetRequest
5437 << " atime=" << dpi.myArrivalTime
5438 << "\n";
5439 }
5440 }
5441#endif
5442}
5443
5444
5445void
5447 DriveProcessItem dpi(0, dist);
5448 dpi.myLink = link;
5449 const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
5450 link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
5451 // ensure cleanup in the next step
5452 myLFLinkLanes.push_back(dpi);
5454}
5455
5456
5457void
5458MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
5459 myAmOnNet = !onTeleporting;
5460 // vaporizing edge?
5461 /*
5462 if (enteredLane->getEdge().isVaporizing()) {
5463 // yep, let's do the vaporization...
5464 myLane = enteredLane;
5465 return true;
5466 }
5467 */
5468 // Adjust MoveReminder offset to the next lane
5469 adaptLaneEntering2MoveReminder(*enteredLane);
5470 // set the entered lane as the current lane
5471 MSLane* oldLane = myLane;
5472 myLane = enteredLane;
5473 myLastBestLanesEdge = nullptr;
5474
5475 // internal edges are not a part of the route...
5476 if (!enteredLane->getEdge().isInternal()) {
5477 ++myCurrEdge;
5479 }
5480 if (myInfluencer != nullptr) {
5482 }
5483 if (!onTeleporting) {
5487 // transform lateral position when the lane width changes
5488 assert(oldLane != nullptr);
5489 const MSLink* const link = oldLane->getLinkTo(myLane);
5490 if (link != nullptr) {
5491 myState.myPosLat += link->getLateralShift();
5492 } else {
5494 }
5495 } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
5496 const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
5497 const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5498 const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5499 myState.myPosLat *= range2 / range;
5500 }
5501 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5502 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5503 // (unless the lane is shared with cars)
5505 }
5506 } else {
5507 // normal move() isn't called so reset position here. must be done
5508 // before calling reminders
5509 myState.myPos = 0;
5512 }
5513 // update via
5514 if (myParameter->via.size() > 0 && myLane->getEdge().getID() == myParameter->via.front()) {
5515 myParameter->via.erase(myParameter->via.begin());
5516 }
5517}
5518
5519
5520void
5522 myAmOnNet = true;
5523 myLane = enteredLane;
5525 // need to update myCurrentLaneInBestLanes
5527 // switch to and activate the new lane's reminders
5528 // keep OldLaneReminders
5529 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5530 addReminder(*rem);
5531 }
5533 MSLane* lane = myLane;
5534 double leftLength = getVehicleType().getLength() - myState.myPos;
5535 int deleteFurther = 0;
5536#ifdef DEBUG_SETFURTHER
5537 if (DEBUG_COND) {
5538 std::cout << SIMTIME << " enterLaneAtLaneChange entered=" << Named::getIDSecure(enteredLane) << " oldFurther=" << toString(myFurtherLanes) << "\n";
5539 }
5540#endif
5541 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5542 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5543 // (unless the lane is shared with cars)
5545 }
5546 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
5547 if (lane != nullptr) {
5549 }
5550#ifdef DEBUG_SETFURTHER
5551 if (DEBUG_COND) {
5552 std::cout << " enterLaneAtLaneChange i=" << i << " lane=" << Named::getIDSecure(lane) << " leftLength=" << leftLength << "\n";
5553 }
5554#endif
5555 if (leftLength > 0) {
5556 if (lane != nullptr) {
5558 if (myFurtherLanes[i]->getBidiLane() != nullptr
5559 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5560 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5561 }
5562 // lane changing onto longer lanes may reduce the number of
5563 // remaining further lanes
5564 myFurtherLanes[i] = lane;
5566 leftLength -= lane->setPartialOccupation(this);
5567 if (lane->getBidiLane() != nullptr
5568 && (!isRailway(getVClass()) || (lane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5569 lane->getBidiLane()->setPartialOccupation(this);
5570 }
5571 myState.myBackPos = -leftLength;
5572#ifdef DEBUG_SETFURTHER
5573 if (DEBUG_COND) {
5574 std::cout << SIMTIME << " newBackPos=" << myState.myBackPos << "\n";
5575 }
5576#endif
5577 } else {
5578 // keep the old values, but ensure there is no shadow
5581 }
5582 if (myState.myBackPos < 0) {
5583 myState.myBackPos += myFurtherLanes[i]->getLength();
5584 }
5585#ifdef DEBUG_SETFURTHER
5586 if (DEBUG_COND) {
5587 std::cout << SIMTIME << " i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
5588 }
5589#endif
5590 }
5591 } else {
5592 myFurtherLanes[i]->resetPartialOccupation(this);
5593 if (myFurtherLanes[i]->getBidiLane() != nullptr
5594 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5595 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5596 }
5597 deleteFurther++;
5598 }
5599 }
5600 if (deleteFurther > 0) {
5601#ifdef DEBUG_SETFURTHER
5602 if (DEBUG_COND) {
5603 std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
5604 }
5605#endif
5606 myFurtherLanes.erase(myFurtherLanes.end() - deleteFurther, myFurtherLanes.end());
5607 myFurtherLanesPosLat.erase(myFurtherLanesPosLat.end() - deleteFurther, myFurtherLanesPosLat.end());
5608 }
5609#ifdef DEBUG_SETFURTHER
5610 if (DEBUG_COND) {
5611 std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
5612 << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
5613 }
5614#endif
5616}
5617
5618
5619void
5620MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
5621 // build the list of lanes the vehicle is lapping into
5622 if (!myLaneChangeModel->isOpposite()) {
5623 double leftLength = myType->getLength() - pos;
5624 MSLane* clane = enteredLane;
5625 int routeIndex = getRoutePosition();
5626 while (leftLength > 0) {
5627 if (routeIndex > 0 && clane->getEdge().isNormal()) {
5628 // get predecessor lane that corresponds to prior route
5629 routeIndex--;
5630 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
5631 MSLane* target = clane;
5632 clane = nullptr;
5633 for (auto ili : target->getIncomingLanes()) {
5634 if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
5635 clane = ili.lane;
5636 break;
5637 }
5638 }
5639 } else {
5640 clane = clane->getLogicalPredecessorLane();
5641 }
5642 if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
5643 || (clane->isInternal() && (
5644 clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
5645 || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
5646 break;
5647 }
5648 if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
5649 myFurtherLanes.push_back(clane);
5651 clane->setPartialOccupation(this);
5652 if (clane->getBidiLane() != nullptr
5653 && (!isRailway(getVClass()) || (clane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5654 clane->getBidiLane()->setPartialOccupation(this);
5655 }
5656 }
5657 leftLength -= clane->getLength();
5658 }
5659 myState.myBackPos = -leftLength;
5660#ifdef DEBUG_SETFURTHER
5661 if (DEBUG_COND) {
5662 std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
5663 }
5664#endif
5665 } else {
5666 // clear partial occupation
5667 for (MSLane* further : myFurtherLanes) {
5668#ifdef DEBUG_SETFURTHER
5669 if (DEBUG_COND) {
5670 std::cout << SIMTIME << " opposite: resetPartialOccupation " << further->getID() << " \n";
5671 }
5672#endif
5673 further->resetPartialOccupation(this);
5674 if (further->getBidiLane() != nullptr
5675 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5676 further->getBidiLane()->resetPartialOccupation(this);
5677 }
5678 }
5679 myFurtherLanes.clear();
5680 myFurtherLanesPosLat.clear();
5681 }
5682}
5683
5684
5685void
5686MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
5687 myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
5689 onDepart();
5690 }
5692 assert(myState.myPos >= 0);
5693 assert(myState.mySpeed >= 0);
5694 myLane = enteredLane;
5695 myAmOnNet = true;
5696 // schedule action for the next timestep
5698 if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
5699 if (notification == MSMoveReminder::NOTIFICATION_PARKING && myInfluencer != nullptr) {
5700 drawOutsideNetwork(false);
5701 }
5702 // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
5703 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5704 addReminder(*rem);
5705 }
5706 activateReminders(notification, enteredLane);
5707 } else {
5708 myLastBestLanesEdge = nullptr;
5711 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()
5712 && myStops.front().pars.endPos < pos) {
5713 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5714 time2string(MSNet::getInstance()->getCurrentTimeStep()));
5715 myStops.pop_front();
5716 }
5717
5718 }
5719 computeFurtherLanes(enteredLane, pos);
5723 } else if (MSGlobals::gLaneChangeDuration > 0) {
5725 }
5726 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5729 myAngle += M_PI;
5730 }
5731 }
5732 if (MSNet::getInstance()->hasPersons()) {
5733 for (MSLane* further : myFurtherLanes) {
5734 if (further->mustCheckJunctionCollisions()) {
5736 }
5737 }
5738 }
5739}
5740
5741
5742void
5743MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5744 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5745 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5746#ifdef _DEBUG
5747 if (myTraceMoveReminders) {
5748 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5749 }
5750#endif
5751 ++rem;
5752 } else {
5753#ifdef _DEBUG
5754 if (myTraceMoveReminders) {
5755 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5756 }
5757#endif
5758 rem = myMoveReminders.erase(rem);
5759 }
5760 }
5764 && myLane != nullptr) {
5766 }
5767 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
5768 && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5770 }
5772 // @note. In case of lane change, myFurtherLanes and partial occupation
5773 // are handled in enterLaneAtLaneChange()
5774 for (MSLane* further : myFurtherLanes) {
5775#ifdef DEBUG_FURTHER
5776 if (DEBUG_COND) {
5777 std::cout << SIMTIME << " leaveLane \n";
5778 }
5779#endif
5780 further->resetPartialOccupation(this);
5781 if (further->getBidiLane() != nullptr
5782 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5783 further->getBidiLane()->resetPartialOccupation(this);
5784 }
5785 }
5786 myFurtherLanes.clear();
5787 myFurtherLanesPosLat.clear();
5788 }
5790 myAmOnNet = false;
5791 myWaitingTime = 0;
5792 }
5794 myStopDist = std::numeric_limits<double>::max();
5795 if (myPastStops.back().speed <= 0) {
5796 WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
5797 }
5798 }
5800 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5801 if (myStops.front().getSpeed() <= 0) {
5802 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5803 time2string(MSNet::getInstance()->getCurrentTimeStep()))
5804 if (MSStopOut::active()) {
5805 // clean up if stopBlocked was called
5807 }
5808 myStops.pop_front();
5809 } else {
5810 MSStop& stop = myStops.front();
5811 // passed waypoint at the end of the lane
5812 if (!stop.reached) {
5813 if (MSStopOut::active()) {
5815 }
5816 stop.reached = true;
5817 // enter stopping place so leaveFrom works as expected
5818 if (stop.busstop != nullptr) {
5819 // let the bus stop know the vehicle
5820 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5821 }
5822 if (stop.containerstop != nullptr) {
5823 // let the container stop know the vehicle
5825 }
5826 // do not enter parkingarea!
5827 if (stop.chargingStation != nullptr) {
5828 // let the container stop know the vehicle
5830 }
5831 }
5833 }
5834 myStopDist = std::numeric_limits<double>::max();
5835 }
5836 }
5837}
5838
5839
5840void
5842 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5843 if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
5844#ifdef _DEBUG
5845 if (myTraceMoveReminders) {
5846 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
5847 }
5848#endif
5849 ++rem;
5850 } else {
5851#ifdef _DEBUG
5852 if (myTraceMoveReminders) {
5853 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
5854 }
5855#endif
5856 rem = myMoveReminders.erase(rem);
5857 }
5858 }
5859#ifdef DEBUG_MOVEREMINDERS
5860 if (DEBUG_COND) {
5861 std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
5862 for (auto rem : myMoveReminders) {
5863 std::cout << rem.first->getDescription() << " ";
5864 }
5865 std::cout << "\n";
5866 }
5867#endif
5868}
5869
5870
5875
5876
5881
5882bool
5884 return (lane->isInternal()
5885 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5886 : &lane->getEdge() != *myCurrEdge);
5887}
5888
5889const std::vector<MSVehicle::LaneQ>&
5891 return *myBestLanes.begin();
5892}
5893
5894
5895void
5896MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5897#ifdef DEBUG_BESTLANES
5898 if (DEBUG_COND) {
5899 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5900 }
5901#endif
5902 if (startLane == nullptr) {
5903 startLane = myLane;
5904 }
5905 assert(startLane != 0);
5907 // depending on the calling context, startLane might be the forward lane
5908 // or the reverse-direction lane. In the latter case we need to
5909 // transform it to the forward lane.
5910 if (isOppositeLane(startLane)) {
5911 // use leftmost lane of forward edge
5912 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5913 assert(startLane != 0);
5914#ifdef DEBUG_BESTLANES
5915 if (DEBUG_COND) {
5916 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5917 }
5918#endif
5919 }
5920 }
5921 if (forceRebuild) {
5922 myLastBestLanesEdge = nullptr;
5924 }
5925 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5927#ifdef DEBUG_BESTLANES
5928 if (DEBUG_COND) {
5929 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5930 }
5931#endif
5932 return;
5933 }
5934 if (startLane->getEdge().isInternal()) {
5935 if (myBestLanes.size() == 0 || forceRebuild) {
5936 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5937 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5938 }
5939 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5940#ifdef DEBUG_BESTLANES
5941 if (DEBUG_COND) {
5942 std::cout << " nothing to do on internal\n";
5943 }
5944#endif
5945 return;
5946 }
5947 // adapt best lanes to fit the current internal edge:
5948 // keep the entries that are reachable from this edge
5949 const MSEdge* nextEdge = startLane->getNextNormal();
5950 assert(!nextEdge->isInternal());
5951 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5952 std::vector<LaneQ>& lanes = *it;
5953 assert(lanes.size() > 0);
5954 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5955 // keep those lanes which are successors of internal lanes from the edge of startLane
5956 std::vector<LaneQ> oldLanes = lanes;
5957 lanes.clear();
5958 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
5959 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
5960 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
5961 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
5962 lanes.push_back(*it_lane);
5963 break;
5964 }
5965 }
5966 }
5967 assert(lanes.size() == startLane->getEdge().getLanes().size());
5968 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
5969 for (int i = 0; i < (int)lanes.size(); ++i) {
5970 if (i + lanes[i].bestLaneOffset < 0) {
5971 lanes[i].bestLaneOffset = -i;
5972 }
5973 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
5974 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
5975 }
5976 assert(i + lanes[i].bestLaneOffset >= 0);
5977 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
5978 if (lanes[i].bestContinuations[0] != 0) {
5979 // patch length of bestContinuation to match expectations (only once)
5980 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
5981 }
5982 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
5983 myCurrentLaneInBestLanes = lanes.begin() + i;
5984 }
5985 assert(&(lanes[i].lane->getEdge()) == nextEdge);
5986 }
5987 myLastBestLanesInternalLane = startLane;
5989#ifdef DEBUG_BESTLANES
5990 if (DEBUG_COND) {
5991 std::cout << " updated for internal\n";
5992 }
5993#endif
5994 return;
5995 } else {
5996 // remove passed edges
5997 it = myBestLanes.erase(it);
5998 }
5999 }
6000 assert(false); // should always find the next edge
6001 }
6002 // start rebuilding
6004 myLastBestLanesEdge = &startLane->getEdge();
6006
6007 // get information about the next stop
6008 MSRouteIterator nextStopEdge = myRoute->end();
6009 const MSLane* nextStopLane = nullptr;
6010 double nextStopPos = 0;
6011 bool nextStopIsWaypoint = false;
6012 if (!myStops.empty()) {
6013 const MSStop& nextStop = myStops.front();
6014 nextStopLane = nextStop.lane;
6015 if (nextStop.isOpposite) {
6016 // target leftmost lane in forward direction
6017 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
6018 }
6019 nextStopEdge = nextStop.edge;
6020 nextStopPos = nextStop.pars.startPos;
6021 nextStopIsWaypoint = nextStop.getSpeed() > 0;
6022 }
6023 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
6024 if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
6025 nextStopEdge = (myRoute->end() - 1);
6026 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
6027 nextStopPos = myArrivalPos;
6028 }
6029 if (nextStopEdge != myRoute->end()) {
6030 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
6031 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
6032 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
6033 if (nextStopLane->isInternal()) {
6034 // switch to the correct lane before entering the intersection
6035 nextStopPos = (*nextStopEdge)->getLength();
6036 }
6037 }
6038
6039 // go forward along the next lanes;
6040 // trains do not have to deal with lane-changing for stops but their best
6041 // lanes lookahead is needed for rail signal control
6042 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
6043 int seen = 0;
6044 double seenLength = 0;
6045 bool progress = true;
6046 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
6047 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
6048 const double lookahead = getLaneChangeModel().getStrategicLookahead();
6049 for (MSRouteIterator ce = myCurrEdge; progress;) {
6050 std::vector<LaneQ> currentLanes;
6051 const std::vector<MSLane*>* allowed = nullptr;
6052 const MSEdge* nextEdge = nullptr;
6053 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
6054 nextEdge = *(ce + 1);
6055 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
6056 }
6057 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
6058 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
6059 LaneQ q;
6060 MSLane* cl = *i;
6061 q.lane = cl;
6062 q.bestContinuations.push_back(cl);
6063 q.bestLaneOffset = 0;
6064 q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
6065 q.currentLength = q.length;
6066 // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
6067 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
6068 q.occupation = 0;
6069 q.nextOccupation = 0;
6070 currentLanes.push_back(q);
6071 }
6072 //
6073 if (nextStopEdge == ce
6074 // already past the stop edge
6075 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
6076 if (!nextStopLane->isInternal() && !continueAfterStop) {
6077 progress = false;
6078 }
6079 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
6080 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
6081 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
6082 (*q).allowsContinuation = false;
6083 (*q).length = nextStopPos;
6084 (*q).currentLength = (*q).length;
6085 }
6086 }
6087 }
6088
6089 myBestLanes.push_back(currentLanes);
6090 ++seen;
6091 seenLength += currentLanes[0].lane->getLength();
6092 ++ce;
6093 if (lookahead >= 0) {
6094 progress &= (seen <= 2 || seenLength < lookahead); // custom (but we need to look at least one edge ahead)
6095 } else {
6096 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
6097 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
6098 }
6099 progress &= ce != myRoute->end();
6100 /*
6101 if(progress) {
6102 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
6103 }
6104 */
6105 }
6106
6107 // we are examining the last lane explicitly
6108 if (myBestLanes.size() != 0) {
6109 double bestLength = -1;
6110 // minimum and maximum lane index with best length
6111 int bestThisIndex = 0;
6112 int bestThisMaxIndex = 0;
6113 int index = 0;
6114 std::vector<LaneQ>& last = myBestLanes.back();
6115 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6116 if ((*j).length > bestLength) {
6117 bestLength = (*j).length;
6118 bestThisIndex = index;
6119 bestThisMaxIndex = index;
6120 } else if ((*j).length == bestLength) {
6121 bestThisMaxIndex = index;
6122 }
6123 }
6124 index = 0;
6125 bool requiredChangeRightForbidden = false;
6126 int requireChangeToLeftForbidden = -1;
6127 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6128 if ((*j).length < bestLength) {
6129 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6130 (*j).bestLaneOffset = bestThisIndex - index;
6131 } else {
6132 (*j).bestLaneOffset = bestThisMaxIndex - index;
6133 }
6134 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6135 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6136 || requiredChangeRightForbidden)) {
6137 // this lane and all further lanes to the left cannot be used
6138 requiredChangeRightForbidden = true;
6139 (*j).length = 0;
6140 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6141 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6142 // this lane and all previous lanes to the right cannot be used
6143 requireChangeToLeftForbidden = (*j).lane->getIndex();
6144 }
6145 }
6146 }
6147 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
6148 if (last[i].bestLaneOffset > 0) {
6149 last[i].length = 0;
6150 }
6151 }
6152#ifdef DEBUG_BESTLANES
6153 if (DEBUG_COND) {
6154 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6155 std::vector<LaneQ>& laneQs = myBestLanes.back();
6156 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6157 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
6158 }
6159 }
6160#endif
6161 }
6162 // go backward through the lanes
6163 // track back best lane and compute the best prior lane(s)
6164 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
6165 std::vector<LaneQ>& nextLanes = (*(i - 1));
6166 std::vector<LaneQ>& clanes = (*i);
6167 MSEdge* const cE = &clanes[0].lane->getEdge();
6168 int index = 0;
6169 double bestConnectedLength = -1;
6170 double bestLength = -1;
6171 for (const LaneQ& j : nextLanes) {
6172 if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
6173 bestConnectedLength = j.length;
6174 }
6175 if (bestLength < j.length) {
6176 bestLength = j.length;
6177 }
6178 }
6179 // compute index of the best lane (highest length and least offset from the best next lane)
6180 int bestThisIndex = 0;
6181 int bestThisMaxIndex = 0;
6182 if (bestConnectedLength > 0) {
6183 index = 0;
6184 for (LaneQ& j : clanes) {
6185 const LaneQ* bestConnectedNext = nullptr;
6186 if (j.allowsContinuation) {
6187 for (const LaneQ& m : nextLanes) {
6188 if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
6189 && m.lane->isApproachedFrom(cE, j.lane)) {
6190 if (betterContinuation(bestConnectedNext, m)) {
6191 bestConnectedNext = &m;
6192 }
6193 }
6194 }
6195 if (bestConnectedNext != nullptr) {
6196 if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
6197 j.length += bestLength;
6198 } else {
6199 j.length += bestConnectedNext->length;
6200 }
6201 j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
6202 }
6203 }
6204 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
6205 copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
6206 } else {
6207 j.allowsContinuation = false;
6208 }
6209 if (clanes[bestThisIndex].length < j.length
6210 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
6211 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
6212 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
6213 ) {
6214 bestThisIndex = index;
6215 bestThisMaxIndex = index;
6216 } else if (clanes[bestThisIndex].length == j.length
6217 && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
6218 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
6219 bestThisMaxIndex = index;
6220 }
6221 index++;
6222 }
6223
6224 //vehicle with elecHybrid device prefers running under an overhead wire
6225 if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
6226 index = 0;
6227 for (const LaneQ& j : clanes) {
6228 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6229 if (overheadWireSegmentID != "") {
6230 bestThisIndex = index;
6231 bestThisMaxIndex = index;
6232 }
6233 index++;
6234 }
6235 }
6236
6237 } else {
6238 // only needed in case of disconnected routes
6239 int bestNextIndex = 0;
6240 int bestDistToNeeded = (int) clanes.size();
6241 index = 0;
6242 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6243 if ((*j).allowsContinuation) {
6244 int nextIndex = 0;
6245 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
6246 if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
6247 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
6248 bestDistToNeeded = abs((*m).bestLaneOffset);
6249 bestThisIndex = index;
6250 bestThisMaxIndex = index;
6251 bestNextIndex = nextIndex;
6252 }
6253 }
6254 }
6255 }
6256 }
6257 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
6258 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
6259
6260 }
6261 // set bestLaneOffset for all lanes
6262 index = 0;
6263 bool requiredChangeRightForbidden = false;
6264 int requireChangeToLeftForbidden = -1;
6265 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6266 if ((*j).length < clanes[bestThisIndex].length
6267 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
6268 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
6269 ) {
6270 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6271 (*j).bestLaneOffset = bestThisIndex - index;
6272 } else {
6273 (*j).bestLaneOffset = bestThisMaxIndex - index;
6274 }
6275 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
6276 // try to move away from the lower-priority lane before it ends
6277 (*j).length = (*j).currentLength;
6278 }
6279 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6280 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6281 || requiredChangeRightForbidden)) {
6282 // this lane and all further lanes to the left cannot be used
6283 requiredChangeRightForbidden = true;
6284 if ((*j).length == (*j).currentLength) {
6285 (*j).length = 0;
6286 }
6287 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6288 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6289 // this lane and all previous lanes to the right cannot be used
6290 requireChangeToLeftForbidden = (*j).lane->getIndex();
6291 }
6292 } else {
6293 (*j).bestLaneOffset = 0;
6294 }
6295 }
6296 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
6297 if (clanes[idx].length == clanes[idx].currentLength) {
6298 clanes[idx].length = 0;
6299 };
6300 }
6301
6302 //vehicle with elecHybrid device prefers running under an overhead wire
6303 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
6304 index = 0;
6305 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6306 if (overheadWireID != "") {
6307 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6308 (*j).bestLaneOffset = bestThisIndex - index;
6309 }
6310 }
6311 }
6312
6313#ifdef DEBUG_BESTLANES
6314 if (DEBUG_COND) {
6315 std::cout << " edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6316 std::vector<LaneQ>& laneQs = clanes;
6317 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6318 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
6319 }
6320 }
6321#endif
6322
6323 }
6325#ifdef DEBUG_BESTLANES
6326 if (DEBUG_COND) {
6327 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
6328 }
6329#endif
6330}
6331
6332void
6334 if (myLane != nullptr) {
6336 }
6337}
6338
6339bool
6340MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
6341 if (bestConnectedNext == nullptr) {
6342 return true;
6343 } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
6344 return false;
6345 } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
6346 return true;
6347 } else if (bestConnectedNext->length < m.length) {
6348 return true;
6349 } else if (bestConnectedNext->length == m.length) {
6350 if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
6351 return true;
6352 }
6353 const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
6354 if (contRight < 1
6355 // if we don't check for adjacency, the rightmost line will get
6356 // multiple chances to be better which leads to an uninituitve distribution
6357 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
6358 && RandHelper::rand(getRNG()) > contRight) {
6359 return true;
6360 }
6361 }
6362 return false;
6363}
6364
6365
6366int
6367MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
6368 if (conts.size() < 2) {
6369 return -1;
6370 } else {
6371 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
6372 if (link != nullptr) {
6373 return link->havePriority() ? 1 : 0;
6374 } else {
6375 // disconnected route
6376 return -1;
6377 }
6378 }
6379}
6380
6381
6382void
6384 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
6385 std::vector<LaneQ>::iterator i;
6386 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
6387 double nextOccupation = 0;
6388 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
6389 nextOccupation += (*j)->getBruttoVehLenSum();
6390 }
6391 (*i).nextOccupation = nextOccupation;
6392#ifdef DEBUG_BESTLANES
6393 if (DEBUG_COND) {
6394 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
6395 }
6396#endif
6397 if ((*i).lane == startLane) {
6399 }
6400 }
6401}
6402
6403
6404const std::vector<MSLane*>&
6406 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6407 return myEmptyLaneVector;
6408 }
6409 return (*myCurrentLaneInBestLanes).bestContinuations;
6410}
6411
6412
6413const std::vector<MSLane*>&
6415 const MSLane* lane = l;
6416 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
6417 if (lane->getEdge().isInternal()) {
6418 // internal edges are not kept inside the bestLanes structure
6419 lane = lane->getLinkCont()[0]->getLane();
6420 }
6421 if (myBestLanes.size() == 0) {
6422 return myEmptyLaneVector;
6423 }
6424 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
6425 if ((*i).lane == lane) {
6426 return (*i).bestContinuations;
6427 }
6428 }
6429 return myEmptyLaneVector;
6430}
6431
6432const std::vector<const MSLane*>
6433MSVehicle::getUpcomingLanesUntil(double distance) const {
6434 std::vector<const MSLane*> lanes;
6435
6436 if (distance <= 0. || hasArrived()) {
6437 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
6438 return lanes;
6439 }
6440
6441 if (!myLaneChangeModel->isOpposite()) {
6442 distance += getPositionOnLane();
6443 } else {
6444 distance += myLane->getOppositePos(getPositionOnLane());
6445 }
6447 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6448 lanes.insert(lanes.end(), lane);
6449 distance -= lane->getLength();
6450 lane = lane->getLinkCont().front()->getViaLaneOrLane();
6451 }
6452
6453 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
6454 if (contLanes.empty()) {
6455 return lanes;
6456 }
6457 auto contLanesIt = contLanes.begin();
6458 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
6459 while (distance > 0.) {
6460 MSLane* l = nullptr;
6461 if (contLanesIt != contLanes.end()) {
6462 l = *contLanesIt;
6463 if (l != nullptr) {
6464 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
6465 }
6466 ++contLanesIt;
6467 if (l != nullptr || myLane->isInternal()) {
6468 ++routeIt;
6469 }
6470 if (l == nullptr) {
6471 continue;
6472 }
6473 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
6474 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6475 l = (*routeIt)->getLanes().back();
6476 ++routeIt;
6477 } else { // the search distance goes beyond our route
6478 break;
6479 }
6480
6481 assert(l != nullptr);
6482
6483 // insert internal lanes if applicable
6484 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
6485 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
6486 lanes.insert(lanes.end(), internalLane);
6487 distance -= internalLane->getLength();
6488 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6489 }
6490 if (distance <= 0.) {
6491 break;
6492 }
6493
6494 lanes.insert(lanes.end(), l);
6495 distance -= l->getLength();
6496 }
6497
6498 return lanes;
6499}
6500
6501const std::vector<const MSLane*>
6502MSVehicle::getPastLanesUntil(double distance) const {
6503 std::vector<const MSLane*> lanes;
6504
6505 if (distance <= 0.) {
6506 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
6507 return lanes;
6508 }
6509
6510 MSRouteIterator routeIt = myCurrEdge;
6511 if (!myLaneChangeModel->isOpposite()) {
6512 distance += myLane->getLength() - getPositionOnLane();
6513 } else {
6515 }
6517 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6518 lanes.insert(lanes.end(), lane);
6519 distance -= lane->getLength();
6520 lane = lane->getLogicalPredecessorLane();
6521 }
6522
6523 while (distance > 0.) {
6524 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6525 MSLane* l = (*routeIt)->getLanes().back();
6526
6527 // insert internal lanes if applicable
6528 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
6529 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
6530 std::vector<const MSLane*> internalLanes;
6531 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
6532 internalLanes.insert(internalLanes.begin(), internalLane);
6533 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6534 }
6535 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
6536 lanes.insert(lanes.end(), *it);
6537 distance -= (*it)->getLength();
6538 }
6539 if (distance <= 0.) {
6540 break;
6541 }
6542
6543 lanes.insert(lanes.end(), l);
6544 distance -= l->getLength();
6545
6546 // NOTE: we're going backwards with the (bi-directional) Iterator
6547 // TODO: consider make reverse_iterator() when moving on to C++14 or later
6548 if (routeIt != myRoute->begin()) {
6549 --routeIt;
6550 } else { // we went backwards to begin() and already processed the first and final element
6551 break;
6552 }
6553 }
6554
6555 return lanes;
6556}
6557
6558
6559const std::vector<MSLane*>
6561 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6562 std::vector<MSLane*> result;
6563 for (const MSLane* lane : routeLanes) {
6564 MSLane* opposite = lane->getOpposite();
6565 if (opposite != nullptr) {
6566 result.push_back(opposite);
6567 } else {
6568 break;
6569 }
6570 }
6571 return result;
6572}
6573
6574
6575int
6577 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6578 return 0;
6579 } else {
6580 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6581 }
6582}
6583
6584double
6586 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6587 return -1;
6588 } else {
6589 return (*myCurrentLaneInBestLanes).length;
6590 }
6591}
6592
6593
6594
6595void
6596MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6597 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6598 assert(laneIndex < (int)preb.size());
6599 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6600}
6601
6602
6603void
6609
6610std::pair<const MSLane*, double>
6611MSVehicle::getLanePosAfterDist(double distance) const {
6612 if (distance == 0) {
6613 return std::make_pair(myLane, getPositionOnLane());
6614 }
6615 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6616 distance += getPositionOnLane();
6617 for (const MSLane* lane : lanes) {
6618 if (lane->getLength() > distance) {
6619 return std::make_pair(lane, distance);
6620 }
6621 distance -= lane->getLength();
6622 }
6623 return std::make_pair(nullptr, -1);
6624}
6625
6626
6627double
6628MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
6629 if (isOnRoad() && destLane != nullptr) {
6630 return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
6631 }
6632 return std::numeric_limits<double>::max();
6633}
6634
6635
6636std::pair<const MSVehicle* const, double>
6637MSVehicle::getLeader(double dist, bool considerCrossingFoes) const {
6638 if (myLane == nullptr) {
6639 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6640 }
6641 if (dist == 0) {
6643 }
6644 const MSVehicle* lead = nullptr;
6645 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6646 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6647 // vehicle might be outside the road network
6648 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6649 if (it != vehs.end() && it + 1 != vehs.end()) {
6650 lead = *(it + 1);
6651 }
6652 if (lead != nullptr) {
6653 std::pair<const MSVehicle* const, double> result(
6654 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6655 lane->releaseVehicles();
6656 return result;
6657 }
6658 const double seen = myLane->getLength() - getPositionOnLane();
6659 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6660 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts, considerCrossingFoes);
6661 lane->releaseVehicles();
6662 return result;
6663}
6664
6665
6666std::pair<const MSVehicle* const, double>
6667MSVehicle::getFollower(double dist) const {
6668 if (myLane == nullptr) {
6669 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6670 }
6671 if (dist == 0) {
6672 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6673 }
6675}
6676
6677
6678double
6680 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6681 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6682 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6683 return -1;
6684 }
6685 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6686}
6687
6688
6689void
6691 MSBaseVehicle::addTransportable(transportable);
6692 if (myStops.size() > 0 && myStops.front().reached) {
6693 if (transportable->isPerson()) {
6694 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6695 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6696 }
6697 } else {
6698 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6699 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6700 }
6701 }
6702 }
6703}
6704
6705
6706void
6709 int state = myLaneChangeModel->getOwnState();
6710 // do not set blinker for sublane changes or when blocked from changing to the right
6711 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6712 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6716 // lane indices increase from left to right
6717 std::swap(left, right);
6718 }
6719 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6720 switchOnSignal(left);
6721 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6722 switchOnSignal(right);
6723 } else if (myLaneChangeModel->isChangingLanes()) {
6725 switchOnSignal(left);
6726 } else {
6727 switchOnSignal(right);
6728 }
6729 } else {
6730 const MSLane* lane = getLane();
6731 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6732 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6733 switch ((*link)->getDirection()) {
6738 break;
6742 break;
6743 default:
6744 break;
6745 }
6746 }
6747 }
6748 // stopping related signals
6749 if (hasStops()
6750 && (myStops.begin()->reached ||
6752 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6753 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6754 // not stopping on the right. Activate emergency blinkers
6756 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6757 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6759 }
6760 }
6761 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6763 myInfluencer->setSignals(-1); // overwrite computed signals only once
6764 }
6765}
6766
6767void
6769
6770 //TODO look if timestep ist SIMSTEP
6771 if (currentTime % 1000 == 0) {
6774 } else {
6776 }
6777 }
6778}
6779
6780
6781int
6783 return myLane == nullptr ? -1 : myLane->getIndex();
6784}
6785
6786
6787void
6788MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6789 myLane = lane;
6790 myState.myPos = pos;
6791 myState.myPosLat = posLat;
6793}
6794
6795
6796double
6798 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6799}
6800
6801
6802double
6804 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6805}
6806
6807
6808double
6810 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6811}
6812
6813
6814double
6816 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6817}
6818
6819
6820double
6822 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6823}
6824
6825
6826double
6828 return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
6829}
6830
6831
6832double
6834 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6836 } else if (lane == myLaneChangeModel->getShadowLane()) {
6837 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6838 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6839 }
6841 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6842 } else {
6843 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6844 }
6845 } else if (lane == myLane->getBidiLane()) {
6846 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6847 } else {
6848 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6849 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6850 if (myFurtherLanes[i] == lane) {
6851#ifdef DEBUG_FURTHER
6852 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
6853 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6854 << "\n";
6855#endif
6856 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6857 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6858#ifdef DEBUG_FURTHER
6859 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
6860 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6861 << "\n";
6862#endif
6863 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6864 }
6865 }
6866 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6867 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6868 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6869 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6870 if (shadowFurther[i] == lane) {
6871 assert(myLaneChangeModel->getShadowLane() != 0);
6872 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6874 }
6875 }
6876 assert(false);
6877 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6878 }
6879}
6880
6881
6882double
6884 assert(lane != 0);
6885 if (&lane->getEdge() == &myLane->getEdge()) {
6886 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6887 } else if (myLane->getParallelOpposite() == lane) {
6888 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6889 } else if (myLane->getBidiLane() == lane) {
6890 return -2 * getLateralPositionOnLane();
6891 } else {
6892 // Check whether the lane is a further lane for the vehicle
6893 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6894 if (myFurtherLanes[i] == lane) {
6895#ifdef DEBUG_FURTHER
6896 if (DEBUG_COND) {
6897 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6898 }
6899#endif
6901 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6902#ifdef DEBUG_FURTHER
6903 if (DEBUG_COND) {
6904 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
6905 }
6906#endif
6907 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
6908 }
6909 }
6910#ifdef DEBUG_FURTHER
6911 if (DEBUG_COND) {
6912 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6913 }
6914#endif
6915 // Check whether the lane is a "shadow further lane" for the vehicle
6916 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6917 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6918 if (shadowFurther[i] == lane) {
6919#ifdef DEBUG_FURTHER
6920 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6921 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6922 << " lane=" << lane->getID()
6923 << " i=" << i
6924 << " posLat=" << myState.myPosLat
6925 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6926 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6927 << "\n";
6928#endif
6930 }
6931 }
6932 // Check whether the vehicle issued a maneuverReservation on the lane.
6933 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6934 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6935 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6936 MSLane* targetLane = furtherTargets[i];
6937 if (targetLane == lane) {
6938 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6939 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
6940#ifdef DEBUG_TARGET_LANE
6941 if (DEBUG_COND) {
6942 std::cout << " getLatOffset veh=" << getID()
6943 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
6944 << "\n i=" << i
6945 << " posLat=" << myState.myPosLat
6946 << " furtherPosLat=" << myFurtherLanesPosLat[i]
6947 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
6948 << " targetDir=" << targetDir
6949 << " latOffset=" << latOffset
6950 << std::endl;
6951 }
6952#endif
6953 return latOffset;
6954 }
6955 }
6956 assert(false);
6957 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6958 }
6959}
6960
6961
6962double
6963MSVehicle::lateralDistanceToLane(const int offset) const {
6964 // compute the distance when changing to the neighboring lane
6965 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
6966 assert(offset == 0 || offset == 1 || offset == -1);
6967 assert(myLane != nullptr);
6968 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
6969 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
6970 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
6971 const double latPos = getLateralPositionOnLane();
6972 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
6973 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
6974 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
6975 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
6976 if (offset == 0) {
6977 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
6978 // correct overlapping left
6979 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
6980 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
6981 // correct overlapping right
6982 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
6983 }
6984 latLaneDist *= oppositeSign;
6985 } else if (offset == -1) {
6986 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
6987 } else if (offset == 1) {
6988 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
6989 }
6990#ifdef DEBUG_ACTIONSTEPS
6991 if (DEBUG_COND) {
6992 std::cout << SIMTIME
6993 << " veh=" << getID()
6994 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
6995 << " halfVehWidth=" << halfVehWidth
6996 << " latPos=" << latPos
6997 << " latLaneDist=" << latLaneDist
6998 << " leftLimit=" << leftLimit
6999 << " rightLimit=" << rightLimit
7000 << "\n";
7001 }
7002#endif
7003 return latLaneDist;
7004}
7005
7006
7007double
7008MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
7009 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
7010 - 0.5 * lane->getWidth());
7011}
7012
7013double
7017
7018double
7022
7023
7024void
7026 for (const DriveProcessItem& dpi : lfLinks) {
7027 if (dpi.myLink != nullptr) {
7028 dpi.myLink->removeApproaching(this);
7029 }
7030 }
7031 // unregister on all shadow links
7033}
7034
7035
7036bool
7037MSVehicle::unsafeLinkAhead(const MSLane* lane, double zipperDist) const {
7038 // the following links are unsafe:
7039 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
7040 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
7041 double seen = myLane->getLength() - getPositionOnLane();
7042 const double dist = MAX2(zipperDist, getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0));
7043 if (seen < dist) {
7044 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
7045 int view = 1;
7046 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7047 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
7048 while (!lane->isLinkEnd(link) && seen <= dist) {
7049 if ((!lane->isInternal()
7050 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
7051 || !(*link)->havePriority()))
7052 || (lane->isInternal() && zipperDist > 0)) {
7053 // find the drive item corresponding to this link
7054 bool found = false;
7055 while (di != myLFLinkLanes.end() && !found) {
7056 if ((*di).myLink != nullptr) {
7057 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
7058 if (diPredLane != nullptr) {
7059 if (&diPredLane->getEdge() == &lane->getEdge()) {
7060 found = true;
7061 }
7062 }
7063 }
7064 if (!found) {
7065 di++;
7066 }
7067 }
7068 if (found) {
7069 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
7070 (*di).getLeaveSpeed(), getVehicleType().getLength());
7071 const MSLink* entry = (*link)->getCorrespondingEntryLink();
7072 //if (DEBUG_COND) {
7073 // 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";
7074 //}
7075 if (entry->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
7076 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
7077 return true;
7078 }
7079 }
7080 // no drive item is found if the vehicle aborts its request within dist
7081 }
7082 lane = (*link)->getViaLaneOrLane();
7083 if (!lane->getEdge().isInternal()) {
7084 view++;
7085 }
7086 seen += lane->getLength();
7087 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7088 }
7089 }
7090 return false;
7091}
7092
7093
7095MSVehicle::getBoundingBox(double offset) const {
7096 PositionVector centerLine;
7097 Position pos = getPosition();
7098 centerLine.push_back(pos);
7099 switch (myType->getGuiShape()) {
7106 for (MSLane* lane : myFurtherLanes) {
7107 centerLine.push_back(lane->getShape().back());
7108 }
7109 break;
7110 }
7111 default:
7112 break;
7113 }
7114 double l = getLength();
7115 Position backPos = getBackPosition();
7116 if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
7117 // getBackPosition may not match the visual back in networks without internal lanes
7118 double a = getAngle() + M_PI; // angle pointing backwards
7119 backPos = pos + Position(l * cos(a), l * sin(a));
7120 }
7121 centerLine.push_back(backPos);
7122 if (offset != 0) {
7123 centerLine.extrapolate2D(offset);
7124 }
7125 PositionVector result = centerLine;
7126 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7127 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
7128 result.append(centerLine.reverse(), POSITION_EPS);
7129 return result;
7130}
7131
7132
7134MSVehicle::getBoundingPoly(double offset) const {
7135 switch (myType->getGuiShape()) {
7141 // box with corners cut off
7142 PositionVector result;
7143 PositionVector centerLine;
7144 centerLine.push_back(getPosition());
7145 centerLine.push_back(getBackPosition());
7146 if (offset != 0) {
7147 centerLine.extrapolate2D(offset);
7148 }
7149 PositionVector line1 = centerLine;
7150 PositionVector line2 = centerLine;
7151 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
7152 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7153 line2.scaleRelative(0.8);
7154 result.push_back(line1[0]);
7155 result.push_back(line2[0]);
7156 result.push_back(line2[1]);
7157 result.push_back(line1[1]);
7158 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
7159 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
7160 result.push_back(line1[1]);
7161 result.push_back(line2[1]);
7162 result.push_back(line2[0]);
7163 result.push_back(line1[0]);
7164 return result;
7165 }
7166 default:
7167 return getBoundingBox();
7168 }
7169}
7170
7171
7172bool
7174 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
7175 if (&(*i)->getEdge() == edge) {
7176 return true;
7177 }
7178 }
7179 return false;
7180}
7181
7182
7183bool
7184MSVehicle::isBidiOn(const MSLane* lane) const {
7185 return lane->getBidiLane() != nullptr && (
7186 myLane == lane->getBidiLane()
7187 || onFurtherEdge(&lane->getBidiLane()->getEdge()));
7188}
7189
7190
7191bool
7192MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
7193 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
7194 // consistency in the behaviour.
7195
7196 // get vehicle params
7197 MSParkingArea* destParkArea = getNextParkingArea();
7198 const MSRoute& route = getRoute();
7199 const MSEdge* lastEdge = route.getLastEdge();
7200
7201 if (destParkArea == nullptr) {
7202 // not driving towards a parking area
7203 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
7204 return false;
7205 }
7206
7207 // if the current route ends at the parking area, the new route will also and at the new area
7208 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
7209 && getArrivalPos() >= destParkArea->getBeginLanePosition()
7210 && getArrivalPos() <= destParkArea->getEndLanePosition());
7211
7212 // retrieve info on the new parking area
7214 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
7215
7216 if (newParkingArea == nullptr) {
7217 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
7218 return false;
7219 }
7220
7221 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
7223
7224 // Compute the route from the current edge to the parking area edge
7225 ConstMSEdgeVector edgesToPark;
7226 router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
7227
7228 // Compute the route from the parking area edge to the end of the route
7229 ConstMSEdgeVector edgesFromPark;
7230 if (!newDestination) {
7231 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
7232 } else {
7233 // adapt plans of any riders
7234 for (MSTransportable* p : getPersons()) {
7235 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
7236 }
7237 }
7238
7239 // we have a new destination, let's replace the vehicle route
7240 ConstMSEdgeVector edges = edgesToPark;
7241 if (edgesFromPark.size() > 0) {
7242 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
7243 }
7244
7245 if (newDestination) {
7246 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
7247 *newParameter = getParameter();
7249 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
7250 replaceParameter(newParameter);
7251 }
7252 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
7253 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
7254 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
7255 if (replaceParkingArea(newParkingArea, errorMsg)) {
7256 const bool onInit = myLane == nullptr;
7257 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
7258 } else {
7259 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
7260 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
7261 return false;
7262 }
7263 return true;
7264}
7265
7266
7267bool
7269 const int numStops = (int)myStops.size();
7270 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
7271 if (myLane != nullptr && numStops != (int)myStops.size()) {
7272 updateBestLanes(true);
7273 }
7274 return result;
7275}
7276
7277
7278bool
7279MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
7280 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
7281 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
7282 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
7283 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
7284 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
7285 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
7286 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
7287 // << " vNew=" << vNew
7288 // << "\n";
7289 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
7292 if (myState.myPos < myType->getLength()) {
7296 myAngle += M_PI;
7297 }
7298 }
7299 }
7300 }
7301 return true;
7302}
7303
7304
7305bool
7307 if (isStopped()) {
7311 }
7312 MSStop& stop = myStops.front();
7313 // we have waited long enough and fulfilled any passenger-requirements
7314 if (stop.busstop != nullptr) {
7315 // inform bus stop about leaving it
7316 stop.busstop->leaveFrom(this);
7317 }
7318 // we have waited long enough and fulfilled any container-requirements
7319 if (stop.containerstop != nullptr) {
7320 // inform container stop about leaving it
7321 stop.containerstop->leaveFrom(this);
7322 }
7323 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
7324 // inform parking area about leaving it
7325 stop.parkingarea->leaveFrom(this);
7326 }
7327 if (stop.chargingStation != nullptr) {
7328 // inform charging station about leaving it
7329 stop.chargingStation->leaveFrom(this);
7330 }
7331 // the current stop is no longer valid
7332 myLane->getEdge().removeWaiting(this);
7333 // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
7334 if (stop.pars.started == -1) {
7335 // waypoint edge was passed in a single step
7337 }
7338 if (MSStopOut::active()) {
7339 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
7340 }
7342 for (const auto& rem : myMoveReminders) {
7343 rem.first->notifyStopEnded();
7344 }
7346 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
7347 }
7349 // reset lateral position to default
7350 myState.myPosLat = 0;
7351 }
7352 myPastStops.push_back(stop.pars);
7353 myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
7354 myStops.pop_front();
7355 myStopDist = std::numeric_limits<double>::max();
7356 // do not count the stopping time towards gridlock time.
7357 // Other outputs use an independent counter and are not affected.
7358 myWaitingTime = 0;
7359 // maybe the next stop is on the same edge; let's rebuild best lanes
7360 updateBestLanes(true);
7361 // continue as wished...
7364 return true;
7365 }
7366 return false;
7367}
7368
7369
7372 if (myInfluencer == nullptr) {
7373 myInfluencer = new Influencer();
7374 }
7375 return *myInfluencer;
7376}
7377
7382
7383
7386 return myInfluencer;
7387}
7388
7391 return myInfluencer;
7392}
7393
7394
7395double
7397 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
7398 // influencer original speed is -1 on initialization
7400 }
7401 return myState.mySpeed;
7402}
7403
7404
7405int
7407 if (hasInfluencer()) {
7409 MSNet::getInstance()->getCurrentTimeStep(),
7410 myLane->getEdge(),
7411 getLaneIndex(),
7412 state);
7413 }
7414 return state;
7415}
7416
7417
7418void
7422
7423
7424bool
7428
7429
7430bool
7434
7435
7436bool
7437MSVehicle::keepClear(const MSLink* link) const {
7438 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
7439 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
7440 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
7441 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
7442 } else {
7443 return false;
7444 }
7445}
7446
7447
7448bool
7449MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
7450 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
7451 return true;
7452 }
7453 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
7454#ifdef DEBUG_IGNORE_RED
7455 if (DEBUG_COND) {
7456 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
7457 }
7458#endif
7459 if (ignoreRedTime < 0) {
7460 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
7461 if (ignoreYellowTime > 0 && link->haveYellow()) {
7462 assert(link->getTLLogic() != 0);
7463 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7464 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
7465 return !canBrake || ignoreYellowTime > yellowDuration;
7466 } else {
7467 return false;
7468 }
7469 } else if (link->haveYellow()) {
7470 // always drive at yellow when ignoring red
7471 return true;
7472 } else if (link->haveRed()) {
7473 assert(link->getTLLogic() != 0);
7474 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7475#ifdef DEBUG_IGNORE_RED
7476 if (DEBUG_COND) {
7477 std::cout
7478 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
7479 << " ignoreRedTime=" << ignoreRedTime
7480 << " spentRed=" << redDuration
7481 << " canBrake=" << canBrake << "\n";
7482 }
7483#endif
7484 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
7485 return !canBrake || ignoreRedTime > redDuration;
7486 } else {
7487 return false;
7488 }
7489}
7490
7491bool
7494 return false;
7495 }
7496 for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
7497 if (typeID == foe->getVehicleType().getID()) {
7498 return true;
7499 }
7500 }
7501 for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
7502 if (id == foe->getID()) {
7503 return true;
7504 }
7505 }
7506 return false;
7507}
7508
7509bool
7511 // either on an internal lane that was entered via minor link
7512 // or on approach to minor link below visibility distance
7513 if (myLane == nullptr) {
7514 return false;
7515 }
7516 if (myLane->getEdge().isInternal()) {
7517 return !myLane->getIncomingLanes().front().viaLink->havePriority();
7518 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
7519 MSLink* link = myLFLinkLanes.front().myLink;
7520 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
7521 }
7522 return false;
7523}
7524
7525bool
7526MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
7527 assert(link->fromInternalLane());
7528 if (veh == nullptr) {
7529 return false;
7530 }
7531 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
7532 // if this vehicle is not yet on the junction, every vehicle is a leader
7533 return true;
7534 }
7535 if (veh->getLaneChangeModel().hasBlueLight()) {
7536 // blue light device automatically gets right of way
7537 return true;
7538 }
7539 const MSLane* foeLane = veh->getLane();
7540 if (foeLane->isInternal()) {
7541 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
7543 SUMOTime foeET = veh->myJunctionEntryTime;
7544 // check relationship between link and foeLane
7546 // we are entering the junction from the same lane
7548 foeET = veh->myJunctionEntryTimeNeverYield;
7551 }
7552 } else {
7553 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
7554 const MSJunctionLogic* logic = link->getJunction()->getLogic();
7555 assert(logic != nullptr);
7556 // determine who has right of way
7557 bool response; // ego response to foe
7558 bool response2; // foe response to ego
7559 // attempt 1: tlLinkState
7560 const MSLink* entry = link->getCorrespondingEntryLink();
7561 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
7562 if (entry->haveRed() || foeEntry->haveRed()) {
7563 // ensure that vehicles which are stuck on the intersection may exit
7564 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
7565 // foe might be oncoming, don't drive unless foe can still brake safely
7566 const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
7567 const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
7568 foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
7569 // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
7570 // so the -2* makes it point in the right direction
7571 const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
7572#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7573 if (DEBUG_COND) {
7574 std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
7575
7576 }
7577#endif
7578 if (foeGap < foeBrakeGap) {
7579 response = true;
7580 response2 = false;
7581 } else {
7582 response = false;
7583 response2 = true;
7584 }
7585 } else {
7586 // let conflict entry time decide
7587 response = true;
7588 response2 = true;
7589 }
7590 } else if (entry->havePriority() != foeEntry->havePriority()) {
7591 response = !entry->havePriority();
7592 response2 = !foeEntry->havePriority();
7593 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
7594 // let the faster vehicle keep moving
7595 response = veh->getSpeed() >= getSpeed();
7596 response2 = getSpeed() >= veh->getSpeed();
7597 } else {
7598 // fallback if pedestrian crossings are involved
7599 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
7600 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
7601 }
7602#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7603 if (DEBUG_COND) {
7604 std::cout << SIMTIME
7605 << " foeLane=" << foeLane->getID()
7606 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
7607 << " linkIndex=" << link->getIndex()
7608 << " foeLinkIndex=" << foeLink->getIndex()
7609 << " entryState=" << toString(entry->getState())
7610 << " entryState2=" << toString(foeEntry->getState())
7611 << " response=" << response
7612 << " response2=" << response2
7613 << "\n";
7614 }
7615#endif
7616 if (!response) {
7617 // if we have right of way over the foe, entryTime does not matter
7618 foeET = veh->myJunctionConflictEntryTime;
7619 egoET = myJunctionEntryTime;
7620 } else if (response && response2) {
7621 // in a mutual conflict scenario, use entry time to avoid deadlock
7622 foeET = veh->myJunctionConflictEntryTime;
7624 }
7625 }
7626 if (egoET == foeET) {
7627 // try to use speed as tie braker
7628 if (getSpeed() == veh->getSpeed()) {
7629 // use ID as tie braker
7630#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7631 if (DEBUG_COND) {
7632 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7633 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7634 }
7635#endif
7636 return getID() < veh->getID();
7637 } else {
7638#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7639 if (DEBUG_COND) {
7640 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7641 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7642 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7643 << "\n";
7644 }
7645#endif
7646 return getSpeed() < veh->getSpeed();
7647 }
7648 } else {
7649 // leader was on the junction first
7650#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7651 if (DEBUG_COND) {
7652 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7653 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7654 }
7655#endif
7656 return egoET > foeET;
7657 }
7658 } else {
7659 // vehicle can only be partially on the junction. Must be a leader
7660 return true;
7661 }
7662 } else {
7663 // vehicle can only be partially on the junction. Must be a leader
7664 return true;
7665 }
7666}
7667
7668void
7671 // here starts the vehicle internal part (see loading)
7672 std::vector<std::string> internals;
7673 internals.push_back(toString(myParameter->parametersSet));
7674 internals.push_back(toString(myDeparture));
7675 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7676 internals.push_back(toString(myDepartPos));
7677 internals.push_back(toString(myWaitingTime));
7678 internals.push_back(toString(myTimeLoss));
7679 internals.push_back(toString(myLastActionTime));
7680 internals.push_back(toString(isStopped()));
7681 internals.push_back(toString(myPastStops.size()));
7682 out.writeAttr(SUMO_ATTR_STATE, internals);
7684 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7689 // save past stops
7691 stop.write(out, false);
7692 // do not write started and ended twice
7693 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7694 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7695 }
7696 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7697 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7698 }
7699 stop.writeParams(out);
7700 out.closeTag();
7701 }
7702 // save upcoming stops
7703 for (MSStop& stop : myStops) {
7704 stop.write(out);
7705 }
7706 // save parameters and device states
7708 for (MSVehicleDevice* const dev : myDevices) {
7709 dev->saveState(out);
7710 }
7711 out.closeTag();
7712}
7713
7714void
7716 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7717 throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
7718 }
7719 int routeOffset;
7720 bool stopped;
7721 int pastStops;
7722
7723 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7724 bis >> myParameter->parametersSet;
7725 bis >> myDeparture;
7726 bis >> routeOffset;
7727 bis >> myDepartPos;
7728 bis >> myWaitingTime;
7729 bis >> myTimeLoss;
7730 bis >> myLastActionTime;
7731 bis >> stopped;
7732 bis >> pastStops;
7733
7735 bool ok;
7736 myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
7737 }
7738 // load stops
7739 myStops.clear();
7741
7742 if (hasDeparted()) {
7743 myCurrEdge = myRoute->begin() + routeOffset;
7744 myDeparture -= offset;
7745 // fix stops
7746 while (pastStops > 0) {
7747 myPastStops.push_back(myStops.front().pars);
7748 myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
7749 myStops.pop_front();
7750 pastStops--;
7751 }
7752 // see MSBaseVehicle constructor
7755 }
7756 // a (tentative lane is needed for calling hasArrivedInternal
7757 myLane = (*myCurrEdge)->getLanes()[0];
7758 }
7761 WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
7762 }
7763 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7765 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7770 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7771 dis >> myOdometer >> myNumberReroutes;
7773 if (stopped) {
7774 myStops.front().startedFromState = true;
7775 myStopDist = 0;
7776 }
7778 // no need to reset myCachedPosition here since state loading happens directly after creation
7779}
7780
7781void
7783 SUMOTime arrivalTime, double arrivalSpeed,
7784 double arrivalSpeedBraking,
7785 double dist, double leaveSpeed) {
7786 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7787 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7788 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7789
7790}
7791
7792
7793std::shared_ptr<MSSimpleDriverState>
7797
7798
7799double
7801 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7802}
7803
7804
7805void
7806MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7807 myState.mySpeed = MAX2(0., prevSpeed);
7808 // also retcon acceleration
7809 if (prevAcceleration != std::numeric_limits<double>::min()) {
7810 myAcceleration = prevAcceleration;
7811 } else {
7813 }
7814}
7815
7816
7817double
7819 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7821}
7822
7823/****************************************************************************/
7824bool
7828
7829/* -------------------------------------------------------------------------
7830 * methods of MSVehicle::manoeuvre
7831 * ----------------------------------------------------------------------- */
7832
7833MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7834
7835
7837 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7838 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7839 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7840 myManoeuvreType = manoeuvre.myManoeuvreType;
7841 myGUIIncrement = manoeuvre.myGUIIncrement;
7842}
7843
7844
7847 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7848 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7849 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7850 myManoeuvreType = manoeuvre.myManoeuvreType;
7851 myGUIIncrement = manoeuvre.myGUIIncrement;
7852 return *this;
7853}
7854
7855
7856bool
7858 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7859 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7860 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7861 myManoeuvreType != manoeuvre.myManoeuvreType ||
7862 myGUIIncrement != manoeuvre.myGUIIncrement
7863 );
7864}
7865
7866
7867double
7869 return (myGUIIncrement);
7870}
7871
7872
7875 return (myManoeuvreType);
7876}
7877
7878
7883
7884
7885void
7889
7890
7891void
7893 myManoeuvreType = mType;
7894}
7895
7896
7897bool
7899 if (!veh->hasStops()) {
7900 return false; // should never happen - checked before call
7901 }
7902
7903 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7904 const MSStop& stop = veh->getNextStop();
7905
7906 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7907 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7908 if (abs(GUIAngle) < 0.1) {
7909 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7910 }
7911 myManoeuvreVehicleID = veh->getID();
7912 myManoeuvreStop = stop.parkingarea->getID();
7913 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7914 myManoeuvreStartTime = currentTime;
7915 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7916 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7917
7918#ifdef DEBUG_STOPS
7919 if (veh->isSelected()) {
7920 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 <<
7921 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7922 }
7923#endif
7924
7925 return (true);
7926}
7927
7928
7929bool
7931 // At the moment we only want to set for parking areas
7932 if (!veh->hasStops()) {
7933 return true;
7934 }
7935 if (veh->getNextStop().parkingarea == nullptr) {
7936 return true;
7937 }
7938
7939 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
7940 return (false);
7941 }
7942
7943 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7944
7945 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
7946 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
7947 if (abs(GUIAngle) < 0.1) {
7948 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
7949 }
7950
7951 myManoeuvreVehicleID = veh->getID();
7952 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
7953 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
7954 myManoeuvreStartTime = currentTime;
7955 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
7956 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7957 if (veh->remainingStopDuration() > 0) {
7958 myManoeuvreCompleteTime += veh->remainingStopDuration();
7959 }
7960
7961#ifdef DEBUG_STOPS
7962 if (veh->isSelected()) {
7963 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
7964 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7965 }
7966#endif
7967
7968 return (true);
7969}
7970
7971
7972bool
7974 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
7975 if (!veh->hasStops()) {
7976 return (true);
7977 }
7978 MSStop* currentStop = &veh->myStops.front();
7979 if (currentStop->parkingarea == nullptr) {
7980 return true;
7981 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
7982 if (configureEntryManoeuvre(veh)) {
7984 return (false);
7985 } else { // cannot configure entry so stop trying
7986 return true;
7987 }
7988 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7989 return false;
7990 } else { // manoeuvre complete
7991 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
7992 return true;
7993 }
7994}
7995
7996
7997bool
7999 if (checkType != myManoeuvreType) {
8000 return true; // we're not maneuvering / wrong manoeuvre
8001 }
8002
8003 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
8004 return false;
8005 } else {
8006 return true;
8007 }
8008}
8009
8010
8011bool
8013 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
8014}
8015
8016
8017bool
8021
8022
8023std::pair<double, double>
8025 if (hasStops()) {
8026 MSLane* lane = myLane;
8027 if (lane == nullptr) {
8028 // not in network
8029 lane = getEdge()->getLanes()[0];
8030 }
8031 const MSStop& stop = myStops.front();
8032 auto it = myCurrEdge + 1;
8033 // drive to end of current edge
8034 double dist = (lane->getLength() - getPositionOnLane());
8035 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
8036 // drive until stop edge
8037 while (it != myRoute->end() && it < stop.edge) {
8038 travelTime += (*it)->getMinimumTravelTime(this);
8039 dist += (*it)->getLength();
8040 it++;
8041 }
8042 // drive up to the stop position
8043 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
8044 dist += stopEdgeDist;
8045 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
8046 // estimate time loss due to acceleration and deceleration
8047 // maximum speed is limited by available distance:
8048 const double a = getCarFollowModel().getMaxAccel();
8049 const double b = getCarFollowModel().getMaxDecel();
8050 const double c = getSpeed();
8051 const double d = dist;
8052 const double len = getVehicleType().getLength();
8053 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
8054 // distAccel = (v - c)^2 / (2a)
8055 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
8056 // distAccel + distDecel < d
8057 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))))
8058 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
8059 it = myCurrEdge;
8060 double v0 = c;
8061 bool v0Stable = getAcceleration() == 0 && v0 > 0;
8062 double timeLossAccel = 0;
8063 double timeLossDecel = 0;
8064 double timeLossLength = 0;
8065 while (it != myRoute->end() && it <= stop.edge) {
8066 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
8067 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
8068 if (edgeLength <= len && v0Stable && v0 < v) {
8069 const double lengthDist = MIN2(len, edgeLength);
8070 const double dTL = lengthDist / v0 - lengthDist / v;
8071 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
8072 timeLossLength += dTL;
8073 }
8074 if (edgeLength > len) {
8075 const double dv = v - v0;
8076 if (dv > 0) {
8077 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8078 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8079 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8080 timeLossAccel += dTA;
8081 // time loss from vehicle length
8082 } else if (dv < 0) {
8083 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8084 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8085 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8086 timeLossDecel += dTD;
8087 }
8088 v0 = v;
8089 v0Stable = true;
8090 }
8091 it++;
8092 }
8093 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
8094 double v = vs;
8095 const double dv = v - v0;
8096 if (dv > 0) {
8097 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8098 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8099 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8100 timeLossAccel += dTA;
8101 // time loss from vehicle length
8102 } else if (dv < 0) {
8103 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8104 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8105 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8106 timeLossDecel += dTD;
8107 }
8108 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
8109 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
8110 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
8111 return {MAX2(0.0, result), dist};
8112 } else {
8114 }
8115}
8116
8117
8118double
8120 if (hasStops() && myStops.front().pars.until >= 0) {
8121 const MSStop& stop = myStops.front();
8122 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
8123 if (stop.reached) {
8124 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
8125 }
8126 if (stop.pars.duration > 0) {
8127 estimatedDepart += stop.pars.duration;
8128 }
8129 estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
8130 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
8131 return result;
8132 } else {
8133 // vehicles cannot drive before 'until' so stop delay can never be
8134 // negative and we can use -1 to signal "undefined"
8135 return -1;
8136 }
8137}
8138
8139
8140double
8142 if (hasStops() && myStops.front().pars.arrival >= 0) {
8143 const MSStop& stop = myStops.front();
8144 if (stop.reached) {
8145 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
8146 } else {
8147 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
8148 }
8149 } else {
8150 // vehicles can arrival earlier than planned so arrival delay can be negative
8151 return INVALID_DOUBLE;
8152 }
8153}
8154
8155
8156const MSEdge*
8158 return myLane != nullptr ? &myLane->getEdge() : getEdge();
8159}
8160
8161
8162const MSEdge*
8164 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
8165 return nullptr;
8166 }
8167 if (myLane->isInternal()) {
8169 } else {
8170 const MSEdge* nextNormal = succEdge(1);
8171 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
8172 return nextInternal ? nextInternal : nextNormal;
8173 }
8174}
8175
8176
8177const MSLane*
8178MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
8179 if (furtherIndex < (int)myFurtherLanes.size()) {
8180 return myFurtherLanes[furtherIndex++];
8181 } else {
8182 // try to use route information
8183 int routeIndex = getRoutePosition();
8184 bool resultInternal;
8185 if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
8186 if (myLane->isInternal()) {
8187 if (furtherIndex % 2 == 0) {
8188 routeIndex -= (furtherIndex + 0) / 2;
8189 resultInternal = false;
8190 } else {
8191 routeIndex -= (furtherIndex + 1) / 2;
8192 resultInternal = false;
8193 }
8194 } else {
8195 if (furtherIndex % 2 != 0) {
8196 routeIndex -= (furtherIndex + 1) / 2;
8197 resultInternal = false;
8198 } else {
8199 routeIndex -= (furtherIndex + 2) / 2;
8200 resultInternal = true;
8201 }
8202 }
8203 } else {
8204 routeIndex -= furtherIndex;
8205 resultInternal = false;
8206 }
8207 furtherIndex++;
8208 if (routeIndex >= 0) {
8209 if (resultInternal) {
8210 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
8211 for (MSLane* cand : prevNormal->getLanes()) {
8212 for (MSLink* link : cand->getLinkCont()) {
8213 if (link->getLane() == current) {
8214 if (link->getViaLane() != nullptr) {
8215 return link->getViaLane();
8216 } else {
8217 return const_cast<MSLane*>(link->getLaneBefore());
8218 }
8219 }
8220 }
8221 }
8222 } else {
8223 return myRoute->getEdges()[routeIndex]->getLanes()[0];
8224 }
8225 }
8226 }
8227 return current;
8228}
8229
8232 // this vehicle currently has the highest priority on the allway_stop
8233 return link == myHaveStoppedFor ? SUMOTime_MAX : getWaitingTime();
8234}
8235
8236
8237void
8239 bool diverged = false;
8240 const ConstMSEdgeVector& route = myRoute->getEdges();
8241 int ri = getRoutePosition();
8242 for (const DriveProcessItem& dpi : myLFLinkLanes) {
8243 if (dpi.myLink != nullptr) {
8244 if (!diverged) {
8245 const MSEdge* next = route[ri + 1];
8246 if (&dpi.myLink->getLane()->getEdge() != next) {
8247 diverged = true;
8248 } else {
8249 if (dpi.myLink->getViaLane() == nullptr) {
8250 ri++;
8251 }
8252 }
8253 }
8254 if (diverged) {
8255 dpi.myLink->removeApproaching(this);
8256 }
8257 }
8258 }
8259}
8260
8261/****************************************************************************/
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.
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:1102
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:1350
bool isFringe() const
return whether this edge is at the fringe of the network
Definition MSEdge.h:772
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition MSEdge.cpp:957
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:482
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:282
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:263
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition MSEdge.cpp:1168
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:1372
bool hasLaneChanger() const
Definition MSEdge.h:746
const MSJunction * getToJunction() const
Definition MSEdge.h:426
const MSJunction * getFromJunction() const
Definition MSEdge.h:422
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:484
bool isRoundabout() const
Definition MSEdge.h:729
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:268
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:664
bool isVaporizing() const
Returns whether vehicles on this edge shall be vaporized.
Definition MSEdge.h:442
void addWaiting(SUMOVehicle *vehicle) const
Adds a vehicle to the list of waiting vehicles.
Definition MSEdge.cpp:1461
const MSEdge * getInternalFollowingEdge(const MSEdge *followerAfterInternal, SUMOVehicleClass vClass) const
Definition MSEdge.cpp:910
void removeWaiting(const SUMOVehicle *vehicle) const
Removes a vehicle from the list of waiting vehicles.
Definition MSEdge.cpp:1470
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1268
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:1291
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:4401
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:4575
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:2851
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2833
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:2681
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2769
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:1164
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition MSLane.cpp:2695
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2434
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2746
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1393
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3779
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:2466
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:619
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:955
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3273
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:2908
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:2758
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:1446
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:2992
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition MSLane.h:858
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:930
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:1200
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4568
int getIndex() const
Returns the lane's index.
Definition MSLane.h:647
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3297
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4396
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3217
double getCenterOnEdge() const
Definition MSLane.h:1208
bool isNormal() const
Definition MSLane.cpp:2627
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2662
bool isInternal() const
Definition MSLane.cpp:2621
@ FOLLOW_NEVER
Definition MSLane.h:979
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:4384
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:4686
double interpolateLanePosToGeometryPos(double lanePos) const
Definition MSLane.h:554
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4680
@ 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:4390
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:4695
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3242
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:3804
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:2653
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition MSLane.h:560
static CollisionAction getCollisionAction()
Definition MSLane.h:1362
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:1326
VehicleState
Definition of a vehicle state.
Definition MSNet.h:622
@ 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:186
virtual MSTransportableControl & getContainerControl()
Returns the container control.
Definition MSNet.cpp:1259
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:1474
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:1453
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1318
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:1335
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:1250
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:435
bool hasElevation() const
return whether the network contains elevation data
Definition MSNet.h:804
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.
void enter(SUMOVehicle *veh)
Called if a vehicle enters this stop.
int getLotIndex(const SUMOVehicle *veh) const
compute lot for this vehicle
int getLastFreeLotAngle() const
Return the angle of myLastFreeLot - the next parking lot only expected to be called after we have est...
bool parkOnRoad() const
whether vehicles park on the road
double getLastFreePosWithReservation(SUMOTime t, const SUMOVehicle &forVehicle, double brakePos)
Returns the last free position on this stop including reservations from the current lane and time ste...
double getLastFreeLotGUIAngle() const
Return the GUI angle of myLastFreeLot - the angle the GUI uses to rotate into the next parking lot as...
int getManoeuverAngle(const SUMOVehicle &forVehicle) const
Return the manoeuver angle of the lot where the vehicle is parked.
int getOccupancy() const
Returns the area occupancy.
double getGUIAngle(const SUMOVehicle &forVehicle) const
Return the GUI angle of the lot where the vehicle is parked.
void notifyApproach(const MSLink *link)
switch rail signal to active
static MSRailSignalControl & getInstance()
const ConstMSEdgeVector & getEdges() const
Definition MSRoute.h:125
const MSEdge * getLastEdge() const
returns the destination edge
Definition MSRoute.cpp:91
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
const MSLane * lane
The lane to stop at (microsim only)
Definition MSStop.h:50
bool triggered
whether an arriving person lets the vehicle continue
Definition MSStop.h:69
bool containerTriggered
whether an arriving container lets the vehicle continue
Definition MSStop.h:71
SUMOTime timeToLoadNextContainer
The time at which the vehicle is able to load another container.
Definition MSStop.h:83
MSStoppingPlace * containerstop
(Optional) container stop if one is assigned to the stop
Definition MSStop.h:56
double getSpeed() const
return speed for passing waypoint / skipping on-demand stop
Definition MSStop.cpp:176
bool joinTriggered
whether coupling another vehicle (train) the vehicle continue
Definition MSStop.h:73
bool isOpposite
whether this an opposite-direction stop
Definition MSStop.h:87
SUMOTime getMinDuration(SUMOTime time) const
return minimum stop duration when starting stop at time
Definition MSStop.cpp:134
int numExpectedContainer
The number of still expected containers.
Definition MSStop.h:79
bool reached
Information whether the stop has been reached.
Definition MSStop.h:75
MSRouteIterator edge
The edge in the route to stop at.
Definition MSStop.h:48
SUMOTime timeToBoardNextPerson
The time at which the vehicle is able to board another person.
Definition MSStop.h:81
bool skipOnDemand
whether the decision to skip this stop has been made
Definition MSStop.h:89
const MSEdge * getEdge() const
Definition MSStop.cpp:54
double getReachedThreshold() const
return startPos taking into account opposite stopping
Definition MSStop.cpp:64
SUMOTime endBoarding
the maximum time at which persons may board this vehicle
Definition MSStop.h:85
double getEndPos(const SUMOVehicle &veh) const
return halting position for upcoming stop;
Definition MSStop.cpp:35
int numExpectedPerson
The number of still expected persons.
Definition MSStop.h:77
MSParkingArea * parkingarea
(Optional) parkingArea if one is assigned to the stop
Definition MSStop.h:58
bool startedFromState
whether the 'started' value was loaded from simulaton state
Definition MSStop.h:91
MSStoppingPlace * chargingStation
(Optional) charging station if one is assigned to the stop
Definition MSStop.h:60
SUMOTime duration
The stopping duration.
Definition MSStop.h:67
SUMOTime getUntil() const
return until / ended time
Definition MSStop.cpp:151
const SUMOVehicleParameter::Stop pars
The stop parameter.
Definition MSStop.h:65
MSStoppingPlace * busstop
(Optional) bus stop if one is assigned to the stop
Definition MSStop.h:54
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.
bool fits(double pos, const SUMOVehicle &veh) const
return whether the given vehicle fits at the given position
double getEndLanePosition() const
Returns the end position of this stop.
void enter(SUMOVehicle *veh, bool parking)
Called if a vehicle enters this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
void leaveFrom(SUMOVehicle *what)
Called if a vehicle leaves this stop.
bool hasAnyWaiting(const MSEdge *edge, SUMOVehicle *vehicle) const
check whether any transportables are waiting for the given vehicle
bool loadAnyWaiting(const MSEdge *edge, SUMOVehicle *vehicle, SUMOTime &timeToLoadNext, SUMOTime &stopDuration, MSTransportable *const force=nullptr)
load any applicable transportables Loads any person / container that is waiting on that edge for the ...
bool isPerson() const
Whether it is a person.
A static instance of this class in GapControlState deactivates gap control for vehicles whose referen...
Definition MSVehicle.h:1354
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:1349
void setLaneChangeMode(int value)
Sets lane changing behavior.
TraciLaneChangePriority myTraciLaneChangePriority
flags for determining the priority of traci lane change requests
Definition MSVehicle.h:1671
bool getEmergencyBrakeRedLight() const
Returns whether red lights shall be a reason to brake.
Definition MSVehicle.h:1519
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:1616
int getSignals() const
Definition MSVehicle.h:1587
bool myConsiderMaxDeceleration
Whether the maximum deceleration shall be regarded.
Definition MSVehicle.h:1637
void setLaneTimeLine(const std::vector< std::pair< SUMOTime, int > > &laneTimeLine)
Sets a new lane timeline.
bool myRespectJunctionLeaderPriority
Whether the junction priority rules are respected (within)
Definition MSVehicle.h:1646
void setOriginalSpeed(double speed)
Stores the originally longitudinal speed.
double myOriginalSpeed
The velocity before influence.
Definition MSVehicle.h:1619
bool myConsiderSpeedLimit
Whether the speed limit shall be regarded.
Definition MSVehicle.h:1631
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:1655
bool getRespectJunctionLeaderPriority() const
Returns whether junction priority rules within the junction shall be respected (concerns vehicles wit...
Definition MSVehicle.h:1527
LaneChangeMode myStrategicLC
lane changing which is necessary to follow the current route
Definition MSVehicle.h:1660
LaneChangeMode mySpeedGainLC
lane changing to travel with higher speed
Definition MSVehicle.h:1664
void init()
Static initalization.
LaneChangeMode mySublaneLC
changing to the prefered lateral alignment
Definition MSVehicle.h:1668
bool getRespectJunctionPriority() const
Returns whether junction priority rules shall be respected (concerns approaching vehicles outside the...
Definition MSVehicle.h:1511
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:1628
bool mySpeedAdaptationStarted
Whether influencing the speed has already started.
Definition MSVehicle.h:1625
~Influencer()
Destructor.
void setSignals(int signals)
Definition MSVehicle.h:1583
double myLatDist
The requested lateral change.
Definition MSVehicle.h:1622
bool considerSpeedLimit() const
Returns whether speed limits shall be considered.
Definition MSVehicle.h:1538
bool myEmergencyBrakeRedLight
Whether red lights are a reason to brake.
Definition MSVehicle.h:1643
LaneChangeMode myRightDriveLC
changing to the rightmost lane
Definition MSVehicle.h:1666
void setSpeedTimeLine(const std::vector< std::pair< SUMOTime, double > > &speedTimeLine)
Sets a new velocity timeline.
void updateRemoteControlRoute(MSVehicle *v)
update route if provided by remote control
SUMOTime getLastAccessTimeStep() const
Definition MSVehicle.h:1563
bool myConsiderMaxAcceleration
Whether the maximum acceleration shall be regarded.
Definition MSVehicle.h:1634
LaneChangeMode myCooperativeLC
lane changing with the intent to help other vehicles
Definition MSVehicle.h:1662
bool isRemoteControlled() const
bool myRespectJunctionPriority
Whether the junction priority rules are respected (approaching)
Definition MSVehicle.h:1640
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:1273
SUMOTime myManoeuvreCompleteTime
Time at which this manoeuvre should complete.
Definition MSVehicle.h:1325
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:1319
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:1328
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:1322
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:1151
@ LCP_OPPORTUNISTIC
Definition MSVehicle.h:1155
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:1930
SUMOTime myWaitingTime
The time the vehicle waits (is not faster than 0.1m/s) in seconds.
Definition MSVehicle.h:1866
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:1870
SUMOTime myLastActionTime
Action offset (actions are taken at time myActionOffset + N*getActionStepLength()) Initialized to 0,...
Definition MSVehicle.h:1885
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:1948
double getLeftSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
PositionVector getBoundingPoly(double offset=0) const
get bounding polygon
void setTentativeLaneAndPosition(MSLane *lane, double pos, double posLat=0)
set tentative lane and position during insertion to ensure that all cfmodels work (some of them requi...
bool brakeForOverlap(const MSLink *link, const MSLane *lane) const
handle with transitions
void workOnMoveReminders(double oldPos, double newPos, double newSpeed)
Processes active move reminder.
bool isStoppedOnLane() const
double getDistanceToPosition(double destPos, const MSLane *destLane) const
bool brokeDown() const
Returns how long the vehicle has been stopped already due to lack of energy.
double myAcceleration
The current acceleration after dawdling in m/s.
Definition MSVehicle.h:1912
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:1892
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:1919
bool signalSet(int which) const
Returns whether the given signal is on.
Definition MSVehicle.h:1187
MSCFModel::VehicleVariables * myCFVariables
The per vehicle variables of the car following model.
Definition MSVehicle.h:2160
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:1916
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:1927
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:2074
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:1907
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:1895
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:1867
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:1246
@ MANOEUVRE_ENTRY
Manoeuvre into stopping place.
Definition MSVehicle.h:1248
@ MANOEUVRE_NONE
not manouevring
Definition MSVehicle.h:1252
@ MANOEUVRE_EXIT
Manoeuvre out of stopping place.
Definition MSVehicle.h:1250
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:1894
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:2163
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:2017
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:2030
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:1952
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:1947
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:1170
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:1924
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:1938
Signalling
Some boolean values which describe the state of some vehicle parts.
Definition MSVehicle.h:1105
@ VEH_SIGNAL_BLINKER_RIGHT
Right blinker lights are switched on.
Definition MSVehicle.h:1109
@ VEH_SIGNAL_BRAKELIGHT
The brake lights are on.
Definition MSVehicle.h:1115
@ VEH_SIGNAL_EMERGENCY_BLUE
A blue emergency light is on.
Definition MSVehicle.h:1131
@ VEH_SIGNAL_BLINKER_LEFT
Left blinker lights are switched on.
Definition MSVehicle.h:1111
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:1932
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:1941
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:2023
std::vector< std::vector< LaneQ > > myBestLanes
Definition MSVehicle.h:1902
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:1882
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:1951
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:1909
Position myCachedPosition
Definition MSVehicle.h:1943
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:1921
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:1935
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:1876
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:1890
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:1335
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:1690
MSDevice_Friction * myFrictionDevice
This vehicle's friction perception.
Definition MSVehicle.h:1879
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:1143
virtual void drawOutsideNetwork(bool)
register vehicle for drawing while outside the network
Definition MSVehicle.h:1841
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:1873
double getCenterOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
void adaptToLeader(const std::pair< const MSVehicle *, double > leaderInfo, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
void switchOnSignal(int signal)
Switches the given signal on.
Definition MSVehicle.h:1162
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:2020
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:1946
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:1959
void adaptStopSpeed(const double v)
Definition MSVehicle.h:2006
double getLeaveSpeed() const
Definition MSVehicle.h:2010
void adaptLeaveSpeed(const double v)
Definition MSVehicle.h:1998
static std::map< const MSVehicle *, GapControlState * > refVehMap
stores reference vehicles currently in use by a gapController
Definition MSVehicle.h:1408
static GapControlVehStateListener * myVehStateListener
Definition MSVehicle.h:1411
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