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