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