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
1039
1040
1041void
1043 for (MSLane* further : myFurtherLanes) {
1044 further->resetPartialOccupation(this);
1045 if (further->getBidiLane() != nullptr
1046 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
1047 further->getBidiLane()->resetPartialOccupation(this);
1048 }
1049 }
1050 if (myLaneChangeModel != nullptr) {
1054 // still needed when calling resetPartialOccupation (getShadowLane) and when removing
1055 // approach information from parallel links
1056 }
1057 myFurtherLanes.clear();
1058 myFurtherLanesPosLat.clear();
1059}
1060
1061
1062void
1064#ifdef DEBUG_ACTIONSTEPS
1065 if (DEBUG_COND) {
1066 std::cout << SIMTIME << " Removing vehicle '" << getID() << "' (reason: " << toString(reason) << ")" << std::endl;
1067 }
1068#endif
1071 leaveLane(reason);
1074 }
1075}
1076
1077
1078void
1085
1086
1087// ------------ interaction with the route
1088bool
1090 // note: not a const method because getDepartLane may call updateBestLanes
1091 if (!(*myCurrEdge)->isTazConnector()) {
1093 if ((*myCurrEdge)->getDepartLane(*this) == nullptr) {
1094 msg = "Invalid departlane definition for vehicle '" + getID() + "'.";
1095 if (myParameter->departLane >= (int)(*myCurrEdge)->getLanes().size()) {
1097 } else {
1099 }
1100 return false;
1101 }
1102 } else {
1103 if ((*myCurrEdge)->allowedLanes(getVClass(), ignoreTransientPermissions()) == nullptr) {
1104 msg = "Vehicle '" + getID() + "' is not allowed to depart on any lane of edge '" + (*myCurrEdge)->getID() + "'.";
1106 return false;
1107 }
1108 }
1110 msg = "Departure speed for vehicle '" + getID() + "' is too high for the vehicle type '" + myType->getID() + "'.";
1112 return false;
1113 }
1114 }
1116 return true;
1117}
1118
1119
1120bool
1122 return hasArrivedInternal(false);
1123}
1124
1125
1126bool
1127MSVehicle::hasArrivedInternal(bool oppositeTransformed) const {
1128 return ((myCurrEdge == myRoute->end() - 1 || (myParameter->arrivalEdge >= 0 && getRoutePosition() >= myParameter->arrivalEdge))
1129 && (myStops.empty() || myStops.front().edge != myCurrEdge || myStops.front().getSpeed() > 0)
1130 && ((myLaneChangeModel->isOpposite() && !oppositeTransformed) ? myLane->getLength() - myState.myPos : myState.myPos) > MIN2(myLane->getLength(), myArrivalPos) - POSITION_EPS
1131 && !isRemoteControlled());
1132}
1133
1134
1135bool
1136MSVehicle::replaceRoute(ConstMSRoutePtr newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
1137 if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
1138 // update best lanes (after stops were added)
1139 myLastBestLanesEdge = nullptr;
1141 updateBestLanes(true, onInit ? (*myCurrEdge)->getLanes().front() : 0);
1142 assert(!removeStops || haveValidStopEdges());
1143 if (myStops.size() == 0) {
1144 myStopDist = std::numeric_limits<double>::max();
1145 }
1146 return true;
1147 }
1148 return false;
1149}
1150
1151
1152// ------------ Interaction with move reminders
1153void
1154MSVehicle::workOnMoveReminders(double oldPos, double newPos, double newSpeed) {
1155 // This erasure-idiom works for all stl-sequence-containers
1156 // See Meyers: Effective STL, Item 9
1157 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
1158 // XXX: calling notifyMove with newSpeed seems not the best choice. For the ballistic update, the average speed is calculated and used
1159 // although a higher order quadrature-formula might be more adequate.
1160 // For the euler case (where the speed is considered constant for each time step) it is conceivable that
1161 // the current calculations may lead to systematic errors for large time steps (compared to reality). Refs. #2579
1162 if (!rem->first->notifyMove(*this, oldPos + rem->second, newPos + rem->second, MAX2(0., newSpeed))) {
1163#ifdef _DEBUG
1164 if (myTraceMoveReminders) {
1165 traceMoveReminder("notifyMove", rem->first, rem->second, false);
1166 }
1167#endif
1168 rem = myMoveReminders.erase(rem);
1169 } else {
1170#ifdef _DEBUG
1171 if (myTraceMoveReminders) {
1172 traceMoveReminder("notifyMove", rem->first, rem->second, true);
1173 }
1174#endif
1175 ++rem;
1176 }
1177 }
1178 if (myEnergyParams != nullptr) {
1179 // TODO make the vehicle energy params a derived class which is a move reminder
1181 }
1182}
1183
1184
1185void
1187 updateWaitingTime(0.); // cf issue 2233
1188
1189 // vehicle move reminders
1190 for (const auto& rem : myMoveReminders) {
1191 rem.first->notifyIdle(*this);
1192 }
1193
1194 // lane move reminders - for aggregated values
1195 for (MSMoveReminder* rem : getLane()->getMoveReminders()) {
1196 rem->notifyIdle(*this);
1197 }
1198}
1199
1200// XXX: consider renaming...
1201void
1203 // save the old work reminders, patching the position information
1204 // add the information about the new offset to the old lane reminders
1205 const double oldLaneLength = myLane->getLength();
1206 for (auto& rem : myMoveReminders) {
1207 rem.second += oldLaneLength;
1208#ifdef _DEBUG
1209// if (rem->first==0) std::cout << "Null reminder (?!)" << std::endl;
1210// std::cout << "Adapted MoveReminder on lane " << ((rem->first->getLane()==0) ? "NULL" : rem->first->getLane()->getID()) <<" position to " << rem->second << std::endl;
1211 if (myTraceMoveReminders) {
1212 traceMoveReminder("adaptedPos", rem.first, rem.second, true);
1213 }
1214#endif
1215 }
1216 for (MSMoveReminder* const rem : enteredLane.getMoveReminders()) {
1217 addReminder(rem);
1218 }
1219}
1220
1221
1222// ------------ Other getter methods
1223double
1225 if (isParking() && getStops().begin()->parkingarea != nullptr) {
1226 return getStops().begin()->parkingarea->getVehicleSlope(*this);
1227 }
1228 if (myLane == nullptr) {
1229 return 0;
1230 }
1231 const double posLat = myState.myPosLat; // @todo get rid of the '-'
1232 Position p1 = getPosition();
1234 if (p2 == Position::INVALID) {
1235 // Handle special case of vehicle's back reaching out of the network
1236 if (myFurtherLanes.size() > 0) {
1237 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1238 if (p2 == Position::INVALID) {
1239 // unsuitable lane geometry
1240 p2 = myLane->geometryPositionAtOffset(0, posLat);
1241 }
1242 } else {
1243 p2 = myLane->geometryPositionAtOffset(0, posLat);
1244 }
1245 }
1247}
1248
1249
1251MSVehicle::getPosition(const double offset) const {
1252 if (myLane == nullptr) {
1253 // when called in the context of GUI-Drawing, the simulation step is already incremented
1255 return myCachedPosition;
1256 } else {
1257 return Position::INVALID;
1258 }
1259 }
1260 if (isParking()) {
1261 if (myInfluencer != nullptr && myInfluencer->getLastAccessTimeStep() > getNextStopParameter()->started) {
1262 return myCachedPosition;
1263 }
1264 if (myStops.begin()->parkingarea != nullptr) {
1265 return myStops.begin()->parkingarea->getVehiclePosition(*this);
1266 } else {
1267 // position beside the road
1268 PositionVector shp = myLane->getEdge().getLanes()[0]->getShape();
1271 }
1272 }
1273 const bool changingLanes = myLaneChangeModel->isChangingLanes();
1274 const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
1275 if (offset == 0. && !changingLanes) {
1278 if (MSNet::getInstance()->hasElevation() && MSGlobals::gSublane) {
1280 }
1281 }
1282 return myCachedPosition;
1283 }
1284 Position result = validatePosition(myLane->geometryPositionAtOffset(getPositionOnLane() + offset, posLat), offset);
1285 interpolateLateralZ(result, getPositionOnLane() + offset, posLat);
1286 return result;
1287}
1288
1289
1290void
1291MSVehicle::interpolateLateralZ(Position& pos, double offset, double posLat) const {
1292 const MSLane* shadow = myLaneChangeModel->getShadowLane();
1293 if (shadow != nullptr && pos != Position::INVALID) {
1294 // ignore negative offset
1295 const Position shadowPos = shadow->geometryPositionAtOffset(MAX2(0.0, offset));
1296 if (shadowPos != Position::INVALID && pos.z() != shadowPos.z()) {
1297 const double centerDist = (myLane->getWidth() + shadow->getWidth()) * 0.5;
1298 double relOffset = fabs(posLat) / centerDist;
1299 double newZ = (1 - relOffset) * pos.z() + relOffset * shadowPos.z();
1300 pos.setz(newZ);
1301 }
1302 }
1303}
1304
1305
1306double
1308 double result = getLength() - getPositionOnLane();
1309 if (myLane->isNormal()) {
1310 return MAX2(0.0, result);
1311 }
1312 const MSLane* lane = myLane;
1313 while (lane->isInternal()) {
1314 result += lane->getLength();
1315 lane = lane->getCanonicalSuccessorLane();
1316 }
1317 return result;
1318}
1319
1320
1324 if (!isOnRoad()) {
1325 return Position::INVALID;
1326 }
1327 const std::vector<MSLane*>& bestLanes = getBestLanesContinuation();
1328 auto nextBestLane = bestLanes.begin();
1329 const bool opposite = myLaneChangeModel->isOpposite();
1330 double pos = opposite ? myLane->getLength() - myState.myPos : myState.myPos;
1331 const MSLane* lane = opposite ? myLane->getParallelOpposite() : getLane();
1332 assert(lane != 0);
1333 bool success = true;
1334
1335 while (offset > 0) {
1336 // take into account lengths along internal lanes
1337 while (lane->isInternal() && offset > 0) {
1338 if (offset > lane->getLength() - pos) {
1339 offset -= lane->getLength() - pos;
1340 lane = lane->getLinkCont()[0]->getViaLaneOrLane();
1341 pos = 0.;
1342 if (lane == nullptr) {
1343 success = false;
1344 offset = 0.;
1345 }
1346 } else {
1347 pos += offset;
1348 offset = 0;
1349 }
1350 }
1351 // set nextBestLane to next non-internal lane
1352 while (nextBestLane != bestLanes.end() && *nextBestLane == nullptr) {
1353 ++nextBestLane;
1354 }
1355 if (offset > 0) {
1356 assert(!lane->isInternal());
1357 assert(lane == *nextBestLane);
1358 if (offset > lane->getLength() - pos) {
1359 offset -= lane->getLength() - pos;
1360 ++nextBestLane;
1361 assert(nextBestLane == bestLanes.end() || *nextBestLane != 0);
1362 if (nextBestLane == bestLanes.end()) {
1363 success = false;
1364 offset = 0.;
1365 } else {
1366 const MSLink* link = lane->getLinkTo(*nextBestLane);
1367 assert(link != nullptr);
1368 lane = link->getViaLaneOrLane();
1369 pos = 0.;
1370 }
1371 } else {
1372 pos += offset;
1373 offset = 0;
1374 }
1375 }
1376
1377 }
1378
1379 if (success) {
1381 } else {
1382 return Position::INVALID;
1383 }
1384}
1385
1386
1387double
1389 if (myLane != nullptr) {
1390 return myLane->getVehicleMaxSpeed(this);
1391 }
1392 return myType->getMaxSpeed();
1393}
1394
1395
1397MSVehicle::validatePosition(Position result, double offset) const {
1398 int furtherIndex = 0;
1399 double lastLength = getPositionOnLane();
1400 while (result == Position::INVALID) {
1401 if (furtherIndex >= (int)myFurtherLanes.size()) {
1402 //WRITE_WARNINGF(TL("Could not compute position for vehicle '%', time=%."), getID(), time2string(MSNet::getInstance()->getCurrentTimeStep()));
1403 break;
1404 }
1405 //std::cout << SIMTIME << " veh=" << getID() << " lane=" << myLane->getID() << " pos=" << getPositionOnLane() << " posLat=" << getLateralPositionOnLane() << " offset=" << offset << " result=" << result << " i=" << furtherIndex << " further=" << myFurtherLanes.size() << "\n";
1406 MSLane* further = myFurtherLanes[furtherIndex];
1407 offset += lastLength;
1408 result = further->geometryPositionAtOffset(further->getLength() + offset, -getLateralPositionOnLane());
1409 lastLength = further->getLength();
1410 furtherIndex++;
1411 //std::cout << SIMTIME << " newResult=" << result << "\n";
1412 }
1413 return result;
1414}
1415
1416
1417ConstMSEdgeVector::const_iterator
1419 // too close to the next junction, so avoid an emergency brake here
1420 if (myLane != nullptr && (myCurrEdge + 1) != myRoute->end() && !isRailway(getVClass())) {
1421 if (myLane->isInternal()) {
1422 return myCurrEdge + 1;
1423 }
1424 if (myState.myPos > myLane->getLength() - getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)) {
1425 return myCurrEdge + 1;
1426 }
1428 return myCurrEdge + 1;
1429 }
1430 }
1431 return myCurrEdge;
1432}
1433
1434void
1435MSVehicle::setAngle(double angle, bool straightenFurther) {
1436#ifdef DEBUG_FURTHER
1437 if (DEBUG_COND) {
1438 std::cout << SIMTIME << " veh '" << getID() << " setAngle(" << angle << ") straightenFurther=" << straightenFurther << std::endl;
1439 }
1440#endif
1441 myAngle = angle;
1442 MSLane* next = myLane;
1443 if (straightenFurther && myFurtherLanesPosLat.size() > 0) {
1444 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
1445 MSLane* further = myFurtherLanes[i];
1446 const MSLink* link = further->getLinkTo(next);
1447 if (link != nullptr) {
1449 next = further;
1450 } else {
1451 break;
1452 }
1453 }
1454 }
1455}
1456
1457
1458void
1459MSVehicle::setActionStepLength(double actionStepLength, bool resetOffset) {
1460 SUMOTime actionStepLengthMillisecs = SUMOVehicleParserHelper::processActionStepLength(actionStepLength);
1461 SUMOTime previousActionStepLength = getActionStepLength();
1462 const bool newActionStepLength = actionStepLengthMillisecs != previousActionStepLength;
1463 if (newActionStepLength) {
1464 getSingularType().setActionStepLength(actionStepLengthMillisecs, resetOffset);
1465 if (!resetOffset) {
1466 updateActionOffset(previousActionStepLength, actionStepLengthMillisecs);
1467 }
1468 }
1469 if (resetOffset) {
1471 }
1472}
1473
1474
1475bool
1477 return myState.mySpeed < (60.0 / 3.6) || myLane->getSpeedLimit() < (60.1 / 3.6);
1478}
1479
1480
1481double
1483 Position p1;
1484 const double posLat = -myState.myPosLat; // @todo get rid of the '-'
1485 const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
1486
1487 // if parking manoeuvre is happening then rotate vehicle on each step
1490 }
1491
1492 if (isParking()) {
1493 if (myStops.begin()->parkingarea != nullptr) {
1494 return myStops.begin()->parkingarea->getVehicleAngle(*this);
1495 } else {
1497 }
1498 }
1500 // cannot use getPosition() because it already includes the offset to the side and thus messes up the angle
1501 p1 = myLane->geometryPositionAtOffset(myState.myPos, lefthandSign * posLat);
1502 if (p1 == Position::INVALID && myLane->getShape().length2D() == 0. && myLane->isInternal()) {
1503 // workaround: extrapolate the preceding lane shape
1504 MSLane* predecessorLane = myLane->getCanonicalPredecessorLane();
1505 p1 = predecessorLane->geometryPositionAtOffset(predecessorLane->getLength() + myState.myPos, lefthandSign * posLat);
1506 }
1507 } else {
1508 p1 = getPosition();
1509 }
1510
1511 Position p2;
1512 if (getVehicleType().getParameter().locomotiveLength > 0) {
1513 // articulated vehicle should use the heading of the first part
1514 const double locoLength = MIN2(getVehicleType().getParameter().locomotiveLength, getLength());
1515 p2 = getPosition(-locoLength);
1516 } else {
1517 p2 = getBackPosition();
1518 }
1519 if (p2 == Position::INVALID) {
1520 // Handle special case of vehicle's back reaching out of the network
1521 if (myFurtherLanes.size() > 0) {
1522 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1523 if (p2 == Position::INVALID) {
1524 // unsuitable lane geometry
1525 p2 = myLane->geometryPositionAtOffset(0, posLat);
1526 }
1527 } else {
1528 p2 = myLane->geometryPositionAtOffset(0, posLat);
1529 }
1530 }
1531 double result = (p1 != p2 ? p2.angleTo2D(p1) :
1533
1534 result += lefthandSign * myLaneChangeModel->calcAngleOffset();
1535
1536#ifdef DEBUG_FURTHER
1537 if (DEBUG_COND) {
1538 std::cout << SIMTIME << " computeAngle veh=" << getID() << " p1=" << p1 << " p2=" << p2 << " angle=" << RAD2DEG(result) << " naviDegree=" << GeomHelper::naviDegree(result) << "\n";
1539 }
1540#endif
1541 return result;
1542}
1543
1544
1545const Position
1547 const double posLat = MSGlobals::gLefthand ? myState.myPosLat : -myState.myPosLat;
1548 Position result;
1549 if (myState.myPos >= myType->getLength()) {
1550 // vehicle is fully on the new lane
1552 } else {
1554 // special case where the target lane has no predecessor
1555#ifdef DEBUG_FURTHER
1556 if (DEBUG_COND) {
1557 std::cout << " getBackPosition veh=" << getID() << " specialCase using myLane=" << myLane->getID() << " pos=0 posLat=" << myState.myPosLat << " result=" << myLane->geometryPositionAtOffset(0, posLat) << "\n";
1558 }
1559#endif
1560 result = myLane->geometryPositionAtOffset(0, posLat);
1561 } else {
1562#ifdef DEBUG_FURTHER
1563 if (DEBUG_COND) {
1564 std::cout << " getBackPosition veh=" << getID() << " myLane=" << myLane->getID() << " further=" << toString(myFurtherLanes) << " myFurtherLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
1565 }
1566#endif
1567 if (myFurtherLanes.size() > 0 && !myLaneChangeModel->isChangingLanes()) {
1568 // truncate to 0 if vehicle starts on an edge that is shorter than its length
1569 const double backPos = MAX2(0.0, getBackPositionOnLane(myFurtherLanes.back()));
1570 result = myFurtherLanes.back()->geometryPositionAtOffset(backPos, -myFurtherLanesPosLat.back() * (MSGlobals::gLefthand ? -1 : 1));
1571 } else {
1572 result = myLane->geometryPositionAtOffset(0, posLat);
1573 }
1574 }
1575 }
1577 interpolateLateralZ(result, myState.myPos - myType->getLength(), posLat);
1578 }
1579 return result;
1580}
1581
1582
1583bool
1585 return !isStopped() && !myStops.empty() && myLane != nullptr && &myStops.front().lane->getEdge() == &myLane->getEdge();
1586}
1587
1588bool
1590 return isStopped() && myStops.front().lane == myLane;
1591}
1592
1593bool
1594MSVehicle::keepStopping(bool afterProcessing) const {
1595 if (isStopped()) {
1596 // when coming out of vehicleTransfer we must shift the time forward
1597 return (myStops.front().duration - (afterProcessing ? DELTA_T : 0) > 0 || isStoppedTriggered() || myStops.front().pars.collision
1598 || myStops.front().pars.breakDown || (myStops.front().getSpeed() > 0
1599 && (myState.myPos < MIN2(myStops.front().pars.endPos, myStops.front().lane->getLength() - POSITION_EPS))
1600 && (myStops.front().pars.parking == ParkingType::ONROAD || getSpeed() >= SUMO_const_haltingSpeed)));
1601 } else {
1602 return false;
1603 }
1604}
1605
1606
1609 if (isStopped()) {
1610 return myStops.front().duration;
1611 }
1612 return 0;
1613}
1614
1615
1618 return (myStops.empty() || !myStops.front().pars.collision) ? myCollisionImmunity : MAX2((SUMOTime)0, myStops.front().duration);
1619}
1620
1621
1622bool
1624 return isStopped() && !myStops.empty() && myStops.front().pars.breakDown;
1625}
1626
1627
1628bool
1630 return myCollisionImmunity > 0;
1631}
1632
1633
1634double
1635MSVehicle::processNextStop(double currentVelocity) {
1636 if (myStops.empty()) {
1637 // no stops; pass
1638 return currentVelocity;
1639 }
1640
1641#ifdef DEBUG_STOPS
1642 if (DEBUG_COND) {
1643 std::cout << "\nPROCESS_NEXT_STOP\n" << SIMTIME << " vehicle '" << getID() << "'" << std::endl;
1644 }
1645#endif
1646
1647 MSStop& stop = myStops.front();
1649 if (stop.reached) {
1650 stop.duration -= getActionStepLength();
1651
1652#ifdef DEBUG_STOPS
1653 if (DEBUG_COND) {
1654 std::cout << SIMTIME << " vehicle '" << getID() << "' reached stop.\n"
1655 << "Remaining duration: " << STEPS2TIME(stop.duration) << std::endl;
1656 if (stop.getSpeed() > 0) {
1657 std::cout << " waypointSpeed=" << stop.getSpeed() << " vehPos=" << myState.myPos << " endPos=" << stop.pars.endPos << "\n";
1658 }
1659 }
1660#endif
1661 if (stop.duration <= 0 && stop.pars.join != "") {
1662 // join this train (part) to another one
1663 MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
1664 if (joinVeh && joinVeh->hasDeparted() && (joinVeh->joinTrainPart(this) || joinVeh->joinTrainPartFront(this))) {
1665 stop.joinTriggered = false;
1669 }
1670 // avoid collision warning before this vehicle is removed (joinVeh was already made longer)
1672 // mark this vehicle as arrived
1674 const_cast<SUMOVehicleParameter*>(myParameter)->arrivalEdge = getRoutePosition();
1675 // handle transportables that want to continue in the other vehicle
1676 if (myPersonDevice != nullptr) {
1678 }
1679 if (myContainerDevice != nullptr) {
1681 }
1682 }
1683 }
1684 boardTransportables(stop);
1685 if (time > stop.endBoarding) {
1686 // for taxi: cancel customers
1687 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1688 if (taxiDevice != nullptr) {
1689 // may invalidate stops including the current reference
1690 taxiDevice->cancelCurrentCustomers();
1692 return currentVelocity;
1693 }
1694 }
1695 if (!keepStopping() && isOnRoad()) {
1696#ifdef DEBUG_STOPS
1697 if (DEBUG_COND) {
1698 std::cout << SIMTIME << " vehicle '" << getID() << "' resumes from stopping." << std::endl;
1699 }
1700#endif
1702 if (isRail() && hasStops()) {
1703 // stay on the current lane in case of a double stop
1704 const MSStop& nextStop = getNextStop();
1705 if (nextStop.edge == myCurrEdge) {
1706 const double stopSpeed = getCarFollowModel().stopSpeed(this, getSpeed(), nextStop.pars.endPos - myState.myPos);
1707 //std::cout << SIMTIME << " veh=" << getID() << " resumedFromStopping currentVelocity=" << currentVelocity << " stopSpeed=" << stopSpeed << "\n";
1708 return stopSpeed;
1709 }
1710 }
1711 } else {
1712 if (stop.triggered) {
1713 if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
1714 WRITE_WARNINGF(TL("Vehicle '%' ignores triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1715 stop.triggered = false;
1716 } else if (!myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1717 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1720#ifdef DEBUG_STOPS
1721 if (DEBUG_COND) {
1722 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for person." << std::endl;
1723 }
1724#endif
1725 }
1726 }
1727 if (stop.containerTriggered) {
1728 if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
1729 WRITE_WARNINGF(TL("Vehicle '%' ignores container triggered stop on lane '%' due to capacity constraints."), getID(), stop.lane->getID());
1730 stop.containerTriggered = false;
1731 } else if (stop.containerTriggered && !myAmRegisteredAsWaiting && stop.duration <= DELTA_T) {
1732 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1735#ifdef DEBUG_STOPS
1736 if (DEBUG_COND) {
1737 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for container." << std::endl;
1738 }
1739#endif
1740 }
1741 }
1742 // joining only takes place after stop duration is over
1744 && stop.duration <= (stop.pars.extension >= 0 ? -stop.pars.extension : 0)) {
1745 if (stop.pars.extension >= 0) {
1746 WRITE_WARNINGF(TL("Vehicle '%' aborts joining after extension of %s at time %."), getID(), STEPS2TIME(stop.pars.extension), time2string(SIMSTEP));
1747 stop.joinTriggered = false;
1748 } else {
1749 // keep stopping indefinitely but ensure that simulation terminates
1752 }
1753 }
1754 if (stop.getSpeed() > 0) {
1755 //waypoint mode
1756 if (stop.duration == 0) {
1757 return stop.getSpeed();
1758 } else {
1759 // stop for 'until' (computed in planMove)
1760 return currentVelocity;
1761 }
1762 } else {
1763 // brake
1765 return 0;
1766 } else {
1767 // ballistic:
1768 return getSpeed() - getCarFollowModel().getMaxDecel();
1769 }
1770 }
1771 }
1772 } else {
1773
1774#ifdef DEBUG_STOPS
1775 if (DEBUG_COND) {
1776 std::cout << SIMTIME << " vehicle '" << getID() << "' hasn't reached next stop." << std::endl;
1777 }
1778#endif
1779 //std::cout << SIMTIME << " myStopDist=" << myStopDist << " bGap=" << getBrakeGap(myLane->getVehicleMaxSpeed(this)) << "\n";
1780 if (stop.pars.onDemand && !stop.skipOnDemand && myStopDist <= getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this))) {
1781 MSNet* const net = MSNet::getInstance();
1782 const bool noExits = ((myPersonDevice == nullptr || !myPersonDevice->anyLeavingAtStop(stop))
1783 && (myContainerDevice == nullptr || !myContainerDevice->anyLeavingAtStop(stop)));
1784 const bool noEntries = ((!net->hasPersons() || !net->getPersonControl().hasAnyWaiting(stop.getEdge(), this))
1785 && (!net->hasContainers() || !net->getContainerControl().hasAnyWaiting(stop.getEdge(), this)));
1786 if (noExits && noEntries) {
1787 //std::cout << " skipOnDemand\n";
1788 stop.skipOnDemand = true;
1789 // bestLanes must be extended past this stop
1790 updateBestLanes(true);
1791 }
1792 }
1793 // is the next stop on the current lane?
1794 if (stop.edge == myCurrEdge) {
1795 // get the stopping position
1796 bool useStoppingPlace = stop.busstop != nullptr || stop.containerstop != nullptr || stop.parkingarea != nullptr;
1797 bool fitsOnStoppingPlace = true;
1798 if (!stop.skipOnDemand) { // no need to check available space if we skip it anyway
1799 if (stop.busstop != nullptr) {
1800 fitsOnStoppingPlace &= stop.busstop->fits(myState.myPos, *this);
1801 }
1802 if (stop.containerstop != nullptr) {
1803 fitsOnStoppingPlace &= stop.containerstop->fits(myState.myPos, *this);
1804 }
1805 // if the stop is a parking area we check if there is a free position on the area
1806 if (stop.parkingarea != nullptr) {
1807 fitsOnStoppingPlace &= myState.myPos > stop.parkingarea->getBeginLanePosition();
1808 if (stop.parkingarea->getOccupancy() >= stop.parkingarea->getCapacity()) {
1809 fitsOnStoppingPlace = false;
1810 // trigger potential parkingZoneReroute
1811 MSParkingArea* oldParkingArea = stop.parkingarea;
1812 for (MSMoveReminder* rem : myLane->getMoveReminders()) {
1813 if (rem->isParkingRerouter()) {
1814 rem->notifyEnter(*this, MSMoveReminder::NOTIFICATION_PARKING_REROUTE, myLane);
1815 }
1816 }
1817 if (myStops.empty() || myStops.front().parkingarea != oldParkingArea) {
1818 // rerouted, keep driving
1819 return currentVelocity;
1820 }
1821 } else if (stop.parkingarea->getOccupancyIncludingReservations(this) >= stop.parkingarea->getCapacity()) {
1822 fitsOnStoppingPlace = false;
1823 } else if (stop.parkingarea->parkOnRoad() && stop.parkingarea->getLotIndex(this) < 0) {
1824 fitsOnStoppingPlace = false;
1825 }
1826 }
1827 }
1828 const double targetPos = myState.myPos + myStopDist + (stop.getSpeed() > 0 ? (stop.pars.startPos - stop.pars.endPos) : 0);
1829 double reachedThreshold = (useStoppingPlace ? targetPos - STOPPING_PLACE_OFFSET : stop.getReachedThreshold()) - NUMERICAL_EPS;
1830 if (stop.busstop != nullptr && stop.getSpeed() <= 0 && getWaitingTime() > DELTA_T && myLane == stop.lane) {
1831 // count (long) busStop as reached when fully within and jammed before the designated spot
1832 reachedThreshold = MIN2(reachedThreshold, stop.pars.startPos + getLength());
1833 }
1834#ifdef DEBUG_STOPS
1835 if (DEBUG_COND) {
1836 std::cout << " pos=" << myState.pos() << " speed=" << currentVelocity << " targetPos=" << targetPos << " fits=" << fitsOnStoppingPlace
1837 << " reachedThresh=" << reachedThreshold
1838 << " myLane=" << Named::getIDSecure(myLane)
1839 << " stopLane=" << Named::getIDSecure(stop.lane)
1840 << "\n";
1841 }
1842#endif
1843 const bool posReached = myState.pos() >= reachedThreshold && currentVelocity <= stop.getSpeed() + SUMO_const_haltingSpeed && myLane == stop.lane;
1844 if (posReached && !fitsOnStoppingPlace && MSStopOut::active()) {
1845 MSStopOut::getInstance()->stopBlocked(this, time);
1846 }
1847 if (fitsOnStoppingPlace && posReached && (!MSGlobals::gModelParkingManoeuver || myManoeuvre.entryManoeuvreIsComplete(this))) {
1848 // ok, we may stop (have reached the stop) and either we are not modelling maneuvering or have completed entry
1849 stop.reached = true;
1850 if (!stop.startedFromState) {
1851 stop.pars.started = time;
1852 }
1853#ifdef DEBUG_STOPS
1854 if (DEBUG_COND) {
1855 std::cout << SIMTIME << " vehicle '" << getID() << "' reached next stop." << std::endl;
1856 }
1857#endif
1858 if (MSStopOut::active()) {
1860 }
1861 myLane->getEdge().addWaiting(this);
1864 // compute stopping time
1865 stop.duration = stop.getMinDuration(time);
1866 stop.endBoarding = stop.pars.extension >= 0 ? time + stop.duration + stop.pars.extension : SUMOTime_MAX;
1867 MSDevice_Taxi* taxiDevice = static_cast<MSDevice_Taxi*>(getDevice(typeid(MSDevice_Taxi)));
1868 if (taxiDevice != nullptr && stop.pars.extension >= 0) {
1869 // earliestPickupTime is set with waitUntil
1870 stop.endBoarding = MAX2(time, stop.pars.waitUntil) + stop.pars.extension;
1871 }
1872 if (stop.getSpeed() > 0) {
1873 // ignore duration parameter in waypoint mode unless 'until' or 'ended' are set
1874 if (stop.getUntil() > time) {
1875 stop.duration = stop.getUntil() - time;
1876 } else {
1877 stop.duration = 0;
1878 }
1879 }
1880 if (stop.busstop != nullptr) {
1881 // let the bus stop know the vehicle
1882 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
1883 }
1884 if (stop.containerstop != nullptr) {
1885 // let the container stop know the vehicle
1887 }
1888 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
1889 // let the parking area know the vehicle
1890 stop.parkingarea->enter(this, stop.pars.parking == ParkingType::OFFROAD);
1891 }
1892 if (stop.chargingStation != nullptr) {
1893 // let the container stop know the vehicle
1895 }
1896
1897 if (stop.pars.tripId != "") {
1898 ((SUMOVehicleParameter&)getParameter()).setParameter("tripId", stop.pars.tripId);
1899 }
1900 if (stop.pars.line != "") {
1901 ((SUMOVehicleParameter&)getParameter()).line = stop.pars.line;
1902 }
1903 if (stop.pars.split != "") {
1904 // split the train
1905 MSVehicle* splitVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.split));
1906 if (splitVeh == nullptr) {
1907 WRITE_WARNINGF(TL("Vehicle '%' to split from vehicle '%' is not known. time=%."), stop.pars.split, getID(), SIMTIME)
1908 } else {
1910 splitVeh->getRoute().getEdges()[0]->removeWaiting(splitVeh);
1912 const double newLength = MAX2(myType->getLength() - splitVeh->getVehicleType().getLength(),
1914 getSingularType().setLength(newLength);
1915 // handle transportables that want to continue in the split part
1916 if (myPersonDevice != nullptr) {
1918 }
1919 if (myContainerDevice != nullptr) {
1921 }
1923 const double backShift = splitVeh->getLength() + getVehicleType().getMinGap();
1924 myState.myPos -= backShift;
1925 myState.myBackPos -= backShift;
1926 }
1927 }
1928 }
1929
1930 boardTransportables(stop);
1931 if (stop.pars.posLat != INVALID_DOUBLE) {
1932 myState.myPosLat = stop.pars.posLat;
1933 }
1934 }
1935 }
1936 }
1937 return currentVelocity;
1938}
1939
1940
1941void
1943 if (stop.skipOnDemand) {
1944 return;
1945 }
1946 // we have reached the stop
1947 // any waiting persons may board now
1949 MSNet* const net = MSNet::getInstance();
1950 const bool boarded = (time <= stop.endBoarding
1951 && net->hasPersons()
1953 && stop.numExpectedPerson == 0);
1954 // load containers
1955 const bool loaded = (time <= stop.endBoarding
1956 && net->hasContainers()
1958 && stop.numExpectedContainer == 0);
1959
1960 bool unregister = false;
1961 if (time > stop.endBoarding) {
1962 stop.triggered = false;
1963 stop.containerTriggered = false;
1965 unregister = true;
1967 }
1968 }
1969 if (boarded) {
1970 // the triggering condition has been fulfilled. Maybe we want to wait a bit longer for additional riders (car pooling)
1972 unregister = true;
1973 }
1974 stop.triggered = false;
1976 }
1977 if (loaded) {
1978 // the triggering condition has been fulfilled
1980 unregister = true;
1981 }
1982 stop.containerTriggered = false;
1984 }
1985
1986 if (unregister) {
1988#ifdef DEBUG_STOPS
1989 if (DEBUG_COND) {
1990 std::cout << SIMTIME << " vehicle '" << getID() << "' unregisters as waiting for transportable." << std::endl;
1991 }
1992#endif
1993 }
1994}
1995
1996bool
1998 // check if veh is close enough to be joined to the rear of this vehicle
1999 MSLane* backLane = myFurtherLanes.size() == 0 ? myLane : myFurtherLanes.back();
2000 double gap = getBackPositionOnLane() - veh->getPositionOnLane();
2001 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == veh->getLane()
2002 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
2003 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
2004 getSingularType().setLength(newLength);
2005 myStops.begin()->joinTriggered = false;
2009 }
2010 return true;
2011 } else {
2012 return false;
2013 }
2014}
2015
2016
2017bool
2019 // check if veh is close enough to be joined to the front of this vehicle
2020 MSLane* backLane = veh->myFurtherLanes.size() == 0 ? veh->myLane : veh->myFurtherLanes.back();
2021 double gap = veh->getBackPositionOnLane(backLane) - getPositionOnLane();
2022 if (isStopped() && myStops.begin()->duration <= DELTA_T && myStops.begin()->joinTriggered && backLane == getLane()
2023 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
2024 double skippedLaneLengths = 0;
2025 if (veh->myFurtherLanes.size() > 0) {
2026 skippedLaneLengths += getLane()->getLength();
2027 // this vehicle must be moved to the lane of veh
2028 // ensure that lane and furtherLanes of veh match our route
2029 int routeIndex = getRoutePosition();
2030 if (myLane->isInternal()) {
2031 routeIndex++;
2032 }
2033 for (int i = (int)veh->myFurtherLanes.size() - 1; i >= 0; i--) {
2034 MSEdge* edge = &veh->myFurtherLanes[i]->getEdge();
2035 if (edge->isInternal()) {
2036 continue;
2037 }
2038 if (!edge->isInternal() && edge != myRoute->getEdges()[routeIndex]) {
2039 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
2040 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
2041 return false;
2042 }
2043 routeIndex++;
2044 }
2045 if (veh->getCurrentEdge()->getNormalSuccessor() != myRoute->getEdges()[routeIndex]) {
2046 std::string warn = TL("Cannot join vehicle '%' to vehicle '%' due to incompatible routes. time=%.");
2047 WRITE_WARNINGF(warn, veh->getID(), getID(), time2string(SIMSTEP));
2048 return false;
2049 }
2050 for (int i = (int)veh->myFurtherLanes.size() - 2; i >= 0; i--) {
2051 skippedLaneLengths += veh->myFurtherLanes[i]->getLength();
2052 }
2053 }
2054
2055 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
2056 getSingularType().setLength(newLength);
2057 // lane will be advanced just as for regular movement
2058 myState.myPos = skippedLaneLengths + veh->getPositionOnLane();
2059 myStops.begin()->joinTriggered = false;
2063 }
2064 return true;
2065 } else {
2066 return false;
2067 }
2068}
2069
2070double
2071MSVehicle::getBrakeGap(bool delayed) const {
2072 return getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), delayed ? getCarFollowModel().getHeadwayTime() : 0);
2073}
2074
2075
2076bool
2079 if (myActionStep) {
2080 myLastActionTime = t;
2081 }
2082 return myActionStep;
2083}
2084
2085
2086void
2087MSVehicle::resetActionOffset(const SUMOTime timeUntilNextAction) {
2088 myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + timeUntilNextAction;
2089}
2090
2091
2092void
2093MSVehicle::updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength) {
2095 SUMOTime timeSinceLastAction = now - myLastActionTime;
2096 if (timeSinceLastAction == 0) {
2097 // Action was scheduled now, may be delayed be new action step length
2098 timeSinceLastAction = oldActionStepLength;
2099 }
2100 if (timeSinceLastAction >= newActionStepLength) {
2101 // Action point required in this step
2102 myLastActionTime = now;
2103 } else {
2104 SUMOTime timeUntilNextAction = newActionStepLength - timeSinceLastAction;
2105 resetActionOffset(timeUntilNextAction);
2106 }
2107}
2108
2109
2110
2111void
2112MSVehicle::planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront) {
2113#ifdef DEBUG_PLAN_MOVE
2114 if (DEBUG_COND) {
2115 std::cout
2116 << "\nPLAN_MOVE\n"
2117 << SIMTIME
2118 << std::setprecision(gPrecision)
2119 << " veh=" << getID()
2120 << " lane=" << myLane->getID()
2121 << " pos=" << getPositionOnLane()
2122 << " posLat=" << getLateralPositionOnLane()
2123 << " speed=" << getSpeed()
2124 << "\n";
2125 }
2126#endif
2127 // Update the driver state
2128 if (hasDriverState()) {
2130 setActionStepLength(myDriverState->getDriverState()->getActionStepLength(), false);
2131 }
2132
2134 if (!checkActionStep(t)) {
2135#ifdef DEBUG_ACTIONSTEPS
2136 if (DEBUG_COND) {
2137 std::cout << STEPS2TIME(t) << " vehicle '" << getID() << "' skips action." << std::endl;
2138 }
2139#endif
2140 // During non-action passed drive items still need to be removed
2141 // @todo rather work with updating myCurrentDriveItem (refs #3714)
2143 return;
2144 } else {
2145#ifdef DEBUG_ACTIONSTEPS
2146 if (DEBUG_COND) {
2147 std::cout << STEPS2TIME(t) << " vehicle = '" << getID() << "' takes action." << std::endl;
2148 }
2149#endif
2151 if (myInfluencer != nullptr) {
2153 }
2155#ifdef DEBUG_PLAN_MOVE
2156 if (DEBUG_COND) {
2157 DriveItemVector::iterator i;
2158 for (i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
2159 std::cout
2160 << " vPass=" << (*i).myVLinkPass
2161 << " vWait=" << (*i).myVLinkWait
2162 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
2163 << " request=" << (*i).mySetRequest
2164 << "\n";
2165 }
2166 }
2167#endif
2168 checkRewindLinkLanes(lengthsInFront, myLFLinkLanes);
2170 // ideally would only do this with the call inside planMoveInternal - but that needs a const method
2171 // so this is a kludge here - nuisance as it adds an extra check in a busy loop
2175 }
2176 }
2177 }
2179}
2180
2181
2182bool
2183MSVehicle::brakeForOverlap(const MSLink* link, const MSLane* lane) const {
2184 // @review needed
2185 //const double futurePosLat = getLateralPositionOnLane() + link->getLateralShift();
2186 //const double overlap = getLateralOverlap(futurePosLat, link->getViaLaneOrLane());
2187 //const double edgeWidth = link->getViaLaneOrLane()->getEdge().getWidth();
2188 const double futurePosLat = getLateralPositionOnLane() + (
2189 lane != myLane && lane->isInternal() ? lane->getIncomingLanes()[0].viaLink->getLateralShift() : 0);
2190 const double overlap = getLateralOverlap(futurePosLat, lane);
2191 const double edgeWidth = lane->getEdge().getWidth();
2192 const bool result = (overlap > POSITION_EPS
2193 // do not get stuck on narrow edges
2194 && getVehicleType().getWidth() <= edgeWidth
2195 && link->getViaLane() == nullptr
2196 // this is the exit link of a junction. The normal edge should support the shadow
2197 && ((myLaneChangeModel->getShadowLane(link->getLane()) == nullptr)
2198 // the shadow lane must be permitted
2199 || !myLaneChangeModel->getShadowLane(link->getLane())->allowsVehicleClass(getVClass())
2200 // the internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
2201 || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
2202 // ignore situations where the shadow lane is part of a double-connection with the current lane
2203 && (myLaneChangeModel->getShadowLane() == nullptr
2204 || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
2205 || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != link->getLane())
2206 // emergency vehicles may do some crazy stuff
2208
2209#ifdef DEBUG_PLAN_MOVE
2210 if (DEBUG_COND) {
2211 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getDescription() << " lane=" << lane->getID()
2212 << " linkLane=" << link->getLane()->getID()
2213 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
2214 << " shift=" << link->getLateralShift()
2215 << " fpLat=" << futurePosLat << " overlap=" << overlap << " w=" << getVehicleType().getWidth()
2216 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane(link->getLane()))
2217 << " result=" << result << "\n";
2218 }
2219#endif
2220 return result;
2221}
2222
2223
2224
2225void
2226MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, double& newStopSpeed, std::pair<double, const MSLink*>& nextTurn) const {
2227 lfLinks.clear();
2228 newStopDist = std::numeric_limits<double>::max();
2229 //
2230 const MSCFModel& cfModel = getCarFollowModel();
2231 const double vehicleLength = getVehicleType().getLength();
2232 const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
2233 const double maxVD = MAX2(getMaxSpeed(), MIN2(maxV, getDesiredMaxSpeed()));
2234 const bool opposite = myLaneChangeModel->isOpposite();
2235 // maxVD is possibly higher than vType-maxSpeed and in this case laneMaxV may be higher as well
2236 double laneMaxV = myLane->getVehicleMaxSpeed(this, maxVD);
2237 const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
2238 double lateralShift = 0;
2239 if (isRail()) {
2240 // speed limits must hold for the whole length of the train
2241 for (MSLane* l : myFurtherLanes) {
2242 laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this, maxVD));
2243#ifdef DEBUG_PLAN_MOVE
2244 if (DEBUG_COND) {
2245 std::cout << " laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
2246 }
2247#endif
2248 }
2249 }
2250 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2251 laneMaxV = MAX2(laneMaxV, vMinComfortable);
2253 laneMaxV = std::numeric_limits<double>::max();
2254 }
2255 // v is the initial maximum velocity of this vehicle in this step
2256 double v = cfModel.maximumLaneSpeedCF(this, maxV, laneMaxV);
2257 // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
2258 // in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
2261 }
2262
2263 if (myInfluencer != nullptr) {
2264 const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
2265#ifdef DEBUG_TRACI
2266 if (DEBUG_COND) {
2267 std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
2268 }
2269#endif
2270 v = myInfluencer->influenceSpeed(t, v, v, vMin, maxV);
2271#ifdef DEBUG_TRACI
2272 if (DEBUG_COND) {
2273 std::cout << " influencedSpeed=" << v;
2274 }
2275#endif
2276 v = myInfluencer->gapControlSpeed(t, this, v, v, vMin, maxV);
2277#ifdef DEBUG_TRACI
2278 if (DEBUG_COND) {
2279 std::cout << " gapControlSpeed=" << v << "\n";
2280 }
2281#endif
2282 }
2283 // all links within dist are taken into account (potentially)
2284 const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
2285
2286 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
2287#ifdef DEBUG_PLAN_MOVE
2288 if (DEBUG_COND) {
2289 std::cout << " dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
2290 << "\n maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
2291 }
2292#endif
2293 assert(bestLaneConts.size() > 0);
2294 bool hadNonInternal = false;
2295 // the distance already "seen"; in the following always up to the end of the current "lane"
2296 double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
2297 nextTurn.first = seen;
2298 nextTurn.second = nullptr;
2299 bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
2300 double seenNonInternal = 0;
2301 double seenInternal = myLane->isInternal() ? seen : 0;
2302 double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2303 int view = 0;
2304 DriveProcessItem* lastLink = nullptr;
2305 bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
2306 double mustSeeBeforeReversal = 0;
2307 // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
2308 const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
2309 assert(lane != 0);
2310 const MSLane* leaderLane = myLane;
2311 bool foundRailSignal = !isRail();
2312 bool planningToStop = false;
2313#ifdef PARALLEL_STOPWATCH
2314 myLane->getStopWatch()[0].start();
2315#endif
2316
2317 // optionally slow down to match arrival time
2318 const double sfp = getVehicleType().getParameter().speedFactorPremature;
2319 if (v > vMinComfortable && hasStops() && myStops.front().pars.arrival >= 0 && sfp > 0
2320 && v > myLane->getSpeedLimit() * sfp
2321 && !myStops.front().reached) {
2322 const double vSlowDown = slowDownForSchedule(vMinComfortable);
2323 v = MIN2(v, vSlowDown);
2324 }
2325 auto stopIt = myStops.begin();
2326 while (true) {
2327 // check leader on lane
2328 // leader is given for the first edge only
2329 if (opposite &&
2330 (leaderLane->getVehicleNumberWithPartials() > 1
2331 || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
2332 ahead.clear();
2333 // find opposite-driving leader that must be respected on the currently looked at lane
2334 // (only looking at one lane at a time)
2335 const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
2336 const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
2337 const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
2338 MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
2339 const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 * myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
2340 for (int i = 0; i < cands.numSublanes(); i++) {
2341 CLeaderDist cand = cands[i];
2342 if (cand.first != 0) {
2343 if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
2344 || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
2345 // respect leaders that also drive in the opposite direction (fully or with some overlap)
2346 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
2347 } else {
2348 // avoid frontal collision
2349 const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
2350 const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
2351 if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
2352 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
2353 }
2354 }
2355 }
2356 }
2357#ifdef DEBUG_PLAN_MOVE
2358 if (DEBUG_COND) {
2359 std::cout << " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
2360 << " cands=" << cands.toString() << " oppositeLeaders=" << oppositeLeaders.toString() << "\n";
2361 }
2362#endif
2363 adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
2364 } else {
2366 const double rightOL = getRightSideOnLane(lane) + lateralShift;
2367 const double leftOL = getLeftSideOnLane(lane) + lateralShift;
2368 const bool outsideLeft = leftOL > lane->getWidth();
2369#ifdef DEBUG_PLAN_MOVE
2370 if (DEBUG_COND) {
2371 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
2372 }
2373#endif
2374 if (rightOL < 0 || outsideLeft) {
2375 MSLeaderInfo outsideLeaders(lane->getWidth());
2376 // if ego is driving outside lane bounds we must consider
2377 // potential leaders that are also outside bounds
2378 int sublaneOffset = 0;
2379 if (outsideLeft) {
2380 sublaneOffset = MIN2(-1, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution));
2381 } else {
2382 sublaneOffset = MAX2(1, (int)ceil(-rightOL / MSGlobals::gLateralResolution));
2383 }
2384 outsideLeaders.setSublaneOffset(sublaneOffset);
2385#ifdef DEBUG_PLAN_MOVE
2386 if (DEBUG_COND) {
2387 std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
2388 }
2389#endif
2390 for (const MSVehicle* cand : lane->getVehiclesSecure()) {
2391 if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
2392 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
2393 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
2394 outsideLeaders.addLeader(cand, true);
2395#ifdef DEBUG_PLAN_MOVE
2396 if (DEBUG_COND) {
2397 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << outsideLeaders.toString() << "\n";
2398 }
2399#endif
2400 }
2401 }
2402 lane->releaseVehicles();
2403 if (outsideLeaders.hasVehicles()) {
2404 adaptToLeaders(outsideLeaders, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2405 }
2406 }
2407 }
2408 adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2409 }
2410 if (lastLink != nullptr) {
2411 lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
2412 }
2413#ifdef DEBUG_PLAN_MOVE
2414 if (DEBUG_COND) {
2415 std::cout << "\nv = " << v << "\n";
2416
2417 }
2418#endif
2419 // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
2420 if (myLaneChangeModel->getShadowLane() != nullptr) {
2421 // also slow down for leaders on the shadowLane relative to the current lane
2422 const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
2423 if (shadowLane != nullptr
2424 && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
2425 // continous lane change cannot be stopped so we must adapt to the leader on the target lane
2427 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
2430 // ego posLat is added when retrieving sublanes but it
2431 // should be negated (subtract twice to compensate)
2432 latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
2433 - 2 * getLateralPositionOnLane());
2434
2435 }
2436 MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
2437#ifdef DEBUG_PLAN_MOVE
2439 std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2440 }
2441#endif
2443 // ignore oncoming vehicles on the shadow lane
2444 shadowLeaders.removeOpposite(shadowLane);
2445 }
2446 const double turningDifference = MAX2(0.0, leaderLane->getLength() - shadowLane->getLength());
2447 adaptToLeaders(shadowLeaders, latOffset, seen - turningDifference, lastLink, shadowLane, v, vLinkPass);
2448 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
2449 // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
2450 // (and thus in the same direction as ego)
2451 MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
2452 const double latOffset = 0;
2453#ifdef DEBUG_PLAN_MOVE
2454 if (DEBUG_COND) {
2455 std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
2456 << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2457 }
2458#endif
2459 shadowLeaders.fixOppositeGaps(true);
2460#ifdef DEBUG_PLAN_MOVE
2461 if (DEBUG_COND) {
2462 std::cout << " shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
2463 }
2464#endif
2465 adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
2466 }
2467 }
2468 }
2469 // adapt to pedestrians on the same lane
2470 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2471 const double relativePos = lane->getLength() - seen;
2472#ifdef DEBUG_PLAN_MOVE
2473 if (DEBUG_COND) {
2474 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2475 }
2476#endif
2477 const double stopTime = MAX2(1.0, ceil(getSpeed() / cfModel.getMaxDecel()));
2478 PersonDist leader = lane->nextBlocking(relativePos,
2479 getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
2480 if (leader.first != 0) {
2481 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2482 v = MIN2(v, stopSpeed);
2483#ifdef DEBUG_PLAN_MOVE
2484 if (DEBUG_COND) {
2485 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2486 }
2487#endif
2488 }
2489 }
2490 if (lane->getBidiLane() != nullptr) {
2491 // adapt to pedestrians on the bidi lane
2492 const MSLane* bidiLane = lane->getBidiLane();
2493 if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
2494 const double relativePos = seen;
2495#ifdef DEBUG_PLAN_MOVE
2496 if (DEBUG_COND) {
2497 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2498 }
2499#endif
2500 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2501 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
2502 PersonDist leader = bidiLane->nextBlocking(relativePos,
2503 leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
2504 if (leader.first != 0) {
2505 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2506 v = MIN2(v, stopSpeed);
2507#ifdef DEBUG_PLAN_MOVE
2508 if (DEBUG_COND) {
2509 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2510 }
2511#endif
2512 }
2513 }
2514 }
2515 // adapt to vehicles blocked from (urgent) lane-changing
2516 if (!opposite && lane->getEdge().hasLaneChanger()) {
2517 const double vHelp = myLaneChangeModel->getCooperativeHelpSpeed(lane, seen);
2518#ifdef DEBUG_PLAN_MOVE
2519 if (DEBUG_COND && vHelp < v) {
2520 std::cout << SIMTIME << " applying cooperativeHelpSpeed v=" << vHelp << "\n";
2521 }
2522#endif
2523 v = MIN2(v, vHelp);
2524 }
2525
2526 // process all stops and waypoints on the current edge
2527 bool foundRealStop = false;
2528 while (stopIt != myStops.end()
2529 && ((&stopIt->lane->getEdge() == &lane->getEdge())
2530 || (stopIt->isOpposite && stopIt->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
2531 // ignore stops that occur later in a looped route
2532 && stopIt->edge == myCurrEdge + view) {
2533 double stopDist = std::numeric_limits<double>::max();
2534 const MSStop& stop = *stopIt;
2535 const bool isFirstStop = stopIt == myStops.begin();
2536 stopIt++;
2537 if (!stop.reached || (stop.getSpeed() > 0 && keepStopping())) {
2538 // we are approaching a stop on the edge; must not drive further
2539 bool isWaypoint = stop.getSpeed() > 0;
2540 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
2541 if (stop.parkingarea != nullptr) {
2542 // leave enough space so parking vehicles can exit
2543 const double brakePos = getBrakeGap() + lane->getLength() - seen;
2544 endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
2545 } else if (isWaypoint && !stop.reached) {
2546 endPos = stop.pars.startPos;
2547 }
2548 stopDist = seen + endPos - lane->getLength();
2549#ifdef DEBUG_STOPS
2550 if (DEBUG_COND) {
2551 std::cout << SIMTIME << " veh=" << getID() << " stopDist=" << stopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
2552 }
2553#endif
2554 double stopSpeed = laneMaxV;
2555 if (isWaypoint) {
2556 bool waypointWithStop = false;
2557 if (stop.getUntil() > t) {
2558 // check if we have to slow down or even stop
2559 SUMOTime time2end = 0;
2560 if (stop.reached) {
2561 time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
2562 } else {
2563 time2end = TIME2STEPS(
2564 // time to reach waypoint start
2565 stopDist / ((getSpeed() + stop.getSpeed()) / 2)
2566 // time to reach waypoint end
2567 + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
2568 }
2569 if (stop.getUntil() > t + time2end) {
2570 // we need to stop
2571 double distToEnd = stopDist;
2572 if (!stop.reached) {
2573 distToEnd += stop.pars.endPos - stop.pars.startPos;
2574 }
2575 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
2576 waypointWithStop = true;
2577 }
2578 }
2579 if (stop.reached) {
2580 stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
2581 if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
2582 stopDist = std::numeric_limits<double>::max();
2583 }
2584 } else {
2585 stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), stopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
2586 if (!stop.reached) {
2587 stopDist += stop.pars.endPos - stop.pars.startPos;
2588 }
2589 if (lastLink != nullptr) {
2590 lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
2591 }
2592 }
2593 } else {
2594 stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist);
2595 if (!instantStopping()) {
2596 // regular stops are not emergencies
2597 stopSpeed = MAX2(stopSpeed, vMinComfortable);
2599 std::vector<std::pair<SUMOTime, double> > speedTimeLine;
2600 speedTimeLine.push_back(std::make_pair(SIMSTEP, getSpeed()));
2601 speedTimeLine.push_back(std::make_pair(SIMSTEP + DELTA_T, stopSpeed));
2602 myInfluencer->setSpeedTimeLine(speedTimeLine);
2603 }
2604 if (lastLink != nullptr) {
2605 lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
2606 }
2607 }
2608 newStopSpeed = MIN2(newStopSpeed, stopSpeed);
2609 v = MIN2(v, stopSpeed);
2610 if (lane->isInternal()) {
2611 std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2612 assert(!lane->isLinkEnd(exitLink));
2613 bool dummySetRequest;
2614 double dummyVLinkWait;
2615 checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
2616 }
2617
2618#ifdef DEBUG_PLAN_MOVE
2619 if (DEBUG_COND) {
2620 std::cout << "\n" << SIMTIME << " next stop: distance = " << stopDist << " requires stopSpeed = " << stopSpeed << "\n";
2621
2622 }
2623#endif
2624 if (isFirstStop) {
2625 newStopDist = stopDist;
2626 // if the vehicle is going to stop we don't need to look further
2627 // (except for trains that make use of further link-approach registration for safety purposes)
2628 if (!isWaypoint) {
2629 planningToStop = true;
2630 if (!isRail()) {
2631 lfLinks.emplace_back(v, stopDist);
2632 foundRealStop = true;
2633 break;
2634 }
2635 }
2636 }
2637 }
2638 }
2639 if (foundRealStop) {
2640 break;
2641 }
2642
2643 // move to next lane
2644 // get the next link used
2645 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2646 if (lane->isLinkEnd(link) && myLaneChangeModel->hasBlueLight() && myCurrEdge != myRoute->end() - 1) {
2647 // emergency vehicle is on the wrong lane. Obtain the link that it would use from the correct turning lane
2648 const int currentIndex = lane->getIndex();
2649 const MSLane* bestJump = nullptr;
2650 for (const LaneQ& preb : getBestLanes()) {
2651 if (preb.allowsContinuation &&
2652 (bestJump == nullptr
2653 || abs(currentIndex - preb.lane->getIndex()) < abs(currentIndex - bestJump->getIndex()))) {
2654 bestJump = preb.lane;
2655 }
2656 }
2657 if (bestJump != nullptr) {
2658 const MSEdge* nextEdge = *(myCurrEdge + 1);
2659 for (auto cand_it = bestJump->getLinkCont().begin(); cand_it != bestJump->getLinkCont().end(); cand_it++) {
2660 if (&(*cand_it)->getLane()->getEdge() == nextEdge) {
2661 link = cand_it;
2662 break;
2663 }
2664 }
2665 }
2666 }
2667
2668 // Check whether this is a turn (to save info about the next upcoming turn)
2669 if (!encounteredTurn) {
2670 if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
2671 LinkDirection linkDir = (*link)->getDirection();
2672 switch (linkDir) {
2675 break;
2676 default:
2677 nextTurn.first = seen;
2678 nextTurn.second = *link;
2679 encounteredTurn = true;
2680#ifdef DEBUG_NEXT_TURN
2681 if (DEBUG_COND) {
2682 std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(linkDir)
2683 << " at " << nextTurn.first << "m." << std::endl;
2684 }
2685#endif
2686 }
2687 }
2688 }
2689
2690 // check whether the vehicle is on its final edge
2691 if (myCurrEdge + view + 1 == myRoute->end()
2692 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
2693 const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
2694 myParameter->arrivalSpeed : laneMaxV);
2695 // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
2696 // XXX: This does not work for ballistic update refs #2579
2697 const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
2698 const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
2699 v = MIN2(v, va);
2700 if (lastLink != nullptr) {
2701 lastLink->adaptLeaveSpeed(va);
2702 }
2703 lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
2704 break;
2705 }
2706 // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
2707 if (lane->isLinkEnd(link)
2708 || (MSGlobals::gSublane && brakeForOverlap(*link, lane))
2709 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
2711 double va = cfModel.stopSpeed(this, getSpeed(), seen);
2712 if (lastLink != nullptr) {
2713 lastLink->adaptLeaveSpeed(va);
2714 }
2717 } else {
2718 v = MIN2(va, v);
2719 }
2720#ifdef DEBUG_PLAN_MOVE
2721 if (DEBUG_COND) {
2722 std::cout << " braking for link end lane=" << lane->getID() << " seen=" << seen
2723 << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
2724
2725 }
2726#endif
2727 if (lane->isLinkEnd(link)) {
2728 lfLinks.emplace_back(v, seen);
2729 break;
2730 }
2731 }
2732 lateralShift += (*link)->getLateralShift();
2733 const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
2734 // We distinguish 3 cases when determining the point at which a vehicle stops:
2735 // - allway_stop: the vehicle should stop close to the stop line but may stop at larger distance
2736 // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
2737 // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
2738 // to minimize the time window for passing the junction. If the
2739 // vehicle 'decides' to accelerate and cannot enter the junction in
2740 // the next step, new foes may appear and cause a collision (see #1096)
2741 // - major links: stopping point is irrelevant
2742 double laneStopOffset;
2743 const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
2744 // override low desired decel at yellow and red
2745 const double stopDecel = yellowOrRed && !isRail() ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
2746 const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
2747 const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
2748 const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
2749 if (yellowOrRed) {
2750 // Wait at red traffic light with full distance if possible
2751 laneStopOffset = majorStopOffset;
2752 } else if ((*link)->havePriority()) {
2753 // On priority link, we should never stop below visibility distance
2754 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
2755 } else {
2756 double minorStopOffset = MAX2(lane->getVehicleStopOffset(this),
2757 getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
2758#ifdef DEBUG_PLAN_MOVE
2759 if (DEBUG_COND) {
2760 std::cout << " minorStopOffset=" << minorStopOffset << " distToFoePedCrossing=" << (*link)->getDistToFoePedCrossing() << "\n";
2761 }
2762#endif
2763 if ((*link)->getState() == LINKSTATE_ALLWAY_STOP) {
2764 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, 0));
2765 } else {
2766 minorStopOffset = MAX2(minorStopOffset, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP_MINOR, 0));
2767 }
2768 // On minor link, we should likewise never stop below visibility distance
2769 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
2770 }
2771#ifdef DEBUG_PLAN_MOVE
2772 if (DEBUG_COND) {
2773 std::cout << SIMTIME << " veh=" << getID() << " desired stopOffset on lane '" << lane->getID() << "' is " << laneStopOffset << "\n";
2774 }
2775#endif
2776 if (canBrakeBeforeLaneEnd) {
2777 // avoid emergency braking if possible
2778 laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
2779 }
2780 laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
2781 double stopDist = MAX2(0., seen - laneStopOffset);
2782 if (yellowOrRed && getDevice(typeid(MSDevice_GLOSA)) != nullptr
2783 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->getOverrideSafety()
2784 && static_cast<MSDevice_GLOSA*>(getDevice(typeid(MSDevice_GLOSA)))->isSpeedAdviceActive()) {
2785 stopDist = std::numeric_limits<double>::max();
2786 }
2787 if (newStopDist != std::numeric_limits<double>::max()) {
2788 stopDist = MAX2(stopDist, newStopDist);
2789 }
2790#ifdef DEBUG_PLAN_MOVE
2791 if (DEBUG_COND) {
2792 std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
2793 << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
2794 }
2795#endif
2796 if (isRail()
2797 && !lane->isInternal()) {
2798 // check for train direction reversal
2799 if (lane->getBidiLane() != nullptr
2800 && (*link)->getLane()->getBidiLane() == lane) {
2801 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
2802 if (seen < 1) {
2803 mustSeeBeforeReversal = 2 * seen + getLength();
2804 }
2805 v = MIN2(v, vMustReverse);
2806 }
2807 // signal that is passed in the current step does not count
2808 foundRailSignal |= ((*link)->getTLLogic() != nullptr
2809 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
2810 && seen > SPEED2DIST(v));
2811 }
2812
2813 bool canReverseEventually = false;
2814 const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
2815 v = MIN2(v, vReverse);
2816#ifdef DEBUG_PLAN_MOVE
2817 if (DEBUG_COND) {
2818 std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
2819 }
2820#endif
2821
2822 // check whether we need to slow down in order to finish a continuous lane change
2824 if ( // slow down to finish lane change before a turn lane
2825 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
2826 // slow down to finish lane change before the shadow lane ends
2827 (myLaneChangeModel->getShadowLane() != nullptr &&
2828 (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
2829 // XXX maybe this is too harsh. Vehicles could cut some corners here
2830 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
2831 assert(timeRemaining != 0);
2832 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
2833 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
2834 (seen - POSITION_EPS) / timeRemaining);
2835#ifdef DEBUG_PLAN_MOVE
2836 if (DEBUG_COND) {
2837 std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
2838 << " link=" << (*link)->getViaLaneOrLane()->getID()
2839 << " timeRemaining=" << timeRemaining
2840 << " v=" << v
2841 << " va=" << va
2842 << std::endl;
2843 }
2844#endif
2845 v = MIN2(va, v);
2846 }
2847 }
2848
2849 // - always issue a request to leave the intersection we are currently on
2850 const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
2851 // - do not issue a request to enter an intersection after we already slowed down for an earlier one
2852 const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
2853 // - even if red, if we cannot break we should issue a request
2854 bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
2855
2856 double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
2857 double vLinkWait = MIN2(v, stopSpeed);
2858#ifdef DEBUG_PLAN_MOVE
2859 if (DEBUG_COND) {
2860 std::cout
2861 << " stopDist=" << stopDist
2862 << " stopDecel=" << stopDecel
2863 << " vLinkWait=" << vLinkWait
2864 << " brakeDist=" << brakeDist
2865 << " seen=" << seen
2866 << " leaveIntersection=" << leavingCurrentIntersection
2867 << " setRequest=" << setRequest
2868 //<< std::setprecision(16)
2869 //<< " v=" << v
2870 //<< " speedEps=" << NUMERICAL_EPS_SPEED
2871 //<< std::setprecision(gPrecision)
2872 << "\n";
2873 }
2874#endif
2875
2876 if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
2877 if (lane->isInternal()) {
2878 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2879 }
2880 // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
2881 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
2882 // the vehicle is able to brake in front of a yellow/red traffic light
2883 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
2884 //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
2885 break;
2886 }
2887
2888 const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
2889 if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
2890 // restrict speed when ignoring a red light
2891 const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
2892 const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
2893 v = MIN2(va, v);
2894#ifdef DEBUG_PLAN_MOVE
2895 if (DEBUG_COND) std::cout
2896 << " ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
2897 << " redSpeed=" << redSpeed
2898 << " va=" << va
2899 << " v=" << v
2900 << "\n";
2901#endif
2902 }
2903
2904 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2905
2906 if (lastLink != nullptr) {
2907 lastLink->adaptLeaveSpeed(laneMaxV);
2908 }
2909 double arrivalSpeed = vLinkPass;
2910 // vehicles should decelerate when approaching a minor link
2911 // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
2912 // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
2913
2914 // whether the vehicle/driver is close enough to the link to see all possible foes #2123
2915 const double visibilityDistance = (*link)->getFoeVisibilityDistance();
2916 const double determinedFoePresence = seen <= visibilityDistance;
2917// // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
2918// double foeRecognitionTime = 0.0;
2919// double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
2920
2921#ifdef DEBUG_PLAN_MOVE
2922 if (DEBUG_COND) {
2923 std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
2924 }
2925#endif
2926
2927 const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
2928 if (couldBrakeForMinor && !determinedFoePresence) {
2929 // vehicle decelerates just enough to be able to stop if necessary and then accelerates
2930 double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0., false);
2931 // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
2932 double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
2933 arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
2934 slowedDownForMinor = true;
2935#ifdef DEBUG_PLAN_MOVE
2936 if (DEBUG_COND) {
2937 std::cout << " slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
2938 }
2939#endif
2940 } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
2941 // check for deadlock (circular yielding)
2942 //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
2943 std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
2944 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2945 int n = 100;
2946 while (blocker.second != nullptr && blocker.second != *link && n > 0) {
2947 blocker = blocker.second->getFirstApproachingFoe(*link);
2948 n--;
2949 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2950 }
2951 if (n == 0) {
2952 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
2953 }
2954 //std::cout << " blockerLink=" << blocker.second << " link=" << *link << "\n";
2955 if (blocker.second == *link) {
2956 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
2957 if (RandHelper::rand(getRNG()) < threshold) {
2958 //std::cout << " abort request, threshold=" << threshold << "\n";
2959 setRequest = false;
2960 }
2961 }
2962 }
2963
2964 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
2965 if (couldBrakeForMinor && determinedFoePresence && (*link)->getLane()->getEdge().isRoundabout()) {
2966 const bool wasOpened = (*link)->opened(arrivalTime, arrivalSpeed, arrivalSpeed,
2968 getCarFollowModel().getMaxDecel(),
2970 nullptr, false, this);
2971 if (!wasOpened) {
2972 slowedDownForMinor = true;
2973 }
2974#ifdef DEBUG_PLAN_MOVE
2975 if (DEBUG_COND) {
2976 std::cout << " slowedDownForMinor at roundabout=" << (!wasOpened) << "\n";
2977 }
2978#endif
2979 }
2980
2981 // compute arrival speed and arrival time if vehicle starts braking now
2982 // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
2983 double arrivalSpeedBraking = 0;
2984 const double bGap = cfModel.brakeGap(v);
2985 if (seen < bGap && !isStopped() && !planningToStop) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
2986 // vehicle cannot come to a complete stop in time
2988 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
2989 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
2990 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
2991 } else {
2992 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
2993 }
2994 }
2995
2996 // estimate leave speed for passing time computation
2997 // l=linkLength, a=accel, t=continuousTime, v=vLeave
2998 // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
2999 const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this, maxVD),
3000 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
3001 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
3002 arrivalTime, arrivalSpeed,
3003 arrivalSpeedBraking,
3004 seen, estimatedLeaveSpeed));
3005 if ((*link)->getViaLane() == nullptr) {
3006 hadNonInternal = true;
3007 ++view;
3008 }
3009#ifdef DEBUG_PLAN_MOVE
3010 if (DEBUG_COND) {
3011 std::cout << " checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
3012 << " seenNonInternal=" << seenNonInternal
3013 << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
3014 }
3015#endif
3016 // we need to look ahead far enough to see available space for checkRewindLinkLanes
3017 if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
3018 break;
3019 }
3020 // get the following lane
3021 lane = (*link)->getViaLaneOrLane();
3022 laneMaxV = lane->getVehicleMaxSpeed(this, maxVD);
3024 laneMaxV = std::numeric_limits<double>::max();
3025 }
3026 // the link was passed
3027 // compute the velocity to use when the link is not blocked by other vehicles
3028 // the vehicle shall be not faster when reaching the next lane than allowed
3029 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
3030 const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable - NUMERICAL_EPS);
3031 v = MIN2(va, v);
3032#ifdef DEBUG_PLAN_MOVE
3033 if (DEBUG_COND) {
3034 std::cout << " laneMaxV=" << laneMaxV << " freeSpeed=" << va << " v=" << v << "\n";
3035 }
3036#endif
3037 if (lane->getEdge().isInternal()) {
3038 seenInternal += lane->getLength();
3039 } else {
3040 seenNonInternal += lane->getLength();
3041 }
3042 // do not restrict results to the current vehicle to allow caching for the current time step
3043 leaderLane = opposite ? lane->getParallelOpposite() : lane;
3044 if (leaderLane == nullptr) {
3045
3046 break;
3047 }
3048 ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
3049 seen += lane->getLength();
3050 vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
3051 lastLink = &lfLinks.back();
3052 }
3053
3054//#ifdef DEBUG_PLAN_MOVE
3055// if(DEBUG_COND){
3056// std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
3057// }
3058//#endif
3059
3060#ifdef PARALLEL_STOPWATCH
3061 myLane->getStopWatch()[0].stop();
3062#endif
3063}
3064
3065
3066double
3067MSVehicle::slowDownForSchedule(double vMinComfortable) const {
3068 const double sfp = getVehicleType().getParameter().speedFactorPremature;
3069 const MSStop& stop = myStops.front();
3070 std::pair<double, double> timeDist = estimateTimeToNextStop();
3071 double arrivalDelay = SIMTIME + timeDist.first - STEPS2TIME(stop.pars.arrival);
3072 double t = STEPS2TIME(stop.pars.arrival - SIMSTEP);
3075 arrivalDelay += STEPS2TIME(stop.pars.arrival - flexStart);
3076 t = STEPS2TIME(flexStart - SIMSTEP);
3077 } else if (stop.pars.started >= 0 && MSGlobals::gUseStopStarted) {
3078 arrivalDelay += STEPS2TIME(stop.pars.arrival - stop.pars.started);
3079 t = STEPS2TIME(stop.pars.started - SIMSTEP);
3080 }
3081 if (arrivalDelay < 0 && sfp < getChosenSpeedFactor()) {
3082 // we can slow down to better match the schedule (and increase energy efficiency)
3083 const double vSlowDownMin = MAX2(myLane->getSpeedLimit() * sfp, vMinComfortable);
3084 const double s = timeDist.second;
3085 const double b = getCarFollowModel().getMaxDecel();
3086 // x = speed for arriving in t seconds
3087 // u = time at full speed
3088 // u * x + (t - u) * 0.5 * x = s
3089 // t - u = x / b
3090 // eliminate u, solve x
3091 const double radicand = 4 * t * t * b * b - 8 * s * b;
3092 const double x = radicand >= 0 ? t * b - sqrt(radicand) * 0.5 : vSlowDownMin;
3093 double vSlowDown = x < vSlowDownMin ? vSlowDownMin : x;
3094#ifdef DEBUG_PLAN_MOVE
3095 if (DEBUG_COND) {
3096 std::cout << SIMTIME << " veh=" << getID() << " ad=" << arrivalDelay << " t=" << t << " vsm=" << vSlowDownMin
3097 << " r=" << radicand << " vs=" << vSlowDown << "\n";
3098 }
3099#endif
3100 return vSlowDown;
3101 } else if (arrivalDelay > 0 && sfp > getChosenSpeedFactor()) {
3102 // in principle we could up to catch up with the schedule
3103 // but at this point we can only lower the speed, the
3104 // information would have to be used when computing getVehicleMaxSpeed
3105 }
3106 return getMaxSpeed();
3107}
3108
3110MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
3111 const MSCFModel& cfModel = getCarFollowModel();
3112 SUMOTime arrivalTime;
3114 // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
3115 // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
3116 // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
3117 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
3118 } else {
3119 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
3120 }
3121 if (isStopped()) {
3122 arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
3123 }
3124 return arrivalTime;
3125}
3126
3127
3128void
3129MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
3130 const double seen, DriveProcessItem* const lastLink,
3131 const MSLane* const lane, double& v, double& vLinkPass) const {
3132 int rightmost;
3133 int leftmost;
3134 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3135#ifdef DEBUG_PLAN_MOVE
3136 if (DEBUG_COND) std::cout << SIMTIME
3137 << "\nADAPT_TO_LEADERS\nveh=" << getID()
3138 << " lane=" << lane->getID()
3139 << " latOffset=" << latOffset
3140 << " rm=" << rightmost
3141 << " lm=" << leftmost
3142 << " shift=" << ahead.getSublaneOffset()
3143 << " ahead=" << ahead.toString()
3144 << "\n";
3145#endif
3146 /*
3147 if (myLaneChangeModel->getCommittedSpeed() > 0) {
3148 v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
3149 vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
3150 #ifdef DEBUG_PLAN_MOVE
3151 if (DEBUG_COND) std::cout << " hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
3152 #endif
3153 return;
3154 }
3155 */
3156 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3157 const MSVehicle* pred = ahead[sublane];
3158 if (pred != nullptr && pred != this) {
3159 // @todo avoid multiple adaptations to the same leader
3160 const double predBack = pred->getBackPositionOnLane(lane);
3161 double gap = (lastLink == nullptr
3162 ? predBack - myState.myPos - getVehicleType().getMinGap()
3163 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3164 bool oncoming = false;
3166 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
3167 // ego might and leader are driving against lane
3168 gap = (lastLink == nullptr
3169 ? myState.myPos - predBack - getVehicleType().getMinGap()
3170 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3171 } else {
3172 // ego and leader are driving in the same direction as lane (shadowlane for ego)
3173 gap = (lastLink == nullptr
3174 ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
3175 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
3176 }
3177 } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
3178 // must react to stopped / dangerous oncoming vehicles
3179 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
3180 // try to avoid collision in the next second
3181 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
3182#ifdef DEBUG_PLAN_MOVE
3183 if (DEBUG_COND) {
3184 std::cout << " fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
3185 }
3186#endif
3187 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
3188 gap -= predMaxDist;
3189 }
3190 } else if (pred->getLane() == lane->getBidiLane()) {
3191 gap -= pred->getVehicleType().getLengthWithGap();
3192 oncoming = true;
3193 }
3194#ifdef DEBUG_PLAN_MOVE
3195 if (DEBUG_COND) {
3196 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";
3197 }
3198#endif
3199 if (oncoming && gap >= 0) {
3200 adaptToOncomingLeader(std::make_pair(pred, gap), lastLink, v, vLinkPass);
3201 } else {
3202 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
3203 }
3204 }
3205 }
3206}
3207
3208void
3210 double seen,
3211 DriveProcessItem* const lastLink,
3212 double& v, double& vLinkPass) const {
3213 int rightmost;
3214 int leftmost;
3215 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
3216#ifdef DEBUG_PLAN_MOVE
3217 if (DEBUG_COND) std::cout << SIMTIME
3218 << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
3219 << " latOffset=" << latOffset
3220 << " rm=" << rightmost
3221 << " lm=" << leftmost
3222 << " ahead=" << ahead.toString()
3223 << "\n";
3224#endif
3225 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
3226 CLeaderDist predDist = ahead[sublane];
3227 const MSVehicle* pred = predDist.first;
3228 if (pred != nullptr && pred != this) {
3229#ifdef DEBUG_PLAN_MOVE
3230 if (DEBUG_COND) {
3231 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
3232 }
3233#endif
3234 adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
3235 }
3236 }
3237}
3238
3239
3240void
3241MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3242 double seen,
3243 DriveProcessItem* const lastLink,
3244 double& v, double& vLinkPass) const {
3245 if (leaderInfo.first != 0) {
3246 if (ignoreFoe(leaderInfo.first)) {
3247#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3248 if (DEBUG_COND) {
3249 std::cout << " foe ignored\n";
3250 }
3251#endif
3252 return;
3253 }
3254 const MSCFModel& cfModel = getCarFollowModel();
3255 double vsafeLeader = 0;
3257 vsafeLeader = -std::numeric_limits<double>::max();
3258 }
3259 bool backOnRoute = true;
3260 if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
3261 backOnRoute = false;
3262 // this can either be
3263 // a) a merging situation (leader back is is not our route) or
3264 // b) a minGap violation / collision
3265 MSLane* current = lastLink->myLink->getViaLaneOrLane();
3266 if (leaderInfo.first->getBackLane() == current) {
3267 backOnRoute = true;
3268 } else {
3269 for (MSLane* lane : getBestLanesContinuation()) {
3270 if (lane == current) {
3271 break;
3272 }
3273 if (leaderInfo.first->getBackLane() == lane) {
3274 backOnRoute = true;
3275 }
3276 }
3277 }
3278#ifdef DEBUG_PLAN_MOVE
3279 if (DEBUG_COND) {
3280 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
3281 }
3282#endif
3283 if (!backOnRoute) {
3284 double stopDist = seen - current->getLength() - POSITION_EPS;
3285 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
3286 // do not drive onto the junction conflict area
3287 stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
3288 }
3289 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
3290 }
3291 }
3292 if (backOnRoute) {
3293 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3294 }
3295 if (lastLink != nullptr) {
3296 const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
3297 lastLink->adaptLeaveSpeed(futureVSafe);
3298#ifdef DEBUG_PLAN_MOVE
3299 if (DEBUG_COND) {
3300 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3301 }
3302#endif
3303 }
3304 v = MIN2(v, vsafeLeader);
3305 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3306#ifdef DEBUG_PLAN_MOVE
3307 if (DEBUG_COND) std::cout
3308 << SIMTIME
3309 //std::cout << std::setprecision(10);
3310 << " veh=" << getID()
3311 << " lead=" << leaderInfo.first->getID()
3312 << " leadSpeed=" << leaderInfo.first->getSpeed()
3313 << " gap=" << leaderInfo.second
3314 << " leadLane=" << leaderInfo.first->getLane()->getID()
3315 << " predPos=" << leaderInfo.first->getPositionOnLane()
3316 << " myLane=" << myLane->getID()
3317 << " v=" << v
3318 << " vSafeLeader=" << vsafeLeader
3319 << " vLinkPass=" << vLinkPass
3320 << "\n";
3321#endif
3322 }
3323}
3324
3325
3326void
3327MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3328 const double seen, DriveProcessItem* const lastLink,
3329 const MSLane* const lane, double& v, double& vLinkPass,
3330 double distToCrossing) const {
3331 if (leaderInfo.first != 0) {
3332 if (ignoreFoe(leaderInfo.first)) {
3333#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3334 if (DEBUG_COND) {
3335 std::cout << " junction foe ignored\n";
3336 }
3337#endif
3338 return;
3339 }
3340 const MSCFModel& cfModel = getCarFollowModel();
3341 double vsafeLeader = 0;
3343 vsafeLeader = -std::numeric_limits<double>::max();
3344 }
3345 if (leaderInfo.second >= 0) {
3346 if (hasDeparted()) {
3347 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3348 } else {
3349 // called in the context of MSLane::isInsertionSuccess
3350 vsafeLeader = cfModel.insertionFollowSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3351 }
3352 } else if (leaderInfo.first != this) {
3353 // the leading, in-lapping vehicle is occupying the complete next lane
3354 // stop before entering this lane
3355 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
3356#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3357 if (DEBUG_COND) {
3358 std::cout << SIMTIME << " veh=" << getID() << " stopping before junction: lane=" << lane->getID() << " seen=" << seen
3359 << " laneLength=" << lane->getLength()
3360 << " stopDist=" << seen - lane->getLength() - POSITION_EPS
3361 << " vsafeLeader=" << vsafeLeader
3362 << " distToCrossing=" << distToCrossing
3363 << "\n";
3364 }
3365#endif
3366 }
3367 if (distToCrossing >= 0) {
3368 // can the leader still stop in the way?
3369 const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
3370 if (leaderInfo.first == this) {
3371 // braking for pedestrian
3372 const double vStopCrossing = cfModel.stopSpeed(this, getSpeed(), distToCrossing);
3373 vsafeLeader = vStopCrossing;
3374#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3375 if (DEBUG_COND) {
3376 std::cout << " breaking for pedestrian distToCrossing=" << distToCrossing << " vStopCrossing=" << vStopCrossing << "\n";
3377 }
3378#endif
3379 if (lastLink != nullptr) {
3380 lastLink->adaptStopSpeed(vsafeLeader);
3381 }
3382 } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
3383 // drive up to the crossing point and stop
3384#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3385 if (DEBUG_COND) {
3386 std::cout << " stop at crossing point for critical leader vStop=" << vStop << "\n";
3387 };
3388#endif
3389 vsafeLeader = MAX2(vsafeLeader, vStop);
3390 } else {
3391 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
3392 // estimate the time at which the leader has gone past the crossing point
3393 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
3394 // reach distToCrossing after that time
3395 // avgSpeed * leaderPastCPTime = distToCrossing
3396 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
3397 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
3398 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
3399 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
3400#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3401 if (DEBUG_COND) {
3402 std::cout << " driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
3403 << " leaderPastCPTime=" << leaderPastCPTime
3404 << " vFinal=" << vFinal
3405 << " v2=" << v2
3406 << " vStop=" << vStop
3407 << " vsafeLeader=" << vsafeLeader << "\n";
3408 }
3409#endif
3410 }
3411 }
3412 if (lastLink != nullptr) {
3413 lastLink->adaptLeaveSpeed(vsafeLeader);
3414 }
3415 v = MIN2(v, vsafeLeader);
3416 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3417#ifdef DEBUG_PLAN_MOVE
3418 if (DEBUG_COND) std::cout
3419 << SIMTIME
3420 //std::cout << std::setprecision(10);
3421 << " veh=" << getID()
3422 << " lead=" << leaderInfo.first->getID()
3423 << " leadSpeed=" << leaderInfo.first->getSpeed()
3424 << " gap=" << leaderInfo.second
3425 << " leadLane=" << leaderInfo.first->getLane()->getID()
3426 << " predPos=" << leaderInfo.first->getPositionOnLane()
3427 << " seen=" << seen
3428 << " lane=" << lane->getID()
3429 << " myLane=" << myLane->getID()
3430 << " dTC=" << distToCrossing
3431 << " v=" << v
3432 << " vSafeLeader=" << vsafeLeader
3433 << " vLinkPass=" << vLinkPass
3434 << "\n";
3435#endif
3436 }
3437}
3438
3439
3440void
3441MSVehicle::adaptToOncomingLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3442 DriveProcessItem* const lastLink,
3443 double& v, double& vLinkPass) const {
3444 if (leaderInfo.first != 0) {
3445 if (ignoreFoe(leaderInfo.first)) {
3446#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3447 if (DEBUG_COND) {
3448 std::cout << " oncoming foe ignored\n";
3449 }
3450#endif
3451 return;
3452 }
3453 const MSCFModel& cfModel = getCarFollowModel();
3454 const MSVehicle* lead = leaderInfo.first;
3455 const MSCFModel& cfModelL = lead->getCarFollowModel();
3456 // assume the leader reacts symmetrically (neither stopping instantly nor ignoring ego)
3457 const double leaderBrakeGap = cfModelL.brakeGap(lead->getSpeed(), cfModelL.getMaxDecel(), 0);
3458 const double egoBrakeGap = cfModel.brakeGap(getSpeed(), cfModel.getMaxDecel(), 0);
3459 const double gapSum = leaderBrakeGap + egoBrakeGap;
3460 // ensure that both vehicles can leave an intersection if they are currently on it
3461 double egoExit = getDistanceToLeaveJunction();
3462 const double leaderExit = lead->getDistanceToLeaveJunction();
3463 double gap = leaderInfo.second;
3464 if (egoExit + leaderExit < gap) {
3465 gap -= egoExit + leaderExit;
3466 } else {
3467 egoExit = 0;
3468 }
3469 // split any distance in excess of brakeGaps evenly
3470 const double freeGap = MAX2(0.0, gap - gapSum);
3471 const double splitGap = MIN2(gap, gapSum);
3472 // assume remaining distance is allocated in proportion to braking distance
3473 const double gapRatio = gapSum > 0 ? egoBrakeGap / gapSum : 0.5;
3474 const double vsafeLeader = cfModel.stopSpeed(this, getSpeed(), splitGap * gapRatio + egoExit + 0.5 * freeGap);
3475 if (lastLink != nullptr) {
3476 const double futureVSafe = cfModel.stopSpeed(this, lastLink->accelV, leaderInfo.second, MSCFModel::CalcReason::FUTURE);
3477 lastLink->adaptLeaveSpeed(futureVSafe);
3478#ifdef DEBUG_PLAN_MOVE
3479 if (DEBUG_COND) {
3480 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3481 }
3482#endif
3483 }
3484 v = MIN2(v, vsafeLeader);
3485 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3486#ifdef DEBUG_PLAN_MOVE
3487 if (DEBUG_COND) std::cout
3488 << SIMTIME
3489 //std::cout << std::setprecision(10);
3490 << " veh=" << getID()
3491 << " oncomingLead=" << lead->getID()
3492 << " leadSpeed=" << lead->getSpeed()
3493 << " gap=" << leaderInfo.second
3494 << " gap2=" << gap
3495 << " gapRatio=" << gapRatio
3496 << " leadLane=" << lead->getLane()->getID()
3497 << " predPos=" << lead->getPositionOnLane()
3498 << " myLane=" << myLane->getID()
3499 << " v=" << v
3500 << " vSafeLeader=" << vsafeLeader
3501 << " vLinkPass=" << vLinkPass
3502 << "\n";
3503#endif
3504 }
3505}
3506
3507
3508void
3509MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
3510 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
3512 // we want to pass the link but need to check for foes on internal lanes
3513 checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
3514 if (myLaneChangeModel->getShadowLane() != nullptr) {
3515 const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
3516 if (parallelLink != nullptr) {
3517 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
3518 }
3519 }
3520 }
3521
3522}
3523
3524void
3525MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
3526 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
3527 bool isShadowLink) const {
3528#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3529 if (DEBUG_COND) {
3530 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3531 }
3532#endif
3533 const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
3534#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3535 if (DEBUG_COND) {
3536 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3537 }
3538#endif
3539 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3540 // the vehicle to enter the junction first has priority
3541 const MSVehicle* leader = (*it).vehAndGap.first;
3542 if (leader == nullptr) {
3543 // leader is a pedestrian. Passing 'this' as a dummy.
3544#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3545 if (DEBUG_COND) {
3546 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
3547 }
3548#endif
3551#ifdef DEBUG_PLAN_MOVE
3552 if (DEBUG_COND) {
3553 std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
3554 }
3555#endif
3556 continue;
3557 }
3558 adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3559 // if blocked by a pedestrian for too long we must yield our request
3561 setRequest = false;
3562#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3563 if (DEBUG_COND) {
3564 std::cout << " aborting request\n";
3565 }
3566#endif
3567 }
3568 } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay()) {
3571#ifdef DEBUG_PLAN_MOVE
3572 if (DEBUG_COND) {
3573 std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
3574 }
3575#endif
3576 continue;
3577 }
3579 // sibling link (XXX: could also be partial occupator where this check fails)
3580 &leader->getLane()->getEdge() == &lane->getEdge()) {
3581 // check for sublane obstruction (trivial for sibling link leaders)
3582 const MSLane* conflictLane = link->getInternalLaneBefore();
3583 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
3584 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
3585 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
3586 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
3587 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
3588#ifdef DEBUG_PLAN_MOVE
3589 if (DEBUG_COND) {
3590 std::cout << SIMTIME << " veh=" << getID()
3591 << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
3592 << " isShadowLink=" << isShadowLink
3593 << " lane=" << lane->getID()
3594 << " foe=" << leader->getID()
3595 << " foeLane=" << leader->getLane()->getID()
3596 << " latOffset=" << latOffset
3597 << " latOffsetFoe=" << leader->getLatOffset(lane)
3598 << " linkLeadersAhead=" << linkLeadersAhead.toString()
3599 << "\n";
3600 }
3601#endif
3602 } else {
3603#ifdef DEBUG_PLAN_MOVE
3604 if (DEBUG_COND) {
3605 std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
3606 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3607 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3608 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3609 << "\n";
3610 }
3611#endif
3612 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3613 }
3614 if (lastLink != nullptr) {
3615 // we are not yet on the junction with this linkLeader.
3616 // at least we can drive up to the previous link and stop there
3617 v = MAX2(v, lastLink->myVLinkWait);
3618 }
3619 // if blocked by a leader from the same or next lane we must yield our request
3620 // also, if blocked by a stopped or blocked leader
3622 //&& leader->getSpeed() < SUMO_const_haltingSpeed
3624 || leader->getLane()->getLogicalPredecessorLane() == myLane
3625 || leader->isStopped()
3627 setRequest = false;
3628#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3629 if (DEBUG_COND) {
3630 std::cout << " aborting request\n";
3631 }
3632#endif
3633 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
3634 // we are not yet on the junction so must abort that request as well
3635 // (or maybe we are already on the junction and the leader is a partial occupator beyond)
3636 lastLink->mySetRequest = false;
3637#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3638 if (DEBUG_COND) {
3639 std::cout << " aborting previous request\n";
3640 }
3641#endif
3642 }
3643 }
3644 }
3645#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3646 else {
3647 if (DEBUG_COND) {
3648 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
3649 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3650 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3651 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3652 << "\n";
3653 }
3654 }
3655#endif
3656 }
3657 // if this is the link between two internal lanes we may have to slow down for pedestrians
3658 vLinkWait = MIN2(vLinkWait, v);
3659}
3660
3661
3662double
3663MSVehicle::getDeltaPos(const double accel) const {
3664 double vNext = myState.mySpeed + ACCEL2SPEED(accel);
3666 // apply implicit Euler positional update
3667 return SPEED2DIST(MAX2(vNext, 0.));
3668 } else {
3669 // apply ballistic update
3670 if (vNext >= 0) {
3671 // assume constant acceleration during this time step
3672 return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
3673 } else {
3674 // negative vNext indicates a stop within the middle of time step
3675 // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
3676 // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
3677 // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
3678 // until the vehicle stops.
3679 return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
3680 }
3681 }
3682}
3683
3684void
3685MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
3686
3687 // Speed limit due to zipper merging
3688 double vSafeZipper = std::numeric_limits<double>::max();
3689
3690 myHaveToWaitOnNextLink = false;
3691 bool canBrakeVSafeMin = false;
3692
3693 // Get safe velocities from DriveProcessItems.
3694 assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
3695 for (const DriveProcessItem& dpi : myLFLinkLanes) {
3696 MSLink* const link = dpi.myLink;
3697
3698#ifdef DEBUG_EXEC_MOVE
3699 if (DEBUG_COND) {
3700 std::cout
3701 << SIMTIME
3702 << " veh=" << getID()
3703 << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
3704 << " req=" << dpi.mySetRequest
3705 << " vP=" << dpi.myVLinkPass
3706 << " vW=" << dpi.myVLinkWait
3707 << " d=" << dpi.myDistance
3708 << "\n";
3709 gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
3710 }
3711#endif
3712
3713 // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
3714 if (link != nullptr && dpi.mySetRequest) {
3715
3716 const LinkState ls = link->getState();
3717 // vehicles should brake when running onto a yellow light if the distance allows to halt in front
3718 const bool yellow = link->haveYellow();
3719 const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
3721 assert(link->getLaneBefore() != nullptr);
3722 const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
3723 const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
3724 if (yellow && canBrake && !ignoreRedLink) {
3725 vSafe = dpi.myVLinkWait;
3727#ifdef DEBUG_CHECKREWINDLINKLANES
3728 if (DEBUG_COND) {
3729 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
3730 }
3731#endif
3732 break;
3733 }
3734 const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
3735 MSLink::BlockingFoes collectFoes;
3736 bool opened = (yellow || influencerPrio
3737 || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3739 canBrake ? getImpatience() : 1,
3742 ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
3743 ignoreRedLink, this, dpi.myDistance));
3744 if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
3745 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
3746 if (parallelLink != nullptr) {
3747 const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
3749 opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3752 getWaitingTimeFor(link), shadowLatPos, nullptr,
3753 ignoreRedLink, this, dpi.myDistance));
3754#ifdef DEBUG_EXEC_MOVE
3755 if (DEBUG_COND) {
3756 std::cout << SIMTIME
3757 << " veh=" << getID()
3758 << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
3759 << " shadowDir=" << myLaneChangeModel->getShadowDirection()
3760 << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
3761 << " opened=" << opened
3762 << "\n";
3763 }
3764#endif
3765 }
3766 }
3767 // vehicles should decelerate when approaching a minor link
3768#ifdef DEBUG_EXEC_MOVE
3769 if (DEBUG_COND) {
3770 std::cout << SIMTIME
3771 << " opened=" << opened
3772 << " influencerPrio=" << influencerPrio
3773 << " linkPrio=" << link->havePriority()
3774 << " lastContMajor=" << link->lastWasContMajor()
3775 << " isCont=" << link->isCont()
3776 << " ignoreRed=" << ignoreRedLink
3777 << "\n";
3778 }
3779#endif
3780 double visibilityDistance = link->getFoeVisibilityDistance();
3781 bool determinedFoePresence = dpi.myDistance <= visibilityDistance;
3782 if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
3783 if (!determinedFoePresence && (canBrake || !yellow)) {
3784 vSafe = dpi.myVLinkWait;
3786#ifdef DEBUG_CHECKREWINDLINKLANES
3787 if (DEBUG_COND) {
3788 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
3789 }
3790#endif
3791 break;
3792 } else {
3793 // past the point of no return. we need to drive fast enough
3794 // to make it across the link. However, minor slowdowns
3795 // should be permissible to follow leading traffic safely
3796 // basically, this code prevents dawdling
3797 // (it's harder to do this later using
3798 // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
3799 // vehicle is already too close to stop at that part of the code)
3800 //
3801 // XXX: There is a problem in subsecond simulation: If we cannot
3802 // make it across the minor link in one step, new traffic
3803 // could appear on a major foe link and cause a collision. Refs. #1845, #2123
3804 vSafeMinDist = dpi.myDistance; // distance that must be covered
3806 vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3807 } else {
3808 vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3809 }
3810 canBrakeVSafeMin = canBrake;
3811#ifdef DEBUG_EXEC_MOVE
3812 if (DEBUG_COND) {
3813 std::cout << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
3814 }
3815#endif
3816 }
3817 }
3818 // have waited; may pass if opened...
3819 if (opened) {
3820 vSafe = dpi.myVLinkPass;
3821 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
3822 // this vehicle is probably not gonna drive across the next junction (heuristic)
3824#ifdef DEBUG_CHECKREWINDLINKLANES
3825 if (DEBUG_COND) {
3826 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
3827 }
3828#endif
3829 }
3830 if (link->mustStop() && determinedFoePresence && myHaveStoppedFor == nullptr) {
3831 myHaveStoppedFor = link;
3832 }
3833 } else if (link->getState() == LINKSTATE_ZIPPER) {
3834 vSafeZipper = MIN2(vSafeZipper,
3835 link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
3836 } else if (!canBrake
3837 // always brake hard for traffic lights (since an emergency stop is necessary anyway)
3838 && link->getTLLogic() == nullptr
3839 // cannot brake even with emergency deceleration
3840 && dpi.myDistance < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0.)) {
3841#ifdef DEBUG_EXEC_MOVE
3842 if (DEBUG_COND) {
3843 std::cout << SIMTIME << " too fast to brake for closed link\n";
3844 }
3845#endif
3846 vSafe = dpi.myVLinkPass;
3847 } else {
3848 vSafe = dpi.myVLinkWait;
3850#ifdef DEBUG_CHECKREWINDLINKLANES
3851 if (DEBUG_COND) {
3852 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
3853 }
3854#endif
3855#ifdef DEBUG_EXEC_MOVE
3856 if (DEBUG_COND) {
3857 std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
3858 }
3859#endif
3860 break;
3861 }
3863 // request was renewed, restoring entry time
3864 // @note: using myJunctionEntryTimeNeverYield could lead to inconsistencies with other vehicles already on the junction
3866 }
3867 } else {
3868 if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
3869 // blocked on the junction. yield request so other vehicles may
3870 // become junction leader
3871#ifdef DEBUG_EXEC_MOVE
3872 if (DEBUG_COND) {
3873 std::cout << SIMTIME << " resetting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
3874 }
3875#endif
3878 }
3879 // we have: i->link == 0 || !i->setRequest
3880 vSafe = dpi.myVLinkWait;
3881 if (link != nullptr || myStopDist < (myLane->getLength() - getPositionOnLane())) {
3882 if (vSafe < getSpeed()) {
3884#ifdef DEBUG_CHECKREWINDLINKLANES
3885 if (DEBUG_COND) {
3886 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
3887 }
3888#endif
3889 } else if (vSafe < SUMO_const_haltingSpeed) {
3891#ifdef DEBUG_CHECKREWINDLINKLANES
3892 if (DEBUG_COND) {
3893 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
3894 }
3895#endif
3896 }
3897 }
3898 if (link == nullptr && myLFLinkLanes.size() == 1
3899 && getBestLanesContinuation().size() > 1
3900 && getBestLanesContinuation()[1]->hadPermissionChanges()
3901 && myLane->getFirstAnyVehicle() == this) {
3902 // temporal lane closing without notification, visible to the
3903 // vehicle at the front of the queue
3904 updateBestLanes(true);
3905 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
3906 }
3907 break;
3908 }
3909 }
3910
3911//#ifdef DEBUG_EXEC_MOVE
3912// if (DEBUG_COND) {
3913// std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
3914// std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
3915// std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
3916// std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
3917//
3918// double gap = getLeader().second;
3919// std::cout << "gap = " << toString(gap, 24) << std::endl;
3920// std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
3921// << "\n" << std::endl;
3922// }
3923//#endif
3924
3925 if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
3926 || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
3927 // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
3928 // 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
3929#ifdef DEBUG_EXEC_MOVE
3930 if (DEBUG_COND) {
3931 std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
3932 }
3933#endif
3934 if (canBrakeVSafeMin && vSafe < getSpeed()) {
3935 // cannot drive across a link so we need to stop before it
3936 vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
3937 getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
3938 vSafeMin = 0;
3940#ifdef DEBUG_CHECKREWINDLINKLANES
3941 if (DEBUG_COND) {
3942 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
3943 }
3944#endif
3945 } else {
3946 // if the link is yellow or visibility distance is large
3947 // then we might not make it across the link in one step anyway..
3948 // Possibly, the lane after the intersection has a lower speed limit so
3949 // we really need to drive slower already
3950 // -> keep driving without dawdling
3951 vSafeMin = vSafe;
3952 }
3953 }
3954
3955 // vehicles inside a roundabout should maintain their requests
3956 if (myLane->getEdge().isRoundabout()) {
3957 myHaveToWaitOnNextLink = false;
3958 }
3959
3960 vSafe = MIN2(vSafe, vSafeZipper);
3961}
3962
3963
3964double
3965MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
3966 if (myInfluencer != nullptr) {
3968#ifdef DEBUG_TRACI
3969 if DEBUG_COND2(this) {
3970 std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
3971 << " vSafe=" << vSafe << " (init)vNext=" << vNext << " keepStopping=" << keepStopping();
3972 }
3973#endif
3976 }
3977 const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
3980 vMin = MAX2(0., vMin);
3981 }
3982 vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
3983 if (keepStopping() && myStops.front().getSpeed() == 0) {
3984 // avoid driving while stopped (unless it's actually a waypoint
3985 vNext = myInfluencer->getOriginalSpeed();
3986 }
3987#ifdef DEBUG_TRACI
3988 if DEBUG_COND2(this) {
3989 std::cout << " (processed)vNext=" << vNext << std::endl;
3990 }
3991#endif
3992 }
3993 return vNext;
3994}
3995
3996
3997void
3999#ifdef DEBUG_ACTIONSTEPS
4000 if (DEBUG_COND) {
4001 std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
4002 << " Current items: ";
4003 for (auto& j : myLFLinkLanes) {
4004 if (j.myLink == 0) {
4005 std::cout << "\n Stop at distance " << j.myDistance;
4006 } else {
4007 const MSLane* to = j.myLink->getViaLaneOrLane();
4008 const MSLane* from = j.myLink->getLaneBefore();
4009 std::cout << "\n Link at distance " << j.myDistance << ": '"
4010 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
4011 }
4012 }
4013 std::cout << "\n myNextDriveItem: ";
4014 if (myLFLinkLanes.size() != 0) {
4015 if (myNextDriveItem->myLink == 0) {
4016 std::cout << "\n Stop at distance " << myNextDriveItem->myDistance;
4017 } else {
4018 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
4019 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
4020 std::cout << "\n Link at distance " << myNextDriveItem->myDistance << ": '"
4021 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
4022 }
4023 }
4024 std::cout << std::endl;
4025 }
4026#endif
4027 for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
4028#ifdef DEBUG_ACTIONSTEPS
4029 if (DEBUG_COND) {
4030 std::cout << " Removing item: ";
4031 if (j->myLink == 0) {
4032 std::cout << "Stop at distance " << j->myDistance;
4033 } else {
4034 const MSLane* to = j->myLink->getViaLaneOrLane();
4035 const MSLane* from = j->myLink->getLaneBefore();
4036 std::cout << "Link at distance " << j->myDistance << ": '"
4037 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
4038 }
4039 std::cout << std::endl;
4040 }
4041#endif
4042 if (j->myLink != nullptr) {
4043 j->myLink->removeApproaching(this);
4044 }
4045 }
4048}
4049
4050
4051void
4053#ifdef DEBUG_ACTIONSTEPS
4054 if (DEBUG_COND) {
4055 std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
4056 for (const auto& dpi : myLFLinkLanes) {
4057 std::cout
4058 << " vPass=" << dpi.myVLinkPass
4059 << " vWait=" << dpi.myVLinkWait
4060 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4061 << " request=" << dpi.mySetRequest
4062 << "\n";
4063 }
4064 std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
4065 }
4066#endif
4067 if (myLFLinkLanes.size() == 0) {
4068 // nothing to update
4069 return;
4070 }
4071 const MSLink* nextPlannedLink = nullptr;
4072// auto i = myLFLinkLanes.begin();
4073 auto i = myNextDriveItem;
4074 while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
4075 nextPlannedLink = i->myLink;
4076 ++i;
4077 }
4078
4079 if (nextPlannedLink == nullptr) {
4080 // No link for upcoming item -> no need for an update
4081#ifdef DEBUG_ACTIONSTEPS
4082 if (DEBUG_COND) {
4083 std::cout << "Found no link-related drive item." << std::endl;
4084 }
4085#endif
4086 return;
4087 }
4088
4089 if (getLane() == nextPlannedLink->getLaneBefore()) {
4090 // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
4091#ifdef DEBUG_ACTIONSTEPS
4092 if (DEBUG_COND) {
4093 std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
4094 }
4095#endif
4096 return;
4097 }
4098 // Lane must have been changed, determine the change direction
4099 const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
4100 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4101 // lcDir = 1;
4102 } else {
4103 parallelLink = nextPlannedLink->getParallelLink(-1);
4104 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
4105 // lcDir = -1;
4106 } else {
4107 // If the vehicle's current lane is not the approaching lane for the next
4108 // drive process item's link, it is expected to lead to a parallel link,
4109 // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
4110 // Then a stop item should be scheduled! -> TODO!
4111 //assert(false);
4112 return;
4113 }
4114 }
4115#ifdef DEBUG_ACTIONSTEPS
4116 if (DEBUG_COND) {
4117 std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
4118 }
4119#endif
4120 // Trace link sequence along current best lanes and transfer drive items to the corresponding links
4121// DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
4122 DriveItemVector::iterator driveItemIt = myNextDriveItem;
4123 // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
4124 const MSLane* lane = myLane;
4125 assert(myLane == parallelLink->getLaneBefore());
4126 // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
4127 std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
4128 // Pointer to the new link for the current drive process item
4129 MSLink* newLink = nullptr;
4130 while (driveItemIt != myLFLinkLanes.end()) {
4131 if (driveItemIt->myLink == nullptr) {
4132 // Items not related to a specific link are not updated
4133 // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
4134 // the update necessary, this may slow down the vehicle's continuation on the new lane...)
4135 ++driveItemIt;
4136 continue;
4137 }
4138 // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
4139 // We just remove the leftover link-items, as they cannot be mapped to new links.
4140 if (bestLaneIt == getBestLanesContinuation().end()) {
4141#ifdef DEBUG_ACTIONSTEPS
4142 if (DEBUG_COND) {
4143 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
4144 }
4145#endif
4146 while (driveItemIt != myLFLinkLanes.end()) {
4147 if (driveItemIt->myLink == nullptr) {
4148 ++driveItemIt;
4149 continue;
4150 } else {
4151 driveItemIt->myLink->removeApproaching(this);
4152 driveItemIt = myLFLinkLanes.erase(driveItemIt);
4153 }
4154 }
4155 break;
4156 }
4157 // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
4158 const MSLane* const target = *bestLaneIt;
4159 assert(!target->isInternal());
4160 newLink = nullptr;
4161 for (MSLink* const link : lane->getLinkCont()) {
4162 if (link->getLane() == target) {
4163 newLink = link;
4164 break;
4165 }
4166 }
4167
4168 if (newLink == driveItemIt->myLink) {
4169 // new continuation merged into previous - stop update
4170#ifdef DEBUG_ACTIONSTEPS
4171 if (DEBUG_COND) {
4172 std::cout << "Old and new continuation sequences merge at link\n"
4173 << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
4174 << "\nNo update beyond merge required." << std::endl;
4175 }
4176#endif
4177 break;
4178 }
4179
4180#ifdef DEBUG_ACTIONSTEPS
4181 if (DEBUG_COND) {
4182 std::cout << "lane=" << lane->getID() << "\nUpdating link\n '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
4183 << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
4184 }
4185#endif
4186 newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
4187 driveItemIt->myLink->removeApproaching(this);
4188 driveItemIt->myLink = newLink;
4189 lane = newLink->getViaLaneOrLane();
4190 ++driveItemIt;
4191 if (!lane->isInternal()) {
4192 ++bestLaneIt;
4193 }
4194 }
4195#ifdef DEBUG_ACTIONSTEPS
4196 if (DEBUG_COND) {
4197 std::cout << "Updated drive items:" << std::endl;
4198 for (const auto& dpi : myLFLinkLanes) {
4199 std::cout
4200 << " vPass=" << dpi.myVLinkPass
4201 << " vWait=" << dpi.myVLinkWait
4202 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4203 << " request=" << dpi.mySetRequest
4204 << "\n";
4205 }
4206 }
4207#endif
4208}
4209
4210
4211void
4213 // To avoid casual blinking brake lights at high speeds due to dawdling of the
4214 // leading vehicle, we don't show brake lights when the deceleration could be caused
4215 // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
4216 double pseudoFriction = (0.05 + 0.005 * getSpeed()) * getSpeed();
4217 bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
4218
4219 if (vNext <= SUMO_const_haltingSpeed) {
4220 brakelightsOn = true;
4221 }
4222 if (brakelightsOn && !isStopped()) {
4224 } else {
4226 }
4227}
4228
4229
4230void
4235 } else {
4236 myWaitingTime = 0;
4238 if (hasInfluencer()) {
4240 }
4241 }
4242}
4243
4244
4245void
4247 // update time loss (depends on the updated edge)
4248 if (!isStopped()) {
4249 // some cfModels (i.e. EIDM may drive faster than predicted by maxNextSpeed)
4250 const double vmax = MIN2(myLane->getVehicleMaxSpeed(this), MAX2(myStopSpeed, vNext));
4251 if (vmax > 0) {
4252 myTimeLoss += TS * (vmax - vNext) / vmax;
4253 }
4254 }
4255}
4256
4257
4258double
4259MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
4260 const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
4261 || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
4262#ifdef DEBUG_REVERSE_BIDI
4263 if (DEBUG_COND) std::cout << SIMTIME << " checkReversal lane=" << myLane->getID()
4264 << " pos=" << myState.myPos
4265 << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
4266 << " speedThreshold=" << speedThreshold
4267 << " seen=" << seen
4268 << " isRail=" << isRail()
4269 << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
4270 << " posOK=" << (myState.myPos <= myLane->getLength())
4271 << " normal=" << !myLane->isInternal()
4272 << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
4273 << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
4274 << " stopOk=" << stopOk
4275 << "\n";
4276#endif
4277 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4278 && getPreviousSpeed() <= speedThreshold
4279 && myState.myPos <= myLane->getLength()
4280 && !myLane->isInternal()
4281 && (myCurrEdge + 1) != myRoute->end()
4282 && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
4283 // ensure there are no further stops on this edge
4284 && stopOk
4285 ) {
4286 //if (isSelected()) std::cout << " check1 passed\n";
4287
4288 // ensure that the vehicle is fully on bidi edges that allow reversal
4289 const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
4290 ? myFurtherLanes.size()
4291 : ceil((double)myFurtherLanes.size() / 2.0));
4292 const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
4293 if (remainingRoute < neededFutureRoute) {
4294#ifdef DEBUG_REVERSE_BIDI
4295 if (DEBUG_COND) {
4296 std::cout << " fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
4297 }
4298#endif
4299 return getMaxSpeed();
4300 }
4301 //if (isSelected()) std::cout << " check2 passed\n";
4302
4303 // ensure that the turn-around connection exists from the current edge to its bidi-edge
4304 const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
4305 if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
4306#ifdef DEBUG_REVERSE_BIDI
4307 if (DEBUG_COND) {
4308 std::cout << " noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
4309 }
4310#endif
4311 return getMaxSpeed();
4312 }
4313 //if (isSelected()) std::cout << " check3 passed\n";
4314
4315 // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
4316 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
4317 const double stopPos = myStops.front().getEndPos(*this);
4318 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4319 const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
4320 if (newPos > stopPos) {
4321#ifdef DEBUG_REVERSE_BIDI
4322 if (DEBUG_COND) {
4323 std::cout << " reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
4324 }
4325#endif
4326 if (seen > MAX2(brakeDist, 1.0)) {
4327 return getMaxSpeed();
4328 } else {
4329#ifdef DEBUG_REVERSE_BIDI
4330 if (DEBUG_COND) {
4331 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4332 }
4333#endif
4334 }
4335 }
4336 }
4337 //if (isSelected()) std::cout << " check4 passed\n";
4338
4339 // ensure that bidi-edges exist for all further edges
4340 // and that no stops will be skipped when reversing
4341 // and that the train will not be on top of a red rail signal after reversal
4342 const MSLane* bidi = myLane->getBidiLane();
4343 int view = 2;
4344 for (MSLane* further : myFurtherLanes) {
4345 if (!further->getEdge().isInternal()) {
4346 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
4347#ifdef DEBUG_REVERSE_BIDI
4348 if (DEBUG_COND) {
4349 std::cout << " noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
4350 }
4351#endif
4352 return getMaxSpeed();
4353 }
4354 const MSLane* nextBidi = further->getBidiLane();
4355 const MSLink* toNext = bidi->getLinkTo(nextBidi);
4356 if (toNext == nullptr) {
4357 // can only happen if the route is invalid
4358 return getMaxSpeed();
4359 }
4360 if (toNext->haveRed()) {
4361#ifdef DEBUG_REVERSE_BIDI
4362 if (DEBUG_COND) {
4363 std::cout << " do not reverse on a red signal\n";
4364 }
4365#endif
4366 return getMaxSpeed();
4367 }
4368 bidi = nextBidi;
4369 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
4370 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
4371 const double stopPos = myStops.front().getEndPos(*this);
4372 const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
4373 if (newPos > stopPos) {
4374#ifdef DEBUG_REVERSE_BIDI
4375 if (DEBUG_COND) {
4376 std::cout << " reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
4377 }
4378#endif
4379 if (seen > MAX2(brakeDist, 1.0)) {
4380 canReverse = false;
4381 return getMaxSpeed();
4382 } else {
4383#ifdef DEBUG_REVERSE_BIDI
4384 if (DEBUG_COND) {
4385 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
4386 }
4387#endif
4388 }
4389 }
4390 }
4391 view++;
4392 }
4393 }
4394 // reverse as soon as comfortably possible
4395 const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
4396#ifdef DEBUG_REVERSE_BIDI
4397 if (DEBUG_COND) {
4398 std::cout << SIMTIME << " seen=" << seen << " vReverseOK=" << vMinComfortable << "\n";
4399 }
4400#endif
4401 canReverse = true;
4402 return vMinComfortable;
4403 }
4404 return getMaxSpeed();
4405}
4406
4407
4408void
4409MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
4410 for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
4411 passedLanes.push_back(*i);
4412 }
4413 if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
4414 passedLanes.push_back(myLane);
4415 }
4416 // let trains reverse direction
4417 bool reverseTrain = false;
4418 checkReversal(reverseTrain);
4419 if (reverseTrain) {
4420 // Train is 'reversing' so toggle the logical state
4422 // add some slack to ensure that the back of train does appear looped
4423 myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
4424 myState.mySpeed = 0;
4425#ifdef DEBUG_REVERSE_BIDI
4426 if (DEBUG_COND) {
4427 std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
4428 }
4429#endif
4430 }
4431 // move on lane(s)
4432 if (myState.myPos > myLane->getLength()) {
4433 // The vehicle has moved at least to the next lane (maybe it passed even more than one)
4434 if (myCurrEdge != myRoute->end() - 1) {
4435 MSLane* approachedLane = myLane;
4436 // move the vehicle forward
4438 while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
4439 const MSLink* link = myNextDriveItem->myLink;
4440 const double linkDist = myNextDriveItem->myDistance;
4442 // check whether the vehicle was allowed to enter lane
4443 // otherwise it is decelerated and we do not need to test for it's
4444 // approach on the following lanes when a lane changing is performed
4445 // proceed to the next lane
4446 if (approachedLane->mustCheckJunctionCollisions()) {
4447 // vehicle moves past approachedLane within a single step, collision checking must still be done
4449 }
4450 if (link != nullptr) {
4451 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4452 && !myLane->isInternal()
4453 && myLane->getBidiLane() != nullptr
4454 && link->getLane()->getBidiLane() == myLane
4455 && !reverseTrain) {
4456 emergencyReason = " because it must reverse direction";
4457 approachedLane = nullptr;
4458 break;
4459 }
4460 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4461 && myState.myPos < myLane->getLength() + NUMERICAL_EPS
4462 && hasStops() && getNextStop().edge == myCurrEdge) {
4463 // avoid skipping stop due to numerical instability
4464 // this is a special case for rail vehicles because they
4465 // continue myLFLinkLanes past stops
4466 approachedLane = myLane;
4468 break;
4469 }
4470 approachedLane = link->getViaLaneOrLane();
4472 bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
4473 if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
4474 emergencyReason = " because of a red traffic light";
4475 break;
4476 }
4477 }
4478 if (reverseTrain && approachedLane->isInternal()) {
4479 // avoid getting stuck on a slow turn-around internal lane
4480 myState.myPos += approachedLane->getLength();
4481 }
4482 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4483 // avoid warning due to numerical instability
4484 approachedLane = myLane;
4486 } else if (reverseTrain) {
4487 approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
4488 link = myLane->getLinkTo(approachedLane);
4489 assert(link != 0);
4490 while (link->getViaLane() != nullptr) {
4491 link = link->getViaLane()->getLinkCont()[0];
4492 }
4494 } else {
4495 emergencyReason = " because there is no connection to the next edge";
4496 approachedLane = nullptr;
4497 break;
4498 }
4499 if (approachedLane != myLane && approachedLane != nullptr) {
4502 assert(myState.myPos > 0);
4503 enterLaneAtMove(approachedLane);
4504 if (link->isEntryLink()) {
4507 myHaveStoppedFor = nullptr;
4508 }
4509 if (link->isConflictEntryLink()) {
4511 // renew yielded request
4513 }
4514 if (link->isExitLink()) {
4515 // passed junction, reset for approaching the next one
4519 }
4520#ifdef DEBUG_PLAN_MOVE_LEADERINFO
4521 if (DEBUG_COND) {
4522 std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
4523 << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
4524 << " ET=" << myJunctionEntryTime
4525 << " ETN=" << myJunctionEntryTimeNeverYield
4526 << " CET=" << myJunctionConflictEntryTime
4527 << "\n";
4528 }
4529#endif
4530 if (hasArrivedInternal()) {
4531 break;
4532 }
4535 // abort lane change
4536 WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
4537 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4539 }
4540 }
4541 if (approachedLane->getEdge().isVaporizing()) {
4543 break;
4544 }
4545 passedLanes.push_back(approachedLane);
4546 }
4547 }
4548 // NOTE: Passed drive items will be erased in the next simstep's planMove()
4549
4550#ifdef DEBUG_ACTIONSTEPS
4551 if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
4552 std::cout << "Updated drive items:" << std::endl;
4553 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
4554 std::cout
4555 << " vPass=" << (*i).myVLinkPass
4556 << " vWait=" << (*i).myVLinkWait
4557 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
4558 << " request=" << (*i).mySetRequest
4559 << "\n";
4560 }
4561 }
4562#endif
4563 } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4564 // avoid warning due to numerical instability when stopping at the end of the route
4566 }
4567
4568 }
4569}
4570
4571
4572
4573bool
4575#ifdef DEBUG_EXEC_MOVE
4576 if (DEBUG_COND) {
4577 std::cout << "\nEXECUTE_MOVE\n"
4578 << SIMTIME
4579 << " veh=" << getID()
4580 << " speed=" << getSpeed() // toString(getSpeed(), 24)
4581 << std::endl;
4582 }
4583#endif
4584
4585
4586 // Maximum safe velocity
4587 double vSafe = std::numeric_limits<double>::max();
4588 // Minimum safe velocity (lower bound).
4589 double vSafeMin = -std::numeric_limits<double>::max();
4590 // The distance to a link, which should either be crossed this step
4591 // or in front of which we need to stop.
4592 double vSafeMinDist = 0;
4593
4594 if (myActionStep) {
4595 // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
4596 processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
4597#ifdef DEBUG_ACTIONSTEPS
4598 if (DEBUG_COND) {
4599 std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
4600 " vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
4601 }
4602#endif
4603 } else {
4604 // Continue with current acceleration
4605 vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
4606#ifdef DEBUG_ACTIONSTEPS
4607 if (DEBUG_COND) {
4608 std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
4609 " continues with constant accel " << myAcceleration << "...\n"
4610 << "speed: " << getSpeed() << " -> " << vSafe << std::endl;
4611 }
4612#endif
4613 }
4614
4615
4616//#ifdef DEBUG_EXEC_MOVE
4617// if (DEBUG_COND) {
4618// std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
4619// }
4620//#endif
4621
4622 // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
4623 // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
4624 double vNext = vSafe;
4625 const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
4626 if (vNext <= SUMO_const_haltingSpeed * TS && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting() && myActionStep) {
4628 } else if (isStopped()) {
4629 // do not apply startupDelay for waypoints
4630 if (getCarFollowModel().startupDelayStopped() && getNextStop().pars.speed <= 0) {
4632 } else {
4633 // do not apply startupDelay but signal that a stop has taken place
4635 }
4636 } else {
4637 // identify potential startup (before other effects reduce the speed again)
4639 }
4640 if (myActionStep) {
4641 vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
4642 if (vNext > 0) {
4643 vNext = MAX2(vNext, vSafeMin);
4644 }
4645 }
4646 // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
4647 // (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
4648 // (Jakob) We also need to make sure to reach a stop at the start of the next edge
4649 if (fabs(vNext) < NUMERICAL_EPS_SPEED && (myStopDist > POSITION_EPS || (hasStops() && myCurrEdge == getNextStop().edge))) {
4650 vNext = 0.;
4651 }
4652#ifdef DEBUG_EXEC_MOVE
4653 if (DEBUG_COND) {
4654 std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
4655 << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
4656 }
4657#endif
4658
4659 // vNext may be higher than vSafe without implying a bug:
4660 // - when approaching a green light that suddenly switches to yellow
4661 // - when using unregulated junctions
4662 // - when using tau < step-size
4663 // - when using unsafe car following models
4664 // - when using TraCI and some speedMode / laneChangeMode settings
4665 //if (vNext > vSafe + NUMERICAL_EPS) {
4666 // WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
4667 // + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
4668 // + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4669 //}
4670
4672 vNext = MAX2(vNext, 0.);
4673 } else {
4674 // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
4675 }
4676
4677 // Check for speed advices from the traci client
4678 vNext = processTraCISpeedControl(vSafe, vNext);
4679
4680 // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
4681 MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
4682 if (elecHybridOfVehicle != nullptr) {
4683 // this is the consumption given by the car following model-computed acceleration
4684 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4685 // but the maximum power of the electric motor may be lower
4686 // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
4687 double maxPower = getEmissionParameters()->getDoubleOptional(SUMO_ATTR_MAXIMUMPOWER, 100000.) / 3600;
4688 if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
4689 // no, we cannot accelerate that fast, recompute the maximum possible acceleration
4690 double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
4691 // and update the speed of the vehicle
4692 vNext = MIN2(vNext, this->getSpeed() + accel * TS);
4693 vNext = MAX2(vNext, 0.);
4694 // and set the vehicle consumption to reflect this
4695 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4696 }
4697 }
4698
4699 setBrakingSignals(vNext);
4700
4701 // update position and speed
4702 int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
4703 const MSLane* oldLaneMaybeOpposite = myLane;
4705 // transform to the forward-direction lane, move and then transform back
4708 }
4709 updateState(vNext);
4710 updateWaitingTime(vNext);
4711
4712 // Lanes, which the vehicle touched at some moment of the executed simstep
4713 std::vector<MSLane*> passedLanes;
4714 // remember previous lane (myLane is updated in processLaneAdvances)
4715 const MSLane* oldLane = myLane;
4716 // Reason for a possible emergency stop
4717 std::string emergencyReason;
4718 processLaneAdvances(passedLanes, emergencyReason);
4719
4720 updateTimeLoss(vNext);
4722
4724 if (myState.myPos > myLane->getLength()) {
4725 if (emergencyReason == "") {
4726 emergencyReason = TL(" for unknown reasons");
4727 }
4728 WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
4729 getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
4734 myState.mySpeed = 0;
4735 myAcceleration = 0;
4736 }
4737 const MSLane* oldBackLane = getBackLane();
4739 passedLanes.clear(); // ignore back occupation
4740 }
4741#ifdef DEBUG_ACTIONSTEPS
4742 if (DEBUG_COND) {
4743 std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
4744 }
4745#endif
4747 if (passedLanes.size() > 1 && isRail()) {
4748 for (auto pi = passedLanes.rbegin(); pi != passedLanes.rend(); ++pi) {
4749 MSLane* pLane = *pi;
4750 if (pLane != myLane && std::find(myFurtherLanes.begin(), myFurtherLanes.end(), pLane) == myFurtherLanes.end()) {
4752 }
4753 }
4754 }
4755 // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
4757 if (myLane != oldLane || oldBackLane != getBackLane()) {
4758 if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
4759 // shadow lane must be updated if the front or back lane changed
4760 // either if we already have a shadowLane or if there is lateral overlap
4762 }
4764 // The vehicles target lane must be also be updated if the front or back lane changed
4766 }
4767 }
4768 setBlinkerInformation(); // needs updated bestLanes
4769 //change the blue light only for emergency vehicles SUMOVehicleClass
4771 setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
4772 }
4773 // must be done before angle computation
4774 // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
4775 if (myActionStep) {
4776 // check (#2681): Can this be skipped?
4778 } else {
4780#ifdef DEBUG_ACTIONSTEPS
4781 if (DEBUG_COND) {
4782 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
4783 }
4784#endif
4785 }
4788 }
4789
4790#ifdef DEBUG_EXEC_MOVE
4791 if (DEBUG_COND) {
4792 std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
4793 gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
4794 }
4795#endif
4797 // transform back to the opposite-direction lane
4798 MSLane* newOpposite = nullptr;
4799 const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
4800 if (newOppositeEdge != nullptr) {
4801 newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
4802#ifdef DEBUG_EXEC_MOVE
4803 if (DEBUG_COND) {
4804 std::cout << SIMTIME << " newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
4805 }
4806#endif
4807 }
4808 if (newOpposite == nullptr) {
4810 // unusual overtaking at junctions is ok for emergency vehicles
4811 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
4813 }
4815 if (myState.myPos < getLength()) {
4816 // further lanes is always cleared during opposite driving
4817 MSLane* oldOpposite = oldLane->getOpposite();
4818 if (oldOpposite != nullptr) {
4819 myFurtherLanes.push_back(oldOpposite);
4820 myFurtherLanesPosLat.push_back(0);
4821 // small value since the lane is going in the other direction
4824 } else {
4825 SOFT_ASSERT(false);
4826 }
4827 }
4828 } else {
4830 myLane = newOpposite;
4831 oldLane = oldLaneMaybeOpposite;
4832 //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
4835 }
4836 }
4838 // Return whether the vehicle did move to another lane
4839 return myLane != oldLane;
4840}
4841
4842void
4844 myState.myPos += dist;
4847
4848 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
4850 for (int i = 0; i < (int)lanes.size(); i++) {
4851 MSLink* link = nullptr;
4852 if (i + 1 < (int)lanes.size()) {
4853 const MSLane* const to = lanes[i + 1];
4854 const bool internal = to->isInternal();
4855 for (MSLink* const l : lanes[i]->getLinkCont()) {
4856 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
4857 link = l;
4858 break;
4859 }
4860 }
4861 }
4862 myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
4863 }
4864 // minimum execute move:
4865 std::vector<MSLane*> passedLanes;
4866 // Reason for a possible emergency stop
4867 if (lanes.size() > 1) {
4869 }
4870 std::string emergencyReason;
4871 processLaneAdvances(passedLanes, emergencyReason);
4872#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
4873 if (DEBUG_COND) {
4874 std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
4875 << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
4876 << " finalPos=" << myState.myPos
4877 << " speed=" << getSpeed()
4878 << " myFurtherLanes=" << toString(myFurtherLanes)
4879 << "\n";
4880 }
4881#endif
4883 if (lanes.size() > 1) {
4884 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
4885#ifdef DEBUG_FURTHER
4886 if (DEBUG_COND) {
4887 std::cout << SIMTIME << " leaveLane \n";
4888 }
4889#endif
4890 (*i)->resetPartialOccupation(this);
4891 }
4892 myFurtherLanes.clear();
4893 myFurtherLanesPosLat.clear();
4895 }
4896}
4897
4898
4899void
4900MSVehicle::updateState(double vNext, bool parking) {
4901 // update position and speed
4902 double deltaPos; // positional change
4904 // euler
4905 deltaPos = SPEED2DIST(vNext);
4906 } else {
4907 // ballistic
4908 deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
4909 }
4910
4911 // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
4912 // NOTE: for the ballistic update vNext may be negative, indicating a stop.
4914
4915#ifdef DEBUG_EXEC_MOVE
4916 if (DEBUG_COND) {
4917 std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
4918 << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
4919 }
4920#endif
4921 double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
4922 if (decelPlus > 0) {
4923 const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
4924 if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
4925 // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
4926 decelPlus += 2 * NUMERICAL_EPS;
4927 const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
4928 if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
4929 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
4930 //+ " decelPlus=" + toString(decelPlus)
4931 //+ " prevAccel=" + toString(previousAcceleration)
4932 //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
4933 getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
4935 }
4936 }
4937 }
4938
4940 myState.mySpeed = MAX2(vNext, 0.);
4941
4942 if (isRemoteControlled()) {
4943 deltaPos = myInfluencer->implicitDeltaPosRemote(this);
4944 }
4945
4946 myState.myPos += deltaPos;
4947 myState.myLastCoveredDist = deltaPos;
4948 myNextTurn.first -= deltaPos;
4949
4950 if (!parking) {
4952 }
4953}
4954
4955void
4957 updateState(0, true);
4958 // deboard while parked
4959 if (myPersonDevice != nullptr) {
4961 }
4962 if (myContainerDevice != nullptr) {
4964 }
4965 for (MSVehicleDevice* const dev : myDevices) {
4966 dev->notifyParking();
4967 }
4968}
4969
4970
4971void
4977
4978
4979const MSLane*
4981 if (myFurtherLanes.size() > 0) {
4982 return myFurtherLanes.back();
4983 } else {
4984 return myLane;
4985 }
4986}
4987
4988
4989double
4990MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
4991 const std::vector<MSLane*>& passedLanes) {
4992#ifdef DEBUG_SETFURTHER
4993 if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
4994 << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
4995 << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
4996 << " passed=" << toString(passedLanes)
4997 << "\n";
4998#endif
4999 for (MSLane* further : furtherLanes) {
5000 further->resetPartialOccupation(this);
5001 if (further->getBidiLane() != nullptr
5002 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5003 further->getBidiLane()->resetPartialOccupation(this);
5004 }
5005 }
5006
5007 std::vector<MSLane*> newFurther;
5008 std::vector<double> newFurtherPosLat;
5009 double backPosOnPreviousLane = myState.myPos - getLength();
5010 bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
5011 if (passedLanes.size() > 1) {
5012 // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
5013 std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
5014 std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
5015 for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
5016 // As long as vehicle back reaches into passed lane, add it to the further lanes
5017 MSLane* further = *pi;
5018 newFurther.push_back(further);
5019 backPosOnPreviousLane += further->setPartialOccupation(this);
5020 if (further->getBidiLane() != nullptr
5021 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5022 further->getBidiLane()->setPartialOccupation(this);
5023 }
5024 if (fi != furtherLanes.end() && further == *fi) {
5025 // Lateral position on this lane is already known. Assume constant and use old value.
5026 newFurtherPosLat.push_back(*fpi);
5027 ++fi;
5028 ++fpi;
5029 } else {
5030 // The lane *pi was not in furtherLanes before.
5031 // If it is downstream, we assume as lateral position the current position
5032 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
5033 // we assign the last known lateral position.
5034 if (newFurtherPosLat.size() == 0) {
5035 if (widthShift) {
5036 newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
5037 } else {
5038 newFurtherPosLat.push_back(myState.myPosLat);
5039 }
5040 } else {
5041 newFurtherPosLat.push_back(newFurtherPosLat.back());
5042 }
5043 }
5044#ifdef DEBUG_SETFURTHER
5045 if (DEBUG_COND) {
5046 std::cout << SIMTIME << " updateFurtherLanes \n"
5047 << " further lane '" << further->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
5048 << std::endl;
5049 }
5050#endif
5051 }
5052 furtherLanes = newFurther;
5053 furtherLanesPosLat = newFurtherPosLat;
5054 } else {
5055 furtherLanes.clear();
5056 furtherLanesPosLat.clear();
5057 }
5058#ifdef DEBUG_SETFURTHER
5059 if (DEBUG_COND) std::cout
5060 << " newFurther=" << toString(furtherLanes)
5061 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
5062 << " newBackPos=" << backPosOnPreviousLane
5063 << "\n";
5064#endif
5065 return backPosOnPreviousLane;
5066}
5067
5068
5069double
5070MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
5071#ifdef DEBUG_FURTHER
5072 if (DEBUG_COND) {
5073 std::cout << SIMTIME
5074 << " getBackPositionOnLane veh=" << getID()
5075 << " lane=" << Named::getIDSecure(lane)
5076 << " cbgP=" << calledByGetPosition
5077 << " pos=" << myState.myPos
5078 << " backPos=" << myState.myBackPos
5079 << " myLane=" << myLane->getID()
5080 << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
5081 << " further=" << toString(myFurtherLanes)
5082 << " furtherPosLat=" << toString(myFurtherLanesPosLat)
5083 << "\n shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
5084 << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
5085 << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
5086 << "\n targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
5087 << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
5088 << std::endl;
5089 }
5090#endif
5091 if (lane == myLane
5092 || lane == myLaneChangeModel->getShadowLane()
5093 || lane == myLaneChangeModel->getTargetLane()) {
5095 if (lane == myLaneChangeModel->getShadowLane()) {
5096 return lane->getLength() - myState.myPos - myType->getLength();
5097 } else {
5098 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5099 }
5100 } else if (&lane->getEdge() != &myLane->getEdge()) {
5101 return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
5102 } else {
5103 // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
5104 return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
5105 }
5106 } else if (lane == myLane->getBidiLane()) {
5107 return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
5108 } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
5109 return myState.myBackPos;
5110 } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
5111 || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
5112 assert(myFurtherLanes.size() > 0);
5113 if (lane->getLength() == myFurtherLanes.back()->getLength()) {
5114 return myState.myBackPos;
5115 } else {
5116 // interpolate
5117 //if (DEBUG_COND) {
5118 //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
5119 // std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
5120 // << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
5121 // << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
5122 //}
5123 return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
5124 }
5125 } else {
5126 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
5127 double leftLength = myType->getLength() - myState.myPos;
5128
5129 std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
5130 while (leftLength > 0 && i != myFurtherLanes.end()) {
5131 leftLength -= (*i)->getLength();
5132 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5133 if (*i == lane) {
5134 return -leftLength;
5135 } else if (*i == lane->getBidiLane()) {
5136 return lane->getLength() + leftLength - (calledByGetPosition ? 2 * myType->getLength() : 0);
5137 }
5138 ++i;
5139 }
5140 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
5141 leftLength = myType->getLength() - myState.myPos;
5143 while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
5144 leftLength -= (*i)->getLength();
5145 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5146 if (*i == lane) {
5147 return -leftLength;
5148 }
5149 ++i;
5150 }
5151 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
5152 leftLength = myType->getLength() - myState.myPos;
5153 i = getFurtherLanes().begin();
5154 const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
5155 auto j = furtherTargetLanes.begin();
5156 while (leftLength > 0 && j != furtherTargetLanes.end()) {
5157 leftLength -= (*i)->getLength();
5158 // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
5159 if (*j == lane) {
5160 return -leftLength;
5161 }
5162 ++i;
5163 ++j;
5164 }
5165 WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
5166 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
5167 SOFT_ASSERT(false);
5168 return myState.myBackPos;
5169 }
5170}
5171
5172
5173double
5175 return getBackPositionOnLane(lane, true) + myType->getLength();
5176}
5177
5178
5179bool
5181 return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
5182}
5183
5184
5185void
5186MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
5188 double seenSpace = -lengthsInFront;
5189#ifdef DEBUG_CHECKREWINDLINKLANES
5190 if (DEBUG_COND) {
5191 std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
5192 };
5193#endif
5194 bool foundStopped = false;
5195 // compute available space until a stopped vehicle is found
5196 // this is the sum of non-interal lane length minus in-between vehicle lengths
5197 for (int i = 0; i < (int)lfLinks.size(); ++i) {
5198 // skip unset links
5199 DriveProcessItem& item = lfLinks[i];
5200#ifdef DEBUG_CHECKREWINDLINKLANES
5201 if (DEBUG_COND) std::cout << SIMTIME
5202 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5203 << " foundStopped=" << foundStopped;
5204#endif
5205 if (item.myLink == nullptr || foundStopped) {
5206 if (!foundStopped) {
5207 item.availableSpace += seenSpace;
5208 } else {
5209 item.availableSpace = seenSpace;
5210 }
5211#ifdef DEBUG_CHECKREWINDLINKLANES
5212 if (DEBUG_COND) {
5213 std::cout << " avail=" << item.availableSpace << "\n";
5214 }
5215#endif
5216 continue;
5217 }
5218 // get the next lane, determine whether it is an internal lane
5219 const MSLane* approachedLane = item.myLink->getViaLane();
5220 if (approachedLane != nullptr) {
5221 if (keepClear(item.myLink)) {
5222 seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
5223 if (approachedLane == myLane) {
5224 seenSpace += getVehicleType().getLengthWithGap();
5225 }
5226 } else {
5227 seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
5228 }
5229 item.availableSpace = seenSpace;
5230#ifdef DEBUG_CHECKREWINDLINKLANES
5231 if (DEBUG_COND) std::cout
5232 << " approached=" << approachedLane->getID()
5233 << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
5234 << " avail=" << item.availableSpace
5235 << " seenSpace=" << seenSpace
5236 << " hadStoppedVehicle=" << item.hadStoppedVehicle
5237 << " lengthsInFront=" << lengthsInFront
5238 << "\n";
5239#endif
5240 continue;
5241 }
5242 approachedLane = item.myLink->getLane();
5243 const MSVehicle* last = approachedLane->getLastAnyVehicle();
5244 if (last == nullptr || last == this) {
5245 if (approachedLane->getLength() > getVehicleType().getLength()
5246 || keepClear(item.myLink)) {
5247 seenSpace += approachedLane->getLength();
5248 }
5249 item.availableSpace = seenSpace;
5250#ifdef DEBUG_CHECKREWINDLINKLANES
5251 if (DEBUG_COND) {
5252 std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
5253 }
5254#endif
5255 } else {
5256 bool foundStopped2 = false;
5257 double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
5258 if (approachedLane->getBidiLane() != nullptr) {
5259 const MSVehicle* oncomingVeh = approachedLane->getBidiLane()->getFirstFullVehicle();
5260 if (oncomingVeh) {
5261 const double oncomingGap = approachedLane->getLength() - oncomingVeh->getPositionOnLane();
5262 const double oncomingBGap = oncomingVeh->getBrakeGap(true);
5263 // oncoming movement until ego enters the junction
5264 const double oncomingMove = STEPS2TIME(item.myArrivalTime - SIMSTEP) * oncomingVeh->getSpeed();
5265 const double spaceTillOncoming = oncomingGap - oncomingBGap - oncomingMove;
5266 spaceTillLastStanding = MIN2(spaceTillLastStanding, spaceTillOncoming);
5267 if (spaceTillOncoming <= getVehicleType().getLengthWithGap()) {
5268 foundStopped = true;
5269 }
5270#ifdef DEBUG_CHECKREWINDLINKLANES
5271 if (DEBUG_COND) {
5272 std::cout << " oVeh=" << oncomingVeh->getID()
5273 << " oGap=" << oncomingGap
5274 << " bGap=" << oncomingBGap
5275 << " mGap=" << oncomingMove
5276 << " sto=" << spaceTillOncoming;
5277 }
5278#endif
5279 }
5280 }
5281 seenSpace += spaceTillLastStanding;
5282 if (foundStopped2) {
5283 foundStopped = true;
5284 item.hadStoppedVehicle = true;
5285 }
5286 item.availableSpace = seenSpace;
5287 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
5288 foundStopped = true;
5289 item.hadStoppedVehicle = true;
5290 }
5291#ifdef DEBUG_CHECKREWINDLINKLANES
5292 if (DEBUG_COND) std::cout
5293 << " approached=" << approachedLane->getID()
5294 << " last=" << last->getID()
5295 << " lastHasToWait=" << last->myHaveToWaitOnNextLink
5296 << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
5297 << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
5298 << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
5299 // gap of last up to the next intersection
5300 - last->getVehicleType().getMinGap())
5301 << " stls=" << spaceTillLastStanding
5302 << " avail=" << item.availableSpace
5303 << " seenSpace=" << seenSpace
5304 << " foundStopped=" << foundStopped
5305 << " foundStopped2=" << foundStopped2
5306 << "\n";
5307#endif
5308 }
5309 }
5310
5311 // check which links allow continuation and add pass available to the previous item
5312 for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
5313 DriveProcessItem& item = lfLinks[i - 1];
5314 DriveProcessItem& nextItem = lfLinks[i];
5315 const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
5316 const bool opened = (item.myLink != nullptr
5317 && (canLeaveJunction || (
5318 // indirect bicycle turn
5319 nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
5320 && (
5321 item.myLink->havePriority()
5322 || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
5324 || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
5327 bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
5328#ifdef DEBUG_CHECKREWINDLINKLANES
5329 if (DEBUG_COND) std::cout
5330 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5331 << " canLeave=" << canLeaveJunction
5332 << " opened=" << opened
5333 << " allowsContinuation=" << allowsContinuation
5334 << " foundStopped=" << foundStopped
5335 << "\n";
5336#endif
5337 if (!opened && item.myLink != nullptr) {
5338 foundStopped = true;
5339 if (i > 1) {
5340 DriveProcessItem& item2 = lfLinks[i - 2];
5341 if (item2.myLink != nullptr && item2.myLink->isCont()) {
5342 allowsContinuation = true;
5343 }
5344 }
5345 }
5346 if (allowsContinuation) {
5347 item.availableSpace = nextItem.availableSpace;
5348#ifdef DEBUG_CHECKREWINDLINKLANES
5349 if (DEBUG_COND) std::cout
5350 << " link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5351 << " copy nextAvail=" << nextItem.availableSpace
5352 << "\n";
5353#endif
5354 }
5355 }
5356
5357 // find removalBegin
5358 int removalBegin = -1;
5359 for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
5360 // skip unset links
5361 const DriveProcessItem& item = lfLinks[i];
5362 if (item.myLink == nullptr) {
5363 continue;
5364 }
5365 /*
5366 double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
5367 if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
5368 removalBegin = lastLinkToInternal;
5369 }
5370 */
5371
5372 const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
5373#ifdef DEBUG_CHECKREWINDLINKLANES
5374 if (DEBUG_COND) std::cout
5375 << SIMTIME
5376 << " veh=" << getID()
5377 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
5378 << " avail=" << item.availableSpace
5379 << " leftSpace=" << leftSpace
5380 << "\n";
5381#endif
5382 if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
5383 double impatienceCorrection = 0;
5384 /*
5385 if(item.myLink->getState()==LINKSTATE_MINOR) {
5386 impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
5387 }
5388 */
5389 // may ignore keepClear rules
5390 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
5391 removalBegin = i;
5392 }
5393 //removalBegin = i;
5394 }
5395 }
5396 // abort requests
5397 if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
5398 const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
5399 while (removalBegin < (int)(lfLinks.size())) {
5400 DriveProcessItem& dpi = lfLinks[removalBegin];
5401 if (dpi.myLink == nullptr) {
5402 break;
5403 }
5404 dpi.myVLinkPass = dpi.myVLinkWait;
5405#ifdef DEBUG_CHECKREWINDLINKLANES
5406 if (DEBUG_COND) {
5407 std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
5408 }
5409#endif
5410 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
5411 // always leave junctions after requesting to enter
5412 if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
5413 dpi.mySetRequest = false;
5414 }
5415 }
5416 ++removalBegin;
5417 }
5418 }
5419 }
5420}
5421
5422
5423void
5425 if (!myActionStep) {
5426 return;
5427 }
5429 for (DriveProcessItem& dpi : myLFLinkLanes) {
5430 if (dpi.myLink != nullptr) {
5431 if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
5432 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
5433 }
5434 dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5435 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance, getLateralPositionOnLane());
5436 }
5437 }
5438 if (isRail()) {
5439 for (DriveProcessItem& dpi : myLFLinkLanes) {
5440 if (dpi.myLink != nullptr && dpi.myLink->getTLLogic() != nullptr && dpi.myLink->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL) {
5442 }
5443 }
5444 }
5445 if (myLaneChangeModel->getShadowLane() != nullptr) {
5446 // register on all shadow links
5447 for (const DriveProcessItem& dpi : myLFLinkLanes) {
5448 if (dpi.myLink != nullptr) {
5449 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
5450 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
5451 // register on opposite direction entry link to warn foes at minor side road
5452 parallelLink = dpi.myLink->getOppositeDirectionLink();
5453 }
5454 if (parallelLink != nullptr) {
5455 const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
5456 parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
5457 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTimeFor(dpi.myLink), dpi.myDistance,
5458 latOffset);
5460 }
5461 }
5462 }
5463 }
5464#ifdef DEBUG_PLAN_MOVE
5465 if (DEBUG_COND) {
5466 std::cout << SIMTIME
5467 << " veh=" << getID()
5468 << " after checkRewindLinkLanes\n";
5469 for (DriveProcessItem& dpi : myLFLinkLanes) {
5470 std::cout
5471 << " vPass=" << dpi.myVLinkPass
5472 << " vWait=" << dpi.myVLinkWait
5473 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
5474 << " request=" << dpi.mySetRequest
5475 << " atime=" << dpi.myArrivalTime
5476 << "\n";
5477 }
5478 }
5479#endif
5480}
5481
5482
5483void
5485 DriveProcessItem dpi(0, dist);
5486 dpi.myLink = link;
5487 const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
5488 link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
5489 // ensure cleanup in the next step
5490 myLFLinkLanes.push_back(dpi);
5492}
5493
5494
5495void
5496MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
5497 myAmOnNet = !onTeleporting;
5498 // vaporizing edge?
5499 /*
5500 if (enteredLane->getEdge().isVaporizing()) {
5501 // yep, let's do the vaporization...
5502 myLane = enteredLane;
5503 return true;
5504 }
5505 */
5506 // Adjust MoveReminder offset to the next lane
5507 adaptLaneEntering2MoveReminder(*enteredLane);
5508 // set the entered lane as the current lane
5509 MSLane* oldLane = myLane;
5510 myLane = enteredLane;
5511 myLastBestLanesEdge = nullptr;
5512
5513 // internal edges are not a part of the route...
5514 if (!enteredLane->getEdge().isInternal()) {
5515 ++myCurrEdge;
5517 }
5518 if (myInfluencer != nullptr) {
5520 }
5521 if (!onTeleporting) {
5525 // transform lateral position when the lane width changes
5526 assert(oldLane != nullptr);
5527 const MSLink* const link = oldLane->getLinkTo(myLane);
5528 if (link != nullptr) {
5529 myState.myPosLat += link->getLateralShift();
5530 } else {
5532 }
5533 } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
5534 const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
5535 const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5536 const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5537 myState.myPosLat *= range2 / range;
5538 }
5539 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5540 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5541 // (unless the lane is shared with cars)
5543 }
5544 } else {
5545 // normal move() isn't called so reset position here. must be done
5546 // before calling reminders
5547 myState.myPos = 0;
5550 }
5551 // update via
5552 if (myParameter->via.size() > 0 && myLane->getEdge().getID() == myParameter->via.front()) {
5553 myParameter->via.erase(myParameter->via.begin());
5554 }
5555}
5556
5557
5558void
5560 myAmOnNet = true;
5561 myLane = enteredLane;
5563 // need to update myCurrentLaneInBestLanes
5565 // switch to and activate the new lane's reminders
5566 // keep OldLaneReminders
5567 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5568 addReminder(*rem);
5569 }
5571 MSLane* lane = myLane;
5572 double leftLength = getVehicleType().getLength() - myState.myPos;
5573 int deleteFurther = 0;
5574#ifdef DEBUG_SETFURTHER
5575 if (DEBUG_COND) {
5576 std::cout << SIMTIME << " enterLaneAtLaneChange entered=" << Named::getIDSecure(enteredLane) << " oldFurther=" << toString(myFurtherLanes) << "\n";
5577 }
5578#endif
5579 if (myLane->getBidiLane() != nullptr && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5580 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5581 // (unless the lane is shared with cars)
5583 }
5584 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
5585 if (lane != nullptr) {
5587 }
5588#ifdef DEBUG_SETFURTHER
5589 if (DEBUG_COND) {
5590 std::cout << " enterLaneAtLaneChange i=" << i << " lane=" << Named::getIDSecure(lane) << " leftLength=" << leftLength << "\n";
5591 }
5592#endif
5593 if (leftLength > 0) {
5594 if (lane != nullptr) {
5596 if (myFurtherLanes[i]->getBidiLane() != nullptr
5597 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5598 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5599 }
5600 // lane changing onto longer lanes may reduce the number of
5601 // remaining further lanes
5602 myFurtherLanes[i] = lane;
5604 leftLength -= lane->setPartialOccupation(this);
5605 if (lane->getBidiLane() != nullptr
5606 && (!isRailway(getVClass()) || (lane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5607 lane->getBidiLane()->setPartialOccupation(this);
5608 }
5609 myState.myBackPos = -leftLength;
5610#ifdef DEBUG_SETFURTHER
5611 if (DEBUG_COND) {
5612 std::cout << SIMTIME << " newBackPos=" << myState.myBackPos << "\n";
5613 }
5614#endif
5615 } else {
5616 // keep the old values, but ensure there is no shadow
5619 }
5620 if (myState.myBackPos < 0) {
5621 myState.myBackPos += myFurtherLanes[i]->getLength();
5622 }
5623#ifdef DEBUG_SETFURTHER
5624 if (DEBUG_COND) {
5625 std::cout << SIMTIME << " i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
5626 }
5627#endif
5628 }
5629 } else {
5630 myFurtherLanes[i]->resetPartialOccupation(this);
5631 if (myFurtherLanes[i]->getBidiLane() != nullptr
5632 && (!isRailway(getVClass()) || (myFurtherLanes[i]->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5633 myFurtherLanes[i]->getBidiLane()->resetPartialOccupation(this);
5634 }
5635 deleteFurther++;
5636 }
5637 }
5638 if (deleteFurther > 0) {
5639#ifdef DEBUG_SETFURTHER
5640 if (DEBUG_COND) {
5641 std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
5642 }
5643#endif
5644 myFurtherLanes.erase(myFurtherLanes.end() - deleteFurther, myFurtherLanes.end());
5645 myFurtherLanesPosLat.erase(myFurtherLanesPosLat.end() - deleteFurther, myFurtherLanesPosLat.end());
5646 }
5647#ifdef DEBUG_SETFURTHER
5648 if (DEBUG_COND) {
5649 std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
5650 << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
5651 }
5652#endif
5654}
5655
5656
5657void
5658MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
5659 // build the list of lanes the vehicle is lapping into
5660 if (!myLaneChangeModel->isOpposite()) {
5661 double leftLength = myType->getLength() - pos;
5662 MSLane* clane = enteredLane;
5663 int routeIndex = getRoutePosition();
5664 while (leftLength > 0) {
5665 if (routeIndex > 0 && clane->getEdge().isNormal()) {
5666 // get predecessor lane that corresponds to prior route
5667 routeIndex--;
5668 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
5669 MSLane* target = clane;
5670 clane = nullptr;
5671 for (auto ili : target->getIncomingLanes()) {
5672 if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
5673 clane = ili.lane;
5674 break;
5675 }
5676 }
5677 } else {
5678 clane = clane->getLogicalPredecessorLane();
5679 }
5680 if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
5681 || (clane->isInternal() && (
5682 clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
5683 || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
5684 break;
5685 }
5686 if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
5687 myFurtherLanes.push_back(clane);
5689 clane->setPartialOccupation(this);
5690 if (clane->getBidiLane() != nullptr
5691 && (!isRailway(getVClass()) || (clane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5692 clane->getBidiLane()->setPartialOccupation(this);
5693 }
5694 }
5695 leftLength -= clane->getLength();
5696 }
5697 myState.myBackPos = -leftLength;
5698#ifdef DEBUG_SETFURTHER
5699 if (DEBUG_COND) {
5700 std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
5701 }
5702#endif
5703 } else {
5704 // clear partial occupation
5705 for (MSLane* further : myFurtherLanes) {
5706#ifdef DEBUG_SETFURTHER
5707 if (DEBUG_COND) {
5708 std::cout << SIMTIME << " opposite: resetPartialOccupation " << further->getID() << " \n";
5709 }
5710#endif
5711 further->resetPartialOccupation(this);
5712 if (further->getBidiLane() != nullptr
5713 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5714 further->getBidiLane()->resetPartialOccupation(this);
5715 }
5716 }
5717 myFurtherLanes.clear();
5718 myFurtherLanesPosLat.clear();
5719 }
5720}
5721
5722
5723void
5724MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
5725 myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
5727 onDepart();
5728 }
5730 assert(myState.myPos >= 0);
5731 assert(myState.mySpeed >= 0);
5732 myLane = enteredLane;
5733 myAmOnNet = true;
5734 // schedule action for the next timestep
5736 if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
5737 if (notification == MSMoveReminder::NOTIFICATION_PARKING && myInfluencer != nullptr) {
5738 drawOutsideNetwork(false);
5739 }
5740 // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
5741 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5742 addReminder(*rem);
5743 }
5744 activateReminders(notification, enteredLane);
5745 } else {
5746 myLastBestLanesEdge = nullptr;
5749 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()
5750 && myStops.front().pars.endPos < pos) {
5751 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5752 time2string(MSNet::getInstance()->getCurrentTimeStep()));
5754 myStops.pop_front();
5755 }
5756 // avoid startup-effects after teleport
5758 myStopSpeed = std::numeric_limits<double>::max();
5759 }
5760 computeFurtherLanes(enteredLane, pos);
5764 } else if (MSGlobals::gLaneChangeDuration > 0) {
5766 }
5767 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5770 myAngle += M_PI;
5771 }
5772 }
5773 if (MSNet::getInstance()->hasPersons()) {
5774 for (MSLane* further : myFurtherLanes) {
5775 if (further->mustCheckJunctionCollisions()) {
5777 }
5778 }
5779 }
5780}
5781
5782
5783void
5784MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5785 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5786 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5787#ifdef _DEBUG
5788 if (myTraceMoveReminders) {
5789 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5790 }
5791#endif
5792 ++rem;
5793 } else {
5794#ifdef _DEBUG
5795 if (myTraceMoveReminders) {
5796 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5797 }
5798#endif
5799 rem = myMoveReminders.erase(rem);
5800 }
5801 }
5805 && myLane != nullptr) {
5807 }
5808 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet
5809 && (!isRailway(getVClass()) || (myLane->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5811 }
5813 // @note. In case of lane change, myFurtherLanes and partial occupation
5814 // are handled in enterLaneAtLaneChange()
5815 for (MSLane* further : myFurtherLanes) {
5816#ifdef DEBUG_FURTHER
5817 if (DEBUG_COND) {
5818 std::cout << SIMTIME << " leaveLane \n";
5819 }
5820#endif
5821 further->resetPartialOccupation(this);
5822 if (further->getBidiLane() != nullptr
5823 && (!isRailway(getVClass()) || (further->getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
5824 further->getBidiLane()->resetPartialOccupation(this);
5825 }
5826 }
5827 myFurtherLanes.clear();
5828 myFurtherLanesPosLat.clear();
5829 }
5831 myAmOnNet = false;
5832 myWaitingTime = 0;
5833 }
5835 myStopDist = std::numeric_limits<double>::max();
5836 if (myPastStops.back().speed <= 0) {
5837 WRITE_WARNINGF(TL("Vehicle '%' aborts stop."), getID());
5838 }
5839 }
5841 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5842 if (myStops.front().getSpeed() <= 0) {
5843 WRITE_WARNINGF(TL("Vehicle '%' skips stop on lane '%' time=%."), getID(), myStops.front().lane->getID(),
5844 time2string(MSNet::getInstance()->getCurrentTimeStep()));
5846 if (MSStopOut::active()) {
5847 // clean up if stopBlocked was called
5849 }
5850 myStops.pop_front();
5851 } else {
5852 MSStop& stop = myStops.front();
5853 // passed waypoint at the end of the lane
5854 if (!stop.reached) {
5855 if (MSStopOut::active()) {
5857 }
5858 stop.reached = true;
5859 // enter stopping place so leaveFrom works as expected
5860 if (stop.busstop != nullptr) {
5861 // let the bus stop know the vehicle
5862 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5863 }
5864 if (stop.containerstop != nullptr) {
5865 // let the container stop know the vehicle
5867 }
5868 // do not enter parkingarea!
5869 if (stop.chargingStation != nullptr) {
5870 // let the container stop know the vehicle
5872 }
5873 }
5875 }
5876 myStopDist = std::numeric_limits<double>::max();
5877 }
5878 }
5879}
5880
5881
5882void
5884 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5885 if (rem->first->notifyLeaveBack(*this, reason, leftLane)) {
5886#ifdef _DEBUG
5887 if (myTraceMoveReminders) {
5888 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, true);
5889 }
5890#endif
5891 ++rem;
5892 } else {
5893#ifdef _DEBUG
5894 if (myTraceMoveReminders) {
5895 traceMoveReminder("notifyLeaveBack", rem->first, rem->second, false);
5896 }
5897#endif
5898 rem = myMoveReminders.erase(rem);
5899 }
5900 }
5901#ifdef DEBUG_MOVEREMINDERS
5902 if (DEBUG_COND) {
5903 std::cout << SIMTIME << " veh=" << getID() << " myReminders:";
5904 for (auto rem : myMoveReminders) {
5905 std::cout << rem.first->getDescription() << " ";
5906 }
5907 std::cout << "\n";
5908 }
5909#endif
5910}
5911
5912
5917
5918
5923
5924bool
5926 return (lane->isInternal()
5927 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5928 : &lane->getEdge() != *myCurrEdge);
5929}
5930
5931const std::vector<MSVehicle::LaneQ>&
5933 return *myBestLanes.begin();
5934}
5935
5936
5937void
5938MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5939#ifdef DEBUG_BESTLANES
5940 if (DEBUG_COND) {
5941 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5942 }
5943#endif
5944 if (startLane == nullptr) {
5945 startLane = myLane;
5946 }
5947 assert(startLane != 0);
5949 // depending on the calling context, startLane might be the forward lane
5950 // or the reverse-direction lane. In the latter case we need to
5951 // transform it to the forward lane.
5952 if (isOppositeLane(startLane)) {
5953 // use leftmost lane of forward edge
5954 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5955 assert(startLane != 0);
5956#ifdef DEBUG_BESTLANES
5957 if (DEBUG_COND) {
5958 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5959 }
5960#endif
5961 }
5962 }
5963 if (forceRebuild) {
5964 myLastBestLanesEdge = nullptr;
5966 }
5967 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5969#ifdef DEBUG_BESTLANES
5970 if (DEBUG_COND) {
5971 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5972 }
5973#endif
5974 return;
5975 }
5976 if (startLane->getEdge().isInternal()) {
5977 if (myBestLanes.size() == 0 || forceRebuild) {
5978 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5979 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5980 }
5981 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5982#ifdef DEBUG_BESTLANES
5983 if (DEBUG_COND) {
5984 std::cout << " nothing to do on internal\n";
5985 }
5986#endif
5987 return;
5988 }
5989 // adapt best lanes to fit the current internal edge:
5990 // keep the entries that are reachable from this edge
5991 const MSEdge* nextEdge = startLane->getNextNormal();
5992 assert(!nextEdge->isInternal());
5993 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5994 std::vector<LaneQ>& lanes = *it;
5995 assert(lanes.size() > 0);
5996 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5997 // keep those lanes which are successors of internal lanes from the edge of startLane
5998 std::vector<LaneQ> oldLanes = lanes;
5999 lanes.clear();
6000 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
6001 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
6002 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
6003 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
6004 lanes.push_back(*it_lane);
6005 break;
6006 }
6007 }
6008 }
6009 assert(lanes.size() == startLane->getEdge().getLanes().size());
6010 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
6011 for (int i = 0; i < (int)lanes.size(); ++i) {
6012 if (i + lanes[i].bestLaneOffset < 0) {
6013 lanes[i].bestLaneOffset = -i;
6014 }
6015 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
6016 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
6017 }
6018 assert(i + lanes[i].bestLaneOffset >= 0);
6019 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
6020 if (lanes[i].bestContinuations[0] != 0) {
6021 // patch length of bestContinuation to match expectations (only once)
6022 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
6023 }
6024 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
6025 myCurrentLaneInBestLanes = lanes.begin() + i;
6026 }
6027 assert(&(lanes[i].lane->getEdge()) == nextEdge);
6028 }
6029 myLastBestLanesInternalLane = startLane;
6031#ifdef DEBUG_BESTLANES
6032 if (DEBUG_COND) {
6033 std::cout << " updated for internal\n";
6034 }
6035#endif
6036 return;
6037 } else {
6038 // remove passed edges
6039 it = myBestLanes.erase(it);
6040 }
6041 }
6042 assert(false); // should always find the next edge
6043 }
6044 // start rebuilding
6046 myLastBestLanesEdge = &startLane->getEdge();
6048
6049 // get information about the next stop
6050 MSRouteIterator nextStopEdge = myRoute->end();
6051 const MSLane* nextStopLane = nullptr;
6052 double nextStopPos = 0;
6053 bool nextStopIsWaypoint = false;
6054 if (!myStops.empty()) {
6055 const MSStop& nextStop = myStops.front();
6056 nextStopLane = nextStop.lane;
6057 if (nextStop.isOpposite) {
6058 // target leftmost lane in forward direction
6059 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
6060 }
6061 nextStopEdge = nextStop.edge;
6062 nextStopPos = nextStop.pars.startPos;
6063 nextStopIsWaypoint = nextStop.getSpeed() > 0;
6064 }
6065 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
6066 if (myParameter->arrivalLaneProcedure >= ArrivalLaneDefinition::GIVEN && nextStopEdge == myRoute->end() && myArrivalLane >= 0) {
6067 nextStopEdge = (myRoute->end() - 1);
6068 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
6069 nextStopPos = myArrivalPos;
6070 }
6071 if (nextStopEdge != myRoute->end()) {
6072 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
6073 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
6074 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
6075 if (nextStopLane->isInternal()) {
6076 // switch to the correct lane before entering the intersection
6077 nextStopPos = (*nextStopEdge)->getLength();
6078 }
6079 }
6080
6081 // go forward along the next lanes;
6082 // trains do not have to deal with lane-changing for stops but their best
6083 // lanes lookahead is needed for rail signal control
6084 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
6085 int seen = 0;
6086 double seenLength = 0;
6087 bool progress = true;
6088 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
6089 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
6090 const double lookahead = getLaneChangeModel().getStrategicLookahead();
6091 for (MSRouteIterator ce = myCurrEdge; progress;) {
6092 std::vector<LaneQ> currentLanes;
6093 const std::vector<MSLane*>* allowed = nullptr;
6094 const MSEdge* nextEdge = nullptr;
6095 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
6096 nextEdge = *(ce + 1);
6097 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
6098 }
6099 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
6100 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
6101 LaneQ q;
6102 MSLane* cl = *i;
6103 q.lane = cl;
6104 q.bestContinuations.push_back(cl);
6105 q.bestLaneOffset = 0;
6106 q.length = cl->allowsVehicleClass(myType->getVehicleClass()) ? (*ce)->getLength() : 0;
6107 q.currentLength = q.length;
6108 // if all lanes are forbidden (i.e. due to a dynamic closing) we want to express no preference
6109 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
6110 q.occupation = 0;
6111 q.nextOccupation = 0;
6112 currentLanes.push_back(q);
6113 }
6114 //
6115 if (nextStopEdge == ce
6116 // already past the stop edge
6117 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
6118 if (!nextStopLane->isInternal() && !continueAfterStop) {
6119 progress = false;
6120 }
6121 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
6122 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
6123 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
6124 (*q).allowsContinuation = false;
6125 (*q).length = nextStopPos;
6126 (*q).currentLength = (*q).length;
6127 }
6128 }
6129 }
6130
6131 myBestLanes.push_back(currentLanes);
6132 ++seen;
6133 seenLength += currentLanes[0].lane->getLength();
6134 ++ce;
6135 if (lookahead >= 0) {
6136 progress &= (seen <= 2 || seenLength < lookahead); // custom (but we need to look at least one edge ahead)
6137 } else {
6138 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
6139 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
6140 }
6141 progress &= ce != myRoute->end();
6142 /*
6143 if(progress) {
6144 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
6145 }
6146 */
6147 }
6148
6149 // we are examining the last lane explicitly
6150 if (myBestLanes.size() != 0) {
6151 double bestLength = -1;
6152 // minimum and maximum lane index with best length
6153 int bestThisIndex = 0;
6154 int bestThisMaxIndex = 0;
6155 int index = 0;
6156 std::vector<LaneQ>& last = myBestLanes.back();
6157 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6158 if ((*j).length > bestLength) {
6159 bestLength = (*j).length;
6160 bestThisIndex = index;
6161 bestThisMaxIndex = index;
6162 } else if ((*j).length == bestLength) {
6163 bestThisMaxIndex = index;
6164 }
6165 }
6166 index = 0;
6167 bool requiredChangeRightForbidden = false;
6168 int requireChangeToLeftForbidden = -1;
6169 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
6170 if ((*j).length < bestLength) {
6171 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6172 (*j).bestLaneOffset = bestThisIndex - index;
6173 } else {
6174 (*j).bestLaneOffset = bestThisMaxIndex - index;
6175 }
6176 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6177 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6178 || requiredChangeRightForbidden)) {
6179 // this lane and all further lanes to the left cannot be used
6180 requiredChangeRightForbidden = true;
6181 (*j).length = 0;
6182 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6183 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6184 // this lane and all previous lanes to the right cannot be used
6185 requireChangeToLeftForbidden = (*j).lane->getIndex();
6186 }
6187 }
6188 }
6189 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
6190 if (last[i].bestLaneOffset > 0) {
6191 last[i].length = 0;
6192 }
6193 }
6194#ifdef DEBUG_BESTLANES
6195 if (DEBUG_COND) {
6196 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6197 std::vector<LaneQ>& laneQs = myBestLanes.back();
6198 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6199 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
6200 }
6201 }
6202#endif
6203 }
6204 // go backward through the lanes
6205 // track back best lane and compute the best prior lane(s)
6206 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
6207 std::vector<LaneQ>& nextLanes = (*(i - 1));
6208 std::vector<LaneQ>& clanes = (*i);
6209 MSEdge* const cE = &clanes[0].lane->getEdge();
6210 int index = 0;
6211 double bestConnectedLength = -1;
6212 double bestLength = -1;
6213 for (const LaneQ& j : nextLanes) {
6214 if (j.lane->isApproachedFrom(cE) && bestConnectedLength < j.length) {
6215 bestConnectedLength = j.length;
6216 }
6217 if (bestLength < j.length) {
6218 bestLength = j.length;
6219 }
6220 }
6221 // compute index of the best lane (highest length and least offset from the best next lane)
6222 int bestThisIndex = 0;
6223 int bestThisMaxIndex = 0;
6224 if (bestConnectedLength > 0) {
6225 index = 0;
6226 for (LaneQ& j : clanes) {
6227 const LaneQ* bestConnectedNext = nullptr;
6228 if (j.allowsContinuation) {
6229 for (const LaneQ& m : nextLanes) {
6230 if ((m.lane->allowsVehicleClass(getVClass()) || m.lane->hadPermissionChanges())
6231 && m.lane->isApproachedFrom(cE, j.lane)) {
6232 if (betterContinuation(bestConnectedNext, m)) {
6233 bestConnectedNext = &m;
6234 }
6235 }
6236 }
6237 if (bestConnectedNext != nullptr) {
6238 if (bestConnectedNext->length == bestConnectedLength && abs(bestConnectedNext->bestLaneOffset) < 2) {
6239 j.length += bestLength;
6240 } else {
6241 j.length += bestConnectedNext->length;
6242 }
6243 j.bestLaneOffset = bestConnectedNext->bestLaneOffset;
6244 }
6245 }
6246 if (bestConnectedNext != nullptr && (bestConnectedNext->allowsContinuation || bestConnectedNext->length > 0)) {
6247 copy(bestConnectedNext->bestContinuations.begin(), bestConnectedNext->bestContinuations.end(), back_inserter(j.bestContinuations));
6248 } else {
6249 j.allowsContinuation = false;
6250 }
6251 if (clanes[bestThisIndex].length < j.length
6252 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) > abs(j.bestLaneOffset))
6253 || (clanes[bestThisIndex].length == j.length && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset) &&
6254 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority(j.bestContinuations))
6255 ) {
6256 bestThisIndex = index;
6257 bestThisMaxIndex = index;
6258 } else if (clanes[bestThisIndex].length == j.length
6259 && abs(clanes[bestThisIndex].bestLaneOffset) == abs(j.bestLaneOffset)
6260 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority(j.bestContinuations)) {
6261 bestThisMaxIndex = index;
6262 }
6263 index++;
6264 }
6265
6266 //vehicle with elecHybrid device prefers running under an overhead wire
6267 if (getDevice(typeid(MSDevice_ElecHybrid)) != nullptr) {
6268 index = 0;
6269 for (const LaneQ& j : clanes) {
6270 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID(j.lane, j.currentLength / 2., SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6271 if (overheadWireSegmentID != "") {
6272 bestThisIndex = index;
6273 bestThisMaxIndex = index;
6274 }
6275 index++;
6276 }
6277 }
6278
6279 } else {
6280 // only needed in case of disconnected routes
6281 int bestNextIndex = 0;
6282 int bestDistToNeeded = (int) clanes.size();
6283 index = 0;
6284 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6285 if ((*j).allowsContinuation) {
6286 int nextIndex = 0;
6287 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
6288 if ((*m).lane->isApproachedFrom(cE, (*j).lane)) {
6289 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
6290 bestDistToNeeded = abs((*m).bestLaneOffset);
6291 bestThisIndex = index;
6292 bestThisMaxIndex = index;
6293 bestNextIndex = nextIndex;
6294 }
6295 }
6296 }
6297 }
6298 }
6299 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
6300 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
6301
6302 }
6303 // set bestLaneOffset for all lanes
6304 index = 0;
6305 bool requiredChangeRightForbidden = false;
6306 int requireChangeToLeftForbidden = -1;
6307 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6308 if ((*j).length < clanes[bestThisIndex].length
6309 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
6310 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
6311 ) {
6312 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
6313 (*j).bestLaneOffset = bestThisIndex - index;
6314 } else {
6315 (*j).bestLaneOffset = bestThisMaxIndex - index;
6316 }
6317 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
6318 // try to move away from the lower-priority lane before it ends
6319 (*j).length = (*j).currentLength;
6320 }
6321 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
6322 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
6323 || requiredChangeRightForbidden)) {
6324 // this lane and all further lanes to the left cannot be used
6325 requiredChangeRightForbidden = true;
6326 if ((*j).length == (*j).currentLength) {
6327 (*j).length = 0;
6328 }
6329 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
6330 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
6331 // this lane and all previous lanes to the right cannot be used
6332 requireChangeToLeftForbidden = (*j).lane->getIndex();
6333 }
6334 } else {
6335 (*j).bestLaneOffset = 0;
6336 }
6337 }
6338 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
6339 if (clanes[idx].length == clanes[idx].currentLength) {
6340 clanes[idx].length = 0;
6341 };
6342 }
6343
6344 //vehicle with elecHybrid device prefers running under an overhead wire
6345 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
6346 index = 0;
6347 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
6348 if (overheadWireID != "") {
6349 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
6350 (*j).bestLaneOffset = bestThisIndex - index;
6351 }
6352 }
6353 }
6354
6355#ifdef DEBUG_BESTLANES
6356 if (DEBUG_COND) {
6357 std::cout << " edge=" << cE->getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
6358 std::vector<LaneQ>& laneQs = clanes;
6359 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
6360 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << " allowCont=" << (*j).allowsContinuation << "\n";
6361 }
6362 }
6363#endif
6364
6365 }
6366 if (myBestLanes.front().front().lane->isInternal()) {
6367 // route starts on an internal lane
6368 if (myLane != nullptr) {
6369 startLane = myLane;
6370 } else {
6371 // vehicle not yet departed
6372 startLane = myBestLanes.front().front().lane;
6373 }
6374 }
6376#ifdef DEBUG_BESTLANES
6377 if (DEBUG_COND) {
6378 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
6379 }
6380#endif
6381}
6382
6383void
6385 if (myLane != nullptr) {
6387 }
6388}
6389
6390bool
6391MSVehicle::betterContinuation(const LaneQ* bestConnectedNext, const LaneQ& m) const {
6392 if (bestConnectedNext == nullptr) {
6393 return true;
6394 } else if (m.lane->getBidiLane() != nullptr && bestConnectedNext->lane->getBidiLane() == nullptr) {
6395 return false;
6396 } else if (bestConnectedNext->lane->getBidiLane() != nullptr && m.lane->getBidiLane() == nullptr) {
6397 return true;
6398 } else if (bestConnectedNext->length < m.length) {
6399 return true;
6400 } else if (bestConnectedNext->length == m.length) {
6401 if (abs(bestConnectedNext->bestLaneOffset) > abs(m.bestLaneOffset)) {
6402 return true;
6403 }
6404 const double contRight = getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_CONTRIGHT, 1);
6405 if (contRight < 1
6406 // if we don't check for adjacency, the rightmost line will get
6407 // multiple chances to be better which leads to an uninituitve distribution
6408 && (m.lane->getIndex() - bestConnectedNext->lane->getIndex()) == 1
6409 && RandHelper::rand(getRNG()) > contRight) {
6410 return true;
6411 }
6412 }
6413 return false;
6414}
6415
6416
6417int
6418MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
6419 if (conts.size() < 2) {
6420 return -1;
6421 } else {
6422 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
6423 if (link != nullptr) {
6424 return link->havePriority() ? 1 : 0;
6425 } else {
6426 // disconnected route
6427 return -1;
6428 }
6429 }
6430}
6431
6432
6433void
6435 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
6436 std::vector<LaneQ>::iterator i;
6437#ifdef _DEBUG
6438 bool found = false;
6439#endif
6440 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
6441 double nextOccupation = 0;
6442 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
6443 nextOccupation += (*j)->getBruttoVehLenSum();
6444 }
6445 (*i).nextOccupation = nextOccupation;
6446#ifdef DEBUG_BESTLANES
6447 if (DEBUG_COND) {
6448 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
6449 }
6450#endif
6451 if ((*i).lane == startLane) {
6453#ifdef _DEBUG
6454 found = true;
6455#endif
6456 }
6457 }
6458#ifdef _DEBUG
6459 assert(found || startLane->isInternal());
6460#endif
6461}
6462
6463
6464const std::vector<MSLane*>&
6466 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6467 return myEmptyLaneVector;
6468 }
6469 return (*myCurrentLaneInBestLanes).bestContinuations;
6470}
6471
6472
6473const std::vector<MSLane*>&
6475 const MSLane* lane = l;
6476 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
6477 if (lane->getEdge().isInternal()) {
6478 // internal edges are not kept inside the bestLanes structure
6479 lane = lane->getLinkCont()[0]->getLane();
6480 }
6481 if (myBestLanes.size() == 0) {
6482 return myEmptyLaneVector;
6483 }
6484 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
6485 if ((*i).lane == lane) {
6486 return (*i).bestContinuations;
6487 }
6488 }
6489 return myEmptyLaneVector;
6490}
6491
6492const std::vector<const MSLane*>
6493MSVehicle::getUpcomingLanesUntil(double distance) const {
6494 std::vector<const MSLane*> lanes;
6495
6496 if (distance <= 0. || hasArrived()) {
6497 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
6498 return lanes;
6499 }
6500
6501 if (!myLaneChangeModel->isOpposite()) {
6502 distance += getPositionOnLane();
6503 } else {
6504 distance += myLane->getOppositePos(getPositionOnLane());
6505 }
6507 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6508 lanes.insert(lanes.end(), lane);
6509 distance -= lane->getLength();
6510 lane = lane->getLinkCont().front()->getViaLaneOrLane();
6511 }
6512
6513 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
6514 if (contLanes.empty()) {
6515 return lanes;
6516 }
6517 auto contLanesIt = contLanes.begin();
6518 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
6519 while (distance > 0.) {
6520 MSLane* l = nullptr;
6521 if (contLanesIt != contLanes.end()) {
6522 l = *contLanesIt;
6523 if (l != nullptr) {
6524 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
6525 }
6526 ++contLanesIt;
6527 if (l != nullptr || myLane->isInternal()) {
6528 ++routeIt;
6529 }
6530 if (l == nullptr) {
6531 continue;
6532 }
6533 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
6534 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6535 l = (*routeIt)->getLanes().back();
6536 ++routeIt;
6537 } else { // the search distance goes beyond our route
6538 break;
6539 }
6540
6541 assert(l != nullptr);
6542
6543 // insert internal lanes if applicable
6544 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
6545 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
6546 lanes.insert(lanes.end(), internalLane);
6547 distance -= internalLane->getLength();
6548 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6549 }
6550 if (distance <= 0.) {
6551 break;
6552 }
6553
6554 lanes.insert(lanes.end(), l);
6555 distance -= l->getLength();
6556 }
6557
6558 return lanes;
6559}
6560
6561const std::vector<const MSLane*>
6562MSVehicle::getPastLanesUntil(double distance) const {
6563 std::vector<const MSLane*> lanes;
6564
6565 if (distance <= 0.) {
6566 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
6567 return lanes;
6568 }
6569
6570 MSRouteIterator routeIt = myCurrEdge;
6571 if (!myLaneChangeModel->isOpposite()) {
6572 distance += myLane->getLength() - getPositionOnLane();
6573 } else {
6575 }
6577 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
6578 lanes.insert(lanes.end(), lane);
6579 distance -= lane->getLength();
6580 lane = lane->getLogicalPredecessorLane();
6581 }
6582
6583 while (distance > 0.) {
6584 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
6585 MSLane* l = (*routeIt)->getLanes().back();
6586
6587 // insert internal lanes if applicable
6588 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
6589 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
6590 std::vector<const MSLane*> internalLanes;
6591 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
6592 internalLanes.insert(internalLanes.begin(), internalLane);
6593 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
6594 }
6595 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
6596 lanes.insert(lanes.end(), *it);
6597 distance -= (*it)->getLength();
6598 }
6599 if (distance <= 0.) {
6600 break;
6601 }
6602
6603 lanes.insert(lanes.end(), l);
6604 distance -= l->getLength();
6605
6606 // NOTE: we're going backwards with the (bi-directional) Iterator
6607 // TODO: consider make reverse_iterator() when moving on to C++14 or later
6608 if (routeIt != myRoute->begin()) {
6609 --routeIt;
6610 } else { // we went backwards to begin() and already processed the first and final element
6611 break;
6612 }
6613 }
6614
6615 return lanes;
6616}
6617
6618
6619const std::vector<MSLane*>
6621 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6622 std::vector<MSLane*> result;
6623 for (const MSLane* lane : routeLanes) {
6624 MSLane* opposite = lane->getOpposite();
6625 if (opposite != nullptr) {
6626 result.push_back(opposite);
6627 } else {
6628 break;
6629 }
6630 }
6631 return result;
6632}
6633
6634
6635int
6637 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6638 return 0;
6639 } else {
6640 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6641 }
6642}
6643
6644double
6646 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6647 return -1;
6648 } else {
6649 return (*myCurrentLaneInBestLanes).length;
6650 }
6651}
6652
6653
6654
6655void
6656MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6657 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6658 assert(laneIndex < (int)preb.size());
6659 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6660}
6661
6662
6663void
6669
6670std::pair<const MSLane*, double>
6671MSVehicle::getLanePosAfterDist(double distance) const {
6672 if (distance == 0) {
6673 return std::make_pair(myLane, getPositionOnLane());
6674 }
6675 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6676 distance += getPositionOnLane();
6677 for (const MSLane* lane : lanes) {
6678 if (lane->getLength() > distance) {
6679 return std::make_pair(lane, distance);
6680 }
6681 distance -= lane->getLength();
6682 }
6683 return std::make_pair(nullptr, -1);
6684}
6685
6686
6687double
6688MSVehicle::getDistanceToPosition(double destPos, const MSLane* destLane) const {
6689 if (isOnRoad() && destLane != nullptr) {
6690 return myRoute->getDistanceBetween(getPositionOnLane(), destPos, myLane, destLane);
6691 }
6692 return std::numeric_limits<double>::max();
6693}
6694
6695
6696std::pair<const MSVehicle* const, double>
6697MSVehicle::getLeader(double dist, bool considerCrossingFoes) const {
6698 if (myLane == nullptr) {
6699 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6700 }
6701 if (dist == 0) {
6703 }
6704 const MSVehicle* lead = nullptr;
6705 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6706 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6707 // vehicle might be outside the road network
6708 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6709 if (it != vehs.end() && it + 1 != vehs.end()) {
6710 lead = *(it + 1);
6711 }
6712 if (lead != nullptr) {
6713 std::pair<const MSVehicle* const, double> result(
6714 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6715 lane->releaseVehicles();
6716 return result;
6717 }
6718 const double seen = myLane->getLength() - getPositionOnLane();
6719 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6720 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts, considerCrossingFoes);
6721 lane->releaseVehicles();
6722 return result;
6723}
6724
6725
6726std::pair<const MSVehicle* const, double>
6727MSVehicle::getFollower(double dist) const {
6728 if (myLane == nullptr) {
6729 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6730 }
6731 if (dist == 0) {
6732 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6733 }
6735}
6736
6737
6738double
6740 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6741 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6742 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6743 return -1;
6744 }
6745 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6746}
6747
6748
6749void
6751 MSBaseVehicle::addTransportable(transportable);
6752 if (myStops.size() > 0 && myStops.front().reached) {
6753 if (transportable->isPerson()) {
6754 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6755 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6756 }
6757 } else {
6758 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6759 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6760 }
6761 }
6762 }
6763}
6764
6765
6766void
6769 int state = myLaneChangeModel->getOwnState();
6770 // do not set blinker for sublane changes or when blocked from changing to the right
6771 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6772 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6776 // lane indices increase from left to right
6777 std::swap(left, right);
6778 }
6779 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6780 switchOnSignal(left);
6781 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6782 switchOnSignal(right);
6783 } else if (myLaneChangeModel->isChangingLanes()) {
6785 switchOnSignal(left);
6786 } else {
6787 switchOnSignal(right);
6788 }
6789 } else {
6790 const MSLane* lane = getLane();
6791 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6792 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6793 switch ((*link)->getDirection()) {
6798 break;
6802 break;
6803 default:
6804 break;
6805 }
6806 }
6807 }
6808 // stopping related signals
6809 if (hasStops()
6810 && (myStops.begin()->reached ||
6812 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6813 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6814 // not stopping on the right. Activate emergency blinkers
6816 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6817 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6819 }
6820 }
6821 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6823 myInfluencer->setSignals(-1); // overwrite computed signals only once
6824 }
6825}
6826
6827void
6829
6830 //TODO look if timestep ist SIMSTEP
6831 if (currentTime % 1000 == 0) {
6834 } else {
6836 }
6837 }
6838}
6839
6840
6841int
6843 return myLane == nullptr ? -1 : myLane->getIndex();
6844}
6845
6846
6847void
6848MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6849 myLane = lane;
6850 myState.myPos = pos;
6851 myState.myPosLat = posLat;
6853}
6854
6855
6856double
6858 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6859}
6860
6861
6862double
6864 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6865}
6866
6867
6868double
6870 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6871}
6872
6873
6874double
6876 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6877}
6878
6879
6880double
6882 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6883}
6884
6885
6886double
6888 return getCenterOnEdge(lane) + 0.5 * getVehicleType().getWidth();
6889}
6890
6891
6892double
6894 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6896 } else if (lane == myLaneChangeModel->getShadowLane()) {
6897 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6898 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6899 }
6901 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6902 } else {
6903 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6904 }
6905 } else if (lane == myLane->getBidiLane()) {
6906 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6907 } else {
6908 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6909 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6910 if (myFurtherLanes[i] == lane) {
6911#ifdef DEBUG_FURTHER
6912 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << 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 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6918#ifdef DEBUG_FURTHER
6919 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat(bidi)=" << myFurtherLanesPosLat[i]
6920 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6921 << "\n";
6922#endif
6923 return lane->getRightSideOnEdge() - myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6924 }
6925 }
6926 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6927 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6928 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6929 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6930 if (shadowFurther[i] == lane) {
6931 assert(myLaneChangeModel->getShadowLane() != 0);
6932 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6934 }
6935 }
6936 assert(false);
6937 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6938 }
6939}
6940
6941
6942double
6944 assert(lane != 0);
6945 if (&lane->getEdge() == &myLane->getEdge()) {
6946 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6947 } else if (myLane->getParallelOpposite() == lane) {
6948 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6949 } else if (myLane->getBidiLane() == lane) {
6950 return -2 * getLateralPositionOnLane();
6951 } else {
6952 // Check whether the lane is a further lane for the vehicle
6953 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6954 if (myFurtherLanes[i] == lane) {
6955#ifdef DEBUG_FURTHER
6956 if (DEBUG_COND) {
6957 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6958 }
6959#endif
6961 } else if (myFurtherLanes[i]->getBidiLane() == lane) {
6962#ifdef DEBUG_FURTHER
6963 if (DEBUG_COND) {
6964 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherBidiLat=" << myFurtherLanesPosLat[i] << "\n";
6965 }
6966#endif
6967 return -2 * (myFurtherLanesPosLat[i] - myState.myPosLat);
6968 }
6969 }
6970#ifdef DEBUG_FURTHER
6971 if (DEBUG_COND) {
6972 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6973 }
6974#endif
6975 // Check whether the lane is a "shadow further lane" for the vehicle
6976 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6977 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6978 if (shadowFurther[i] == lane) {
6979#ifdef DEBUG_FURTHER
6980 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6981 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6982 << " lane=" << lane->getID()
6983 << " i=" << i
6984 << " posLat=" << myState.myPosLat
6985 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6986 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6987 << "\n";
6988#endif
6990 }
6991 }
6992 // Check whether the vehicle issued a maneuverReservation on the lane.
6993 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6994 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6995 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6996 MSLane* targetLane = furtherTargets[i];
6997 if (targetLane == lane) {
6998 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6999 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
7000#ifdef DEBUG_TARGET_LANE
7001 if (DEBUG_COND) {
7002 std::cout << " getLatOffset veh=" << getID()
7003 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
7004 << "\n i=" << i
7005 << " posLat=" << myState.myPosLat
7006 << " furtherPosLat=" << myFurtherLanesPosLat[i]
7007 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
7008 << " targetDir=" << targetDir
7009 << " latOffset=" << latOffset
7010 << std::endl;
7011 }
7012#endif
7013 return latOffset;
7014 }
7015 }
7016 assert(false);
7017 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
7018 }
7019}
7020
7021
7022double
7023MSVehicle::lateralDistanceToLane(const int offset) const {
7024 // compute the distance when changing to the neighboring lane
7025 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
7026 assert(offset == 0 || offset == 1 || offset == -1);
7027 assert(myLane != nullptr);
7028 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
7029 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
7030 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
7031 const double latPos = getLateralPositionOnLane();
7032 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
7033 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
7034 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
7035 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
7036 if (offset == 0) {
7037 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
7038 // correct overlapping left
7039 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
7040 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
7041 // correct overlapping right
7042 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
7043 }
7044 latLaneDist *= oppositeSign;
7045 } else if (offset == -1) {
7046 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
7047 } else if (offset == 1) {
7048 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
7049 }
7050#ifdef DEBUG_ACTIONSTEPS
7051 if (DEBUG_COND) {
7052 std::cout << SIMTIME
7053 << " veh=" << getID()
7054 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
7055 << " halfVehWidth=" << halfVehWidth
7056 << " latPos=" << latPos
7057 << " latLaneDist=" << latLaneDist
7058 << " leftLimit=" << leftLimit
7059 << " rightLimit=" << rightLimit
7060 << "\n";
7061 }
7062#endif
7063 return latLaneDist;
7064}
7065
7066
7067double
7068MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
7069 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
7070 - 0.5 * lane->getWidth());
7071}
7072
7073double
7077
7078double
7082
7083
7084void
7086 for (const DriveProcessItem& dpi : lfLinks) {
7087 if (dpi.myLink != nullptr) {
7088 dpi.myLink->removeApproaching(this);
7089 }
7090 }
7091 // unregister on all shadow links
7093}
7094
7095
7096bool
7097MSVehicle::unsafeLinkAhead(const MSLane* lane, double zipperDist) const {
7098 // the following links are unsafe:
7099 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
7100 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
7101 double seen = myLane->getLength() - getPositionOnLane();
7102 const double dist = MAX2(zipperDist, getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0));
7103 if (seen < dist) {
7104 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
7105 int view = 1;
7106 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7107 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
7108 while (!lane->isLinkEnd(link) && seen <= dist) {
7109 if ((!lane->isInternal()
7110 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
7111 || !(*link)->havePriority()))
7112 || (lane->isInternal() && zipperDist > 0)) {
7113 // find the drive item corresponding to this link
7114 bool found = false;
7115 while (di != myLFLinkLanes.end() && !found) {
7116 if ((*di).myLink != nullptr) {
7117 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
7118 if (diPredLane != nullptr) {
7119 if (&diPredLane->getEdge() == &lane->getEdge()) {
7120 found = true;
7121 }
7122 }
7123 }
7124 if (!found) {
7125 di++;
7126 }
7127 }
7128 if (found) {
7129 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
7130 (*di).getLeaveSpeed(), getVehicleType().getLength());
7131 const MSLink* entry = (*link)->getCorrespondingEntryLink();
7132 //if (DEBUG_COND) {
7133 // 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";
7134 //}
7135 if (entry->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
7136 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
7137 return true;
7138 }
7139 }
7140 // no drive item is found if the vehicle aborts its request within dist
7141 }
7142 lane = (*link)->getViaLaneOrLane();
7143 if (!lane->getEdge().isInternal()) {
7144 view++;
7145 }
7146 seen += lane->getLength();
7147 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
7148 }
7149 }
7150 return false;
7151}
7152
7153
7155MSVehicle::getBoundingBox(double offset) const {
7156 PositionVector centerLine;
7157 Position pos = getPosition();
7158 centerLine.push_back(pos);
7159 switch (myType->getGuiShape()) {
7166 for (MSLane* lane : myFurtherLanes) {
7167 centerLine.push_back(lane->getShape().back());
7168 }
7169 break;
7170 }
7171 default:
7172 break;
7173 }
7174 double l = getLength();
7175 Position backPos = getBackPosition();
7176 if (pos.distanceTo2D(backPos) > l + NUMERICAL_EPS) {
7177 // getBackPosition may not match the visual back in networks without internal lanes
7178 double a = getAngle() + M_PI; // angle pointing backwards
7179 backPos = pos + Position(l * cos(a), l * sin(a));
7180 }
7181 centerLine.push_back(backPos);
7182 if (offset != 0) {
7183 centerLine.extrapolate2D(offset);
7184 }
7185 PositionVector result = centerLine;
7186 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7187 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
7188 result.append(centerLine.reverse(), POSITION_EPS);
7189 return result;
7190}
7191
7192
7194MSVehicle::getBoundingPoly(double offset) const {
7195 switch (myType->getGuiShape()) {
7201 // box with corners cut off
7202 PositionVector result;
7203 PositionVector centerLine;
7204 centerLine.push_back(getPosition());
7205 centerLine.push_back(getBackPosition());
7206 if (offset != 0) {
7207 centerLine.extrapolate2D(offset);
7208 }
7209 PositionVector line1 = centerLine;
7210 PositionVector line2 = centerLine;
7211 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
7212 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
7213 line2.scaleRelative(0.8);
7214 result.push_back(line1[0]);
7215 result.push_back(line2[0]);
7216 result.push_back(line2[1]);
7217 result.push_back(line1[1]);
7218 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
7219 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
7220 result.push_back(line1[1]);
7221 result.push_back(line2[1]);
7222 result.push_back(line2[0]);
7223 result.push_back(line1[0]);
7224 return result;
7225 }
7226 default:
7227 return getBoundingBox();
7228 }
7229}
7230
7231
7232bool
7234 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
7235 if (&(*i)->getEdge() == edge) {
7236 return true;
7237 }
7238 }
7239 return false;
7240}
7241
7242
7243bool
7244MSVehicle::isBidiOn(const MSLane* lane) const {
7245 return lane->getBidiLane() != nullptr && (
7246 myLane == lane->getBidiLane()
7247 || onFurtherEdge(&lane->getBidiLane()->getEdge()));
7248}
7249
7250
7251bool
7252MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
7253 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
7254 // consistency in the behaviour.
7255
7256 // get vehicle params
7257 MSParkingArea* destParkArea = getNextParkingArea();
7258 const MSRoute& route = getRoute();
7259 const MSEdge* lastEdge = route.getLastEdge();
7260
7261 if (destParkArea == nullptr) {
7262 // not driving towards a parking area
7263 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
7264 return false;
7265 }
7266
7267 // if the current route ends at the parking area, the new route will also and at the new area
7268 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
7269 && getArrivalPos() >= destParkArea->getBeginLanePosition()
7270 && getArrivalPos() <= destParkArea->getEndLanePosition());
7271
7272 // retrieve info on the new parking area
7274 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
7275
7276 if (newParkingArea == nullptr) {
7277 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
7278 return false;
7279 }
7280
7281 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
7283
7284 // Compute the route from the current edge to the parking area edge
7285 ConstMSEdgeVector edgesToPark;
7286 router.compute(getEdge(), getPositionOnLane(), newEdge, newParkingArea->getEndLanePosition(), this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
7287
7288 // Compute the route from the parking area edge to the end of the route
7289 ConstMSEdgeVector edgesFromPark;
7290 if (!newDestination) {
7291 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
7292 } else {
7293 // adapt plans of any riders
7294 for (MSTransportable* p : getPersons()) {
7295 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
7296 }
7297 }
7298
7299 // we have a new destination, let's replace the vehicle route
7300 ConstMSEdgeVector edges = edgesToPark;
7301 if (edgesFromPark.size() > 0) {
7302 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
7303 }
7304
7306 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
7307 *newParameter = getParameter();
7309 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
7310 replaceParameter(newParameter);
7311 }
7312 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
7313 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
7314 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
7315 if (replaceParkingArea(newParkingArea, errorMsg)) {
7316 const bool onInit = myLane == nullptr;
7317 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
7318 } else {
7319 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
7320 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
7321 return false;
7322 }
7323 return true;
7324}
7325
7326
7327bool
7329 const int numStops = (int)myStops.size();
7330 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
7331 if (myLane != nullptr && numStops != (int)myStops.size()) {
7332 updateBestLanes(true);
7333 }
7334 return result;
7335}
7336
7337
7338bool
7339MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
7340 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
7341 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
7342 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
7343 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
7344 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
7345 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
7346 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
7347 // << " vNew=" << vNew
7348 // << "\n";
7349 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
7352 if (myState.myPos < myType->getLength()) {
7356 myAngle += M_PI;
7357 }
7358 }
7359 }
7360 }
7361 return true;
7362}
7363
7364
7365bool
7367 if (isStopped()) {
7371 }
7372 MSStop& stop = myStops.front();
7373 // we have waited long enough and fulfilled any passenger-requirements
7374 if (stop.busstop != nullptr) {
7375 // inform bus stop about leaving it
7376 stop.busstop->leaveFrom(this);
7377 }
7378 // we have waited long enough and fulfilled any container-requirements
7379 if (stop.containerstop != nullptr) {
7380 // inform container stop about leaving it
7381 stop.containerstop->leaveFrom(this);
7382 }
7383 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
7384 // inform parking area about leaving it
7385 stop.parkingarea->leaveFrom(this);
7386 }
7387 if (stop.chargingStation != nullptr) {
7388 // inform charging station about leaving it
7389 stop.chargingStation->leaveFrom(this);
7390 }
7391 // the current stop is no longer valid
7392 myLane->getEdge().removeWaiting(this);
7393 // MSStopOut needs to know whether the stop had a loaded 'ended' value so we call this before replacing the value
7394 if (stop.pars.started == -1) {
7395 // waypoint edge was passed in a single step
7397 }
7398 if (MSStopOut::active()) {
7399 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
7400 }
7402 for (const auto& rem : myMoveReminders) {
7403 rem.first->notifyStopEnded();
7404 }
7406 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
7407 }
7409 // reset lateral position to default
7410 myState.myPosLat = 0;
7411 }
7412 const bool wasWaypoint = stop.getSpeed() > 0;
7413 myPastStops.push_back(stop.pars);
7414 myPastStops.back().routeIndex = (int)(stop.edge - myRoute->begin());
7415 myStops.pop_front();
7416 myStopDist = std::numeric_limits<double>::max();
7417 // do not count the stopping time towards gridlock time.
7418 // Other outputs use an independent counter and are not affected.
7419 myWaitingTime = 0;
7421 // maybe the next stop is on the same edge; let's rebuild best lanes
7422 updateBestLanes(true);
7423 // continue as wished...
7426 return !wasWaypoint;
7427 }
7428 return false;
7429}
7430
7431
7434 if (myInfluencer == nullptr) {
7435 myInfluencer = new Influencer();
7436 }
7437 return *myInfluencer;
7438}
7439
7444
7445
7448 return myInfluencer;
7449}
7450
7453 return myInfluencer;
7454}
7455
7456
7457double
7459 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
7460 // influencer original speed is -1 on initialization
7462 }
7463 return myState.mySpeed;
7464}
7465
7466
7467int
7469 if (hasInfluencer()) {
7471 MSNet::getInstance()->getCurrentTimeStep(),
7472 myLane->getEdge(),
7473 getLaneIndex(),
7474 state);
7475 }
7476 return state;
7477}
7478
7479
7480void
7484
7485
7486bool
7490
7491
7492bool
7496
7497
7498bool
7499MSVehicle::keepClear(const MSLink* link) const {
7500 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
7501 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
7502 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
7503 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
7504 } else {
7505 return false;
7506 }
7507}
7508
7509
7510bool
7511MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
7512 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
7513 return true;
7514 }
7515 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
7516#ifdef DEBUG_IGNORE_RED
7517 if (DEBUG_COND) {
7518 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
7519 }
7520#endif
7521 if (ignoreRedTime < 0) {
7522 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
7523 if (ignoreYellowTime > 0 && link->haveYellow()) {
7524 assert(link->getTLLogic() != 0);
7525 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7526 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
7527 return !canBrake || ignoreYellowTime > yellowDuration;
7528 } else {
7529 return false;
7530 }
7531 } else if (link->haveYellow()) {
7532 // always drive at yellow when ignoring red
7533 return true;
7534 } else if (link->haveRed()) {
7535 assert(link->getTLLogic() != 0);
7536 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
7537#ifdef DEBUG_IGNORE_RED
7538 if (DEBUG_COND) {
7539 std::cout
7540 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
7541 << " ignoreRedTime=" << ignoreRedTime
7542 << " spentRed=" << redDuration
7543 << " canBrake=" << canBrake << "\n";
7544 }
7545#endif
7546 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
7547 return !canBrake || ignoreRedTime > redDuration;
7548 } else {
7549 return false;
7550 }
7551}
7552
7553bool
7556 return false;
7557 }
7558 for (const std::string& typeID : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_TYPES), "")).getVector()) {
7559 if (typeID == foe->getVehicleType().getID()) {
7560 return true;
7561 }
7562 }
7563 for (const std::string& id : StringTokenizer(getParameter().getParameter(toString(SUMO_ATTR_CF_IGNORE_IDS), "")).getVector()) {
7564 if (id == foe->getID()) {
7565 return true;
7566 }
7567 }
7568 return false;
7569}
7570
7571bool
7573 // either on an internal lane that was entered via minor link
7574 // or on approach to minor link below visibility distance
7575 if (myLane == nullptr) {
7576 return false;
7577 }
7578 if (myLane->getEdge().isInternal()) {
7579 return !myLane->getIncomingLanes().front().viaLink->havePriority();
7580 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
7581 MSLink* link = myLFLinkLanes.front().myLink;
7582 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
7583 }
7584 return false;
7585}
7586
7587bool
7588MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
7589 assert(link->fromInternalLane());
7590 if (veh == nullptr) {
7591 return false;
7592 }
7593 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
7594 // if this vehicle is not yet on the junction, every vehicle is a leader
7595 return true;
7596 }
7597 if (veh->getLaneChangeModel().hasBlueLight()) {
7598 // blue light device automatically gets right of way
7599 return true;
7600 }
7601 const MSLane* foeLane = veh->getLane();
7602 if (foeLane->isInternal()) {
7603 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
7605 SUMOTime foeET = veh->myJunctionEntryTime;
7606 // check relationship between link and foeLane
7608 // we are entering the junction from the same lane
7610 foeET = veh->myJunctionEntryTimeNeverYield;
7613 }
7614 } else {
7615 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
7616 const MSJunctionLogic* logic = link->getJunction()->getLogic();
7617 assert(logic != nullptr);
7618 // determine who has right of way
7619 bool response; // ego response to foe
7620 bool response2; // foe response to ego
7621 // attempt 1: tlLinkState
7622 const MSLink* entry = link->getCorrespondingEntryLink();
7623 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
7624 if (entry->haveRed() || foeEntry->haveRed()) {
7625 // ensure that vehicles which are stuck on the intersection may exit
7626 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
7627 // foe might be oncoming, don't drive unless foe can still brake safely
7628 const double foeNextSpeed = veh->getSpeed() + ACCEL2SPEED(veh->getCarFollowModel().getMaxAccel());
7629 const double foeBrakeGap = veh->getCarFollowModel().brakeGap(
7630 foeNextSpeed, veh->getCarFollowModel().getMaxDecel(), veh->getCarFollowModel().getHeadwayTime());
7631 // the minGap was subtracted from gap in MSLink::getLeaderInfo (enlarging the negative gap)
7632 // so the -2* makes it point in the right direction
7633 const double foeGap = -gap - veh->getLength() - 2 * getVehicleType().getMinGap();
7634#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7635 if (DEBUG_COND) {
7636 std::cout << " foeGap=" << foeGap << " foeBGap=" << foeBrakeGap << "\n";
7637
7638 }
7639#endif
7640 if (foeGap < foeBrakeGap) {
7641 response = true;
7642 response2 = false;
7643 } else {
7644 response = false;
7645 response2 = true;
7646 }
7647 } else {
7648 // let conflict entry time decide
7649 response = true;
7650 response2 = true;
7651 }
7652 } else if (entry->havePriority() != foeEntry->havePriority()) {
7653 response = !entry->havePriority();
7654 response2 = !foeEntry->havePriority();
7655 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
7656 // let the faster vehicle keep moving
7657 response = veh->getSpeed() >= getSpeed();
7658 response2 = getSpeed() >= veh->getSpeed();
7659 } else {
7660 // fallback if pedestrian crossings are involved
7661 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
7662 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
7663 }
7664#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7665 if (DEBUG_COND) {
7666 std::cout << SIMTIME
7667 << " foeLane=" << foeLane->getID()
7668 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
7669 << " linkIndex=" << link->getIndex()
7670 << " foeLinkIndex=" << foeLink->getIndex()
7671 << " entryState=" << toString(entry->getState())
7672 << " entryState2=" << toString(foeEntry->getState())
7673 << " response=" << response
7674 << " response2=" << response2
7675 << "\n";
7676 }
7677#endif
7678 if (!response) {
7679 // if we have right of way over the foe, entryTime does not matter
7680 foeET = veh->myJunctionConflictEntryTime;
7681 egoET = myJunctionEntryTime;
7682 } else if (response && response2) {
7683 // in a mutual conflict scenario, use entry time to avoid deadlock
7684 foeET = veh->myJunctionConflictEntryTime;
7686 }
7687 }
7688 if (egoET == foeET) {
7689 // try to use speed as tie braker
7690 if (getSpeed() == veh->getSpeed()) {
7691 // use ID as tie braker
7692#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7693 if (DEBUG_COND) {
7694 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7695 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7696 }
7697#endif
7698 return getID() < veh->getID();
7699 } else {
7700#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7701 if (DEBUG_COND) {
7702 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7703 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7704 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7705 << "\n";
7706 }
7707#endif
7708 return getSpeed() < veh->getSpeed();
7709 }
7710 } else {
7711 // leader was on the junction first
7712#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7713 if (DEBUG_COND) {
7714 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7715 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7716 }
7717#endif
7718 return egoET > foeET;
7719 }
7720 } else {
7721 // vehicle can only be partially on the junction. Must be a leader
7722 return true;
7723 }
7724 } else {
7725 // vehicle can only be partially on the junction. Must be a leader
7726 return true;
7727 }
7728}
7729
7730void
7733 // here starts the vehicle internal part (see loading)
7734 std::vector<std::string> internals;
7735 internals.push_back(toString(myParameter->parametersSet));
7736 internals.push_back(toString(myDeparture));
7737 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7738 internals.push_back(toString(myDepartPos));
7739 internals.push_back(toString(myWaitingTime));
7740 internals.push_back(toString(myTimeLoss));
7741 internals.push_back(toString(myLastActionTime));
7742 internals.push_back(toString(isStopped()));
7743 internals.push_back(toString(myPastStops.size()));
7744 out.writeAttr(SUMO_ATTR_STATE, internals);
7746 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7751 // save past stops
7753 stop.write(out, false);
7754 // do not write started and ended twice
7755 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7756 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7757 }
7758 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7759 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7760 }
7761 stop.writeParams(out);
7762 out.closeTag();
7763 }
7764 // save upcoming stops
7765 for (MSStop& stop : myStops) {
7766 stop.write(out);
7767 }
7768 // save parameters and device states
7770 for (MSVehicleDevice* const dev : myDevices) {
7771 dev->saveState(out);
7772 }
7773 out.closeTag();
7774}
7775
7776void
7778 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7779 throw ProcessError(TL("Error: Invalid vehicles in state (may be a meso state)!"));
7780 }
7781 int routeOffset;
7782 bool stopped;
7783 int pastStops;
7784
7785 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7786 bis >> myParameter->parametersSet;
7787 bis >> myDeparture;
7788 bis >> routeOffset;
7789 bis >> myDepartPos;
7790 bis >> myWaitingTime;
7791 bis >> myTimeLoss;
7792 bis >> myLastActionTime;
7793 bis >> stopped;
7794 bis >> pastStops;
7795
7797 bool ok;
7798 myArrivalPos = attrs.get<double>(SUMO_ATTR_ARRIVALPOS_RANDOMIZED, getID().c_str(), ok);
7799 }
7800 // load stops
7801 myStops.clear();
7803
7804 if (hasDeparted()) {
7805 myCurrEdge = myRoute->begin() + routeOffset;
7806 myDeparture -= offset;
7807 // fix stops
7808 while (pastStops > 0) {
7809 myPastStops.push_back(myStops.front().pars);
7810 myPastStops.back().routeIndex = (int)(myStops.front().edge - myRoute->begin());
7811 myStops.pop_front();
7812 pastStops--;
7813 }
7814 // see MSBaseVehicle constructor
7817 }
7818 // a (tentative lane is needed for calling hasArrivedInternal
7819 myLane = (*myCurrEdge)->getLanes()[0];
7820 }
7823 WRITE_WARNINGF(TL("Action steps are out of sync for loaded vehicle '%'."), getID());
7824 }
7825 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7827 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7832 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7833 dis >> myOdometer >> myNumberReroutes;
7835 if (stopped) {
7836 myStops.front().startedFromState = true;
7837 myStopDist = 0;
7838 }
7840 // no need to reset myCachedPosition here since state loading happens directly after creation
7841}
7842
7843void
7845 SUMOTime arrivalTime, double arrivalSpeed,
7846 double arrivalSpeedBraking,
7847 double dist, double leaveSpeed) {
7848 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7849 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7850 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7851
7852}
7853
7854
7855std::shared_ptr<MSSimpleDriverState>
7859
7860
7861double
7863 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7864}
7865
7866
7867void
7868MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7869 myState.mySpeed = MAX2(0., prevSpeed);
7870 // also retcon acceleration
7871 if (prevAcceleration != std::numeric_limits<double>::min()) {
7872 myAcceleration = prevAcceleration;
7873 } else {
7875 }
7876}
7877
7878
7879double
7881 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7883}
7884
7885/****************************************************************************/
7886bool
7890
7891/* -------------------------------------------------------------------------
7892 * methods of MSVehicle::manoeuvre
7893 * ----------------------------------------------------------------------- */
7894
7895MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7896
7897
7899 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7900 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7901 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7902 myManoeuvreType = manoeuvre.myManoeuvreType;
7903 myGUIIncrement = manoeuvre.myGUIIncrement;
7904}
7905
7906
7909 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7910 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7911 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7912 myManoeuvreType = manoeuvre.myManoeuvreType;
7913 myGUIIncrement = manoeuvre.myGUIIncrement;
7914 return *this;
7915}
7916
7917
7918bool
7920 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7921 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7922 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7923 myManoeuvreType != manoeuvre.myManoeuvreType ||
7924 myGUIIncrement != manoeuvre.myGUIIncrement
7925 );
7926}
7927
7928
7929double
7931 return (myGUIIncrement);
7932}
7933
7934
7937 return (myManoeuvreType);
7938}
7939
7940
7945
7946
7947void
7951
7952
7953void
7955 myManoeuvreType = mType;
7956}
7957
7958
7959bool
7961 if (!veh->hasStops()) {
7962 return false; // should never happen - checked before call
7963 }
7964
7965 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7966 const MSStop& stop = veh->getNextStop();
7967
7968 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7969 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7970 if (abs(GUIAngle) < 0.1) {
7971 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7972 }
7973 myManoeuvreVehicleID = veh->getID();
7974 myManoeuvreStop = stop.parkingarea->getID();
7975 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7976 myManoeuvreStartTime = currentTime;
7977 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7978 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7979
7980#ifdef DEBUG_STOPS
7981 if (veh->isSelected()) {
7982 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 <<
7983 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7984 }
7985#endif
7986
7987 return (true);
7988}
7989
7990
7991bool
7993 // At the moment we only want to set for parking areas
7994 if (!veh->hasStops()) {
7995 return true;
7996 }
7997 if (veh->getNextStop().parkingarea == nullptr) {
7998 return true;
7999 }
8000
8001 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
8002 return (false);
8003 }
8004
8005 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
8006
8007 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
8008 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
8009 if (abs(GUIAngle) < 0.1) {
8010 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
8011 }
8012
8013 myManoeuvreVehicleID = veh->getID();
8014 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
8015 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
8016 myManoeuvreStartTime = currentTime;
8017 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
8018 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
8019 if (veh->remainingStopDuration() > 0) {
8020 myManoeuvreCompleteTime += veh->remainingStopDuration();
8021 }
8022
8023#ifdef DEBUG_STOPS
8024 if (veh->isSelected()) {
8025 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
8026 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
8027 }
8028#endif
8029
8030 return (true);
8031}
8032
8033
8034bool
8036 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
8037 if (!veh->hasStops()) {
8038 return (true);
8039 }
8040 MSStop* currentStop = &veh->myStops.front();
8041 if (currentStop->parkingarea == nullptr) {
8042 return true;
8043 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
8044 if (configureEntryManoeuvre(veh)) {
8046 return (false);
8047 } else { // cannot configure entry so stop trying
8048 return true;
8049 }
8050 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
8051 return false;
8052 } else { // manoeuvre complete
8053 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
8054 return true;
8055 }
8056}
8057
8058
8059bool
8061 if (checkType != myManoeuvreType) {
8062 return true; // we're not maneuvering / wrong manoeuvre
8063 }
8064
8065 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
8066 return false;
8067 } else {
8068 return true;
8069 }
8070}
8071
8072
8073bool
8075 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
8076}
8077
8078
8079bool
8083
8084
8085std::pair<double, double>
8087 if (hasStops()) {
8088 MSLane* lane = myLane;
8089 if (lane == nullptr) {
8090 // not in network
8091 lane = getEdge()->getLanes()[0];
8092 }
8093 const MSStop& stop = myStops.front();
8094 auto it = myCurrEdge + 1;
8095 // drive to end of current edge
8096 double dist = (lane->getLength() - getPositionOnLane());
8097 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
8098 // drive until stop edge
8099 while (it != myRoute->end() && it < stop.edge) {
8100 travelTime += (*it)->getMinimumTravelTime(this);
8101 dist += (*it)->getLength();
8102 it++;
8103 }
8104 // drive up to the stop position
8105 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
8106 dist += stopEdgeDist;
8107 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
8108 // estimate time loss due to acceleration and deceleration
8109 // maximum speed is limited by available distance:
8110 const double a = getCarFollowModel().getMaxAccel();
8111 const double b = getCarFollowModel().getMaxDecel();
8112 const double c = getSpeed();
8113 const double d = dist;
8114 const double len = getVehicleType().getLength();
8115 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
8116 // distAccel = (v - c)^2 / (2a)
8117 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
8118 // distAccel + distDecel < d
8119 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))))
8120 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
8121 it = myCurrEdge;
8122 double v0 = c;
8123 bool v0Stable = getAcceleration() == 0 && v0 > 0;
8124 double timeLossAccel = 0;
8125 double timeLossDecel = 0;
8126 double timeLossLength = 0;
8127 while (it != myRoute->end() && it <= stop.edge) {
8128 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
8129 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
8130 if (edgeLength <= len && v0Stable && v0 < v) {
8131 const double lengthDist = MIN2(len, edgeLength);
8132 const double dTL = lengthDist / v0 - lengthDist / v;
8133 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
8134 timeLossLength += dTL;
8135 }
8136 if (edgeLength > len) {
8137 const double dv = v - v0;
8138 if (dv > 0) {
8139 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8140 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8141 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8142 timeLossAccel += dTA;
8143 // time loss from vehicle length
8144 } else if (dv < 0) {
8145 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8146 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8147 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8148 timeLossDecel += dTD;
8149 }
8150 v0 = v;
8151 v0Stable = true;
8152 }
8153 it++;
8154 }
8155 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
8156 double v = vs;
8157 const double dv = v - v0;
8158 if (dv > 0) {
8159 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
8160 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
8161 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
8162 timeLossAccel += dTA;
8163 // time loss from vehicle length
8164 } else if (dv < 0) {
8165 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
8166 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
8167 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
8168 timeLossDecel += dTD;
8169 }
8170 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
8171 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
8172 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
8173 return {MAX2(0.0, result), dist};
8174 } else {
8176 }
8177}
8178
8179
8180double
8182 if (hasStops() && myStops.front().pars.until >= 0) {
8183 const MSStop& stop = myStops.front();
8184 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
8185 if (stop.reached) {
8186 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
8187 }
8188 if (stop.pars.duration > 0) {
8189 estimatedDepart += stop.pars.duration;
8190 }
8191 estimatedDepart += TIME2STEPS(estimateTimeToNextStop().first);
8192 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
8193 return result;
8194 } else {
8195 // vehicles cannot drive before 'until' so stop delay can never be
8196 // negative and we can use -1 to signal "undefined"
8197 return -1;
8198 }
8199}
8200
8201
8202double
8204 if (hasStops() && myStops.front().pars.arrival >= 0) {
8205 const MSStop& stop = myStops.front();
8206 if (stop.reached) {
8207 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
8208 } else {
8209 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop().first - STEPS2TIME(stop.pars.arrival);
8210 }
8211 } else {
8212 // vehicles can arrival earlier than planned so arrival delay can be negative
8213 return INVALID_DOUBLE;
8214 }
8215}
8216
8217
8218const MSEdge*
8220 return myLane != nullptr ? &myLane->getEdge() : getEdge();
8221}
8222
8223
8224const MSEdge*
8226 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
8227 return nullptr;
8228 }
8229 if (myLane->isInternal()) {
8231 } else {
8232 const MSEdge* nextNormal = succEdge(1);
8233 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
8234 return nextInternal ? nextInternal : nextNormal;
8235 }
8236}
8237
8238
8239const MSLane*
8240MSVehicle::getPreviousLane(const MSLane* current, int& furtherIndex) const {
8241 if (furtherIndex < (int)myFurtherLanes.size()) {
8242 return myFurtherLanes[furtherIndex++];
8243 } else {
8244 // try to use route information
8245 int routeIndex = getRoutePosition();
8246 bool resultInternal;
8247 if (MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks()) {
8248 if (myLane->isInternal()) {
8249 if (furtherIndex % 2 == 0) {
8250 routeIndex -= (furtherIndex + 0) / 2;
8251 resultInternal = false;
8252 } else {
8253 routeIndex -= (furtherIndex + 1) / 2;
8254 resultInternal = false;
8255 }
8256 } else {
8257 if (furtherIndex % 2 != 0) {
8258 routeIndex -= (furtherIndex + 1) / 2;
8259 resultInternal = false;
8260 } else {
8261 routeIndex -= (furtherIndex + 2) / 2;
8262 resultInternal = true;
8263 }
8264 }
8265 } else {
8266 routeIndex -= furtherIndex;
8267 resultInternal = false;
8268 }
8269 furtherIndex++;
8270 if (routeIndex >= 0) {
8271 if (resultInternal) {
8272 const MSEdge* prevNormal = myRoute->getEdges()[routeIndex];
8273 for (MSLane* cand : prevNormal->getLanes()) {
8274 for (MSLink* link : cand->getLinkCont()) {
8275 if (link->getLane() == current) {
8276 if (link->getViaLane() != nullptr) {
8277 return link->getViaLane();
8278 } else {
8279 return const_cast<MSLane*>(link->getLaneBefore());
8280 }
8281 }
8282 }
8283 }
8284 } else {
8285 return myRoute->getEdges()[routeIndex]->getLanes()[0];
8286 }
8287 }
8288 }
8289 return current;
8290}
8291
8294 // this vehicle currently has the highest priority on the allway_stop
8295 return link == myHaveStoppedFor ? SUMOTime_MAX : getWaitingTime();
8296}
8297
8298
8299void
8301 bool diverged = false;
8302 const ConstMSEdgeVector& route = myRoute->getEdges();
8303 int ri = getRoutePosition();
8304 for (const DriveProcessItem& dpi : myLFLinkLanes) {
8305 if (dpi.myLink != nullptr) {
8306 if (!diverged) {
8307 const MSEdge* next = route[ri + 1];
8308 if (&dpi.myLink->getLane()->getEdge() != next) {
8309 diverged = true;
8310 } else {
8311 if (dpi.myLink->getViaLane() == nullptr) {
8312 ri++;
8313 }
8314 }
8315 }
8316 if (diverged) {
8317 dpi.myLink->removeApproaching(this);
8318 }
8319 }
8320 }
8321}
8322
8323
8324bool
8328
8329/****************************************************************************/
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:58
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define SIMSTEP
Definition SUMOTime.h:64
#define ACCEL2SPEED(x)
Definition SUMOTime.h:54
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TS
Definition SUMOTime.h:45
#define SIMTIME
Definition SUMOTime.h:65
#define TIME2STEPS(x)
Definition SUMOTime.h:60
#define DIST2SPEED(x)
Definition SUMOTime.h:50
#define SPEED2ACCEL(x)
Definition SUMOTime.h:56
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a (exclusive) railway edge.
@ RAIL_CARGO
render as a cargo train
@ RAIL
render as a rail
@ PASSENGER_VAN
render as a van
@ PASSENGER
render as a passenger vehicle
@ RAIL_CAR
render as a (city) rail without locomotive
@ PASSENGER_HATCHBACK
render as a hatchback passenger vehicle ("Fliessheck")
@ BUS_FLEXIBLE
render as a flexible city bus
@ TRUCK_1TRAILER
render as a transport vehicle with one trailer
@ PASSENGER_SEDAN
render as a sedan passenger vehicle ("Stufenheck")
@ PASSENGER_WAGON
render as a wagon passenger vehicle ("Combi")
@ TRUCK_SEMITRAILER
render as a semi-trailer transport vehicle ("Sattelschlepper")
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_EMERGENCY
public emergency vehicles
const long long int VEHPARS_FORCE_REROUTE
@ GIVEN
The lane is given.
@ GIVEN
The speed is given.
@ SPLIT_FRONT
depart position for a split vehicle is in front of the continuing vehicle
const long long int VEHPARS_CFMODEL_PARAMS_SET
@ GIVEN
The arrival lane is given.
@ GIVEN
The speed is given.
const int STOP_ENDED_SET
@ GIVEN
The arrival position is given.
@ DEFAULT
No information given; use default.
const int STOP_STARTED_SET
@ SUMO_TAG_PARKING_AREA_REROUTE
entry for an alternative parking zone
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_OVERHEAD_WIRE_SEGMENT
An overhead wire segment.
LinkDirection
The different directions a link between two lanes may take (or a stream between two edges)....
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ TURN_LEFTHAND
The link is a 180 degree turn (left-hand network)
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_ALLWAY_STOP
This is an uncontrolled, all-way stop link.
@ LINKSTATE_EQUAL
This is an uncontrolled, right-before-left link.
@ LINKSTATE_ZIPPER
This is an uncontrolled, zipper-merge link.
@ LCA_KEEPRIGHT
The action is due to the default of keeping right "Rechtsfahrgebot".
@ LCA_BLOCKED
blocked in all directions
@ LCA_URGENT
The action is urgent (to be defined by lc-model)
@ LCA_STAY
Needs to stay on the current lane.
@ LCA_SUBLANE
used by the sublane model
@ LCA_WANTS_LANECHANGE_OR_STAY
lane can change or stay
@ LCA_COOPERATIVE
The action is done to help someone else.
@ LCA_OVERLAPPING
The vehicle is blocked being overlapping.
@ LCA_LEFT
Wants go to the left.
@ LCA_STRATEGIC
The action is needed to follow the route (navigational lc)
@ LCA_TRACI
The action is due to a TraCI request.
@ LCA_SPEEDGAIN
The action is due to the wish to be faster (tactical lc)
@ LCA_RIGHT
Wants go to the right.
@ SUMO_ATTR_JM_STOPLINE_GAP_MINOR
@ SUMO_ATTR_JM_STOPLINE_CROSSING_GAP
@ SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_STARTED
@ SUMO_ATTR_MAXIMUMPOWER
Maximum Power.
@ SUMO_ATTR_WAITINGTIME
@ SUMO_ATTR_CF_IGNORE_IDS
@ SUMO_ATTR_JM_STOPLINE_GAP
@ SUMO_ATTR_POSITION_LAT
@ SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME
@ SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME
@ SUMO_ATTR_ENDED
@ SUMO_ATTR_LCA_CONTRIGHT
@ SUMO_ATTR_ANGLE
@ SUMO_ATTR_DISTANCE
@ SUMO_ATTR_CF_IGNORE_TYPES
@ SUMO_ATTR_ARRIVALPOS_RANDOMIZED
@ SUMO_ATTR_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.
void cleanupParkingReservation()
unregisters from a parking reservation when changing or skipping stops
double getLength() const
Returns the vehicle's length.
bool isParking() const
Returns whether the vehicle is parking.
MSParkingArea * getCurrentParkingArea()
get the current parking area stop or nullptr
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
int getPersonNumber() const
Returns the number of persons.
MSRouteIterator myCurrEdge
Iterator to current route-edge.
StopParVector myPastStops
The list of stops that the vehicle has already reached.
bool hasDeparted() const
Returns whether this vehicle has already departed.
bool ignoreTransientPermissions() const
Returns whether this object is ignoring transient permission changes (during routing)
ConstMSRoutePtr myRoute
This vehicle's route.
double getWidth() const
Returns the vehicle's width.
MSDevice_Transportable * myContainerDevice
The containers this vehicle may have.
const std::list< MSStop > & getStops() const
double getDesiredMaxSpeed() const
void addReminder(MSMoveReminder *rem, double pos=0)
Adds a MoveReminder dynamically.
SumoRNG * getRNG() const
SUMOTime getDeparture() const
Returns this vehicle's real departure time.
EnergyParams * getEmissionParameters() const
retrieve parameters for the energy consumption model
MSDevice_Transportable * myPersonDevice
The passengers this vehicle may have.
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
const MSStop & getNextStop() const
@ ROUTE_START_INVALID_PERMISSIONS
void addStops(const bool ignoreStopErrors, MSRouteIterator *searchStart=nullptr, bool addRouteStops=true)
Adds stops to the built vehicle.
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
MSParkingArea * getNextParkingArea()
get the upcoming parking area stop or nullptr
int myArrivalLane
The destination lane where the vehicle stops.
SUMOTime myDeparture
The real departure time.
bool isStoppedTriggered() const
Returns whether the vehicle is on a triggered stop.
void onDepart()
Called when the vehicle is inserted into the network.
virtual bool addTraciStop(SUMOVehicleParameter::Stop stop, std::string &errorMsg)
const MSRoute & getRoute() const
Returns the current route.
int getRoutePosition() const
return index of edge within route
bool replaceParkingArea(MSParkingArea *parkingArea, std::string &errorMsg)
replace the current parking area stop with a new stop with merge duration
static const SUMOTime NOT_YET_DEPARTED
bool myAmRegisteredAsWaiting
Whether this vehicle is registered as waiting for a person or container (for deadlock-recognition)
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT() const
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:1120
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:1368
bool isFringe() const
return whether this edge is at the fringe of the network
Definition MSEdge.h:775
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition MSEdge.cpp:975
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:480
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:1186
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:1390
bool hasLaneChanger() const
Definition MSEdge.h:749
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:732
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:1479
const MSEdge * getInternalFollowingEdge(const MSEdge *followerAfterInternal, SUMOVehicleClass vClass) const
Definition MSEdge.cpp:928
void removeWaiting(const SUMOVehicle *vehicle) const
Removes a vehicle from the list of waiting vehicles.
Definition MSEdge.cpp:1488
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1286
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:1302
const std::vector< MSMoveReminder * > & getMoveReminders() const
Return the list of this lane's move reminders.
Definition MSLane.h:324
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:4412
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:4586
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:2862
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2844
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition MSLane.h:457
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition MSLane.cpp:2693
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2781
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition MSLane.h:465
double getBruttoVehLenSum() const
Returns the sum of lengths of vehicles, including their minGaps, which were on the lane during the la...
Definition MSLane.h:1175
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition MSLane.cpp:2707
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2439
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2758
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1398
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3790
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:603
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:2471
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:625
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:966
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3284
double getLength() const
Returns the lane's length.
Definition MSLane.h:617
double getMaximumBrakeDist() const
compute maximum braking distance on this lane
Definition MSLane.cpp:2919
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:2770
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:1451
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:3003
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition MSLane.h:866
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:941
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition MSLane.cpp:383
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:575
double getRightSideOnEdge() const
Definition MSLane.h:1211
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4579
int getIndex() const
Returns the lane's index.
Definition MSLane.h:653
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3308
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4407
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3228
double getCenterOnEdge() const
Definition MSLane.h:1219
bool isNormal() const
Definition MSLane.cpp:2632
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2674
bool isInternal() const
Definition MSLane.cpp:2626
@ FOLLOW_NEVER
Definition MSLane.h:990
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition MSLane.cpp:402
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4395
virtual const VehCont & getVehiclesSecure() const
Returns the vehicles container; locks it for microsimulation.
Definition MSLane.h:484
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition MSLane.h:514
bool mustCheckJunctionCollisions() const
whether this lane must check for junction collisions
Definition MSLane.cpp:4697
double interpolateLanePosToGeometryPos(double lanePos) const
Definition MSLane.h:555
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4691
@ 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:4401
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:775
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:4706
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3253
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:3815
double getWidth() const
Returns the lane's width.
Definition MSLane.h:646
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:735
MSVehicle * getFirstFullVehicle() const
returns the first vehicle for which this lane is responsible or 0
Definition MSLane.cpp:2665
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition MSLane.h:561
static CollisionAction getCollisionAction()
Definition MSLane.h:1373
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:1338
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:1271
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:1493
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:1472
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition MSNet.cpp:1330
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:1347
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:1262
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:63
Definition of vehicle stop (position and duration)
SUMOTime started
the time at which this stop was reached
ParkingType parking
whether the vehicle is removed from the net while stopping
SUMOTime extension
The maximum time extension for boarding / loading.
std::string split
the id of the vehicle (train portion) that splits of upon reaching this stop
double startPos
The stopping position start.
std::string line
the new line id of the trip within a cyclical public transport route
double posLat
the lateral offset when stopping
bool onDemand
whether the stop may be skipped
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