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