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 // avoid startup-effects after teleport
5719
5720 }
5721 computeFurtherLanes(enteredLane, pos);
5725 } else if (MSGlobals::gLaneChangeDuration > 0) {
5727 }
5728 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5731 myAngle += M_PI;
5732 }
5733 }
5734 if (MSNet::getInstance()->hasPersons()) {
5735 for (MSLane* further : myFurtherLanes) {
5736 if (further->mustCheckJunctionCollisions()) {
5738 }
5739 }
5740 }
5741}
5742
5743
5744void
5745MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5746 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5747 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5748#ifdef _DEBUG
5749 if (myTraceMoveReminders) {
5750 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5751 }
5752#endif
5753 ++rem;
5754 } else {
5755#ifdef _DEBUG
5756 if (myTraceMoveReminders) {
5757 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5758 }
5759#endif
5760 rem = myMoveReminders.erase(rem);
5761 }
5762 }
5766 && myLane != nullptr) {
5768 }
5769 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
5770 && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5772 }
5774 // @note. In case of lane change, myFurtherLanes and partial occupation
5775 // are handled in enterLaneAtLaneChange()
5776 for (MSLane* further : myFurtherLanes) {
5777#ifdef DEBUG_FURTHER
5778 if (DEBUG_COND) {
5779 std::cout << SIMTIME << " leaveLane \n";
5780 }
5781#endif
5782 further->resetPartialOccupation(this);
5783 if (further->getBidiLane() != nullptr
5784 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5785 further->getBidiLane()->resetPartialOccupation(this);
5786 }
5787 }
5788 myFurtherLanes.clear();
5789 myFurtherLanesPosLat.clear();
5790 }
5792 myAmOnNet = false;
5793 myWaitingTime = 0;
5794 }
5796 myStopDist = std::numeric_limits<double>::max();
5797 if (myPastStops.back().speed <= 0) {
5798 WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
5799 }
5800 }
5802 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5803 if (myStops.front().getSpeed() <= 0) {
5804 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5805 time2string(MSNet::getInstance()->getCurrentTimeStep()))
5806 if (MSStopOut::active()) {
5807 // clean up if stopBlocked was called
5809 }
5810 myStops.pop_front();
5811 } else {
5812 MSStop& stop = myStops.front();
5813 // passed waypoint at the end of the lane
5814 if (!stop.reached) {
5815 if (MSStopOut::active()) {
5817 }
5818 stop.reached = true;
5819 // enter stopping place so leaveFrom works as expected
5820 if (stop.busstop != nullptr) {
5821 // let the bus stop know the vehicle
5822 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5823 }
5824 if (stop.containerstop != nullptr) {
5825 // let the container stop know the vehicle
5827 }
5828 // do not enter parkingarea!
5829 if (stop.chargingStation != nullptr) {
5830 // let the container stop know the vehicle
5832 }
5833 }
5835 }
5836 myStopDist = std::numeric_limits<double>::max();
5837 }
5838 }
5839}
5840
5841
5842void
5844 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5845 if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
5846#ifdef _DEBUG
5847 if (myTraceMoveReminders) {
5848 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
5849 }
5850#endif
5851 ++rem;
5852 } else {
5853#ifdef _DEBUG
5854 if (myTraceMoveReminders) {
5855 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
5856 }
5857#endif
5858 rem = myMoveReminders.erase(rem);
5859 }
5860 }
5861#ifdef DEBUG_MOVEREMINDERS
5862 if (DEBUG_COND) {
5863 std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
5864 for (auto rem : myMoveReminders) {
5865 std::cout << rem.first->getDescription() << " ";
5866 }
5867 std::cout << "\n";
5868 }
5869#endif
5870}
5871
5872
5877
5878
5883
5884bool
5886 return (lane->isInternal()
5887 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5888 : &lane->getEdge() != *myCurrEdge);
5889}
5890
5891const std::vector<MSVehicle::LaneQ>&
5893 return *myBestLanes.begin();
5894}
5895
5896
5897void
5898MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5899#ifdef DEBUG_BESTLANES
5900 if (DEBUG_COND) {
5901 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5902 }
5903#endif
5904 if (startLane == nullptr) {
5905 startLane = myLane;
5906 }
5907 assert(startLane != 0);
5909 // depending on the calling context, startLane might be the forward lane
5910 // or the reverse-direction lane. In the latter case we need to
5911 // transform it to the forward lane.
5912 if (isOppositeLane(startLane)) {
5913 // use leftmost lane of forward edge
5914 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5915 assert(startLane != 0);
5916#ifdef DEBUG_BESTLANES
5917 if (DEBUG_COND) {
5918 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5919 }
5920#endif
5921 }
5922 }
5923 if (forceRebuild) {
5924 myLastBestLanesEdge = nullptr;
5926 }
5927 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5929#ifdef DEBUG_BESTLANES
5930 if (DEBUG_COND) {
5931 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5932 }
5933#endif
5934 return;
5935 }
5936 if (startLane->getEdge().isInternal()) {
5937 if (myBestLanes.size() == 0 || forceRebuild) {
5938 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5939 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5940 }
5941 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5942#ifdef DEBUG_BESTLANES
5943 if (DEBUG_COND) {
5944 std::cout << " nothing to do on internal\n";
5945 }
5946#endif
5947 return;
5948 }
5949 // adapt best lanes to fit the current internal edge:
5950 // keep the entries that are reachable from this edge
5951 const MSEdge* nextEdge = startLane->getNextNormal();
5952 assert(!nextEdge->isInternal());
5953 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5954 std::vector<LaneQ>& lanes = *it;
5955 assert(lanes.size() > 0);
5956 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5957 // keep those lanes which are successors of internal lanes from the edge of startLane
5958 std::vector<LaneQ> oldLanes = lanes;
5959 lanes.clear();
5960 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
5961 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
5962 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
5963 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
5964 lanes.push_back(*it_lane);
5965 break;
5966 }
5967 }
5968 }
5969 assert(lanes.size() == startLane->getEdge().getLanes().size());
5970 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
5971 for (int i = 0; i < (int)lanes.size(); ++i) {
5972 if (i + lanes[i].bestLaneOffset < 0) {
5973 lanes[i].bestLaneOffset = -i;
5974 }
5975 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
5976 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
5977 }
5978 assert(i + lanes[i].bestLaneOffset >= 0);
5979 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
5980 if (lanes[i].bestContinuations[0] != 0) {
5981 // patch length of bestContinuation to match expectations (only once)
5982 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
5983 }
5984 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
5985 myCurrentLaneInBestLanes = lanes.begin() + i;
5986 }
5987 assert(&(lanes[i].lane->getEdge()) == nextEdge);
5988 }
5989 myLastBestLanesInternalLane = startLane;
5991#ifdef DEBUG_BESTLANES
5992 if (DEBUG_COND) {
5993 std::cout << " updated for internal\n";
5994 }
5995#endif
5996 return;
5997 } else {
5998 // remove passed edges
5999 it = myBestLanes.erase(it);
6000 }
6001 }
6002 assert(false); // should always find the next edge
6003 }
6004 // start rebuilding
6006 myLastBestLanesEdge = &startLane->getEdge();
6008
6009 // get information about the next stop
6010 MSRouteIterator nextStopEdge = myRoute->end();
6011 const MSLane* nextStopLane = nullptr;
6012 double nextStopPos = 0;
6013 bool nextStopIsWaypoint = false;
6014 if (!myStops.empty()) {
6015 const MSStop& nextStop = myStops.front();
6016 nextStopLane = nextStop.lane;
6017 if (nextStop.isOpposite) {
6018 // target leftmost lane in forward direction
6019 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
6020 }
6021 nextStopEdge = nextStop.edge;
6022 nextStopPos = nextStop.pars.startPos;
6023 nextStopIsWaypoint = nextStop.getSpeed() > 0;
6024 }
6025 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
6026 if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
6027 nextStopEdge = (myRoute->end() - 1);
6028 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
6029 nextStopPos = myArrivalPos;
6030 }
6031 if (nextStopEdge != myRoute->end()) {
6032 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
6033 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
6034 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
6035 if (nextStopLane->isInternal()) {
6036 // switch to the correct lane before entering the intersection
6037 nextStopPos = (*nextStopEdge)->getLength();
6038 }
6039 }
6040
6041 // go forward along the next lanes;
6042 // trains do not have to deal with lane-changing for stops but their best
6043 // lanes lookahead is needed for rail signal control
6044 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
6045 int seen = 0;
6046 double seenLength = 0;
6047 bool progress = true;
6048 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
6049 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
6050 const double lookahead = getLaneChangeModel().getStrategicLookahead();
6051 for (MSRouteIterator ce = myCurrEdge; progress;) {
6052 std::vector<LaneQ> currentLanes;
6053 const std::vector<MSLane*>* allowed = nullptr;
6054 const MSEdge* nextEdge = nullptr;
6055 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
6056 nextEdge = *(ce + 1);
6057 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
6058 }
6059 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
6060 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
6061 LaneQ q;
6062 MSLane* cl = *i;
6063 q.lane = cl;
6064 q.bestContinuations.push_back(cl);
6065 q.bestLaneOffset = 0;
6066 q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
6067 q.currentLength = q.length;
6068 // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
6069 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
6070 q.occupation = 0;
6071 q.nextOccupation = 0;
6072 currentLanes.push_back(q);
6073 }
6074 //
6075 if (nextStopEdge == ce
6076 // already past the stop edge
6077 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
6078 if (!nextStopLane->isInternal() && !continueAfterStop) {
6079 progress = false;
6080 }
6081 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
6082 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
6083 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
6084 (*q).allowsContinuation = false;
6085 (*q).length = nextStopPos;
6086 (*q).currentLength = (*q).length;
6087 }
6088 }
6089 }
6090
6091 myBestLanes.push_back(currentLanes);
6092 ++seen;
6093 seenLength += currentLanes[0].lane->getLength();
6094 ++ce;
6095 if (lookahead >= 0) {
6096 progress &= (seen <= 2 || seenLength < lookahead); // custom (but we need to look at least one edge ahead)
6097 } else {
6098 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
6099 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
6100 }
6101 progress &= ce != myRoute->end();
6102 /*
6103 if(progress) {
6104 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
6105 }
6106 */
6107 }
6108
6109 // we are examining the last lane explicitly
6110 if (myBestLanes.size() != 0) {
6111 double bestLength = -1;
6112 // minimum and maximum lane index with best length
6113 int bestThisIndex = 0;
6114 int bestThisMaxIndex = 0;
6115 int index = 0;
6116 std::vector<LaneQ>& last = myBestLanes.back();
6117 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6118 if ((*j).length > bestLength) {
6119 bestLength = (*j).length;
6120 bestThisIndex = index;
6121 bestThisMaxIndex = index;
6122 } else if ((*j).length == bestLength) {
6123 bestThisMaxIndex = index;
6124 }
6125 }
6126 index = 0;
6127 bool requiredChangeRightForbidden = false;
6128 int requireChangeToLeftForbidden = -1;
6129 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6130 if ((*j).length < bestLength) {
6131 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6132 (*j).bestLaneOffset = bestThisIndex - index;
6133 } else {
6134 (*j).bestLaneOffset = bestThisMaxIndex - index;
6135 }
6136 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6137 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6138 || requiredChangeRightForbidden)) {
6139 // this lane and all further lanes to the left cannot be used
6140 requiredChangeRightForbidden = true;
6141 (*j).length = 0;
6142 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6143 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6144 // this lane and all previous lanes to the right cannot be used
6145 requireChangeToLeftForbidden = (*j).lane->getIndex();
6146 }
6147 }
6148 }
6149 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
6150 if (last[i].bestLaneOffset > 0) {
6151 last[i].length = 0;
6152 }
6153 }
6154#ifdef DEBUG_BESTLANES
6155 if (DEBUG_COND) {
6156 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6157 std::vector<LaneQ>& laneQs = myBestLanes.back();
6158 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6159 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
6160 }
6161 }
6162#endif
6163 }
6164 // go backward through the lanes
6165 // track back best lane and compute the best prior lane(s)
6166 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
6167 std::vector<LaneQ>& nextLanes = (*(i - 1));
6168 std::vector<LaneQ>& clanes = (*i);
6169 MSEdge* const cE = &clanes[0].lane->getEdge();
6170 int index = 0;
6171 double bestConnectedLength = -1;
6172 double bestLength = -1;
6173 for (const LaneQ& j : nextLanes) {
6174 if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
6175 bestConnectedLength = j.length;
6176 }
6177 if (bestLength < j.length) {
6178 bestLength = j.length;
6179 }
6180 }
6181 // compute index of the best lane (highest length and least offset from the best next lane)
6182 int bestThisIndex = 0;
6183 int bestThisMaxIndex = 0;
6184 if (bestConnectedLength > 0) {
6185 index = 0;
6186 for (LaneQ& j : clanes) {
6187 const LaneQ* bestConnectedNext = nullptr;
6188 if (j.allowsContinuation) {
6189 for (const LaneQ& m : nextLanes) {
6190 if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
6191 && m.lane->isApproachedFrom(cE, j.lane)) {
6192 if (betterContinuation(bestConnectedNext, m)) {
6193 bestConnectedNext = &m;
6194 }
6195 }
6196 }
6197 if (bestConnectedNext != nullptr) {
6198 if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
6199 j.length += bestLength;
6200 } else {
6201 j.length += bestConnectedNext->length;
6202 }
6203 j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
6204 }
6205 }
6206 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
6207 copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
6208 } else {
6209 j.allowsContinuation = false;
6210 }
6211 if (clanes[bestThisIndex].length < j.length
6212 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
6213 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
6214 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
6215 ) {
6216 bestThisIndex = index;
6217 bestThisMaxIndex = index;
6218 } else if (clanes[bestThisIndex].length == j.length
6219 && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
6220 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
6221 bestThisMaxIndex = index;
6222 }
6223 index++;
6224 }
6225
6226 //vehicle with elecHybrid device prefers running under an overhead wire
6227 if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
6228 index = 0;
6229 for (const LaneQ& j : clanes) {
6230 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6231 if (overheadWireSegmentID != "") {
6232 bestThisIndex = index;
6233 bestThisMaxIndex = index;
6234 }
6235 index++;
6236 }
6237 }
6238
6239 } else {
6240 // only needed in case of disconnected routes
6241 int bestNextIndex = 0;
6242 int bestDistToNeeded = (int) clanes.size();
6243 index = 0;
6244 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6245 if ((*j).allowsContinuation) {
6246 int nextIndex = 0;
6247 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
6248 if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
6249 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
6250 bestDistToNeeded = abs((*m).bestLaneOffset);
6251 bestThisIndex = index;
6252 bestThisMaxIndex = index;
6253 bestNextIndex = nextIndex;
6254 }
6255 }
6256 }
6257 }
6258 }
6259 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
6260 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
6261
6262 }
6263 // set bestLaneOffset for all lanes
6264 index = 0;
6265 bool requiredChangeRightForbidden = false;
6266 int requireChangeToLeftForbidden = -1;
6267 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6268 if ((*j).length < clanes[bestThisIndex].length
6269 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
6270 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
6271 ) {
6272 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6273 (*j).bestLaneOffset = bestThisIndex - index;
6274 } else {
6275 (*j).bestLaneOffset = bestThisMaxIndex - index;
6276 }
6277 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
6278 // try to move away from the lower-priority lane before it ends
6279 (*j).length = (*j).currentLength;
6280 }
6281 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6282 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6283 || requiredChangeRightForbidden)) {
6284 // this lane and all further lanes to the left cannot be used
6285 requiredChangeRightForbidden = true;
6286 if ((*j).length == (*j).currentLength) {
6287 (*j).length = 0;
6288 }
6289 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6290 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6291 // this lane and all previous lanes to the right cannot be used
6292 requireChangeToLeftForbidden = (*j).lane->getIndex();
6293 }
6294 } else {
6295 (*j).bestLaneOffset = 0;
6296 }
6297 }
6298 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
6299 if (clanes[idx].length == clanes[idx].currentLength) {
6300 clanes[idx].length = 0;
6301 };
6302 }
6303
6304 //vehicle with elecHybrid device prefers running under an overhead wire
6305 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
6306 index = 0;
6307 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6308 if (overheadWireID != "") {
6309 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6310 (*j).bestLaneOffset = bestThisIndex - index;
6311 }
6312 }
6313 }
6314
6315#ifdef DEBUG_BESTLANES
6316 if (DEBUG_COND) {
6317 std::cout << " edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6318 std::vector<LaneQ>& laneQs = clanes;
6319 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6320 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
6321 }
6322 }
6323#endif
6324
6325 }
6327#ifdef DEBUG_BESTLANES
6328 if (DEBUG_COND) {
6329 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
6330 }
6331#endif
6332}
6333
6334void
6336 if (myLane != nullptr) {
6338 }
6339}
6340
6341bool
6342MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
6343 if (bestConnectedNext == nullptr) {
6344 return true;
6345 } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
6346 return false;
6347 } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
6348 return true;
6349 } else if (bestConnectedNext->length < m.length) {
6350 return true;
6351 } else if (bestConnectedNext->length == m.length) {
6352 if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
6353 return true;
6354 }
6355 const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
6356 if (contRight < 1
6357 // if we don't check for adjacency, the rightmost line will get
6358 // multiple chances to be better which leads to an uninituitve distribution
6359 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
6360 && RandHelper::rand(getRNG()) > contRight) {
6361 return true;
6362 }
6363 }
6364 return false;
6365}
6366
6367
6368int
6369MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
6370 if (conts.size() < 2) {
6371 return -1;
6372 } else {
6373 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
6374 if (link != nullptr) {
6375 return link->havePriority() ? 1 : 0;
6376 } else {
6377 // disconnected route
6378 return -1;
6379 }
6380 }
6381}
6382
6383
6384void
6386 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
6387 std::vector<LaneQ>::iterator i;
6388 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
6389 double nextOccupation = 0;
6390 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
6391 nextOccupation += (*j)->getBruttoVehLenSum();
6392 }
6393 (*i).nextOccupation = nextOccupation;
6394#ifdef DEBUG_BESTLANES
6395 if (DEBUG_COND) {
6396 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
6397 }
6398#endif
6399 if ((*i).lane == startLane) {
6401 }
6402 }
6403}
6404
6405
6406const std::vector<MSLane*>&
6408 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6409 return myEmptyLaneVector;
6410 }
6411 return (*myCurrentLaneInBestLanes).bestContinuations;
6412}
6413
6414
6415const std::vector<MSLane*>&
6417 const MSLane* lane = l;
6418 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
6419 if (lane->getEdge().isInternal()) {
6420 // internal edges are not kept inside the bestLanes structure
6421 lane = lane->getLinkCont()[0]->getLane();
6422 }
6423 if (myBestLanes.size() == 0) {
6424 return myEmptyLaneVector;
6425 }
6426 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
6427 if ((*i).lane == lane) {
6428 return (*i).bestContinuations;
6429 }
6430 }
6431 return myEmptyLaneVector;
6432}
6433
6434const std::vector<const MSLane*>
6435MSVehicle::getUpcomingLanesUntil(double distance) const {
6436 std::vector<const MSLane*> lanes;
6437
6438 if (distance <= 0. || hasArrived()) {
6439 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
6440 return lanes;
6441 }
6442
6443 if (!myLaneChangeModel->isOpposite()) {
6444 distance += getPositionOnLane();
6445 } else {
6446 distance += myLane->getOppositePos(getPositionOnLane());
6447 }
6449 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6450 lanes.insert(lanes.end(), lane);
6451 distance -= lane->getLength();
6452 lane = lane->getLinkCont().front()->getViaLaneOrLane();
6453 }
6454
6455 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
6456 if (contLanes.empty()) {
6457 return lanes;
6458 }
6459 auto contLanesIt = contLanes.begin();
6460 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
6461 while (distance > 0.) {
6462 MSLane* l = nullptr;
6463 if (contLanesIt != contLanes.end()) {
6464 l = *contLanesIt;
6465 if (l != nullptr) {
6466 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
6467 }
6468 ++contLanesIt;
6469 if (l != nullptr || myLane->isInternal()) {
6470 ++routeIt;
6471 }
6472 if (l == nullptr) {
6473 continue;
6474 }
6475 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
6476 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6477 l = (*routeIt)->getLanes().back();
6478 ++routeIt;
6479 } else { // the search distance goes beyond our route
6480 break;
6481 }
6482
6483 assert(l != nullptr);
6484
6485 // insert internal lanes if applicable
6486 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
6487 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
6488 lanes.insert(lanes.end(), internalLane);
6489 distance -= internalLane->getLength();
6490 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6491 }
6492 if (distance <= 0.) {
6493 break;
6494 }
6495
6496 lanes.insert(lanes.end(), l);
6497 distance -= l->getLength();
6498 }
6499
6500 return lanes;
6501}
6502
6503const std::vector<const MSLane*>
6504MSVehicle::getPastLanesUntil(double distance) const {
6505 std::vector<const MSLane*> lanes;
6506
6507 if (distance <= 0.) {
6508 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
6509 return lanes;
6510 }
6511
6512 MSRouteIterator routeIt = myCurrEdge;
6513 if (!myLaneChangeModel->isOpposite()) {
6514 distance += myLane->getLength() - getPositionOnLane();
6515 } else {
6517 }
6519 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6520 lanes.insert(lanes.end(), lane);
6521 distance -= lane->getLength();
6522 lane = lane->getLogicalPredecessorLane();
6523 }
6524
6525 while (distance > 0.) {
6526 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6527 MSLane* l = (*routeIt)->getLanes().back();
6528
6529 // insert internal lanes if applicable
6530 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
6531 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
6532 std::vector<const MSLane*> internalLanes;
6533 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
6534 internalLanes.insert(internalLanes.begin(), internalLane);
6535 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6536 }
6537 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
6538 lanes.insert(lanes.end(), *it);
6539 distance -= (*it)->getLength();
6540 }
6541 if (distance <= 0.) {
6542 break;
6543 }
6544
6545 lanes.insert(lanes.end(), l);
6546 distance -= l->getLength();
6547
6548 // NOTE: we're going backwards with the (bi-directional) Iterator
6549 // TODO: consider make reverse_iterator() when moving on to C++14 or later
6550 if (routeIt != myRoute->begin()) {
6551 --routeIt;
6552 } else { // we went backwards to begin() and already processed the first and final element
6553 break;
6554 }
6555 }
6556
6557 return lanes;
6558}
6559
6560
6561const std::vector<MSLane*>
6563 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6564 std::vector<MSLane*> result;
6565 for (const MSLane* lane : routeLanes) {
6566 MSLane* opposite = lane->getOpposite();
6567 if (opposite != nullptr) {
6568 result.push_back(opposite);
6569 } else {
6570 break;
6571 }
6572 }
6573 return result;
6574}
6575
6576
6577int
6579 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6580 return 0;
6581 } else {
6582 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6583 }
6584}
6585
6586double
6588 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6589 return -1;
6590 } else {
6591 return (*myCurrentLaneInBestLanes).length;
6592 }
6593}
6594
6595
6596
6597void
6598MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6599 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6600 assert(laneIndex < (int)preb.size());
6601 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6602}
6603
6604
6605void
6611
6612std::pair<const MSLane*, double>
6613MSVehicle::getLanePosAfterDist(double distance) const {
6614 if (distance == 0) {
6615 return std::make_pair(myLane, getPositionOnLane());
6616 }
6617 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6618 distance += getPositionOnLane();
6619 for (const MSLane* lane : lanes) {
6620 if (lane->getLength() > distance) {
6621 return std::make_pair(lane, distance);
6622 }
6623 distance -= lane->getLength();
6624 }
6625 return std::make_pair(nullptr, -1);
6626}
6627
6628
6629double
6630MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
6631 if (isOnRoad() && destLane != nullptr) {
6632 return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
6633 }
6634 return std::numeric_limits<double>::max();
6635}
6636
6637
6638std::pair<const MSVehicle* const, double>
6639MSVehicle::getLeader(double dist, bool considerCrossingFoes) const {
6640 if (myLane == nullptr) {
6641 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6642 }
6643 if (dist == 0) {
6645 }
6646 const MSVehicle* lead = nullptr;
6647 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6648 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6649 // vehicle might be outside the road network
6650 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6651 if (it != vehs.end() && it + 1 != vehs.end()) {
6652 lead = *(it + 1);
6653 }
6654 if (lead != nullptr) {
6655 std::pair<const MSVehicle* const, double> result(
6656 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6657 lane->releaseVehicles();
6658 return result;
6659 }
6660 const double seen = myLane->getLength() - getPositionOnLane();
6661 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6662 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts, considerCrossingFoes);
6663 lane->releaseVehicles();
6664 return result;
6665}
6666
6667
6668std::pair<const MSVehicle* const, double>
6669MSVehicle::getFollower(double dist) const {
6670 if (myLane == nullptr) {
6671 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6672 }
6673 if (dist == 0) {
6674 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6675 }
6677}
6678
6679
6680double
6682 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6683 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6684 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6685 return -1;
6686 }
6687 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6688}
6689
6690
6691void
6693 MSBaseVehicle::addTransportable(transportable);
6694 if (myStops.size() > 0 && myStops.front().reached) {
6695 if (transportable->isPerson()) {
6696 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6697 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6698 }
6699 } else {
6700 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6701 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6702 }
6703 }
6704 }
6705}
6706
6707
6708void
6711 int state = myLaneChangeModel->getOwnState();
6712 // do not set blinker for sublane changes or when blocked from changing to the right
6713 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6714 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6718 // lane indices increase from left to right
6719 std::swap(left, right);
6720 }
6721 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6722 switchOnSignal(left);
6723 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6724 switchOnSignal(right);
6725 } else if (myLaneChangeModel->isChangingLanes()) {
6727 switchOnSignal(left);
6728 } else {
6729 switchOnSignal(right);
6730 }
6731 } else {
6732 const MSLane* lane = getLane();
6733 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6734 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6735 switch ((*link)->getDirection()) {
6740 break;
6744 break;
6745 default:
6746 break;
6747 }
6748 }
6749 }
6750 // stopping related signals
6751 if (hasStops()
6752 && (myStops.begin()->reached ||
6754 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6755 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6756 // not stopping on the right. Activate emergency blinkers
6758 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6759 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6761 }
6762 }
6763 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6765 myInfluencer->setSignals(-1); // overwrite computed signals only once
6766 }
6767}
6768
6769void
6771
6772 //TODO look if timestep ist SIMSTEP
6773 if (currentTime % 1000 == 0) {
6776 } else {
6778 }
6779 }
6780}
6781
6782
6783int
6785 return myLane == nullptr ? -1 : myLane->getIndex();
6786}
6787
6788
6789void
6790MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6791 myLane = lane;
6792 myState.myPos = pos;
6793 myState.myPosLat = posLat;
6795}
6796
6797
6798double
6800 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6801}
6802
6803
6804double
6806 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6807}
6808
6809
6810double
6812 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6813}
6814
6815
6816double
6818 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6819}
6820
6821
6822double
6824 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6825}
6826
6827
6828double
6830 return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
6831}
6832
6833
6834double
6836 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6838 } else if (lane == myLaneChangeModel->getShadowLane()) {
6839 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6840 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6841 }
6843 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6844 } else {
6845 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6846 }
6847 } else if (lane == myLane->getBidiLane()) {
6848 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6849 } else {
6850 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6851 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6852 if (myFurtherLanes[i] == lane) {
6853#ifdef DEBUG_FURTHER
6854 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
6855 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6856 << "\n";
6857#endif
6858 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6859 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6860#ifdef DEBUG_FURTHER
6861 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
6862 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6863 << "\n";
6864#endif
6865 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6866 }
6867 }
6868 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6869 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6870 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6871 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6872 if (shadowFurther[i] == lane) {
6873 assert(myLaneChangeModel->getShadowLane() != 0);
6874 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6876 }
6877 }
6878 assert(false);
6879 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6880 }
6881}
6882
6883
6884double
6886 assert(lane != 0);
6887 if (&lane->getEdge() == &myLane->getEdge()) {
6888 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6889 } else if (myLane->getParallelOpposite() == lane) {
6890 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6891 } else if (myLane->getBidiLane() == lane) {
6892 return -2 * getLateralPositionOnLane();
6893 } else {
6894 // Check whether the lane is a further lane for the vehicle
6895 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6896 if (myFurtherLanes[i] == lane) {
6897#ifdef DEBUG_FURTHER
6898 if (DEBUG_COND) {
6899 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6900 }
6901#endif
6903 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6904#ifdef DEBUG_FURTHER
6905 if (DEBUG_COND) {
6906 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
6907 }
6908#endif
6909 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
6910 }
6911 }
6912#ifdef DEBUG_FURTHER
6913 if (DEBUG_COND) {
6914 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6915 }
6916#endif
6917 // Check whether the lane is a "shadow further lane" for the vehicle
6918 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6919 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6920 if (shadowFurther[i] == lane) {
6921#ifdef DEBUG_FURTHER
6922 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6923 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6924 << " lane=" << lane->getID()
6925 << " i=" << i
6926 << " posLat=" << myState.myPosLat
6927 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6928 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6929 << "\n";
6930#endif
6932 }
6933 }
6934 // Check whether the vehicle issued a maneuverReservation on the lane.
6935 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6936 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6937 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6938 MSLane* targetLane = furtherTargets[i];
6939 if (targetLane == lane) {
6940 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6941 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
6942#ifdef DEBUG_TARGET_LANE
6943 if (DEBUG_COND) {
6944 std::cout << " getLatOffset veh=" << getID()
6945 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
6946 << "\n i=" << i
6947 << " posLat=" << myState.myPosLat
6948 << " furtherPosLat=" << myFurtherLanesPosLat[i]
6949 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
6950 << " targetDir=" << targetDir
6951 << " latOffset=" << latOffset
6952 << std::endl;
6953 }
6954#endif
6955 return latOffset;
6956 }
6957 }
6958 assert(false);
6959 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6960 }
6961}
6962
6963
6964double
6965MSVehicle::lateralDistanceToLane(const int offset) const {
6966 // compute the distance when changing to the neighboring lane
6967 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
6968 assert(offset == 0 || offset == 1 || offset == -1);
6969 assert(myLane != nullptr);
6970 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
6971 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
6972 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
6973 const double latPos = getLateralPositionOnLane();
6974 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
6975 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
6976 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
6977 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
6978 if (offset == 0) {
6979 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
6980 // correct overlapping left
6981 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
6982 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
6983 // correct overlapping right
6984 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
6985 }
6986 latLaneDist *= oppositeSign;
6987 } else if (offset == -1) {
6988 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
6989 } else if (offset == 1) {
6990 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
6991 }
6992#ifdef DEBUG_ACTIONSTEPS
6993 if (DEBUG_COND) {
6994 std::cout << SIMTIME
6995 << " veh=" << getID()
6996 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
6997 << " halfVehWidth=" << halfVehWidth
6998 << " latPos=" << latPos
6999 << " latLaneDist=" << latLaneDist
7000 << " leftLimit=" << leftLimit
7001 << " rightLimit=" << rightLimit
7002 << "\n";
7003 }
7004#endif
7005 return latLaneDist;
7006}
7007
7008
7009double
7010MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
7011 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
7012 - 0.5 * lane->getWidth());
7013}
7014
7015double
7019
7020double
7024
7025
7026void
7028 for (const DriveProcessItem& dpi : lfLinks) {
7029 if (dpi.myLink != nullptr) {
7030 dpi.myLink->removeApproaching(this);
7031 }
7032 }
7033 // unregister on all shadow links
7035}
7036
7037
7038bool
7039MSVehicle::unsafeLinkAhead(const MSLane* lane, double zipperDist) const {
7040 // the following links are unsafe:
7041 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
7042 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
7043 double seen = myLane->getLength() - getPositionOnLane();
7044 const double dist = MAX2(zipperDist, getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0));
7045 if (seen < dist) {
7046 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
7047 int view = 1;
7048 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7049 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
7050 while (!lane->isLinkEnd(link) && seen <= dist) {
7051 if ((!lane->isInternal()
7052 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
7053 || !(*link)->havePriority()))
7054 || (lane->isInternal() && zipperDist > 0)) {
7055 // find the drive item corresponding to this link
7056 bool found = false;
7057 while (di != myLFLinkLanes.end() && !found) {
7058 if ((*di).myLink != nullptr) {
7059 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
7060 if (diPredLane != nullptr) {
7061 if (&diPredLane->getEdge() == &lane->getEdge()) {
7062 found = true;
7063 }
7064 }
7065 }
7066 if (!found) {
7067 di++;
7068 }
7069 }
7070 if (found) {
7071 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
7072 (*di).getLeaveSpeed(), getVehicleType().getLength());
7073 const MSLink* entry = (*link)->getCorrespondingEntryLink();
7074 //if (DEBUG_COND) {
7075 // 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";
7076 //}
7077 if (entry->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
7078 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
7079 return true;
7080 }
7081 }
7082 // no drive item is found if the vehicle aborts its request within dist
7083 }
7084 lane = (*link)->getViaLaneOrLane();
7085 if (!lane->getEdge().isInternal()) {
7086 view++;
7087 }
7088 seen += lane->getLength();
7089 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7090 }
7091 }
7092 return false;
7093}
7094
7095
7097MSVehicle::getBoundingBox(double offset) const {
7098 PositionVector centerLine;
7099 Position pos = getPosition();
7100 centerLine.push_back(pos);
7101 switch (myType->getGuiShape()) {
7108 for (MSLane* lane : myFurtherLanes) {
7109 centerLine.push_back(lane->getShape().back());
7110 }
7111 break;
7112 }
7113 default:
7114 break;
7115 }
7116 double l = getLength();
7117 Position backPos = getBackPosition();
7118 if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
7119 // getBackPosition may not match the visual back in networks without internal lanes
7120 double a = getAngle() + M_PI; // angle pointing backwards
7121 backPos = pos + Position(l * cos(a), l * sin(a));
7122 }
7123 centerLine.push_back(backPos);
7124 if (offset != 0) {
7125 centerLine.extrapolate2D(offset);
7126 }
7127 PositionVector result = centerLine;
7128 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7129 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
7130 result.append(centerLine.reverse(), POSITION_EPS);
7131 return result;
7132}
7133
7134
7136MSVehicle::getBoundingPoly(double offset) const {
7137 switch (myType->getGuiShape()) {
7143 // box with corners cut off
7144 PositionVector result;
7145 PositionVector centerLine;
7146 centerLine.push_back(getPosition());
7147 centerLine.push_back(getBackPosition());
7148 if (offset != 0) {
7149 centerLine.extrapolate2D(offset);
7150 }
7151 PositionVector line1 = centerLine;
7152 PositionVector line2 = centerLine;
7153 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
7154 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7155 line2.scaleRelative(0.8);
7156 result.push_back(line1[0]);
7157 result.push_back(line2[0]);
7158 result.push_back(line2[1]);
7159 result.push_back(line1[1]);
7160 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
7161 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
7162 result.push_back(line1[1]);
7163 result.push_back(line2[1]);
7164 result.push_back(line2[0]);
7165 result.push_back(line1[0]);
7166 return result;
7167 }
7168 default:
7169 return getBoundingBox();
7170 }
7171}
7172
7173
7174bool
7176 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
7177 if (&(*i)->getEdge() == edge) {
7178 return true;
7179 }
7180 }
7181 return false;
7182}
7183
7184
7185bool
7186MSVehicle::isBidiOn(const MSLane* lane) const {
7187 return lane->getBidiLane() != nullptr && (
7188 myLane == lane->getBidiLane()
7189 || onFurtherEdge(&lane->getBidiLane()->getEdge()));
7190}
7191
7192
7193bool
7194MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
7195 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
7196 // consistency in the behaviour.
7197
7198 // get vehicle params
7199 MSParkingArea* destParkArea = getNextParkingArea();
7200 const MSRoute& route = getRoute();
7201 const MSEdge* lastEdge = route.getLastEdge();
7202
7203 if (destParkArea == nullptr) {
7204 // not driving towards a parking area
7205 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
7206 return false;
7207 }
7208
7209 // if the current route ends at the parking area, the new route will also and at the new area
7210 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
7211 && getArrivalPos() >= destParkArea->getBeginLanePosition()
7212 && getArrivalPos() <= destParkArea->getEndLanePosition());
7213
7214 // retrieve info on the new parking area
7216 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
7217
7218 if (newParkingArea == nullptr) {
7219 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
7220 return false;
7221 }
7222
7223 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
7225
7226 // Compute the route from the current edge to the parking area edge
7227 ConstMSEdgeVector edgesToPark;
7228 router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
7229
7230 // Compute the route from the parking area edge to the end of the route
7231 ConstMSEdgeVector edgesFromPark;
7232 if (!newDestination) {
7233 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
7234 } else {
7235 // adapt plans of any riders
7236 for (MSTransportable* p : getPersons()) {
7237 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
7238 }
7239 }
7240
7241 // we have a new destination, let's replace the vehicle route
7242 ConstMSEdgeVector edges = edgesToPark;
7243 if (edgesFromPark.size() > 0) {
7244 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
7245 }
7246
7247 if (newDestination) {
7248 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
7249 *newParameter = getParameter();
7251 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
7252 replaceParameter(newParameter);
7253 }
7254 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
7255 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
7256 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
7257 if (replaceParkingArea(newParkingArea, errorMsg)) {
7258 const bool onInit = myLane == nullptr;
7259 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
7260 } else {
7261 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
7262 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
7263 return false;
7264 }
7265 return true;
7266}
7267
7268
7269bool
7271 const int numStops = (int)myStops.size();
7272 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
7273 if (myLane != nullptr && numStops != (int)myStops.size()) {
7274 updateBestLanes(true);
7275 }
7276 return result;
7277}
7278
7279
7280bool
7281MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
7282 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
7283 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
7284 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
7285 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
7286 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
7287 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
7288 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
7289 // << " vNew=" << vNew
7290 // << "\n";
7291 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
7294 if (myState.myPos < myType->getLength()) {
7298 myAngle += M_PI;
7299 }
7300 }
7301 }
7302 }
7303 return true;
7304}
7305
7306
7307bool
7309 if (isStopped()) {
7313 }
7314 MSStop& stop = myStops.front();
7315 // we have waited long enough and fulfilled any passenger-requirements
7316 if (stop.busstop != nullptr) {
7317 // inform bus stop about leaving it
7318 stop.busstop->leaveFrom(this);
7319 }
7320 // we have waited long enough and fulfilled any container-requirements
7321 if (stop.containerstop != nullptr) {
7322 // inform container stop about leaving it
7323 stop.containerstop->leaveFrom(this);
7324 }
7325 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
7326 // inform parking area about leaving it
7327 stop.parkingarea->leaveFrom(this);
7328 }
7329 if (stop.chargingStation != nullptr) {
7330 // inform charging station about leaving it
7331 stop.chargingStation->leaveFrom(this);
7332 }
7333 // the current stop is no longer valid
7334 myLane->getEdge().removeWaiting(this);
7335 // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
7336 if (stop.pars.started == -1) {
7337 // waypoint edge was passed in a single step
7339 }
7340 if (MSStopOut::active()) {
7341 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
7342 }
7344 for (const auto& rem : myMoveReminders) {
7345 rem.first->notifyStopEnded();
7346 }
7348 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
7349 }
7351 // reset lateral position to default
7352 myState.myPosLat = 0;
7353 }
7354 myPastStops.push_back(stop.pars);
7355 myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
7356 myStops.pop_front();
7357 myStopDist = std::numeric_limits<double>::max();
7358 // do not count the stopping time towards gridlock time.
7359 // Other outputs use an independent counter and are not affected.
7360 myWaitingTime = 0;
7361 // maybe the next stop is on the same edge; let's rebuild best lanes
7362 updateBestLanes(true);
7363 // continue as wished...
7366 return true;
7367 }
7368 return false;
7369}
7370
7371
7374 if (myInfluencer == nullptr) {
7375 myInfluencer = new Influencer();
7376 }
7377 return *myInfluencer;
7378}
7379
7384
7385
7388 return myInfluencer;
7389}
7390
7393 return myInfluencer;
7394}
7395
7396
7397double
7399 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
7400 // influencer original speed is -1 on initialization
7402 }
7403 return myState.mySpeed;
7404}
7405
7406
7407int
7409 if (hasInfluencer()) {
7411 MSNet::getInstance()->getCurrentTimeStep(),
7412 myLane->getEdge(),
7413 getLaneIndex(),
7414 state);
7415 }
7416 return state;
7417}
7418
7419
7420void
7424
7425
7426bool
7430
7431
7432bool
7436
7437
7438bool
7439MSVehicle::keepClear(const MSLink* link) const {
7440 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
7441 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
7442 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
7443 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
7444 } else {
7445 return false;
7446 }
7447}
7448
7449
7450bool
7451MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
7452 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
7453 return true;
7454 }
7455 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
7456#ifdef DEBUG_IGNORE_RED
7457 if (DEBUG_COND) {
7458 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
7459 }
7460#endif
7461 if (ignoreRedTime < 0) {
7462 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
7463 if (ignoreYellowTime > 0 && link->haveYellow()) {
7464 assert(link->getTLLogic() != 0);
7465 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7466 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
7467 return !canBrake || ignoreYellowTime > yellowDuration;
7468 } else {
7469 return false;
7470 }
7471 } else if (link->haveYellow()) {
7472 // always drive at yellow when ignoring red
7473 return true;
7474 } else if (link->haveRed()) {
7475 assert(link->getTLLogic() != 0);
7476 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7477#ifdef DEBUG_IGNORE_RED
7478 if (DEBUG_COND) {
7479 std::cout
7480 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
7481 << " ignoreRedTime=" << ignoreRedTime
7482 << " spentRed=" << redDuration
7483 << " canBrake=" << canBrake << "\n";
7484 }
7485#endif
7486 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
7487 return !canBrake || ignoreRedTime > redDuration;
7488 } else {
7489 return false;
7490 }
7491}
7492
7493bool
7496 return false;
7497 }
7498 for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
7499 if (typeID == foe->getVehicleType().getID()) {
7500 return true;
7501 }
7502 }
7503 for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
7504 if (id == foe->getID()) {
7505 return true;
7506 }
7507 }
7508 return false;
7509}
7510
7511bool
7513 // either on an internal lane that was entered via minor link
7514 // or on approach to minor link below visibility distance
7515 if (myLane == nullptr) {
7516 return false;
7517 }
7518 if (myLane->getEdge().isInternal()) {
7519 return !myLane->getIncomingLanes().front().viaLink->havePriority();
7520 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
7521 MSLink* link = myLFLinkLanes.front().myLink;
7522 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
7523 }
7524 return false;
7525}
7526
7527bool
7528MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
7529 assert(link->fromInternalLane());
7530 if (veh == nullptr) {
7531 return false;
7532 }
7533 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
7534 // if this vehicle is not yet on the junction, every vehicle is a leader
7535 return true;
7536 }
7537 if (veh->getLaneChangeModel().hasBlueLight()) {
7538 // blue light device automatically gets right of way
7539 return true;
7540 }
7541 const MSLane* foeLane = veh->getLane();
7542 if (foeLane->isInternal()) {
7543 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
7545 SUMOTime foeET = veh->myJunctionEntryTime;
7546 // check relationship between link and foeLane
7548 // we are entering the junction from the same lane
7550 foeET = veh->myJunctionEntryTimeNeverYield;
7553 }
7554 } else {
7555 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
7556 const MSJunctionLogic* logic = link->getJunction()->getLogic();
7557 assert(logic != nullptr);
7558 // determine who has right of way
7559 bool response; // ego response to foe
7560 bool response2; // foe response to ego
7561 // attempt 1: tlLinkState
7562 const MSLink* entry = link->getCorrespondingEntryLink();
7563 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
7564 if (entry->haveRed() || foeEntry->haveRed()) {
7565 // ensure that vehicles which are stuck on the intersection may exit
7566 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
7567 // foe might be oncoming, don't drive unless foe can still brake safely
7568 const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
7569 const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
7570 foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
7571 // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
7572 // so the -2* makes it point in the right direction
7573 const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
7574#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7575 if (DEBUG_COND) {
7576 std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
7577
7578 }
7579#endif
7580 if (foeGap < foeBrakeGap) {
7581 response = true;
7582 response2 = false;
7583 } else {
7584 response = false;
7585 response2 = true;
7586 }
7587 } else {
7588 // let conflict entry time decide
7589 response = true;
7590 response2 = true;
7591 }
7592 } else if (entry->havePriority() != foeEntry->havePriority()) {
7593 response = !entry->havePriority();
7594 response2 = !foeEntry->havePriority();
7595 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
7596 // let the faster vehicle keep moving
7597 response = veh->getSpeed() >= getSpeed();
7598 response2 = getSpeed() >= veh->getSpeed();
7599 } else {
7600 // fallback if pedestrian crossings are involved
7601 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
7602 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
7603 }
7604#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7605 if (DEBUG_COND) {
7606 std::cout << SIMTIME
7607 << " foeLane=" << foeLane->getID()
7608 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
7609 << " linkIndex=" << link->getIndex()
7610 << " foeLinkIndex=" << foeLink->getIndex()
7611 << " entryState=" << toString(entry->getState())
7612 << " entryState2=" << toString(foeEntry->getState())
7613 << " response=" << response
7614 << " response2=" << response2
7615 << "\n";
7616 }
7617#endif
7618 if (!response) {
7619 // if we have right of way over the foe, entryTime does not matter
7620 foeET = veh->myJunctionConflictEntryTime;
7621 egoET = myJunctionEntryTime;
7622 } else if (response && response2) {
7623 // in a mutual conflict scenario, use entry time to avoid deadlock
7624 foeET = veh->myJunctionConflictEntryTime;
7626 }
7627 }
7628 if (egoET == foeET) {
7629 // try to use speed as tie braker
7630 if (getSpeed() == veh->getSpeed()) {
7631 // use ID as tie braker
7632#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7633 if (DEBUG_COND) {
7634 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7635 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7636 }
7637#endif
7638 return getID() < veh->getID();
7639 } else {
7640#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7641 if (DEBUG_COND) {
7642 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7643 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7644 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7645 << "\n";
7646 }
7647#endif
7648 return getSpeed() < veh->getSpeed();
7649 }
7650 } else {
7651 // leader was on the junction first
7652#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7653 if (DEBUG_COND) {
7654 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7655 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7656 }
7657#endif
7658 return egoET > foeET;
7659 }
7660 } else {
7661 // vehicle can only be partially on the junction. Must be a leader
7662 return true;
7663 }
7664 } else {
7665 // vehicle can only be partially on the junction. Must be a leader
7666 return true;
7667 }
7668}
7669
7670void
7673 // here starts the vehicle internal part (see loading)
7674 std::vector<std::string> internals;
7675 internals.push_back(toString(myParameter->parametersSet));
7676 internals.push_back(toString(myDeparture));
7677 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7678 internals.push_back(toString(myDepartPos));
7679 internals.push_back(toString(myWaitingTime));
7680 internals.push_back(toString(myTimeLoss));
7681 internals.push_back(toString(myLastActionTime));
7682 internals.push_back(toString(isStopped()));
7683 internals.push_back(toString(myPastStops.size()));
7684 out.writeAttr(SUMO_ATTR_STATE, internals);
7686 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7691 // save past stops
7693 stop.write(out, false);
7694 // do not write started and ended twice
7695 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7696 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7697 }
7698 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7699 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7700 }
7701 stop.writeParams(out);
7702 out.closeTag();
7703 }
7704 // save upcoming stops
7705 for (MSStop& stop : myStops) {
7706 stop.write(out);
7707 }
7708 // save parameters and device states
7710 for (MSVehicleDevice* const dev : myDevices) {
7711 dev->saveState(out);
7712 }
7713 out.closeTag();
7714}
7715
7716void
7718 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7719 throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
7720 }
7721 int routeOffset;
7722 bool stopped;
7723 int pastStops;
7724
7725 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7726 bis >> myParameter->parametersSet;
7727 bis >> myDeparture;
7728 bis >> routeOffset;
7729 bis >> myDepartPos;
7730 bis >> myWaitingTime;
7731 bis >> myTimeLoss;
7732 bis >> myLastActionTime;
7733 bis >> stopped;
7734 bis >> pastStops;
7735
7737 bool ok;
7738 myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
7739 }
7740 // load stops
7741 myStops.clear();
7743
7744 if (hasDeparted()) {
7745 myCurrEdge = myRoute->begin() + routeOffset;
7746 myDeparture -= offset;
7747 // fix stops
7748 while (pastStops > 0) {
7749 myPastStops.push_back(myStops.front().pars);
7750 myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
7751 myStops.pop_front();
7752 pastStops--;
7753 }
7754 // see MSBaseVehicle constructor
7757 }
7758 // a (tentative lane is needed for calling hasArrivedInternal
7759 myLane = (*myCurrEdge)->getLanes()[0];
7760 }
7763 WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
7764 }
7765 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7767 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7772 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7773 dis >> myOdometer >> myNumberReroutes;
7775 if (stopped) {
7776 myStops.front().startedFromState = true;
7777 myStopDist = 0;
7778 }
7780 // no need to reset myCachedPosition here since state loading happens directly after creation
7781}
7782
7783void
7785 SUMOTime arrivalTime, double arrivalSpeed,
7786 double arrivalSpeedBraking,
7787 double dist, double leaveSpeed) {
7788 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7789 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7790 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7791
7792}
7793
7794
7795std::shared_ptr<MSSimpleDriverState>
7799
7800
7801double
7803 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7804}
7805
7806
7807void
7808MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7809 myState.mySpeed = MAX2(0., prevSpeed);
7810 // also retcon acceleration
7811 if (prevAcceleration != std::numeric_limits<double>::min()) {
7812 myAcceleration = prevAcceleration;
7813 } else {
7815 }
7816}
7817
7818
7819double
7821 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7823}
7824
7825/****************************************************************************/
7826bool
7830
7831/* -------------------------------------------------------------------------
7832 * methods of MSVehicle::manoeuvre
7833 * ----------------------------------------------------------------------- */
7834
7835MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7836
7837
7839 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7840 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7841 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7842 myManoeuvreType = manoeuvre.myManoeuvreType;
7843 myGUIIncrement = manoeuvre.myGUIIncrement;
7844}
7845
7846
7849 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7850 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7851 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7852 myManoeuvreType = manoeuvre.myManoeuvreType;
7853 myGUIIncrement = manoeuvre.myGUIIncrement;
7854 return *this;
7855}
7856
7857
7858bool
7860 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7861 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7862 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7863 myManoeuvreType != manoeuvre.myManoeuvreType ||
7864 myGUIIncrement != manoeuvre.myGUIIncrement
7865 );
7866}
7867
7868
7869double
7871 return (myGUIIncrement);
7872}
7873
7874
7877 return (myManoeuvreType);
7878}
7879
7880
7885
7886
7887void
7891
7892
7893void
7895 myManoeuvreType = mType;
7896}
7897
7898
7899bool
7901 if (!veh->hasStops()) {
7902 return false; // should never happen - checked before call
7903 }
7904
7905 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7906 const MSStop& stop = veh->getNextStop();
7907
7908 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7909 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7910 if (abs(GUIAngle) < 0.1) {
7911 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7912 }
7913 myManoeuvreVehicleID = veh->getID();
7914 myManoeuvreStop = stop.parkingarea->getID();
7915 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7916 myManoeuvreStartTime = currentTime;
7917 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7918 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7919
7920#ifdef DEBUG_STOPS
7921 if (veh->isSelected()) {
7922 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 <<
7923 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7924 }
7925#endif
7926
7927 return (true);
7928}
7929
7930
7931bool
7933 // At the moment we only want to set for parking areas
7934 if (!veh->hasStops()) {
7935 return true;
7936 }
7937 if (veh->getNextStop().parkingarea == nullptr) {
7938 return true;
7939 }
7940
7941 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
7942 return (false);
7943 }
7944
7945 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7946
7947 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
7948 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
7949 if (abs(GUIAngle) < 0.1) {
7950 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
7951 }
7952
7953 myManoeuvreVehicleID = veh->getID();
7954 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
7955 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
7956 myManoeuvreStartTime = currentTime;
7957 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
7958 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7959 if (veh->remainingStopDuration() > 0) {
7960 myManoeuvreCompleteTime += veh->remainingStopDuration();
7961 }
7962
7963#ifdef DEBUG_STOPS
7964 if (veh->isSelected()) {
7965 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
7966 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7967 }
7968#endif
7969
7970 return (true);
7971}
7972
7973
7974bool
7976 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
7977 if (!veh->hasStops()) {
7978 return (true);
7979 }
7980 MSStop* currentStop = &veh->myStops.front();
7981 if (currentStop->parkingarea == nullptr) {
7982 return true;
7983 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
7984 if (configureEntryManoeuvre(veh)) {
7986 return (false);
7987 } else { // cannot configure entry so stop trying
7988 return true;
7989 }
7990 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7991 return false;
7992 } else { // manoeuvre complete
7993 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
7994 return true;
7995 }
7996}
7997
7998
7999bool
8001 if (checkType != myManoeuvreType) {
8002 return true; // we're not maneuvering / wrong manoeuvre
8003 }
8004
8005 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
8006 return false;
8007 } else {
8008 return true;
8009 }
8010}
8011
8012
8013bool
8015 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
8016}
8017
8018
8019bool
8023
8024
8025std::pair<double, double>
8027 if (hasStops()) {
8028 MSLane* lane = myLane;
8029 if (lane == nullptr) {
8030 // not in network
8031 lane = getEdge()->getLanes()[0];
8032 }
8033 const MSStop& stop = myStops.front();
8034 auto it = myCurrEdge + 1;
8035 // drive to end of current edge
8036 double dist = (lane->getLength() - getPositionOnLane());
8037 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
8038 // drive until stop edge
8039 while (it != myRoute->end() && it < stop.edge) {
8040 travelTime += (*it)->getMinimumTravelTime(this);
8041 dist += (*it)->getLength();
8042 it++;
8043 }
8044 // drive up to the stop position
8045 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
8046 dist += stopEdgeDist;
8047 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
8048 // estimate time loss due to acceleration and deceleration
8049 // maximum speed is limited by available distance:
8050 const double a = getCarFollowModel().getMaxAccel();
8051 const double b = getCarFollowModel().getMaxDecel();
8052 const double c = getSpeed();
8053 const double d = dist;
8054 const double len = getVehicleType().getLength();
8055 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
8056 // distAccel = (v - c)^2 / (2a)
8057 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
8058 // distAccel + distDecel < d
8059 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))))
8060 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
8061 it = myCurrEdge;
8062 double v0 = c;
8063 bool v0Stable = getAcceleration() == 0 && v0 > 0;
8064 double timeLossAccel = 0;
8065 double timeLossDecel = 0;
8066 double timeLossLength = 0;
8067 while (it != myRoute->end() && it <= stop.edge) {
8068 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
8069 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
8070 if (edgeLength <= len && v0Stable && v0 < v) {
8071 const double lengthDist = MIN2(len, edgeLength);
8072 const double dTL = lengthDist / v0 - lengthDist / v;
8073 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
8074 timeLossLength += dTL;
8075 }
8076 if (edgeLength > len) {
8077 const double dv = v - v0;
8078 if (dv > 0) {
8079 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8080 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8081 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8082 timeLossAccel += dTA;
8083 // time loss from vehicle length
8084 } else if (dv < 0) {
8085 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8086 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8087 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8088 timeLossDecel += dTD;
8089 }
8090 v0 = v;
8091 v0Stable = true;
8092 }
8093 it++;
8094 }
8095 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
8096 double v = vs;
8097 const double dv = v - v0;
8098 if (dv > 0) {
8099 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8100 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8101 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8102 timeLossAccel += dTA;
8103 // time loss from vehicle length
8104 } else if (dv < 0) {
8105 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8106 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8107 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8108 timeLossDecel += dTD;
8109 }
8110 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
8111 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
8112 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
8113 return {MAX2(0.0, result), dist};
8114 } else {
8116 }
8117}
8118
8119
8120double
8122 if (hasStops() && myStops.front().pars.until >= 0) {
8123 const MSStop& stop = myStops.front();
8124 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
8125 if (stop.reached) {
8126 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
8127 }
8128 if (stop.pars.duration > 0) {
8129 estimatedDepart += stop.pars.duration;
8130 }
8131 estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
8132 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
8133 return result;
8134 } else {
8135 // vehicles cannot drive before 'until' so stop delay can never be
8136 // negative and we can use -1 to signal "undefined"
8137 return -1;
8138 }
8139}
8140
8141
8142double
8144 if (hasStops() && myStops.front().pars.arrival >= 0) {
8145 const MSStop& stop = myStops.front();
8146 if (stop.reached) {
8147 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
8148 } else {
8149 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
8150 }
8151 } else {
8152 // vehicles can arrival earlier than planned so arrival delay can be negative
8153 return INVALID_DOUBLE;
8154 }
8155}
8156
8157
8158const MSEdge*
8160 return myLane != nullptr ? &myLane->getEdge() : getEdge();
8161}
8162
8163
8164const MSEdge*
8166 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
8167 return nullptr;
8168 }
8169 if (myLane->isInternal()) {
8171 } else {
8172 const MSEdge* nextNormal = succEdge(1);
8173 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
8174 return nextInternal ? nextInternal : nextNormal;
8175 }
8176}
8177
8178
8179const MSLane*
8180MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
8181 if (furtherIndex < (int)myFurtherLanes.size()) {
8182 return myFurtherLanes[furtherIndex++];
8183 } else {
8184 // try to use route information
8185 int routeIndex = getRoutePosition();
8186 bool resultInternal;
8187 if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
8188 if (myLane->isInternal()) {
8189 if (furtherIndex % 2 == 0) {
8190 routeIndex -= (furtherIndex + 0) / 2;
8191 resultInternal = false;
8192 } else {
8193 routeIndex -= (furtherIndex + 1) / 2;
8194 resultInternal = false;
8195 }
8196 } else {
8197 if (furtherIndex % 2 != 0) {
8198 routeIndex -= (furtherIndex + 1) / 2;
8199 resultInternal = false;
8200 } else {
8201 routeIndex -= (furtherIndex + 2) / 2;
8202 resultInternal = true;
8203 }
8204 }
8205 } else {
8206 routeIndex -= furtherIndex;
8207 resultInternal = false;
8208 }
8209 furtherIndex++;
8210 if (routeIndex >= 0) {
8211 if (resultInternal) {
8212 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
8213 for (MSLane* cand : prevNormal->getLanes()) {
8214 for (MSLink* link : cand->getLinkCont()) {
8215 if (link->getLane() == current) {
8216 if (link->getViaLane() != nullptr) {
8217 return link->getViaLane();
8218 } else {
8219 return const_cast<MSLane*>(link->getLaneBefore());
8220 }
8221 }
8222 }
8223 }
8224 } else {
8225 return myRoute->getEdges()[routeIndex]->getLanes()[0];
8226 }
8227 }
8228 }
8229 return current;
8230}
8231
8234 // this vehicle currently has the highest priority on the allway_stop
8235 return link == myHaveStoppedFor ? SUMOTime_MAX : getWaitingTime();
8236}
8237
8238
8239void
8241 bool diverged = false;
8242 const ConstMSEdgeVector& route = myRoute->getEdges();
8243 int ri = getRoutePosition();
8244 for (const DriveProcessItem& dpi : myLFLinkLanes) {
8245 if (dpi.myLink != nullptr) {
8246 if (!diverged) {
8247 const MSEdge* next = route[ri + 1];
8248 if (&dpi.myLink->getLane()->getEdge() != next) {
8249 diverged = true;
8250 } else {
8251 if (dpi.myLink->getViaLane() == nullptr) {
8252 ri++;
8253 }
8254 }
8255 }
8256 if (diverged) {
8257 dpi.myLink->removeApproaching(this);
8258 }
8259 }
8260 }
8261}
8262
8263/****************************************************************************/
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:4400
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:4574
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:2850
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2832
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:2680
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2768
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:2694
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2433
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2745
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1392
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3778
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:597
std::vector< MSVehicle * > VehCont
Container for vehicles.
Definition MSLane.h:119
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2465
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:619
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:955
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3272
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:2907
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:2757
const MSLeaderInfo getLastVehicleInformation(const MSVehicle *ego, double latOffset, double minPos=0, bool allowCached=true) const
Returns the last vehicles on the lane.
Definition MSLane.cpp:1445
std::pair< MSVehicle *const, double > getLeaderOnConsecutive(double dist, double seen, double speed, const MSVehicle &veh, const std::vector< MSLane * > &bestLaneConts, bool considerCrossingFoes=true) const
Returns the immediate leader and the distance to him.
Definition MSLane.cpp:2991
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:4567
int getIndex() const
Returns the lane's index.
Definition MSLane.h:647
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3296
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4395
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3216
double getCenterOnEdge() const
Definition MSLane.h:1208
bool isNormal() const
Definition MSLane.cpp:2626
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2661
bool isInternal() const
Definition MSLane.cpp:2620
@ 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:4383
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:4685
double interpolateLanePosToGeometryPos(double lanePos) const
Definition MSLane.h:554
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4679
@ 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:4389
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:4694
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3241
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:3803
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:2652
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:1332
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:1265
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:1480
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:1459
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1324
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:1341
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:1256
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:128
const MSEdge * getLastEdge() const
returns the destination edge
Definition MSRoute.cpp:91
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
const MSLane * lane
The lane to stop at (microsim only)
Definition MSStop.h:50
bool triggered
whether an arriving person lets the vehicle continue
Definition MSStop.h:69
bool containerTriggered
whether an arriving container lets the vehicle continue
Definition MSStop.h:71
SUMOTime timeToLoadNextContainer
The time at which the vehicle is able to load another container.
Definition MSStop.h:83
MSStoppingPlace * containerstop
(Optional) container stop if one is assigned to the stop
Definition MSStop.h:56
double getSpeed() const
return speed for passing waypoint / skipping on-demand stop
Definition MSStop.cpp: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 override
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