Eclipse SUMO - Simulation of Urban MObility
MSVehicle.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 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
296 deactivate();
297}
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(TL("MSVehicle::Influencer::GapControlState::init(): No MSNet instance found!"))
307 }
308}
309
310void
312 MSNet::VehicleStateListener* vsl = dynamic_cast<MSNet::VehicleStateListener*>(&vehStateListener);
314}
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 * ----------------------------------------------------------------------- */
361 myGapControlState(nullptr),
362 myOriginalSpeed(-1),
363 myLatDist(0),
379{}
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_WARNING("Lane change model did not provide a reason for changing (state=" + toString(state) + ", time=" + time2string(currentTime) + "\n");
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("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),
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
992 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
993 (*i)->resetPartialOccupation(this);
994 }
995 if (myLaneChangeModel != nullptr) {
999 // still needed when calling resetPartialOccupation (getShadowLane) and when removing
1000 // approach information from parallel links
1001 delete myLaneChangeModel;
1002 }
1003 myFurtherLanes.clear();
1004 myFurtherLanesPosLat.clear();
1005 //
1006 if (myType->isVehicleSpecific()) {
1008 }
1009 delete myInfluencer;
1010 delete myCFVariables;
1011}
1012
1013
1014void
1016#ifdef DEBUG_ACTIONSTEPS
1017 if (DEBUG_COND) {
1018 std::cout << SIMTIME << " Removing vehicle '" << getID() << "' (reason: " << toString(reason) << ")" << std::endl;
1019 }
1020#endif
1023 leaveLane(reason);
1024}
1025
1026
1027void
1033}
1034
1035
1036// ------------ interaction with the route
1037bool
1039 // note: not a const method because getDepartLane may call updateBestLanes
1040 if (!(*myCurrEdge)->isTazConnector()) {
1042 if ((*myCurrEdge)->getDepartLane(*this) == nullptr) {
1043 msg = "Invalid departlane definition for vehicle '" + getID() + "'.";
1044 if (myParameter->departLane >= (int)(*myCurrEdge)->getLanes().size()) {
1046 } else {
1048 }
1049 return false;
1050 }
1051 } else {
1052 if ((*myCurrEdge)->allowedLanes(getVClass()) == nullptr) {
1053 msg = "Vehicle '" + getID() + "' is not allowed to depart on any lane of edge '" + (*myCurrEdge)->getID() + "'.";
1055 return false;
1056 }
1057 }
1059 msg = "Departure speed for vehicle '" + getID() + "' is too high for the vehicle type '" + myType->getID() + "'.";
1061 return false;
1062 }
1063 }
1065 return true;
1066}
1067
1068
1069bool
1071 return hasArrivedInternal(false);
1072}
1073
1074
1075bool
1076MSVehicle::hasArrivedInternal(bool oppositeTransformed) const {
1078 && (myStops.empty() || myStops.front().edge != myCurrEdge)
1079 && ((myLaneChangeModel->isOpposite() && !oppositeTransformed) ? myLane->getLength() - myState.myPos : myState.myPos) > myArrivalPos - POSITION_EPS
1080 && !isRemoteControlled());
1081}
1082
1083
1084bool
1085MSVehicle::replaceRoute(const MSRoute* newRoute, const std::string& info, bool onInit, int offset, bool addRouteStops, bool removeStops, std::string* msgReturn) {
1086 if (MSBaseVehicle::replaceRoute(newRoute, info, onInit, offset, addRouteStops, removeStops, msgReturn)) {
1087 // update best lanes (after stops were added)
1088 myLastBestLanesEdge = nullptr;
1090 updateBestLanes(true, onInit ? (*myCurrEdge)->getLanes().front() : 0);
1091 assert(!removeStops || haveValidStopEdges());
1092 return true;
1093 }
1094 return false;
1095}
1096
1097
1098// ------------ Interaction with move reminders
1099void
1100MSVehicle::workOnMoveReminders(double oldPos, double newPos, double newSpeed) {
1101 // This erasure-idiom works for all stl-sequence-containers
1102 // See Meyers: Effective STL, Item 9
1103 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
1104 // XXX: calling notifyMove with newSpeed seems not the best choice. For the ballistic update, the average speed is calculated and used
1105 // although a higher order quadrature-formula might be more adequate.
1106 // For the euler case (where the speed is considered constant for each time step) it is conceivable that
1107 // the current calculations may lead to systematic errors for large time steps (compared to reality). Refs. #2579
1108 if (!rem->first->notifyMove(*this, oldPos + rem->second, newPos + rem->second, MAX2(0., newSpeed))) {
1109#ifdef _DEBUG
1110 if (myTraceMoveReminders) {
1111 traceMoveReminder("notifyMove", rem->first, rem->second, false);
1112 }
1113#endif
1114 rem = myMoveReminders.erase(rem);
1115 } else {
1116#ifdef _DEBUG
1117 if (myTraceMoveReminders) {
1118 traceMoveReminder("notifyMove", rem->first, rem->second, true);
1119 }
1120#endif
1121 ++rem;
1122 }
1123 }
1124 if (myEnergyParams != nullptr) {
1125 // TODO make the vehicle energy params a derived class which is a move reminder
1126 const double duration = myEnergyParams->getDouble(SUMO_ATTR_DURATION);
1127 if (isStopped()) {
1128 if (duration < 0) {
1131 }
1132 } else {
1133 if (duration >= 0) {
1135 }
1136 }
1138 }
1139}
1140
1141
1142void
1144 updateWaitingTime(0.); // cf issue 2233
1145
1146 // vehicle move reminders
1147 for (const auto& rem : myMoveReminders) {
1148 rem.first->notifyIdle(*this);
1149 }
1150
1151 // lane move reminders - for aggregated values
1152 for (MSMoveReminder* rem : getLane()->getMoveReminders()) {
1153 rem->notifyIdle(*this);
1154 }
1155}
1156
1157// XXX: consider renaming...
1158void
1160 // save the old work reminders, patching the position information
1161 // add the information about the new offset to the old lane reminders
1162 const double oldLaneLength = myLane->getLength();
1163 for (auto& rem : myMoveReminders) {
1164 rem.second += oldLaneLength;
1165#ifdef _DEBUG
1166// if (rem->first==0) std::cout << "Null reminder (?!)" << std::endl;
1167// std::cout << "Adapted MoveReminder on lane " << ((rem->first->getLane()==0) ? "NULL" : rem->first->getLane()->getID()) <<" position to " << rem->second << std::endl;
1168 if (myTraceMoveReminders) {
1169 traceMoveReminder("adaptedPos", rem.first, rem.second, true);
1170 }
1171#endif
1172 }
1173 for (MSMoveReminder* const rem : enteredLane.getMoveReminders()) {
1174 addReminder(rem);
1175 }
1176}
1177
1178
1179// ------------ Other getter methods
1180double
1182 if (isParking() && getStops().begin()->parkingarea != nullptr) {
1183 return getStops().begin()->parkingarea->getVehicleSlope(*this);
1184 }
1185 if (myLane == nullptr) {
1186 return 0;
1187 }
1188 const double posLat = myState.myPosLat; // @todo get rid of the '-'
1189 Position p1 = getPosition();
1191 if (p2 == Position::INVALID) {
1192 // Handle special case of vehicle's back reaching out of the network
1193 if (myFurtherLanes.size() > 0) {
1194 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1195 if (p2 == Position::INVALID) {
1196 // unsuitable lane geometry
1197 p2 = myLane->geometryPositionAtOffset(0, posLat);
1198 }
1199 } else {
1200 p2 = myLane->geometryPositionAtOffset(0, posLat);
1201 }
1202 }
1204}
1205
1206
1208MSVehicle::getPosition(const double offset) const {
1209 if (myLane == nullptr) {
1210 // when called in the context of GUI-Drawing, the simulation step is already incremented
1212 return myCachedPosition;
1213 } else {
1214 return Position::INVALID;
1215 }
1216 }
1217 if (isParking()) {
1218 if (myStops.begin()->parkingarea != nullptr) {
1219 return myStops.begin()->parkingarea->getVehiclePosition(*this);
1220 } else {
1221 // position beside the road
1222 PositionVector shp = myLane->getEdge().getLanes()[0]->getShape();
1225 }
1226 }
1227 const bool changingLanes = myLaneChangeModel->isChangingLanes();
1228 const double posLat = (MSGlobals::gLefthand ? 1 : -1) * getLateralPositionOnLane();
1229 if (offset == 0. && !changingLanes) {
1232 }
1233 return myCachedPosition;
1234 }
1235 Position result = validatePosition(myLane->geometryPositionAtOffset(getPositionOnLane() + offset, posLat), offset);
1236 return result;
1237}
1238
1239
1243 if (!isOnRoad()) {
1244 return Position::INVALID;
1245 }
1246 const std::vector<MSLane*>& bestLanes = getBestLanesContinuation();
1247 auto nextBestLane = bestLanes.begin();
1248 const bool opposite = myLaneChangeModel->isOpposite();
1249 double pos = opposite ? myLane->getLength() - myState.myPos : myState.myPos;
1250 const MSLane* lane = opposite ? myLane->getParallelOpposite() : getLane();
1251 assert(lane != 0);
1252 bool success = true;
1253
1254 while (offset > 0) {
1255 // take into account lengths along internal lanes
1256 while (lane->isInternal() && offset > 0) {
1257 if (offset > lane->getLength() - pos) {
1258 offset -= lane->getLength() - pos;
1259 lane = lane->getLinkCont()[0]->getViaLaneOrLane();
1260 pos = 0.;
1261 if (lane == nullptr) {
1262 success = false;
1263 offset = 0.;
1264 }
1265 } else {
1266 pos += offset;
1267 offset = 0;
1268 }
1269 }
1270 // set nextBestLane to next non-internal lane
1271 while (nextBestLane != bestLanes.end() && *nextBestLane == nullptr) {
1272 ++nextBestLane;
1273 }
1274 if (offset > 0) {
1275 assert(!lane->isInternal());
1276 assert(lane == *nextBestLane);
1277 if (offset > lane->getLength() - pos) {
1278 offset -= lane->getLength() - pos;
1279 ++nextBestLane;
1280 assert(nextBestLane == bestLanes.end() || *nextBestLane != 0);
1281 if (nextBestLane == bestLanes.end()) {
1282 success = false;
1283 offset = 0.;
1284 } else {
1285 const MSLink* link = lane->getLinkTo(*nextBestLane);
1286 assert(link != nullptr);
1287 lane = link->getViaLaneOrLane();
1288 pos = 0.;
1289 }
1290 } else {
1291 pos += offset;
1292 offset = 0;
1293 }
1294 }
1295
1296 }
1297
1298 if (success) {
1300 } else {
1301 return Position::INVALID;
1302 }
1303}
1304
1305
1306double
1308 if (myLane != nullptr) {
1309 return myLane->getVehicleMaxSpeed(this);
1310 }
1311 return myType->getMaxSpeed();
1312}
1313
1314
1316MSVehicle::validatePosition(Position result, double offset) const {
1317 int furtherIndex = 0;
1318 double lastLength = getPositionOnLane();
1319 while (result == Position::INVALID) {
1320 if (furtherIndex >= (int)myFurtherLanes.size()) {
1321 //WRITE_WARNING("Could not compute position for vehicle '" + getID() + "', time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
1322 break;
1323 }
1324 //std::cout << SIMTIME << " veh=" << getID() << " lane=" << myLane->getID() << " pos=" << getPositionOnLane() << " posLat=" << getLateralPositionOnLane() << " offset=" << offset << " result=" << result << " i=" << furtherIndex << " further=" << myFurtherLanes.size() << "\n";
1325 MSLane* further = myFurtherLanes[furtherIndex];
1326 offset += lastLength;
1327 result = further->geometryPositionAtOffset(further->getLength() + offset, -getLateralPositionOnLane());
1328 lastLength = further->getLength();
1329 furtherIndex++;
1330 //std::cout << SIMTIME << " newResult=" << result << "\n";
1331 }
1332 return result;
1333}
1334
1335
1336const MSEdge*
1338 // too close to the next junction, so avoid an emergency brake here
1339 if (myLane != nullptr && (myCurrEdge + 1) != myRoute->end() &&
1340 myState.myPos > myLane->getLength() - getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)) {
1341 return *(myCurrEdge + 1);
1342 }
1343 if (myLane != nullptr) {
1346 }
1347 return myLane->getNextNormal();
1348 }
1349 return *myCurrEdge;
1350}
1351
1352void
1353MSVehicle::setAngle(double angle, bool straightenFurther) {
1354#ifdef DEBUG_FURTHER
1355 if (DEBUG_COND) {
1356 std::cout << SIMTIME << " veh '" << getID() << " setAngle(" << angle << ") straightenFurther=" << straightenFurther << std::endl;
1357 }
1358#endif
1359 myAngle = angle;
1360 MSLane* next = myLane;
1361 if (straightenFurther && myFurtherLanesPosLat.size() > 0) {
1362 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
1363 MSLane* further = myFurtherLanes[i];
1364 if (further->getLinkTo(next) != nullptr) {
1366 next = further;
1367 } else {
1368 break;
1369 }
1370 }
1371 }
1372}
1373
1374
1375void
1376MSVehicle::setActionStepLength(double actionStepLength, bool resetOffset) {
1377 SUMOTime actionStepLengthMillisecs = SUMOVehicleParserHelper::processActionStepLength(actionStepLength);
1378 SUMOTime previousActionStepLength = getActionStepLength();
1379 const bool newActionStepLength = actionStepLengthMillisecs != previousActionStepLength;
1380 if (newActionStepLength) {
1381 getSingularType().setActionStepLength(actionStepLengthMillisecs, resetOffset);
1382 if (!resetOffset) {
1383 updateActionOffset(previousActionStepLength, actionStepLengthMillisecs);
1384 }
1385 }
1386 if (resetOffset) {
1388 }
1389}
1390
1391
1392bool
1394 return myState.mySpeed < (60.0 / 3.6) || myLane->getSpeedLimit() < (60.1 / 3.6);
1395}
1396
1397
1398double
1400 Position p1;
1401 const double posLat = -myState.myPosLat; // @todo get rid of the '-'
1402 const double lefthandSign = (MSGlobals::gLefthand ? -1 : 1);
1403
1404 // if parking manoeuvre is happening then rotate vehicle on each step
1407 }
1408
1409 if (isParking()) {
1410 if (myStops.begin()->parkingarea != nullptr) {
1411 return myStops.begin()->parkingarea->getVehicleAngle(*this);
1412 } else {
1414 }
1415 }
1417 // cannot use getPosition() because it already includes the offset to the side and thus messes up the angle
1418 p1 = myLane->geometryPositionAtOffset(myState.myPos, lefthandSign * posLat);
1419 if (p1 == Position::INVALID && myLane->getShape().length2D() == 0. && myLane->isInternal()) {
1420 // workaround: extrapolate the preceding lane shape
1421 MSLane* predecessorLane = myLane->getCanonicalPredecessorLane();
1422 p1 = predecessorLane->geometryPositionAtOffset(predecessorLane->getLength() + myState.myPos, lefthandSign * posLat);
1423 }
1424 } else {
1425 p1 = getPosition();
1426 }
1427
1429 if (p2 == Position::INVALID) {
1430 // Handle special case of vehicle's back reaching out of the network
1431 if (myFurtherLanes.size() > 0) {
1432 p2 = myFurtherLanes.back()->geometryPositionAtOffset(0, -myFurtherLanesPosLat.back());
1433 if (p2 == Position::INVALID) {
1434 // unsuitable lane geometry
1435 p2 = myLane->geometryPositionAtOffset(0, posLat);
1436 }
1437 } else {
1438 p2 = myLane->geometryPositionAtOffset(0, posLat);
1439 }
1440 }
1441 double result = (p1 != p2 ? p2.angleTo2D(p1) :
1444 result += lefthandSign * DEG2RAD(myLaneChangeModel->getAngleOffset());
1445 }
1446#ifdef DEBUG_FURTHER
1447 if (DEBUG_COND) {
1448 std::cout << SIMTIME << " computeAngle veh=" << getID() << " p1=" << p1 << " p2=" << p2 << " angle=" << RAD2DEG(result) << " naviDegree=" << GeomHelper::naviDegree(result) << "\n";
1449 }
1450#endif
1451 return result;
1452}
1453
1454
1455const Position
1457 const double posLat = MSGlobals::gLefthand ? myState.myPosLat : -myState.myPosLat;
1458 if (myState.myPos >= myType->getLength()) {
1459 // vehicle is fully on the new lane
1461 } else {
1463 // special case where the target lane has no predecessor
1464#ifdef DEBUG_FURTHER
1465 if (DEBUG_COND) {
1466 std::cout << " getBackPosition veh=" << getID() << " specialCase using myLane=" << myLane->getID() << " pos=0 posLat=" << myState.myPosLat << " result=" << myLane->geometryPositionAtOffset(0, posLat) << "\n";
1467 }
1468#endif
1469 return myLane->geometryPositionAtOffset(0, posLat);
1470 } else {
1471#ifdef DEBUG_FURTHER
1472 if (DEBUG_COND) {
1473 std::cout << " getBackPosition veh=" << getID() << " myLane=" << myLane->getID() << " further=" << toString(myFurtherLanes) << " myFurtherLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
1474 }
1475#endif
1476 if (myFurtherLanes.size() > 0 && !myLaneChangeModel->isChangingLanes()) {
1477 // truncate to 0 if vehicle starts on an edge that is shorter than it's length
1478 const double backPos = MAX2(0.0, getBackPositionOnLane(myFurtherLanes.back()));
1479 return myFurtherLanes.back()->geometryPositionAtOffset(backPos, -myFurtherLanesPosLat.back() * (MSGlobals::gLefthand ? -1 : 1));
1480 } else {
1481 return myLane->geometryPositionAtOffset(0, posLat);
1482 }
1483 }
1484 }
1485}
1486
1487
1488bool
1489MSVehicle::replaceParkingArea(MSParkingArea* parkingArea, std::string& errorMsg) {
1490 // Check if there is a parking area to be replaced
1491 if (parkingArea == 0) {
1492 errorMsg = "new parkingArea is NULL";
1493 return false;
1494 }
1495 if (myStops.size() == 0) {
1496 errorMsg = "vehicle has no stops";
1497 return false;
1498 }
1499 if (myStops.front().parkingarea == 0) {
1500 errorMsg = "first stop is not at parkingArea";
1501 return false;
1502 }
1503 MSStop& first = myStops.front();
1504 SUMOVehicleParameter::Stop& stopPar = const_cast<SUMOVehicleParameter::Stop&>(first.pars);
1505 // merge subsequent duplicate stops equals to parking area
1506 for (std::list<MSStop>::iterator iter = ++myStops.begin(); iter != myStops.end();) {
1507 if (iter->parkingarea == parkingArea) {
1508 stopPar.duration += iter->duration;
1509 myStops.erase(iter++);
1510 } else {
1511 break;
1512 }
1513 }
1514 stopPar.lane = parkingArea->getLane().getID();
1515 stopPar.parkingarea = parkingArea->getID();
1516 stopPar.startPos = parkingArea->getBeginLanePosition();
1517 stopPar.endPos = parkingArea->getEndLanePosition();
1518 first.edge = myRoute->end(); // will be patched in replaceRoute
1519 first.lane = &parkingArea->getLane();
1520 first.parkingarea = parkingArea;
1521 return true;
1522}
1523
1524
1527 MSParkingArea* nextParkingArea = nullptr;
1528 if (!myStops.empty()) {
1530 MSStop stop = myStops.front();
1531 if (!stop.reached && stop.parkingarea != nullptr) {
1532 nextParkingArea = stop.parkingarea;
1533 }
1534 }
1535 return nextParkingArea;
1536}
1537
1538
1541 MSParkingArea* currentParkingArea = nullptr;
1542 if (isParking()) {
1543 currentParkingArea = myStops.begin()->parkingarea;
1544 }
1545 return currentParkingArea;
1546}
1547
1548
1549bool
1551 return !isStopped() && !myStops.empty() && myLane != nullptr && &myStops.front().lane->getEdge() == &myLane->getEdge();
1552}
1553
1554bool
1556 return isStopped() && myStops.front().lane == myLane;
1557}
1558
1559bool
1560MSVehicle::keepStopping(bool afterProcessing) const {
1561 if (isStopped()) {
1562 // when coming out of vehicleTransfer we must shift the time forward
1563 return (myStops.front().duration - (afterProcessing ? DELTA_T : 0) > 0 || isStoppedTriggered() || myStops.front().pars.collision
1564 || (myStops.front().getSpeed() > 0 && myState.myPos < MIN2(myStops.front().pars.endPos, myStops.front().lane->getLength() - POSITION_EPS)));
1565 } else {
1566 return false;
1567 }
1568}
1569
1570
1573 if (isStopped()) {
1574 return myStops.front().duration;
1575 }
1576 return 0;
1577}
1578
1579
1582 return (myStops.empty() || !myStops.front().pars.collision) ? myCollisionImmunity : MAX2((SUMOTime)0, myStops.front().duration);
1583}
1584
1585
1586bool
1588 return myCollisionImmunity > 0;
1589}
1590
1591
1592double
1593MSVehicle::processNextStop(double currentVelocity) {
1594 if (myStops.empty()) {
1595 // no stops; pass
1596 return currentVelocity;
1597 }
1598
1599#ifdef DEBUG_STOPS
1600 if (DEBUG_COND) {
1601 std::cout << "\nPROCESS_NEXT_STOP\n" << SIMTIME << " vehicle '" << getID() << "'" << std::endl;
1602 }
1603#endif
1604
1605 MSStop& stop = myStops.front();
1607 if (stop.reached) {
1608 stop.duration -= getActionStepLength();
1609
1610#ifdef DEBUG_STOPS
1611 if (DEBUG_COND) {
1612 std::cout << SIMTIME << " vehicle '" << getID() << "' reached stop.\n"
1613 << "Remaining duration: " << STEPS2TIME(stop.duration) << std::endl;
1614 if (stop.getSpeed() > 0) {
1615 std::cout << " waypointSpeed=" << stop.getSpeed() << "vehPos=" << myState.myPos << " endPos=" << stop.pars.endPos << "\n";
1616 }
1617 }
1618#endif
1619 if (stop.duration <= 0 && stop.pars.join != "") {
1620 // join this train (part) to another one
1621 MSVehicle* joinVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.join));
1622 if (joinVeh && (joinVeh->joinTrainPart(this) || joinVeh->joinTrainPartFront(this))) {
1623 stop.joinTriggered = false;
1624 // avoid collision warning before this vehicle is removed (joinVeh was already made longer)
1626 // mark this vehicle as arrived
1628 }
1629 }
1630 if (!keepStopping() && isOnRoad()) {
1631#ifdef DEBUG_STOPS
1632 if (DEBUG_COND) {
1633 std::cout << SIMTIME << " vehicle '" << getID() << "' resumes from stopping." << std::endl;
1634 }
1635#endif
1637 if (isRailway(getVClass())
1638 && hasStops()) {
1639 // stay on the current lane in case of a double stop
1640 const MSStop& nextStop = getNextStop();
1641 if (nextStop.edge == myCurrEdge) {
1642 const double stopSpeed = getCarFollowModel().stopSpeed(this, getSpeed(), nextStop.pars.endPos - myState.myPos);
1643 //std::cout << SIMTIME << " veh=" << getID() << " resumedFromStopping currentVelocity=" << currentVelocity << " stopSpeed=" << stopSpeed << "\n";
1644 return stopSpeed;
1645 }
1646 }
1647 } else {
1648 boardTransportables(stop);
1649
1650 if (stop.triggered && !myAmRegisteredAsWaiting) {
1651 if (getVehicleType().getPersonCapacity() == getPersonNumber()) {
1652 WRITE_WARNING("Vehicle '" + getID() + "' ignores triggered stop on lane '" + stop.lane->getID() + "' due to capacity constraints.");
1653 stop.triggered = false;
1654 }
1655 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1658#ifdef DEBUG_STOPS
1659 if (DEBUG_COND) {
1660 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for person." << std::endl;
1661 }
1662#endif
1663 }
1665 if (getVehicleType().getContainerCapacity() == getContainerNumber()) {
1666 WRITE_WARNING("Vehicle '" + getID() + "' ignores container triggered stop on lane '" + stop.lane->getID() + "' due to capacity constraints.");
1667 stop.containerTriggered = false;
1668 }
1669 // we can only register after waiting for one step. otherwise we might falsely signal a deadlock
1672#ifdef DEBUG_STOPS
1673 if (DEBUG_COND) {
1674 std::cout << SIMTIME << " vehicle '" << getID() << "' registers as waiting for container." << std::endl;
1675 }
1676#endif
1677 }
1678 if (stop.getSpeed() > 0) {
1679 //waypoint mode
1680 if (stop.duration == 0) {
1681 return stop.getSpeed();
1682 } else {
1683 // stop for 'until' (computed in planMove)
1684 return currentVelocity;
1685 }
1686 } else {
1687 // brake
1689 return 0;
1690 } else {
1691 // ballistic:
1692 return getSpeed() - getCarFollowModel().getMaxDecel();
1693 }
1694 }
1695 }
1696 } else {
1697
1698#ifdef DEBUG_STOPS
1699 if (DEBUG_COND) {
1700 std::cout << SIMTIME << " vehicle '" << getID() << "' hasn't reached next stop." << std::endl;
1701 }
1702#endif
1703 //std::cout << SIMTIME << " myStopDist=" << myStopDist << " bGap=" << getBrakeGap(myLane->getVehicleMaxSpeed(this)) << "\n";
1704 if (stop.pars.onDemand && !stop.skipOnDemand && myStopDist <= getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this))) {
1705 MSNet* const net = MSNet::getInstance();
1706 const bool noExits = ((myPersonDevice == nullptr || !myPersonDevice->anyLeavingAtStop(stop))
1707 && (myContainerDevice == nullptr || !myContainerDevice->anyLeavingAtStop(stop)));
1708 const bool noEntries = ((!net->hasPersons() || !net->getPersonControl().hasAnyWaiting(stop.getEdge(), this))
1709 && (!net->hasContainers() || !net->getContainerControl().hasAnyWaiting(stop.getEdge(), this)));
1710 if (noExits && noEntries) {
1711 //std::cout << " skipOnDemand\n";
1712 stop.skipOnDemand = true;
1713 }
1714 }
1715
1716 // is the next stop on the current lane?
1717 if (stop.edge == myCurrEdge) {
1718 // get the stopping position
1719 bool useStoppingPlace = stop.busstop != nullptr || stop.containerstop != nullptr || stop.parkingarea != nullptr;
1720 bool fitsOnStoppingPlace = true;
1721 if (stop.busstop != nullptr) {
1722 fitsOnStoppingPlace &= stop.busstop->fits(myState.myPos, *this);
1723 }
1724 if (stop.containerstop != nullptr) {
1725 fitsOnStoppingPlace &= stop.containerstop->fits(myState.myPos, *this);
1726 }
1727 // if the stop is a parking area we check if there is a free position on the area
1728 if (stop.parkingarea != nullptr) {
1729 fitsOnStoppingPlace &= myState.myPos > stop.parkingarea->getBeginLanePosition();
1730 if (stop.parkingarea->getOccupancy() >= stop.parkingarea->getCapacity()) {
1731 fitsOnStoppingPlace = false;
1732 // trigger potential parkingZoneReroute
1733 for (std::vector< MSMoveReminder* >::const_iterator rem = myLane->getMoveReminders().begin(); rem != myLane->getMoveReminders().end(); ++rem) {
1734 addReminder(*rem);
1735 }
1736 MSParkingArea* oldParkingArea = stop.parkingarea;
1738 if (myStops.empty() || myStops.front().parkingarea != oldParkingArea) {
1739 // rerouted, keep driving
1740 return currentVelocity;
1741 }
1742 } else if (stop.parkingarea->getOccupancyIncludingBlocked() >= stop.parkingarea->getCapacity()) {
1743 fitsOnStoppingPlace = false;
1744 } else if (stop.parkingarea->parkOnRoad() && stop.parkingarea->getLotIndex(this) < 0) {
1745 fitsOnStoppingPlace = false;
1746 }
1747 }
1748 const double targetPos = myState.myPos + myStopDist + (stop.getSpeed() > 0 ? (stop.pars.startPos - stop.pars.endPos) : 0);
1749 const double reachedThreshold = (useStoppingPlace ? targetPos - STOPPING_PLACE_OFFSET : stop.getReachedThreshold()) - NUMERICAL_EPS;
1750#ifdef DEBUG_STOPS
1751 if (DEBUG_COND) {
1752 std::cout << " pos=" << myState.pos() << " speed=" << currentVelocity << " targetPos=" << targetPos << " fits=" << fitsOnStoppingPlace
1753 << " reachedThresh=" << reachedThreshold
1754 << " myLane=" << Named::getIDSecure(myLane)
1755 << " stopLane=" << Named::getIDSecure(stop.lane)
1756 << "\n";
1757 }
1758#endif
1759 if (myState.pos() >= reachedThreshold && fitsOnStoppingPlace && currentVelocity <= stop.getSpeed() + SUMO_const_haltingSpeed && myLane == stop.lane
1761 // ok, we may stop (have reached the stop) and either we are not modelling manoeuvering or have completed entry
1762 stop.reached = true;
1763 if (stop.pars.started == -1) { // if not we are probably loading a state
1764 stop.pars.started = time;
1765 }
1766#ifdef DEBUG_STOPS
1767 if (DEBUG_COND) {
1768 std::cout << SIMTIME << " vehicle '" << getID() << "' reached next stop." << std::endl;
1769 }
1770#endif
1771 if (MSStopOut::active()) {
1773 }
1774 myLane->getEdge().addWaiting(this);
1777 // compute stopping time
1778 stop.duration = stop.getMinDuration(time);
1779 stop.endBoarding = stop.pars.extension >= 0 ? time + stop.duration + stop.pars.extension : SUMOTime_MAX;
1780 if (stop.getSpeed() > 0) {
1781 // ignore duration parameter in waypoint mode unless 'until' or 'ended' are set
1782 if (stop.getUntil() > time) {
1783 stop.duration = stop.getUntil() - time;
1784 } else {
1785 stop.duration = 0;
1786 }
1787 }
1788 if (stop.busstop != nullptr) {
1789 // let the bus stop know the vehicle
1790 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
1791 }
1792 if (stop.containerstop != nullptr) {
1793 // let the container stop know the vehicle
1795 }
1796 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
1797 // let the parking area know the vehicle
1798 stop.parkingarea->enter(this);
1799 }
1800 if (stop.chargingStation != nullptr) {
1801 // let the container stop know the vehicle
1803 }
1804
1805 if (stop.pars.tripId != "") {
1806 ((SUMOVehicleParameter&)getParameter()).setParameter("tripId", stop.pars.tripId);
1807 }
1808 if (stop.pars.line != "") {
1809 ((SUMOVehicleParameter&)getParameter()).line = stop.pars.line;
1810 }
1811 if (stop.pars.split != "") {
1812 // split the train
1813 MSVehicle* splitVeh = dynamic_cast<MSVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(stop.pars.split));
1814 if (splitVeh == nullptr) {
1815 WRITE_WARNINGF(TL("Vehicle '%' to split from vehicle '%' is not known. time=%."), stop.pars.split, getID(), SIMTIME)
1816 } else {
1818 splitVeh->getRoute().getEdges()[0]->removeWaiting(splitVeh);
1820 const double newLength = MAX2(myType->getLength() - splitVeh->getVehicleType().getLength(),
1822 getSingularType().setLength(newLength);
1823 }
1824 }
1825
1826 boardTransportables(stop);
1827 if (stop.pars.posLat != INVALID_DOUBLE) {
1828 myState.myPosLat = stop.pars.posLat;
1829 }
1830 }
1831 }
1832 }
1833 return currentVelocity;
1834}
1835
1836
1837void
1839 if (stop.skipOnDemand) {
1840 return;
1841 }
1842 // we have reached the stop
1843 // any waiting persons may board now
1845 MSNet* const net = MSNet::getInstance();
1846 const bool boarded = (time <= stop.endBoarding
1847 && net->hasPersons()
1849 && stop.numExpectedPerson == 0);
1850 // load containers
1851 const bool loaded = (time <= stop.endBoarding
1852 && net->hasContainers()
1854 && stop.numExpectedContainer == 0);
1855
1856 bool unregister = false;
1857 if (time > stop.endBoarding) {
1858 stop.triggered = false;
1859 stop.containerTriggered = false;
1861 unregister = true;
1863 }
1864 }
1865 if (boarded) {
1866 // the triggering condition has been fulfilled. Maybe we want to wait a bit longer for additional riders (car pooling)
1868 unregister = true;
1869 }
1870 stop.triggered = false;
1872 }
1873 if (loaded) {
1874 // the triggering condition has been fulfilled
1876 unregister = true;
1877 }
1878 stop.containerTriggered = false;
1880 }
1881
1882 if (unregister) {
1884#ifdef DEBUG_STOPS
1885 if (DEBUG_COND) {
1886 std::cout << SIMTIME << " vehicle '" << getID() << "' unregisters as waiting for transportable." << std::endl;
1887 }
1888#endif
1889 }
1890}
1891
1892bool
1894 // check if veh is close enough to be joined
1895 MSLane* backLane = myFurtherLanes.size() == 0 ? myLane : myFurtherLanes.back();
1896 double gap = getBackPositionOnLane() - veh->getPositionOnLane();
1897 if (isStopped() && myStops.begin()->joinTriggered && backLane == veh->getLane()
1898 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
1899 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
1900 getSingularType().setLength(newLength);
1901 myStops.begin()->joinTriggered = false;
1902 return true;
1903 } else {
1904 return false;
1905 }
1906}
1907
1908
1909bool
1911 // check if veh is close enough to be joined
1912 MSLane* backLane = veh->myFurtherLanes.size() == 0 ? veh->myLane : veh->myFurtherLanes.back();
1913 double gap = veh->getBackPositionOnLane() - getPositionOnLane();
1914 if (isStopped() && myStops.begin()->joinTriggered && backLane == getLane()
1915 && gap >= 0 && gap <= getVehicleType().getMinGap() + 1) {
1916 if (veh->myFurtherLanes.size() > 0) {
1917 // this vehicle must be moved to the lane of veh
1918 // ensure that lane and furtherLanes of veh match our route
1919 int routeIndex = getRoutePosition();
1920 if (myLane->isInternal()) {
1921 routeIndex++;
1922 }
1923 for (int i = (int)veh->myFurtherLanes.size() - 1; i >= 0; i--) {
1924 MSEdge* edge = &veh->myFurtherLanes[i]->getEdge();
1925 if (!edge->isInternal() && edge != myRoute->getEdges()[routeIndex]) {
1926 WRITE_WARNING("Cannot join vehicle '" + veh->getID() + " to vehicle '" + getID()
1927 + "' due to incompatible routes. time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()));
1928 return false;
1929 }
1930 }
1931 for (int i = (int)veh->myFurtherLanes.size() - 2; i >= 0; i--) {
1933 }
1934 }
1935 const double newLength = myType->getLength() + veh->getVehicleType().getLength();
1936 getSingularType().setLength(newLength);
1937 assert(myLane == veh->getLane());
1939 myStops.begin()->joinTriggered = false;
1940 return true;
1941 } else {
1942 return false;
1943 }
1944}
1945
1946bool
1948 if (stop == nullptr) {
1949 return false;
1950 }
1951 for (const MSStop& s : myStops) {
1952 if (s.busstop == stop
1953 || s.containerstop == stop
1954 || s.parkingarea == stop
1955 || s.chargingStation == stop) {
1956 return true;
1957 }
1958 }
1959 return false;
1960}
1961
1962bool
1963MSVehicle::stopsAtEdge(const MSEdge* edge) const {
1964 for (const MSStop& s : myStops) {
1965 if (&s.lane->getEdge() == edge) {
1966 return true;
1967 }
1968 }
1969 return false;
1970}
1971
1972double
1973MSVehicle::getBrakeGap(bool delayed) const {
1974 return getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), delayed ? getCarFollowModel().getHeadwayTime() : 0);
1975}
1976
1977
1978bool
1981 if (myActionStep) {
1982 myLastActionTime = t;
1983 }
1984 return myActionStep;
1985}
1986
1987
1988void
1989MSVehicle::resetActionOffset(const SUMOTime timeUntilNextAction) {
1990 myLastActionTime = MSNet::getInstance()->getCurrentTimeStep() + timeUntilNextAction;
1991}
1992
1993
1994void
1995MSVehicle::updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength) {
1997 SUMOTime timeSinceLastAction = now - myLastActionTime;
1998 if (timeSinceLastAction == 0) {
1999 // Action was scheduled now, may be delayed be new action step length
2000 timeSinceLastAction = oldActionStepLength;
2001 }
2002 if (timeSinceLastAction >= newActionStepLength) {
2003 // Action point required in this step
2004 myLastActionTime = now;
2005 } else {
2006 SUMOTime timeUntilNextAction = newActionStepLength - timeSinceLastAction;
2007 resetActionOffset(timeUntilNextAction);
2008 }
2009}
2010
2011
2012
2013void
2014MSVehicle::planMove(const SUMOTime t, const MSLeaderInfo& ahead, const double lengthsInFront) {
2015#ifdef DEBUG_PLAN_MOVE
2016 if (DEBUG_COND) {
2017 std::cout
2018 << "\nPLAN_MOVE\n"
2019 << SIMTIME
2020 << std::setprecision(gPrecision)
2021 << " veh=" << getID()
2022 << " lane=" << myLane->getID()
2023 << " pos=" << getPositionOnLane()
2024 << " posLat=" << getLateralPositionOnLane()
2025 << " speed=" << getSpeed()
2026 << "\n";
2027 }
2028#endif
2029 // Update the driver state
2030 if (hasDriverState()) {
2032 setActionStepLength(myDriverState->getDriverState()->getActionStepLength(), false);
2033 }
2034
2035 if (!checkActionStep(t)) {
2036#ifdef DEBUG_ACTIONSTEPS
2037 if (DEBUG_COND) {
2038 std::cout << STEPS2TIME(t) << " vehicle '" << getID() << "' skips action." << std::endl;
2039 }
2040#endif
2041 // During non-action passed drive items still need to be removed
2042 // @todo rather work with updating myCurrentDriveItem (refs #3714)
2044 return;
2045 } else {
2046#ifdef DEBUG_ACTIONSTEPS
2047 if (DEBUG_COND) {
2048 std::cout << STEPS2TIME(t) << " vehicle = '" << getID() << "' takes action." << std::endl;
2049 }
2050#endif
2052 if (myInfluencer != nullptr) {
2054 }
2056#ifdef DEBUG_PLAN_MOVE
2057 if (DEBUG_COND) {
2058 DriveItemVector::iterator i;
2059 for (i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
2060 std::cout
2061 << " vPass=" << (*i).myVLinkPass
2062 << " vWait=" << (*i).myVLinkWait
2063 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
2064 << " request=" << (*i).mySetRequest
2065 << "\n";
2066 }
2067 }
2068#endif
2069 checkRewindLinkLanes(lengthsInFront, myLFLinkLanes);
2071 // ideally would only do this with the call inside planMoveInternal - but that needs a const method
2072 // so this is a kludge here - nuisance as it adds an extra check in a busy loop
2076 }
2077 }
2078 }
2080}
2081
2082void
2083MSVehicle::planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector& lfLinks, double& newStopDist, std::pair<double, LinkDirection>& nextTurn) const {
2084 lfLinks.clear();
2085 newStopDist = std::numeric_limits<double>::max();
2086 //
2087 const MSCFModel& cfModel = getCarFollowModel();
2088 const double vehicleLength = getVehicleType().getLength();
2089 const double maxV = cfModel.maxNextSpeed(myState.mySpeed, this);
2090 const bool opposite = myLaneChangeModel->isOpposite();
2091 double laneMaxV = myLane->getVehicleMaxSpeed(this);
2092 const double vMinComfortable = cfModel.minNextSpeed(getSpeed(), this);
2093 double lateralShift = 0;
2094 if (isRailway((SVCPermissions)getVehicleType().getVehicleClass())) {
2095 // speed limits must hold for the whole length of the train
2096 for (MSLane* l : myFurtherLanes) {
2097 laneMaxV = MIN2(laneMaxV, l->getVehicleMaxSpeed(this));
2098#ifdef DEBUG_PLAN_MOVE
2099 if (DEBUG_COND) {
2100 std::cout << " laneMaxV=" << laneMaxV << " lane=" << l->getID() << "\n";
2101 }
2102#endif
2103 }
2104 }
2105 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2106 laneMaxV = MAX2(laneMaxV, vMinComfortable);
2108 laneMaxV = std::numeric_limits<double>::max();
2109 }
2110 // v is the initial maximum velocity of this vehicle in this step
2111 double v = cfModel.maximumLaneSpeedCF(maxV, laneMaxV);
2112 // if we are modelling parking then we dawdle until the manoeuvre is complete - by setting a very low max speed
2113 // in practice this only applies to exit manoeuvre because entry manoeuvre just delays setting stop.reached - when the vehicle is virtually stopped
2116 }
2117
2118 if (myInfluencer != nullptr) {
2119 const double vMin = MAX2(0., cfModel.minNextSpeed(myState.mySpeed, this));
2120#ifdef DEBUG_TRACI
2121 if (DEBUG_COND) {
2122 std::cout << SIMTIME << " veh=" << getID() << " speedBeforeTraci=" << v;
2123 }
2124#endif
2125 v = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), v, v, vMin, maxV);
2126#ifdef DEBUG_TRACI
2127 if (DEBUG_COND) {
2128 std::cout << " influencedSpeed=" << v;
2129 }
2130#endif
2131 v = myInfluencer->gapControlSpeed(MSNet::getInstance()->getCurrentTimeStep(), this, v, v, vMin, maxV);
2132#ifdef DEBUG_TRACI
2133 if (DEBUG_COND) {
2134 std::cout << " gapControlSpeed=" << v << "\n";
2135 }
2136#endif
2137 }
2138 // all links within dist are taken into account (potentially)
2139 const double dist = SPEED2DIST(maxV) + cfModel.brakeGap(maxV);
2140
2141 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation();
2142#ifdef DEBUG_PLAN_MOVE
2143 if (DEBUG_COND) {
2144 std::cout << " dist=" << dist << " bestLaneConts=" << toString(bestLaneConts)
2145 << "\n maxV=" << maxV << " laneMaxV=" << laneMaxV << " v=" << v << "\n";
2146 }
2147#endif
2148 assert(bestLaneConts.size() > 0);
2149 bool hadNonInternal = false;
2150 // the distance already "seen"; in the following always up to the end of the current "lane"
2151 double seen = opposite ? myState.myPos : myLane->getLength() - myState.myPos;
2152 nextTurn.first = seen;
2153 nextTurn.second = LinkDirection::NODIR;
2154 bool encounteredTurn = (MSGlobals::gLateralResolution <= 0); // next turn is only needed for sublane
2155 double seenNonInternal = 0;
2156 double seenInternal = myLane->isInternal() ? seen : 0;
2157 double vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(seen, v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2158 int view = 0;
2159 DriveProcessItem* lastLink = nullptr;
2160 bool slowedDownForMinor = false; // whether the vehicle already had to slow down on approach to a minor link
2161 double mustSeeBeforeReversal = 0;
2162 // iterator over subsequent lanes and fill lfLinks until stopping distance or stopped
2163 const MSLane* lane = opposite ? myLane->getParallelOpposite() : myLane;
2164 assert(lane != 0);
2165 const MSLane* leaderLane = myLane;
2166 bool foundRailSignal = !isRailway(getVClass());
2167#ifdef PARALLEL_STOPWATCH
2168 myLane->getStopWatch()[0].start();
2169#endif
2170#ifdef _MSC_VER
2171#pragma warning(push)
2172#pragma warning(disable: 4127) // do not warn about constant conditional expression
2173#endif
2174 while (true) {
2175#ifdef _MSC_VER
2176#pragma warning(pop)
2177#endif
2178 // check leader on lane
2179 // leader is given for the first edge only
2180 if (opposite &&
2181 (leaderLane->getVehicleNumberWithPartials() > 1
2182 || (leaderLane != myLane && leaderLane->getVehicleNumber() > 0))) {
2183 ahead.clear();
2184 // find opposite-driving leader that must be respected on the currently looked at lane
2185 // (only looking at one lane at a time)
2186 const double backOffset = leaderLane == myLane ? getPositionOnLane() : leaderLane->getLength();
2187 const double gapOffset = leaderLane == myLane ? 0 : seen - leaderLane->getLength();
2188 const MSLeaderDistanceInfo cands = leaderLane->getFollowersOnConsecutive(this, backOffset, true, backOffset, MSLane::MinorLinkMode::FOLLOW_NEVER);
2189 MSLeaderDistanceInfo oppositeLeaders(leaderLane->getWidth(), this, 0.);
2190 const double minTimeToLeaveLane = MSGlobals::gSublane ? MAX2(TS, (0.5 * myLane->getWidth() - getLateralPositionOnLane()) / getVehicleType().getMaxSpeedLat()) : TS;
2191 for (int i = 0; i < cands.numSublanes(); i++) {
2192 CLeaderDist cand = cands[i];
2193 if (cand.first != 0) {
2194 if ((cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() != leaderLane)
2195 || (!cand.first->myLaneChangeModel->isOpposite() && cand.first->getLaneChangeModel().getShadowLane() == leaderLane)) {
2196 // respect leaders that also drive in the opposite direction (fully or with some overlap)
2197 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - getVehicleType().getMinGap() + cand.first->getVehicleType().getMinGap() - cand.first->getVehicleType().getLength());
2198 } else {
2199 // avoid frontal collision
2200 const bool assumeStopped = cand.first->isStopped() || cand.first->getWaitingSeconds() > 1;
2201 const double predMaxDist = cand.first->getSpeed() + (assumeStopped ? 0 : cand.first->getCarFollowModel().getMaxAccel()) * minTimeToLeaveLane;
2202 if (cand.second >= 0 && (cand.second - v * minTimeToLeaveLane - predMaxDist < 0 || assumeStopped)) {
2203 oppositeLeaders.addLeader(cand.first, cand.second + gapOffset - predMaxDist - getVehicleType().getMinGap());
2204 }
2205 }
2206 }
2207 }
2208#ifdef DEBUG_PLAN_MOVE
2209 if (DEBUG_COND) {
2210 std::cout << " leaderLane=" << leaderLane->getID() << " gapOffset=" << gapOffset << " minTimeToLeaveLane=" << minTimeToLeaveLane
2211 << " cands=" << cands.toString() << " oppositeLeaders=" << oppositeLeaders.toString() << "\n";
2212 }
2213#endif
2214 adaptToLeaderDistance(oppositeLeaders, 0, seen, lastLink, v, vLinkPass);
2215 } else {
2217 && (getLeftSideOnLane(lane) < 0 || getRightSideOnLane(lane) > lane->getWidth())) {
2218 // if ego is driving outside lane bounds we must consider
2219 // potential leaders that are also outside lane bounds
2220 const bool outsideLeft = getLeftSideOnLane(lane) < 0;
2221 if (outsideLeft) {
2223 } else if (getRightSideOnLane(lane) > lane->getWidth()) {
2225 }
2226 for (const MSVehicle* cand : lane->getVehiclesSecure()) {
2227 if ((lane != myLane || cand->getPositionOnLane() > getPositionOnLane())
2228 && ((outsideLeft && cand->getLeftSideOnLane() < 0)
2229 || (!outsideLeft && cand->getRightSideOnEdge() > lane->getWidth()))) {
2230 ahead.addLeader(cand, true);
2231#ifdef DEBUG_PLAN_MOVE
2232 if (DEBUG_COND) {
2233 std::cout << SIMTIME << " veh=" << getID() << " offset=" << ahead.getSublaneOffset() << " outsideLeft=" << outsideLeft << " outsideLeader=" << cand->getID() << "\n";
2234 }
2235#endif
2236 }
2237 }
2238 lane->releaseVehicles();
2239 }
2240 adaptToLeaders(ahead, lateralShift, seen, lastLink, leaderLane, v, vLinkPass);
2241 }
2242 if (lastLink != nullptr) {
2243 lastLink->myVLinkWait = MIN2(lastLink->myVLinkWait, v);
2244 }
2245#ifdef DEBUG_PLAN_MOVE
2246 if (DEBUG_COND) {
2247 std::cout << "\nv = " << v << "\n";
2248
2249 }
2250#endif
2251 // XXX efficiently adapt to shadow leaders using neighAhead by iteration over the whole edge in parallel (lanechanger-style)
2252 if (myLaneChangeModel->getShadowLane() != nullptr) {
2253 // also slow down for leaders on the shadowLane relative to the current lane
2254 const MSLane* shadowLane = myLaneChangeModel->getShadowLane(leaderLane);
2255 if (shadowLane != nullptr
2256 && (MSGlobals::gLateralResolution > 0 || getLateralOverlap() > POSITION_EPS
2257 // continous lane change cannot be stopped so we must adapt to the leader on the target lane
2259 if ((&shadowLane->getEdge() == &leaderLane->getEdge() || myLaneChangeModel->isOpposite())) {
2262 // ego posLat is added when retrieving sublanes but it
2263 // should be negated (subtract twice to compensate)
2264 latOffset = ((myLane->getWidth() + shadowLane->getWidth()) * 0.5
2265 - 2 * getLateralPositionOnLane());
2266
2267 }
2268 MSLeaderInfo shadowLeaders = shadowLane->getLastVehicleInformation(this, latOffset, lane->getLength() - seen);
2269#ifdef DEBUG_PLAN_MOVE
2271 std::cout << SIMTIME << " opposite veh=" << getID() << " shadowLane=" << shadowLane->getID() << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2272 }
2273#endif
2275 // ignore oncoming vehicles on the shadow lane
2276 shadowLeaders.removeOpposite(shadowLane);
2277 }
2278 adaptToLeaders(shadowLeaders, latOffset, seen, lastLink, shadowLane, v, vLinkPass);
2279 } else if (shadowLane == myLaneChangeModel->getShadowLane() && leaderLane == myLane) {
2280 // check for leader vehicles driving in the opposite direction on the opposite-direction shadow lane
2281 // (and thus in the same direction as ego)
2282 MSLeaderDistanceInfo shadowLeaders = shadowLane->getFollowersOnConsecutive(this, myLane->getOppositePos(getPositionOnLane()), true);
2283 const double latOffset = 0;
2284#ifdef DEBUG_PLAN_MOVE
2285 if (DEBUG_COND) {
2286 std::cout << SIMTIME << " opposite shadows veh=" << getID() << " shadowLane=" << shadowLane->getID()
2287 << " latOffset=" << latOffset << " shadowLeaders=" << shadowLeaders.toString() << "\n";
2288 }
2289#endif
2290 shadowLeaders.fixOppositeGaps(true);
2291#ifdef DEBUG_PLAN_MOVE
2292 if (DEBUG_COND) {
2293 std::cout << " shadowLeadersFixed=" << shadowLeaders.toString() << "\n";
2294 }
2295#endif
2296 adaptToLeaderDistance(shadowLeaders, latOffset, seen, lastLink, v, vLinkPass);
2297 }
2298 }
2299 }
2300 // adapt to pedestrians on the same lane
2301 if (lane->getEdge().getPersons().size() > 0 && lane->hasPedestrians()) {
2302 const double relativePos = lane->getLength() - seen;
2303#ifdef DEBUG_PLAN_MOVE
2304 if (DEBUG_COND) {
2305 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2306 }
2307#endif
2308 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2309 PersonDist leader = lane->nextBlocking(relativePos,
2310 getRightSideOnLane(lane), getRightSideOnLane(lane) + getVehicleType().getWidth(), stopTime);
2311 if (leader.first != 0) {
2312 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2313 v = MIN2(v, stopSpeed);
2314#ifdef DEBUG_PLAN_MOVE
2315 if (DEBUG_COND) {
2316 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2317 }
2318#endif
2319 }
2320 }
2321 if (lane->getBidiLane() != nullptr) {
2322 // adapt to pedestrians on the bidi lane
2323 const MSLane* bidiLane = lane->getBidiLane();
2324 if (bidiLane->getEdge().getPersons().size() > 0 && bidiLane->hasPedestrians()) {
2325 const double relativePos = seen;
2326#ifdef DEBUG_PLAN_MOVE
2327 if (DEBUG_COND) {
2328 std::cout << SIMTIME << " adapt to pedestrians on lane=" << lane->getID() << " relPos=" << relativePos << "\n";
2329 }
2330#endif
2331 const double stopTime = ceil(getSpeed() / cfModel.getMaxDecel());
2332 const double leftSideOnLane = bidiLane->getWidth() - getRightSideOnLane(lane);
2333 PersonDist leader = bidiLane->nextBlocking(relativePos,
2334 leftSideOnLane - getVehicleType().getWidth(), leftSideOnLane, stopTime, true);
2335 if (leader.first != 0) {
2336 const double stopSpeed = cfModel.stopSpeed(this, getSpeed(), leader.second - getVehicleType().getMinGap());
2337 v = MIN2(v, stopSpeed);
2338#ifdef DEBUG_PLAN_MOVE
2339 if (DEBUG_COND) {
2340 std::cout << SIMTIME << " pedLeader=" << leader.first->getID() << " dist=" << leader.second << " v=" << v << "\n";
2341 }
2342#endif
2343 }
2344 }
2345 }
2346
2347 // process stops
2348 if (!myStops.empty()
2349 && ((&myStops.begin()->lane->getEdge() == &lane->getEdge())
2350 || (myStops.begin()->isOpposite && myStops.begin()->lane->getEdge().getOppositeEdge() == &lane->getEdge()))
2351 && (!myStops.begin()->reached || (myStops.begin()->getSpeed() > 0 && keepStopping()))
2352 // ignore stops that occur later in a looped route
2353 && myStops.front().edge == myCurrEdge + view) {
2354 // we are approaching a stop on the edge; must not drive further
2355 const MSStop& stop = *myStops.begin();
2356 bool isWaypoint = stop.getSpeed() > 0;
2357 double endPos = stop.getEndPos(*this) + NUMERICAL_EPS;
2358 if (stop.parkingarea != nullptr) {
2359 // leave enough space so parking vehicles can exit
2360 const double brakePos = getBrakeGap() + lane->getLength() - seen;
2361 endPos = stop.parkingarea->getLastFreePosWithReservation(t, *this, brakePos);
2362 } else if (isWaypoint && !stop.reached) {
2363 endPos = stop.pars.startPos;
2364 }
2365 newStopDist = seen + endPos - lane->getLength();
2366#ifdef DEBUG_STOPS
2367 if (DEBUG_COND) {
2368 std::cout << SIMTIME << " veh=" << getID() << " newStopDist=" << newStopDist << " stopLane=" << stop.lane->getID() << " stopEndPos=" << endPos << "\n";
2369 }
2370#endif
2371 // regular stops are not emergencies
2372 double stopSpeed = laneMaxV;
2373 if (isWaypoint) {
2374 bool waypointWithStop = false;
2375 if (stop.getUntil() > t) {
2376 // check if we have to slow down or even stop
2377 SUMOTime time2end = 0;
2378 if (stop.reached) {
2379 time2end = TIME2STEPS((stop.pars.endPos - myState.myPos) / stop.getSpeed());
2380 } else {
2381 time2end = TIME2STEPS(
2382 // time to reach waypoint start
2383 newStopDist / ((getSpeed() + stop.getSpeed()) / 2)
2384 // time to reach waypoint end
2385 + (stop.pars.endPos - stop.pars.startPos) / stop.getSpeed());
2386 }
2387 if (stop.getUntil() > t + time2end) {
2388 // we need to stop
2389 double distToEnd = newStopDist;
2390 if (!stop.reached) {
2391 distToEnd += stop.pars.endPos - stop.pars.startPos;
2392 }
2393 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), distToEnd), vMinComfortable);
2394 waypointWithStop = true;
2395 }
2396 }
2397 if (stop.reached) {
2398 stopSpeed = MIN2(stop.getSpeed(), stopSpeed);
2399 if (myState.myPos >= stop.pars.endPos && !waypointWithStop) {
2400 newStopDist = std::numeric_limits<double>::max();
2401 }
2402 } else {
2403 stopSpeed = MIN2(MAX2(cfModel.freeSpeed(this, getSpeed(), newStopDist, stop.getSpeed()), vMinComfortable), stopSpeed);
2404 if (!stop.reached) {
2405 newStopDist += stop.pars.endPos - stop.pars.startPos;
2406 }
2407 if (lastLink != nullptr) {
2408 lastLink->adaptLeaveSpeed(cfModel.freeSpeed(this, vLinkPass, endPos, stop.getSpeed(), false, MSCFModel::CalcReason::FUTURE));
2409 }
2410 }
2411 } else {
2412 stopSpeed = MAX2(cfModel.stopSpeed(this, getSpeed(), newStopDist), vMinComfortable);
2413 if (lastLink != nullptr) {
2414 lastLink->adaptLeaveSpeed(cfModel.stopSpeed(this, vLinkPass, endPos, MSCFModel::CalcReason::FUTURE));
2415 }
2416 }
2417 v = MIN2(v, stopSpeed);
2418 if (lane->isInternal()) {
2419 std::vector<MSLink*>::const_iterator exitLink = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2420 assert(!lane->isLinkEnd(exitLink));
2421 bool dummySetRequest;
2422 double dummyVLinkWait;
2423 checkLinkLeaderCurrentAndParallel(*exitLink, lane, seen, lastLink, v, vLinkPass, dummyVLinkWait, dummySetRequest);
2424 }
2425
2426#ifdef DEBUG_PLAN_MOVE
2427 if (DEBUG_COND) {
2428 std::cout << "\n" << SIMTIME << " next stop: distance = " << newStopDist << " requires stopSpeed = " << stopSpeed << "\n";
2429
2430 }
2431#endif
2432 if (!isWaypoint && !isRailway(getVClass())) {
2433 lfLinks.emplace_back(v, newStopDist);
2434 break;
2435 }
2436 }
2437
2438 // move to next lane
2439 // get the next link used
2440 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view + 1, *lane, bestLaneConts);
2441
2442 // Check whether this is a turn (to save info about the next upcoming turn)
2443 if (!encounteredTurn) {
2444 if (!lane->isLinkEnd(link) && lane->getLinkCont().size() > 1) {
2445 LinkDirection linkDir = (*link)->getDirection();
2446 switch (linkDir) {
2449 break;
2450 default:
2451 nextTurn.first = seen;
2452 nextTurn.second = linkDir;
2453 encounteredTurn = true;
2454#ifdef DEBUG_NEXT_TURN
2455 if (DEBUG_COND) {
2456 std::cout << SIMTIME << " veh '" << getID() << "' nextTurn: " << toString(nextTurn.second)
2457 << " at " << nextTurn.first << "m." << std::endl;
2458 }
2459#endif
2460 }
2461 }
2462 }
2463
2464 // check whether the vehicle is on its final edge
2465 if (myCurrEdge + view + 1 == myRoute->end()
2466 || (myParameter->arrivalEdge >= 0 && getRoutePosition() + view == myParameter->arrivalEdge)) {
2467 const double arrivalSpeed = (myParameter->arrivalSpeedProcedure == ArrivalSpeedDefinition::GIVEN ?
2468 myParameter->arrivalSpeed : laneMaxV);
2469 // subtract the arrival speed from the remaining distance so we get one additional driving step with arrival speed
2470 // XXX: This does not work for ballistic update refs #2579
2471 const double distToArrival = seen + myArrivalPos - lane->getLength() - SPEED2DIST(arrivalSpeed);
2472 const double va = MAX2(NUMERICAL_EPS, cfModel.freeSpeed(this, getSpeed(), distToArrival, arrivalSpeed));
2473 v = MIN2(v, va);
2474 if (lastLink != nullptr) {
2475 lastLink->adaptLeaveSpeed(va);
2476 }
2477 lfLinks.push_back(DriveProcessItem(v, seen, lane->getEdge().isFringe() ? 1000 : 0));
2478 break;
2479 }
2480 // check whether the lane or the shadowLane is a dead end (allow some leeway on intersections)
2481 if (lane->isLinkEnd(link)
2482 || ((*link)->getViaLane() == nullptr
2485 // account for future shift
2486 + (lane != myLane && lane->isInternal() ? lane->getIncomingLanes()[0].viaLink->getLateralShift() : 0),
2487 lane) > POSITION_EPS
2488 // do not get stuck on narrow edges
2489 && getVehicleType().getWidth() <= lane->getEdge().getWidth()
2490 // this is the exit link of a junction. The normal edge should support the shadow
2491 && ((myLaneChangeModel->getShadowLane((*link)->getLane()) == nullptr)
2492 // the internal lane after an internal junction has no parallel lane. make sure there is no shadow before continuing
2493 || (lane->getEdge().isInternal() && lane->getIncomingLanes()[0].lane->getEdge().isInternal()))
2494 // ignore situations where the shadow lane is part of a double-connection with the current lane
2495 && (myLaneChangeModel->getShadowLane() == nullptr
2496 || myLaneChangeModel->getShadowLane()->getLinkCont().size() == 0
2497 || myLaneChangeModel->getShadowLane()->getLinkCont().front()->getLane() != (*link)->getLane()))
2498 || (opposite && (*link)->getViaLaneOrLane()->getParallelOpposite() == nullptr
2500 double va = cfModel.stopSpeed(this, getSpeed(), seen);
2501 if (lastLink != nullptr) {
2502 lastLink->adaptLeaveSpeed(va);
2503 }
2506 } else {
2507 v = MIN2(va, v);
2508 }
2509#ifdef DEBUG_PLAN_MOVE
2510 if (DEBUG_COND) {
2511 std::cout << " braking for link end lane=" << lane->getID() << " seen=" << seen
2512 << " overlap=" << getLateralOverlap() << " va=" << va << " committed=" << myLaneChangeModel->getCommittedSpeed() << " v=" << v << "\n";
2513
2514 }
2515#endif
2516 if (lane->isLinkEnd(link)) {
2517 lfLinks.emplace_back(v, seen);
2518 break;
2519 }
2520 }
2521 lateralShift += (*link)->getLateralShift();
2522 const bool yellowOrRed = (*link)->haveRed() || (*link)->haveYellow();
2523 // We distinguish 3 cases when determining the point at which a vehicle stops:
2524 // - links that require stopping: here the vehicle needs to stop close to the stop line
2525 // to ensure it gets onto the junction in the next step. Otherwise the vehicle would 'forget'
2526 // that it already stopped and need to stop again. This is necessary pending implementation of #999
2527 // - red/yellow light: here the vehicle 'knows' that it will have priority eventually and does not need to stop on a precise spot
2528 // - other types of minor links: the vehicle needs to stop as close to the junction as necessary
2529 // to minimize the time window for passing the junction. If the
2530 // vehicle 'decides' to accelerate and cannot enter the junction in
2531 // the next step, new foes may appear and cause a collision (see #1096)
2532 // - major links: stopping point is irrelevant
2533 double laneStopOffset;
2534 const double majorStopOffset = MAX2(getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_GAP, DIST_TO_STOPLINE_EXPECT_PRIORITY), lane->getVehicleStopOffset(this));
2535 const double minorStopOffset = lane->getVehicleStopOffset(this);
2536 // override low desired decel at yellow and red
2537 const double stopDecel = yellowOrRed && !isRailway(getVClass()) ? MAX2(MIN2(MSGlobals::gTLSYellowMinDecel, cfModel.getEmergencyDecel()), cfModel.getMaxDecel()) : cfModel.getMaxDecel();
2538 const double brakeDist = cfModel.brakeGap(myState.mySpeed, stopDecel, 0);
2539 const bool canBrakeBeforeLaneEnd = seen >= brakeDist;
2540 const bool canBrakeBeforeStopLine = seen - lane->getVehicleStopOffset(this) >= brakeDist;
2541 if (yellowOrRed) {
2542 // Wait at red traffic light with full distance if possible
2543 laneStopOffset = majorStopOffset;
2544 } else if ((*link)->havePriority()) {
2545 // On priority link, we should never stop below visibility distance
2546 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, majorStopOffset);
2547 } else {
2548 // On minor link, we should likewise never stop below visibility distance
2549 laneStopOffset = MIN2((*link)->getFoeVisibilityDistance() - POSITION_EPS, minorStopOffset);
2550 }
2551 if (canBrakeBeforeLaneEnd) {
2552 // avoid emergency braking if possible
2553 laneStopOffset = MIN2(laneStopOffset, seen - brakeDist);
2554 }
2555 laneStopOffset = MAX2(POSITION_EPS, laneStopOffset);
2556 double stopDist = MAX2(0., seen - laneStopOffset);
2557 if (newStopDist != std::numeric_limits<double>::max()) {
2558 stopDist = MAX2(stopDist, newStopDist);
2559 }
2560#ifdef DEBUG_PLAN_MOVE
2561 if (DEBUG_COND) {
2562 std::cout << SIMTIME << " veh=" << getID() << " effective stopOffset on lane '" << lane->getID()
2563 << "' is " << laneStopOffset << " (-> stopDist=" << stopDist << ")" << std::endl;
2564 }
2565#endif
2566 if (isRailway(getVClass())
2567 && !lane->isInternal()) {
2568 // check for train direction reversal
2569 if (lane->getBidiLane() != nullptr
2570 && (*link)->getLane()->getBidiLane() == lane) {
2571 double vMustReverse = getCarFollowModel().stopSpeed(this, getSpeed(), seen - POSITION_EPS);
2572 if (seen < 1) {
2573 mustSeeBeforeReversal = 2 * seen + getLength();
2574 }
2575 v = MIN2(v, vMustReverse);
2576 }
2577 // signal that is passed in the current step does not count
2578 foundRailSignal |= ((*link)->getTLLogic() != nullptr
2579 && (*link)->getTLLogic()->getLogicType() == TrafficLightType::RAIL_SIGNAL
2580 && seen > SPEED2DIST(v));
2581 }
2582
2583 bool canReverseEventually = false;
2584 const double vReverse = checkReversal(canReverseEventually, laneMaxV, seen);
2585 v = MIN2(v, vReverse);
2586#ifdef DEBUG_PLAN_MOVE
2587 if (DEBUG_COND) {
2588 std::cout << SIMTIME << " veh=" << getID() << " canReverseEventually=" << canReverseEventually << " v=" << v << "\n";
2589 }
2590#endif
2591
2592 // check whether we need to slow down in order to finish a continuous lane change
2594 if ( // slow down to finish lane change before a turn lane
2595 ((*link)->getDirection() == LinkDirection::LEFT || (*link)->getDirection() == LinkDirection::RIGHT) ||
2596 // slow down to finish lane change before the shadow lane ends
2597 (myLaneChangeModel->getShadowLane() != nullptr &&
2598 (*link)->getViaLaneOrLane()->getParallelLane(myLaneChangeModel->getShadowDirection()) == nullptr)) {
2599 // XXX maybe this is too harsh. Vehicles could cut some corners here
2600 const double timeRemaining = STEPS2TIME(myLaneChangeModel->remainingTime());
2601 assert(timeRemaining != 0);
2602 // XXX: Euler-logic (#860), but I couldn't identify problems from this yet (Leo). Refs. #2575
2603 const double va = MAX2(cfModel.stopSpeed(this, getSpeed(), seen - POSITION_EPS),
2604 (seen - POSITION_EPS) / timeRemaining);
2605#ifdef DEBUG_PLAN_MOVE
2606 if (DEBUG_COND) {
2607 std::cout << SIMTIME << " veh=" << getID() << " slowing down to finish continuous change before"
2608 << " link=" << (*link)->getViaLaneOrLane()->getID()
2609 << " timeRemaining=" << timeRemaining
2610 << " v=" << v
2611 << " va=" << va
2612 << std::endl;
2613 }
2614#endif
2615 v = MIN2(va, v);
2616 }
2617 }
2618
2619 // - always issue a request to leave the intersection we are currently on
2620 const bool leavingCurrentIntersection = myLane->getEdge().isInternal() && lastLink == nullptr;
2621 // - do not issue a request to enter an intersection after we already slowed down for an earlier one
2622 const bool abortRequestAfterMinor = slowedDownForMinor && (*link)->getInternalLaneBefore() == nullptr;
2623 // - even if red, if we cannot break we should issue a request
2624 bool setRequest = (v > NUMERICAL_EPS_SPEED && !abortRequestAfterMinor) || (leavingCurrentIntersection);
2625
2626 double stopSpeed = cfModel.stopSpeed(this, getSpeed(), stopDist, stopDecel, MSCFModel::CalcReason::CURRENT_WAIT);
2627 double vLinkWait = MIN2(v, stopSpeed);
2628#ifdef DEBUG_PLAN_MOVE
2629 if (DEBUG_COND) {
2630 std::cout
2631 << " stopDist=" << stopDist
2632 << " stopDecel=" << stopDecel
2633 << " vLinkWait=" << vLinkWait
2634 << " brakeDist=" << brakeDist
2635 << " seen=" << seen
2636 << " leaveIntersection=" << leavingCurrentIntersection
2637 << " setRequest=" << setRequest
2638 //<< std::setprecision(16)
2639 //<< " v=" << v
2640 //<< " speedEps=" << NUMERICAL_EPS_SPEED
2641 //<< std::setprecision(gPrecision)
2642 << "\n";
2643 }
2644#endif
2645
2646 if (yellowOrRed && canBrakeBeforeStopLine && !ignoreRed(*link, canBrakeBeforeStopLine) && seen >= mustSeeBeforeReversal) {
2647 if (lane->isInternal()) {
2648 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2649 }
2650 // arrivalSpeed / arrivalTime when braking for red light is only relevent for rail signal switching
2651 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, vLinkPass);
2652 // the vehicle is able to brake in front of a yellow/red traffic light
2653 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, false, arrivalTime, vLinkWait, 0, seen, -1));
2654 //lfLinks.push_back(DriveProcessItem(0, vLinkWait, vLinkWait, false, 0, 0, stopDist));
2655 break;
2656 }
2657
2658 const MSLink* entryLink = (*link)->getCorrespondingEntryLink();
2659 if (entryLink->haveRed() && ignoreRed(*link, canBrakeBeforeStopLine) && STEPS2TIME(t - entryLink->getLastStateChange()) > 2) {
2660 // restrict speed when ignoring a red light
2661 const double redSpeed = MIN2(v, getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_RED_SPEED, v));
2662 const double va = MAX2(redSpeed, cfModel.freeSpeed(this, getSpeed(), seen, redSpeed));
2663 v = MIN2(va, v);
2664#ifdef DEBUG_PLAN_MOVE
2665 if (DEBUG_COND) std::cout
2666 << " ignoreRed spent=" << STEPS2TIME(t - (*link)->getLastStateChange())
2667 << " redSpeed=" << redSpeed
2668 << " va=" << va
2669 << " v=" << v
2670 << "\n";
2671#endif
2672 }
2673
2674 checkLinkLeaderCurrentAndParallel(*link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
2675
2676 if (lastLink != nullptr) {
2677 lastLink->adaptLeaveSpeed(laneMaxV);
2678 }
2679 double arrivalSpeed = vLinkPass;
2680 // vehicles should decelerate when approaching a minor link
2681 // - unless they are close enough to have clear visibility of all relevant foe lanes and may start to accelerate again
2682 // - and unless they are so close that stopping is impossible (i.e. when a green light turns to yellow when close to the junction)
2683
2684 // whether the vehicle/driver is close enough to the link to see all possible foes #2123
2685 const double visibilityDistance = (*link)->getFoeVisibilityDistance();
2686 const double determinedFoePresence = seen <= visibilityDistance;
2687// // VARIANT: account for time needed to recognize whether relevant vehicles are on the foe lanes. (Leo)
2688// double foeRecognitionTime = 0.0;
2689// double determinedFoePresence = seen < visibilityDistance - myState.mySpeed*foeRecognitionTime;
2690
2691#ifdef DEBUG_PLAN_MOVE
2692 if (DEBUG_COND) {
2693 std::cout << " approaching link=" << (*link)->getViaLaneOrLane()->getID() << " prio=" << (*link)->havePriority() << " seen=" << seen << " visibilityDistance=" << visibilityDistance << " brakeDist=" << brakeDist << "\n";
2694 }
2695#endif
2696
2697 const bool couldBrakeForMinor = !(*link)->havePriority() && brakeDist < seen && !(*link)->lastWasContMajor();
2698 if (couldBrakeForMinor && !determinedFoePresence) {
2699 // vehicle decelerates just enough to be able to stop if necessary and then accelerates
2700 double maxSpeedAtVisibilityDist = cfModel.maximumSafeStopSpeed(visibilityDistance, cfModel.getMaxDecel(), myState.mySpeed, false, 0.);
2701 // XXX: estimateSpeedAfterDistance does not use euler-logic (thus returns a lower value than possible here...)
2702 double maxArrivalSpeed = cfModel.estimateSpeedAfterDistance(visibilityDistance, maxSpeedAtVisibilityDist, cfModel.getMaxAccel());
2703 arrivalSpeed = MIN2(vLinkPass, maxArrivalSpeed);
2704 slowedDownForMinor = true;
2705#ifdef DEBUG_PLAN_MOVE
2706 if (DEBUG_COND) {
2707 std::cout << " slowedDownForMinor maxSpeedAtVisDist=" << maxSpeedAtVisibilityDist << " maxArrivalSpeed=" << maxArrivalSpeed << " arrivalSpeed=" << arrivalSpeed << "\n";
2708 }
2709#endif
2710 } else if ((*link)->getState() == LINKSTATE_EQUAL && myWaitingTime > 0) {
2711 // check for deadlock (circular yielding)
2712 //std::cout << SIMTIME << " veh=" << getID() << " check rbl-deadlock\n";
2713 std::pair<const SUMOVehicle*, const MSLink*> blocker = (*link)->getFirstApproachingFoe(*link);
2714 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2715 int n = 100;
2716 while (blocker.second != nullptr && blocker.second != *link && n > 0) {
2717 blocker = blocker.second->getFirstApproachingFoe(*link);
2718 n--;
2719 //std::cout << " blocker=" << Named::getIDSecure(blocker.first) << "\n";
2720 }
2721 if (n == 0) {
2722 WRITE_WARNINGF(TL("Suspicious right_before_left junction '%'."), lane->getEdge().getToJunction()->getID());
2723 }
2724 //std::cout << " blockerLink=" << blocker.second << " link=" << *link << "\n";
2725 if (blocker.second == *link) {
2726 const double threshold = (*link)->getDirection() == LinkDirection::STRAIGHT ? 0.25 : 0.75;
2727 if (RandHelper::rand(getRNG()) < threshold) {
2728 //std::cout << " abort request, threshold=" << threshold << "\n";
2729 setRequest = false;
2730 }
2731 }
2732 }
2733 if (couldBrakeForMinor && (*link)->getLane()->getEdge().isRoundabout()) {
2734 slowedDownForMinor = true;
2735#ifdef DEBUG_PLAN_MOVE
2736 if (DEBUG_COND) {
2737 std::cout << " slowedDownForMinor at roundabout\n";
2738 }
2739#endif
2740 }
2741
2742 const SUMOTime arrivalTime = getArrivalTime(t, seen, v, arrivalSpeed);
2743
2744 // compute arrival speed and arrival time if vehicle starts braking now
2745 // if stopping is possible, arrivalTime can be arbitrarily large. A small value keeps fractional times (impatience) meaningful
2746 double arrivalSpeedBraking = 0;
2747 const double bGap = cfModel.brakeGap(v);
2748 if (seen < bGap && !isStopped()) { // XXX: should this use the current speed (at least for the ballistic case)? (Leo) Refs. #2575
2749 // vehicle cannot come to a complete stop in time
2751 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeedEuler(seen, v);
2752 // due to discrete/continuous mismatch (when using Euler update) we have to ensure that braking actually helps
2753 arrivalSpeedBraking = MIN2(arrivalSpeedBraking, arrivalSpeed);
2754 } else {
2755 arrivalSpeedBraking = cfModel.getMinimalArrivalSpeed(seen, myState.mySpeed);
2756 }
2757 }
2758
2759 // estimate leave speed for passing time computation
2760 // l=linkLength, a=accel, t=continuousTime, v=vLeave
2761 // l=v*t + 0.5*a*t^2, solve for t and multiply with a, then add v
2762 const double estimatedLeaveSpeed = MIN2((*link)->getViaLaneOrLane()->getVehicleMaxSpeed(this),
2763 getCarFollowModel().estimateSpeedAfterDistance((*link)->getLength(), arrivalSpeed, getVehicleType().getCarFollowModel().getMaxAccel()));
2764 lfLinks.push_back(DriveProcessItem(*link, v, vLinkWait, setRequest,
2765 arrivalTime, arrivalSpeed,
2766 arrivalSpeedBraking,
2767 seen, estimatedLeaveSpeed));
2768 if ((*link)->getViaLane() == nullptr) {
2769 hadNonInternal = true;
2770 ++view;
2771 }
2772#ifdef DEBUG_PLAN_MOVE
2773 if (DEBUG_COND) {
2774 std::cout << " checkAbort setRequest=" << setRequest << " v=" << v << " seen=" << seen << " dist=" << dist
2775 << " seenNonInternal=" << seenNonInternal
2776 << " seenInternal=" << seenInternal << " length=" << vehicleLength << "\n";
2777 }
2778#endif
2779 // we need to look ahead far enough to see available space for checkRewindLinkLanes
2780 if ((!setRequest || v <= 0 || seen > dist) && hadNonInternal && seenNonInternal > MAX2(vehicleLength * CRLL_LOOK_AHEAD, vehicleLength + seenInternal) && foundRailSignal) {
2781 break;
2782 }
2783 // get the following lane
2784 lane = (*link)->getViaLaneOrLane();
2785 laneMaxV = lane->getVehicleMaxSpeed(this);
2787 laneMaxV = std::numeric_limits<double>::max();
2788 }
2789 // the link was passed
2790 // compute the velocity to use when the link is not blocked by other vehicles
2791 // the vehicle shall be not faster when reaching the next lane than allowed
2792 // speed limits are not emergencies (e.g. when the limit changes suddenly due to TraCI or a variableSpeedSignal)
2793 const double va = MAX2(cfModel.freeSpeed(this, getSpeed(), seen, laneMaxV), vMinComfortable);
2794 v = MIN2(va, v);
2795 if (lane->getEdge().isInternal()) {
2796 seenInternal += lane->getLength();
2797 } else {
2798 seenNonInternal += lane->getLength();
2799 }
2800 // do not restrict results to the current vehicle to allow caching for the current time step
2801 leaderLane = opposite ? lane->getParallelOpposite() : lane;
2802 if (leaderLane == nullptr) {
2803
2804 break;
2805 }
2806 ahead = opposite ? MSLeaderInfo(leaderLane->getWidth()) : leaderLane->getLastVehicleInformation(nullptr, 0);
2807 seen += lane->getLength();
2808 vLinkPass = MIN2(cfModel.estimateSpeedAfterDistance(lane->getLength(), v, cfModel.getMaxAccel()), laneMaxV); // upper bound
2809 lastLink = &lfLinks.back();
2810 }
2811
2812//#ifdef DEBUG_PLAN_MOVE
2813// if(DEBUG_COND){
2814// std::cout << "planMoveInternal found safe speed v = " << v << std::endl;
2815// }
2816//#endif
2817
2818#ifdef PARALLEL_STOPWATCH
2819 myLane->getStopWatch()[0].stop();
2820#endif
2821}
2822
2823
2825MSVehicle::getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const {
2826 const MSCFModel& cfModel = getCarFollowModel();
2827 SUMOTime arrivalTime;
2829 // @note intuitively it would make sense to compare arrivalSpeed with getSpeed() instead of v
2830 // however, due to the current position update rule (ticket #860) the vehicle moves with v in this step
2831 // subtract DELTA_T because t is the time at the end of this step and the movement is not carried out yet
2832 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, v, arrivalSpeed);
2833 } else {
2834 arrivalTime = t - DELTA_T + cfModel.getMinimalArrivalTime(seen, myState.mySpeed, arrivalSpeed);
2835 }
2836 if (isStopped()) {
2837 arrivalTime += MAX2((SUMOTime)0, myStops.front().duration);
2838 }
2839 return arrivalTime;
2840}
2841
2842
2843void
2844MSVehicle::adaptToLeaders(const MSLeaderInfo& ahead, double latOffset,
2845 const double seen, DriveProcessItem* const lastLink,
2846 const MSLane* const lane, double& v, double& vLinkPass) const {
2847 int rightmost;
2848 int leftmost;
2849 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
2850#ifdef DEBUG_PLAN_MOVE
2851 if (DEBUG_COND) std::cout << SIMTIME
2852 << "\nADAPT_TO_LEADERS\nveh=" << getID()
2853 << " lane=" << lane->getID()
2854 << " latOffset=" << latOffset
2855 << " rm=" << rightmost
2856 << " lm=" << leftmost
2857 << " shift=" << ahead.getSublaneOffset()
2858 << " ahead=" << ahead.toString()
2859 << "\n";
2860#endif
2861 /*
2862 if (myLaneChangeModel->getCommittedSpeed() > 0) {
2863 v = MIN2(v, myLaneChangeModel->getCommittedSpeed());
2864 vLinkPass = MIN2(vLinkPass, myLaneChangeModel->getCommittedSpeed());
2865 #ifdef DEBUG_PLAN_MOVE
2866 if (DEBUG_COND) std::cout << " hasCommitted=" << myLaneChangeModel->getCommittedSpeed() << "\n";
2867 #endif
2868 return;
2869 }
2870 */
2871 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
2872 const MSVehicle* pred = ahead[sublane];
2873 if (pred != nullptr && pred != this) {
2874 // @todo avoid multiple adaptations to the same leader
2875 const double predBack = pred->getBackPositionOnLane(lane);
2876 double gap = (lastLink == nullptr
2877 ? predBack - myState.myPos - getVehicleType().getMinGap()
2878 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
2880 if (pred->getLaneChangeModel().isOpposite() || lane == pred->getLaneChangeModel().getShadowLane()) {
2881 // ego might and leader are driving against lane
2882 gap = (lastLink == nullptr
2883 ? myState.myPos - predBack - getVehicleType().getMinGap()
2884 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
2885 } else {
2886 // ego and leader are driving in the same direction as lane (shadowlane for ego)
2887 gap = (lastLink == nullptr
2888 ? predBack - (myLane->getLength() - myState.myPos) - getVehicleType().getMinGap()
2889 : predBack + seen - lane->getLength() - getVehicleType().getMinGap());
2890 }
2891 } else if (pred->getLaneChangeModel().isOpposite() && pred->getLaneChangeModel().getShadowLane() != lane) {
2892 // must react to stopped / dangerous oncoming vehicles
2893 gap += -pred->getVehicleType().getLength() + getVehicleType().getMinGap() - MAX2(getVehicleType().getMinGap(), pred->getVehicleType().getMinGap());
2894 // try to avoid collision in the next second
2895 const double predMaxDist = pred->getSpeed() + pred->getCarFollowModel().getMaxAccel();
2896#ifdef DEBUG_PLAN_MOVE
2897 if (DEBUG_COND) {
2898 std::cout << " fixedGap=" << gap << " predMaxDist=" << predMaxDist << "\n";
2899 }
2900#endif
2901 if (gap < predMaxDist + getSpeed() || pred->getLane() == lane->getBidiLane()) {
2902 gap -= predMaxDist;
2903 }
2904 } else if (pred->getLane() == lane->getBidiLane()) {
2905 gap += -pred->getVehicleType().getLength() - pred->getVehicleType().getMinGap();
2906 // when computing followSpeed, the distance of the vehicle is
2907 // interpreted with the wrong sign. We increase the gap to compensate
2908 gap -= pred->getSpeed() + ACCEL2SPEED(pred->getCarFollowModel().getMaxAccel())
2910 gap = MAX2(0.0, gap);
2911 }
2912#ifdef DEBUG_PLAN_MOVE
2913 if (DEBUG_COND) {
2914 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()) << "\n";
2915 }
2916#endif
2917 adaptToLeader(std::make_pair(pred, gap), seen, lastLink, v, vLinkPass);
2918 }
2919 }
2920}
2921
2922void
2924 double seen,
2925 DriveProcessItem* const lastLink,
2926 double& v, double& vLinkPass) const {
2927 int rightmost;
2928 int leftmost;
2929 ahead.getSubLanes(this, latOffset, rightmost, leftmost);
2930#ifdef DEBUG_PLAN_MOVE
2931 if (DEBUG_COND) std::cout << SIMTIME
2932 << "\nADAPT_TO_LEADERS_DISTANCE\nveh=" << getID()
2933 << " latOffset=" << latOffset
2934 << " rm=" << rightmost
2935 << " lm=" << leftmost
2936 << " ahead=" << ahead.toString()
2937 << "\n";
2938#endif
2939 for (int sublane = rightmost; sublane <= leftmost; ++sublane) {
2940 CLeaderDist predDist = ahead[sublane];
2941 const MSVehicle* pred = predDist.first;
2942 if (pred != nullptr && pred != this) {
2943#ifdef DEBUG_PLAN_MOVE
2944 if (DEBUG_COND) {
2945 std::cout << " pred=" << pred->getID() << " predLane=" << pred->getLane()->getID() << " predPos=" << pred->getPositionOnLane() << " gap=" << predDist.second << "\n";
2946 }
2947#endif
2948 adaptToLeader(predDist, seen, lastLink, v, vLinkPass);
2949 }
2950 }
2951}
2952
2953
2954void
2955MSVehicle::adaptToLeader(const std::pair<const MSVehicle*, double> leaderInfo,
2956 double seen,
2957 DriveProcessItem* const lastLink,
2958 double& v, double& vLinkPass) const {
2959 if (leaderInfo.first != 0) {
2960 assert(leaderInfo.first != 0);
2961 const MSCFModel& cfModel = getCarFollowModel();
2962 double vsafeLeader = 0;
2964 vsafeLeader = -std::numeric_limits<double>::max();
2965 }
2966 bool backOnRoute = true;
2967 if (leaderInfo.second < 0 && lastLink != nullptr && lastLink->myLink != nullptr) {
2968 backOnRoute = false;
2969 // this can either be
2970 // a) a merging situation (leader back is is not our route) or
2971 // b) a minGap violation / collision
2972 MSLane* current = lastLink->myLink->getViaLaneOrLane();
2973 if (leaderInfo.first->getBackLane() == current) {
2974 backOnRoute = true;
2975 } else {
2976 for (MSLane* lane : getBestLanesContinuation()) {
2977 if (lane == current) {
2978 break;
2979 }
2980 if (leaderInfo.first->getBackLane() == lane) {
2981 backOnRoute = true;
2982 }
2983 }
2984 }
2985#ifdef DEBUG_PLAN_MOVE
2986 if (DEBUG_COND) {
2987 std::cout << SIMTIME << " current=" << current->getID() << " leaderBackLane=" << leaderInfo.first->getBackLane()->getID() << " backOnRoute=" << backOnRoute << "\n";
2988 }
2989#endif
2990 if (!backOnRoute) {
2991 double stopDist = seen - current->getLength() - POSITION_EPS;
2992 if (lastLink->myLink->getInternalLaneBefore() != nullptr) {
2993 // do not drive onto the junction conflict area
2994 stopDist -= lastLink->myLink->getInternalLaneBefore()->getLength();
2995 }
2996 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), stopDist);
2997 }
2998 }
2999 if (backOnRoute) {
3000 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3001 }
3002 if (lastLink != nullptr) {
3003 const double futureVSafe = cfModel.followSpeed(this, lastLink->accelV, leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first, MSCFModel::CalcReason::FUTURE);
3004 lastLink->adaptLeaveSpeed(futureVSafe);
3005#ifdef DEBUG_PLAN_MOVE
3006 if (DEBUG_COND) {
3007 std::cout << " vlinkpass=" << lastLink->myVLinkPass << " futureVSafe=" << futureVSafe << "\n";
3008 }
3009#endif
3010 }
3011 v = MIN2(v, vsafeLeader);
3012 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3013#ifdef DEBUG_PLAN_MOVE
3014 if (DEBUG_COND) std::cout
3015 << SIMTIME
3016 //std::cout << std::setprecision(10);
3017 << " veh=" << getID()
3018 << " lead=" << leaderInfo.first->getID()
3019 << " leadSpeed=" << leaderInfo.first->getSpeed()
3020 << " gap=" << leaderInfo.second
3021 << " leadLane=" << leaderInfo.first->getLane()->getID()
3022 << " predPos=" << leaderInfo.first->getPositionOnLane()
3023 << " myLane=" << myLane->getID()
3024 << " v=" << v
3025 << " vSafeLeader=" << vsafeLeader
3026 << " vLinkPass=" << vLinkPass
3027 << "\n";
3028#endif
3029 }
3030}
3031
3032
3033void
3034MSVehicle::adaptToJunctionLeader(const std::pair<const MSVehicle*, double> leaderInfo,
3035 const double seen, DriveProcessItem* const lastLink,
3036 const MSLane* const lane, double& v, double& vLinkPass,
3037 double distToCrossing) const {
3038 if (leaderInfo.first != 0) {
3039 const MSCFModel& cfModel = getCarFollowModel();
3040 double vsafeLeader = 0;
3042 vsafeLeader = -std::numeric_limits<double>::max();
3043 }
3044 if (leaderInfo.second >= 0) {
3045 vsafeLeader = cfModel.followSpeed(this, getSpeed(), leaderInfo.second, leaderInfo.first->getSpeed(), leaderInfo.first->getCurrentApparentDecel(), leaderInfo.first);
3046 } else if (leaderInfo.first != this) {
3047 // the leading, in-lapping vehicle is occupying the complete next lane
3048 // stop before entering this lane
3049 vsafeLeader = cfModel.stopSpeed(this, getSpeed(), seen - lane->getLength() - POSITION_EPS);
3050#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3051 if (DEBUG_COND) {
3052 std::cout << SIMTIME << " veh=" << getID() << " stopping before junction: lane=" << lane->getID() << " seen=" << seen
3053 << " laneLength=" << lane->getLength()
3054 << " stopDist=" << seen - lane->getLength() - POSITION_EPS
3055 << " vsafeLeader=" << vsafeLeader
3056 << " distToCrossing=" << distToCrossing
3057 << "\n";
3058 }
3059#endif
3060 }
3061 if (distToCrossing >= 0) {
3062 // can the leader still stop in the way?
3063 const double vStop = cfModel.stopSpeed(this, getSpeed(), distToCrossing - getVehicleType().getMinGap());
3064 if (leaderInfo.first == this) {
3065 // braking for pedestrian
3066 vsafeLeader = vStop;
3067#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3068 if (DEBUG_COND) {
3069 std::cout << " breaking for pedestrian distToCrossing=" << distToCrossing << " vStop=" << vStop << "\n";
3070 }
3071#endif
3072 } else if (leaderInfo.second == -std::numeric_limits<double>::max()) {
3073 // drive up to the crossing point and stop
3074#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3075 if (DEBUG_COND) {
3076 std::cout << " stop at crossing point for critical leader\n";
3077 };
3078#endif
3079 vsafeLeader = MAX2(vsafeLeader, vStop);
3080 } else {
3081 const double leaderDistToCrossing = distToCrossing - leaderInfo.second;
3082 // estimate the time at which the leader has gone past the crossing point
3083 const double leaderPastCPTime = leaderDistToCrossing / MAX2(leaderInfo.first->getSpeed(), SUMO_const_haltingSpeed);
3084 // reach distToCrossing after that time
3085 // avgSpeed * leaderPastCPTime = distToCrossing
3086 // ballistic: avgSpeed = (getSpeed + vFinal) / 2
3087 const double vFinal = MAX2(getSpeed(), 2 * (distToCrossing - getVehicleType().getMinGap()) / leaderPastCPTime - getSpeed());
3088 const double v2 = getSpeed() + ACCEL2SPEED((vFinal - getSpeed()) / leaderPastCPTime);
3089 vsafeLeader = MAX2(vsafeLeader, MIN2(v2, vStop));
3090#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3091 if (DEBUG_COND) {
3092 std::cout << " driving up to the crossing point (distToCrossing=" << distToCrossing << ")"
3093 << " leaderPastCPTime=" << leaderPastCPTime
3094 << " vFinal=" << vFinal
3095 << " v2=" << v2
3096 << " vStop=" << vStop
3097 << " vsafeLeader=" << vsafeLeader << "\n";
3098 }
3099#endif
3100 }
3101 }
3102 if (lastLink != nullptr) {
3103 lastLink->adaptLeaveSpeed(vsafeLeader);
3104 }
3105 v = MIN2(v, vsafeLeader);
3106 vLinkPass = MIN2(vLinkPass, vsafeLeader);
3107#ifdef DEBUG_PLAN_MOVE
3108 if (DEBUG_COND) std::cout
3109 << SIMTIME
3110 //std::cout << std::setprecision(10);
3111 << " veh=" << getID()
3112 << " lead=" << leaderInfo.first->getID()
3113 << " leadSpeed=" << leaderInfo.first->getSpeed()
3114 << " gap=" << leaderInfo.second
3115 << " leadLane=" << leaderInfo.first->getLane()->getID()
3116 << " predPos=" << leaderInfo.first->getPositionOnLane()
3117 << " seen=" << seen
3118 << " lane=" << lane->getID()
3119 << " myLane=" << myLane->getID()
3120 << " dTC=" << distToCrossing
3121 << " v=" << v
3122 << " vSafeLeader=" << vsafeLeader
3123 << " vLinkPass=" << vLinkPass
3124 << "\n";
3125#endif
3126 }
3127}
3128
3129
3130void
3131MSVehicle::checkLinkLeaderCurrentAndParallel(const MSLink* link, const MSLane* lane, double seen,
3132 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest) const {
3134 // we want to pass the link but need to check for foes on internal lanes
3135 checkLinkLeader(link, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest);
3136 if (myLaneChangeModel->getShadowLane() != nullptr) {
3137 const MSLink* const parallelLink = link->getParallelLink(myLaneChangeModel->getShadowDirection());
3138 if (parallelLink != nullptr) {
3139 checkLinkLeader(parallelLink, lane, seen, lastLink, v, vLinkPass, vLinkWait, setRequest, true);
3140 }
3141 }
3142 }
3143
3144}
3145
3146void
3147MSVehicle::checkLinkLeader(const MSLink* link, const MSLane* lane, double seen,
3148 DriveProcessItem* const lastLink, double& v, double& vLinkPass, double& vLinkWait, bool& setRequest,
3149 bool isShadowLink) const {
3150#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3151 if (DEBUG_COND) {
3152 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3153 }
3154#endif
3155 const MSLink::LinkLeaders linkLeaders = link->getLeaderInfo(this, seen, nullptr, isShadowLink);
3156#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3157 if (DEBUG_COND) {
3158 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3159 }
3160#endif
3161 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3162 // the vehicle to enter the junction first has priority
3163 const MSVehicle* leader = (*it).vehAndGap.first;
3164 if (leader == nullptr) {
3165 // leader is a pedestrian. Passing 'this' as a dummy.
3166#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3167 if (DEBUG_COND) {
3168 std::cout << SIMTIME << " veh=" << getID() << " is blocked on link to " << link->getViaLaneOrLane()->getID() << " by pedestrian. dist=" << it->distToCrossing << "\n";
3169 }
3170#endif
3173#ifdef DEBUG_PLAN_MOVE
3174 if (DEBUG_COND) {
3175 std::cout << SIMTIME << " veh=" << getID() << " is ignoring pedestrian (jmIgnoreJunctionFoeProb)\n";
3176 }
3177#endif
3178 continue;
3179 }
3180 adaptToJunctionLeader(std::make_pair(this, -1), seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3181 } else if (isLeader(link, leader, (*it).vehAndGap.second) || (*it).inTheWay) {
3184#ifdef DEBUG_PLAN_MOVE
3185 if (DEBUG_COND) {
3186 std::cout << SIMTIME << " veh=" << getID() << " is ignoring linkLeader=" << leader->getID() << " (jmIgnoreJunctionFoeProb)\n";
3187 }
3188#endif
3189 continue;
3190 }
3192 // sibling link (XXX: could also be partial occupator where this check fails)
3193 &leader->getLane()->getEdge() == &lane->getEdge()) {
3194 // check for sublane obstruction (trivial for sibling link leaders)
3195 const MSLane* conflictLane = link->getInternalLaneBefore();
3196 MSLeaderInfo linkLeadersAhead = MSLeaderInfo(conflictLane->getWidth());
3197 linkLeadersAhead.addLeader(leader, false, 0); // assume sibling lane has the same geometry as the leader lane
3198 const double latOffset = isShadowLink ? (getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge()) : 0;
3199 // leader is neither on lane nor conflictLane (the conflict is only established geometrically)
3200 adaptToLeaders(linkLeadersAhead, latOffset, seen, lastLink, leader->getLane(), v, vLinkPass);
3201#ifdef DEBUG_PLAN_MOVE
3202 if (DEBUG_COND) {
3203 std::cout << SIMTIME << " veh=" << getID()
3204 << " siblingFoe link=" << link->getViaLaneOrLane()->getID()
3205 << " isShadowLink=" << isShadowLink
3206 << " lane=" << lane->getID()
3207 << " foe=" << leader->getID()
3208 << " foeLane=" << leader->getLane()->getID()
3209 << " latOffset=" << latOffset
3210 << " latOffsetFoe=" << leader->getLatOffset(lane)
3211 << " linkLeadersAhead=" << linkLeadersAhead.toString()
3212 << "\n";
3213 }
3214#endif
3215 } else {
3216#ifdef DEBUG_PLAN_MOVE
3217 if (DEBUG_COND) {
3218 std::cout << SIMTIME << " veh=" << getID() << " linkLeader=" << leader->getID() << " gap=" << it->vehAndGap.second
3219 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3220 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3221 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3222 << "\n";
3223 }
3224#endif
3225 adaptToJunctionLeader(it->vehAndGap, seen, lastLink, lane, v, vLinkPass, it->distToCrossing);
3226 }
3227 if (lastLink != nullptr) {
3228 // we are not yet on the junction with this linkLeader.
3229 // at least we can drive up to the previous link and stop there
3230 v = MAX2(v, lastLink->myVLinkWait);
3231 }
3232 // if blocked by a leader from the same or next lane we must yield our request
3233 // also, if blocked by a stopped or blocked leader
3235 //&& leader->getSpeed() < SUMO_const_haltingSpeed
3237 || leader->getLane()->getLogicalPredecessorLane() == myLane
3238 || leader->isStopped()
3240 setRequest = false;
3241#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3242 if (DEBUG_COND) {
3243 std::cout << " aborting request\n";
3244 }
3245#endif
3246 if (lastLink != nullptr && leader->getLane()->getLogicalPredecessorLane() == myLane) {
3247 // we are not yet on the junction so must abort that request as well
3248 // (or maybe we are already on the junction and the leader is a partial occupator beyond)
3249 lastLink->mySetRequest = false;
3250#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3251 if (DEBUG_COND) {
3252 std::cout << " aborting previous request\n";
3253 }
3254#endif
3255 }
3256 }
3257 }
3258#ifdef DEBUG_PLAN_MOVE_LEADERINFO
3259 else {
3260 if (DEBUG_COND) {
3261 std::cout << SIMTIME << " veh=" << getID() << " ignoring leader " << leader->getID() << " gap=" << (*it).vehAndGap.second << " dtC=" << (*it).distToCrossing
3262 << " ET=" << myJunctionEntryTime << " lET=" << leader->myJunctionEntryTime
3263 << " ETN=" << myJunctionEntryTimeNeverYield << " lETN=" << leader->myJunctionEntryTimeNeverYield
3264 << " CET=" << myJunctionConflictEntryTime << " lCET=" << leader->myJunctionConflictEntryTime
3265 << "\n";
3266 }
3267 }
3268#endif
3269 }
3270 // if this is the link between two internal lanes we may have to slow down for pedestrians
3271 vLinkWait = MIN2(vLinkWait, v);
3272}
3273
3274
3275double
3276MSVehicle::getDeltaPos(const double accel) const {
3277 double vNext = myState.mySpeed + ACCEL2SPEED(accel);
3279 // apply implicit Euler positional update
3280 return SPEED2DIST(MAX2(vNext, 0.));
3281 } else {
3282 // apply ballistic update
3283 if (vNext >= 0) {
3284 // assume constant acceleration during this time step
3285 return SPEED2DIST(myState.mySpeed + 0.5 * ACCEL2SPEED(accel));
3286 } else {
3287 // negative vNext indicates a stop within the middle of time step
3288 // The corresponding stop time is s = mySpeed/deceleration \in [0,dt], and the
3289 // covered distance is therefore deltaPos = mySpeed*s - 0.5*deceleration*s^2.
3290 // Here, deceleration = (myState.mySpeed - vNext)/dt is the constant deceleration
3291 // until the vehicle stops.
3292 return -SPEED2DIST(0.5 * myState.mySpeed * myState.mySpeed / ACCEL2SPEED(accel));
3293 }
3294 }
3295}
3296
3297void
3298MSVehicle::processLinkApproaches(double& vSafe, double& vSafeMin, double& vSafeMinDist) {
3299
3300 // Speed limit due to zipper merging
3301 double vSafeZipper = std::numeric_limits<double>::max();
3302
3303 myHaveToWaitOnNextLink = false;
3304 bool canBrakeVSafeMin = false;
3305
3306 // Get safe velocities from DriveProcessItems.
3307 assert(myLFLinkLanes.size() != 0 || isRemoteControlled());
3308 for (const DriveProcessItem& dpi : myLFLinkLanes) {
3309 MSLink* const link = dpi.myLink;
3310
3311#ifdef DEBUG_EXEC_MOVE
3312 if (DEBUG_COND) {
3313 std::cout
3314 << SIMTIME
3315 << " veh=" << getID()
3316 << " link=" << (link == 0 ? "NULL" : link->getViaLaneOrLane()->getID())
3317 << " req=" << dpi.mySetRequest
3318 << " vP=" << dpi.myVLinkPass
3319 << " vW=" << dpi.myVLinkWait
3320 << " d=" << dpi.myDistance
3321 << "\n";
3322 gDebugFlag1 = true; // See MSLink_DEBUG_OPENED
3323 }
3324#endif
3325
3326 // the vehicle must change the lane on one of the next lanes (XXX: refs to code further below???, Leo)
3327 if (link != nullptr && dpi.mySetRequest) {
3328
3329 const LinkState ls = link->getState();
3330 // vehicles should brake when running onto a yellow light if the distance allows to halt in front
3331 const bool yellow = link->haveYellow();
3332 const bool canBrake = (dpi.myDistance > getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.)
3334 assert(link->getLaneBefore() != nullptr);
3335 const bool beyondStopLine = dpi.myDistance < link->getLaneBefore()->getVehicleStopOffset(this);
3336 const bool ignoreRedLink = ignoreRed(link, canBrake) || beyondStopLine;
3337 if (yellow && canBrake && !ignoreRedLink) {
3338 vSafe = dpi.myVLinkWait;
3340#ifdef DEBUG_CHECKREWINDLINKLANES
3341 if (DEBUG_COND) {
3342 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (yellow)\n";
3343 }
3344#endif
3345 break;
3346 }
3347 const bool influencerPrio = (myInfluencer != nullptr && !myInfluencer->getRespectJunctionPriority());
3348 MSLink::BlockingFoes collectFoes;
3349 bool opened = (yellow || influencerPrio
3350 || link->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3352 canBrake ? getImpatience() : 1,
3355 ls == LINKSTATE_ZIPPER ? &collectFoes : nullptr,
3356 ignoreRedLink, this));
3357 if (opened && myLaneChangeModel->getShadowLane() != nullptr) {
3358 const MSLink* const parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
3359 if (parallelLink != nullptr) {
3360 const double shadowLatPos = getLateralPositionOnLane() - myLaneChangeModel->getShadowDirection() * 0.5 * (
3362 opened = yellow || influencerPrio || (opened && parallelLink->opened(dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
3365 getWaitingTime(), shadowLatPos, nullptr,
3366 ignoreRedLink, this));
3367#ifdef DEBUG_EXEC_MOVE
3368 if (DEBUG_COND) {
3369 std::cout << SIMTIME
3370 << " veh=" << getID()
3371 << " shadowLane=" << myLaneChangeModel->getShadowLane()->getID()
3372 << " shadowDir=" << myLaneChangeModel->getShadowDirection()
3373 << " parallelLink=" << (parallelLink == 0 ? "NULL" : parallelLink->getViaLaneOrLane()->getID())
3374 << " opened=" << opened
3375 << "\n";
3376 }
3377#endif
3378 }
3379 }
3380 // vehicles should decelerate when approaching a minor link
3381#ifdef DEBUG_EXEC_MOVE
3382 if (DEBUG_COND) {
3383 std::cout << SIMTIME
3384 << " opened=" << opened
3385 << " influencerPrio=" << influencerPrio
3386 << " linkPrio=" << link->havePriority()
3387 << " lastContMajor=" << link->lastWasContMajor()
3388 << " isCont=" << link->isCont()
3389 << " ignoreRed=" << ignoreRedLink
3390 << "\n";
3391 }
3392#endif
3393 if (opened && !influencerPrio && !link->havePriority() && !link->lastWasContMajor() && !link->isCont() && !ignoreRedLink) {
3394 double visibilityDistance = link->getFoeVisibilityDistance();
3395 double determinedFoePresence = dpi.myDistance <= visibilityDistance;
3396 if (!determinedFoePresence && (canBrake || !yellow)) {
3397 vSafe = dpi.myVLinkWait;
3399#ifdef DEBUG_CHECKREWINDLINKLANES
3400 if (DEBUG_COND) {
3401 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (minor)\n";
3402 }
3403#endif
3404 break;
3405 } else {
3406 // past the point of no return. we need to drive fast enough
3407 // to make it across the link. However, minor slowdowns
3408 // should be permissible to follow leading traffic safely
3409 // basically, this code prevents dawdling
3410 // (it's harder to do this later using
3411 // SUMO_ATTR_JM_SIGMA_MINOR because we don't know whether the
3412 // vehicle is already too close to stop at that part of the code)
3413 //
3414 // XXX: There is a problem in subsecond simulation: If we cannot
3415 // make it across the minor link in one step, new traffic
3416 // could appear on a major foe link and cause a collision. Refs. #1845, #2123
3417 vSafeMinDist = dpi.myDistance; // distance that must be covered
3419 vSafeMin = MIN3((double)DIST2SPEED(vSafeMinDist + POSITION_EPS), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3420 } else {
3421 vSafeMin = MIN3((double)DIST2SPEED(2 * vSafeMinDist + NUMERICAL_EPS) - getSpeed(), dpi.myVLinkPass, getCarFollowModel().maxNextSafeMin(getSpeed(), this));
3422 }
3423 canBrakeVSafeMin = canBrake;
3424#ifdef DEBUG_EXEC_MOVE
3425 if (DEBUG_COND) {
3426 std::cout << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << " canBrake=" << canBrake << "\n";
3427 }
3428#endif
3429 }
3430 }
3431 // have waited; may pass if opened...
3432 if (opened) {
3433 vSafe = dpi.myVLinkPass;
3434 if (vSafe < getCarFollowModel().getMaxDecel() && vSafe <= dpi.myVLinkWait && vSafe < getCarFollowModel().maxNextSpeed(getSpeed(), this)) {
3435 // this vehicle is probably not gonna drive across the next junction (heuristic)
3437#ifdef DEBUG_CHECKREWINDLINKLANES
3438 if (DEBUG_COND) {
3439 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (very slow)\n";
3440 }
3441#endif
3442 }
3443 } else if (link->getState() == LINKSTATE_ZIPPER) {
3444 vSafeZipper = MIN2(vSafeZipper,
3445 link->getZipperSpeed(this, dpi.myDistance, dpi.myVLinkPass, dpi.myArrivalTime, &collectFoes));
3446 } else {
3447 vSafe = dpi.myVLinkWait;
3449#ifdef DEBUG_CHECKREWINDLINKLANES
3450 if (DEBUG_COND) {
3451 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (closed)\n";
3452 }
3453#endif
3454#ifdef DEBUG_EXEC_MOVE
3455 if (DEBUG_COND) {
3456 std::cout << SIMTIME << " braking for closed link=" << link->getViaLaneOrLane()->getID() << "\n";
3457 }
3458#endif
3459 break;
3460 }
3461 } else {
3462 if (link != nullptr && link->getInternalLaneBefore() != nullptr && myLane->isInternal() && link->getJunction() == myLane->getEdge().getToJunction()) {
3463 // blocked on the junction. yield request so other vehicles may
3464 // become junction leader
3465#ifdef DEBUG_EXEC_MOVE
3466 if (DEBUG_COND) {
3467 std::cout << SIMTIME << " reseting junctionEntryTime at junction '" << link->getJunction()->getID() << "' beause of non-request exitLink\n";
3468 }
3469#endif
3472 }
3473 // we have: i->link == 0 || !i->setRequest
3474 vSafe = dpi.myVLinkWait;
3475 if (vSafe < getSpeed()) {
3477#ifdef DEBUG_CHECKREWINDLINKLANES
3478 if (DEBUG_COND) {
3479 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, braking) vSafe=" << vSafe << "\n";
3480 }
3481#endif
3482 } else if (vSafe < SUMO_const_haltingSpeed) {
3484#ifdef DEBUG_CHECKREWINDLINKLANES
3485 if (DEBUG_COND) {
3486 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (no request, stopping)\n";
3487 }
3488#endif
3489 }
3490 if (link == nullptr && myLFLinkLanes.size() == 1
3491 && getBestLanesContinuation().size() > 1
3492 && getBestLanesContinuation()[1]->hadPermissionChanges()
3493 && myLane->getFirstAnyVehicle() == this) {
3494 // temporal lane closing without notification, visible to the
3495 // vehicle at the front of the queue
3496 updateBestLanes(true);
3497 //std::cout << SIMTIME << " veh=" << getID() << " updated bestLanes=" << toString(getBestLanesContinuation()) << "\n";
3498 }
3499 break;
3500 }
3501 }
3502
3503//#ifdef DEBUG_EXEC_MOVE
3504// if (DEBUG_COND) {
3505// std::cout << "\nvCurrent = " << toString(getSpeed(), 24) << "" << std::endl;
3506// std::cout << "vSafe = " << toString(vSafe, 24) << "" << std::endl;
3507// std::cout << "vSafeMin = " << toString(vSafeMin, 24) << "" << std::endl;
3508// std::cout << "vSafeMinDist = " << toString(vSafeMinDist, 24) << "" << std::endl;
3509//
3510// double gap = getLeader().second;
3511// std::cout << "gap = " << toString(gap, 24) << std::endl;
3512// std::cout << "vSafeStoppedLeader = " << toString(getCarFollowModel().stopSpeed(this, getSpeed(), gap, MSCFModel::CalcReason::FUTURE), 24)
3513// << "\n" << std::endl;
3514// }
3515//#endif
3516
3517 if ((MSGlobals::gSemiImplicitEulerUpdate && vSafe + NUMERICAL_EPS < vSafeMin)
3518 || (!MSGlobals::gSemiImplicitEulerUpdate && (vSafe + NUMERICAL_EPS < vSafeMin && vSafeMin != 0))) { // this might be good for the euler case as well
3519 // XXX: (Leo) This often called stopSpeed with vSafeMinDist==0 (for the ballistic update), since vSafe can become negative
3520 // 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
3521#ifdef DEBUG_EXEC_MOVE
3522 if (DEBUG_COND) {
3523 std::cout << "vSafeMin Problem? vSafe=" << vSafe << " vSafeMin=" << vSafeMin << " vSafeMinDist=" << vSafeMinDist << std::endl;
3524 }
3525#endif
3526 if (canBrakeVSafeMin && vSafe < getSpeed()) {
3527 // cannot drive across a link so we need to stop before it
3528 vSafe = MIN2(vSafe, MAX2(getCarFollowModel().minNextSpeed(getSpeed(), this),
3529 getCarFollowModel().stopSpeed(this, getSpeed(), vSafeMinDist)));
3530 vSafeMin = 0;
3532#ifdef DEBUG_CHECKREWINDLINKLANES
3533 if (DEBUG_COND) {
3534 std::cout << SIMTIME << " veh=" << getID() << " haveToWait (vSafe=" << vSafe << " < vSafeMin=" << vSafeMin << ")\n";
3535 }
3536#endif
3537 } else {
3538 // if the link is yellow or visibility distance is large
3539 // then we might not make it across the link in one step anyway..
3540 // Possibly, the lane after the intersection has a lower speed limit so
3541 // we really need to drive slower already
3542 // -> keep driving without dawdling
3543 vSafeMin = vSafe;
3544 }
3545 }
3546
3547 // vehicles inside a roundabout should maintain their requests
3548 if (myLane->getEdge().isRoundabout()) {
3549 myHaveToWaitOnNextLink = false;
3550 }
3551
3552 vSafe = MIN2(vSafe, vSafeZipper);
3553}
3554
3555
3556double
3557MSVehicle::processTraCISpeedControl(double vSafe, double vNext) {
3558 if (myInfluencer != nullptr) {
3560#ifdef DEBUG_TRACI
3561 if DEBUG_COND2(this) {
3562 std::cout << SIMTIME << " MSVehicle::processTraCISpeedControl() for vehicle '" << getID() << "'"
3563 << " vSafe=" << vSafe << " (init)vNext=" << vNext;
3564 }
3565#endif
3568 }
3569 const double vMax = getVehicleType().getCarFollowModel().maxNextSpeed(myState.mySpeed, this);
3572 vMin = MAX2(0., vMin);
3573 }
3574 vNext = myInfluencer->influenceSpeed(MSNet::getInstance()->getCurrentTimeStep(), vNext, vSafe, vMin, vMax);
3575#ifdef DEBUG_TRACI
3576 if DEBUG_COND2(this) {
3577 std::cout << " (processed)vNext=" << vNext << std::endl;
3578 }
3579#endif
3580 }
3581 return vNext;
3582}
3583
3584
3585void
3587#ifdef DEBUG_ACTIONSTEPS
3588 if (DEBUG_COND) {
3589 std::cout << SIMTIME << " veh=" << getID() << " removePassedDriveItems()\n"
3590 << " Current items: ";
3591 for (auto& j : myLFLinkLanes) {
3592 if (j.myLink == 0) {
3593 std::cout << "\n Stop at distance " << j.myDistance;
3594 } else {
3595 const MSLane* to = j.myLink->getViaLaneOrLane();
3596 const MSLane* from = j.myLink->getLaneBefore();
3597 std::cout << "\n Link at distance " << j.myDistance << ": '"
3598 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3599 }
3600 }
3601 std::cout << "\n myNextDriveItem: ";
3602 if (myLFLinkLanes.size() != 0) {
3603 if (myNextDriveItem->myLink == 0) {
3604 std::cout << "\n Stop at distance " << myNextDriveItem->myDistance;
3605 } else {
3606 const MSLane* to = myNextDriveItem->myLink->getViaLaneOrLane();
3607 const MSLane* from = myNextDriveItem->myLink->getLaneBefore();
3608 std::cout << "\n Link at distance " << myNextDriveItem->myDistance << ": '"
3609 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3610 }
3611 }
3612 std::cout << std::endl;
3613 }
3614#endif
3615 for (auto j = myLFLinkLanes.begin(); j != myNextDriveItem; ++j) {
3616#ifdef DEBUG_ACTIONSTEPS
3617 if (DEBUG_COND) {
3618 std::cout << " Removing item: ";
3619 if (j->myLink == 0) {
3620 std::cout << "Stop at distance " << j->myDistance;
3621 } else {
3622 const MSLane* to = j->myLink->getViaLaneOrLane();
3623 const MSLane* from = j->myLink->getLaneBefore();
3624 std::cout << "Link at distance " << j->myDistance << ": '"
3625 << (from == 0 ? "NONE" : from->getID()) << "' -> '" << (to == 0 ? "NONE" : to->getID()) << "'";
3626 }
3627 std::cout << std::endl;
3628 }
3629#endif
3630 if (j->myLink != nullptr) {
3631 j->myLink->removeApproaching(this);
3632 }
3633 }
3636}
3637
3638
3639void
3641#ifdef DEBUG_ACTIONSTEPS
3642 if (DEBUG_COND) {
3643 std::cout << SIMTIME << " updateDriveItems(), veh='" << getID() << "' (lane: '" << getLane()->getID() << "')\nCurrent drive items:" << std::endl;
3644 for (const auto& dpi : myLFLinkLanes) {
3645 std::cout
3646 << " vPass=" << dpi.myVLinkPass
3647 << " vWait=" << dpi.myVLinkWait
3648 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
3649 << " request=" << dpi.mySetRequest
3650 << "\n";
3651 }
3652 std::cout << " myNextDriveItem's linked lane: " << (myNextDriveItem->myLink == 0 ? "NULL" : myNextDriveItem->myLink->getViaLaneOrLane()->getID()) << std::endl;
3653 }
3654#endif
3655 if (myLFLinkLanes.size() == 0) {
3656 // nothing to update
3657 return;
3658 }
3659 const MSLink* nextPlannedLink = nullptr;
3660// auto i = myLFLinkLanes.begin();
3661 auto i = myNextDriveItem;
3662 while (i != myLFLinkLanes.end() && nextPlannedLink == nullptr) {
3663 nextPlannedLink = i->myLink;
3664 ++i;
3665 }
3666
3667 if (nextPlannedLink == nullptr) {
3668 // No link for upcoming item -> no need for an update
3669#ifdef DEBUG_ACTIONSTEPS
3670 if (DEBUG_COND) {
3671 std::cout << "Found no link-related drive item." << std::endl;
3672 }
3673#endif
3674 return;
3675 }
3676
3677 if (getLane() == nextPlannedLink->getLaneBefore()) {
3678 // Current lane approaches the stored next link, i.e. no LC happend and no update is required.
3679#ifdef DEBUG_ACTIONSTEPS
3680 if (DEBUG_COND) {
3681 std::cout << "Continuing on planned lane sequence, no update required." << std::endl;
3682 }
3683#endif
3684 return;
3685 }
3686 // Lane must have been changed, determine the change direction
3687 const MSLink* parallelLink = nextPlannedLink->getParallelLink(1);
3688 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
3689 // lcDir = 1;
3690 } else {
3691 parallelLink = nextPlannedLink->getParallelLink(-1);
3692 if (parallelLink != nullptr && parallelLink->getLaneBefore() == getLane()) {
3693 // lcDir = -1;
3694 } else {
3695 // If the vehicle's current lane is not the approaching lane for the next
3696 // drive process item's link, it is expected to lead to a parallel link,
3697 // XXX: What if the lc was an overtaking maneuver and there is no upcoming link?
3698 // Then a stop item should be scheduled! -> TODO!
3699 //assert(false);
3700 return;
3701 }
3702 }
3703#ifdef DEBUG_ACTIONSTEPS
3704 if (DEBUG_COND) {
3705 std::cout << "Changed lane. Drive items will be updated along the current lane continuation." << std::endl;
3706 }
3707#endif
3708 // Trace link sequence along current best lanes and transfer drive items to the corresponding links
3709// DriveItemVector::iterator driveItemIt = myLFLinkLanes.begin();
3710 DriveItemVector::iterator driveItemIt = myNextDriveItem;
3711 // In the loop below, lane holds the currently considered lane on the vehicles continuation (including internal lanes)
3712 const MSLane* lane = myLane;
3713 assert(myLane == parallelLink->getLaneBefore());
3714 // *lit is a pointer to the next lane in best continuations for the current lane (always non-internal)
3715 std::vector<MSLane*>::const_iterator bestLaneIt = getBestLanesContinuation().begin() + 1;
3716 // Pointer to the new link for the current drive process item
3717 MSLink* newLink = nullptr;
3718 while (driveItemIt != myLFLinkLanes.end()) {
3719 if (driveItemIt->myLink == nullptr) {
3720 // Items not related to a specific link are not updated
3721 // (XXX: when a stop item corresponded to a dead end, which is overcome by the LC that made
3722 // the update necessary, this may slow down the vehicle's continuation on the new lane...)
3723 ++driveItemIt;
3724 continue;
3725 }
3726 // Continuation links for current best lanes are less than for the former drive items (myLFLinkLanes)
3727 // We just remove the leftover link-items, as they cannot be mapped to new links.
3728 if (bestLaneIt == getBestLanesContinuation().end()) {
3729#ifdef DEBUG_ACTIONSTEPS
3730 if (DEBUG_COND) {
3731 std::cout << "Reached end of the new continuation sequence. Erasing leftover link-items." << std::endl;
3732 }
3733#endif
3734 while (driveItemIt != myLFLinkLanes.end()) {
3735 if (driveItemIt->myLink == nullptr) {
3736 ++driveItemIt;
3737 continue;
3738 } else {
3739 driveItemIt->myLink->removeApproaching(this);
3740 driveItemIt = myLFLinkLanes.erase(driveItemIt);
3741 }
3742 }
3743 break;
3744 }
3745 // Do the actual link-remapping for the item. And un/register approaching information on the corresponding links
3746 const MSLane* const target = *bestLaneIt;
3747 assert(!target->isInternal());
3748 newLink = nullptr;
3749 for (MSLink* const link : lane->getLinkCont()) {
3750 if (link->getLane() == target) {
3751 newLink = link;
3752 break;
3753 }
3754 }
3755
3756 if (newLink == driveItemIt->myLink) {
3757 // new continuation merged into previous - stop update
3758#ifdef DEBUG_ACTIONSTEPS
3759 if (DEBUG_COND) {
3760 std::cout << "Old and new continuation sequences merge at link\n"
3761 << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'"
3762 << "\nNo update beyond merge required." << std::endl;
3763 }
3764#endif
3765 break;
3766 }
3767
3768#ifdef DEBUG_ACTIONSTEPS
3769 if (DEBUG_COND) {
3770 std::cout << "lane=" << lane->getID() << "\nUpdating link\n '" << driveItemIt->myLink->getLaneBefore()->getID() << "'->'" << driveItemIt->myLink->getViaLaneOrLane()->getID() << "'"
3771 << "==> " << "'" << newLink->getLaneBefore()->getID() << "'->'" << newLink->getViaLaneOrLane()->getID() << "'" << std::endl;
3772 }
3773#endif
3774 newLink->setApproaching(this, driveItemIt->myLink->getApproaching(this));
3775 driveItemIt->myLink->removeApproaching(this);
3776 driveItemIt->myLink = newLink;
3777 lane = newLink->getViaLaneOrLane();
3778 ++driveItemIt;
3779 if (!lane->isInternal()) {
3780 ++bestLaneIt;
3781 }
3782 }
3783#ifdef DEBUG_ACTIONSTEPS
3784 if (DEBUG_COND) {
3785 std::cout << "Updated drive items:" << std::endl;
3786 for (const auto& dpi : myLFLinkLanes) {
3787 std::cout
3788 << " vPass=" << dpi.myVLinkPass
3789 << " vWait=" << dpi.myVLinkWait
3790 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
3791 << " request=" << dpi.mySetRequest
3792 << "\n";
3793 }
3794 }
3795#endif
3796}
3797
3798
3799void
3801 // To avoid casual blinking brake lights at high speeds due to dawdling of the
3802 // leading vehicle, we don't show brake lights when the deceleration could be caused
3803 // by frictional forces and air resistance (i.e. proportional to v^2, coefficient could be adapted further)
3804 double pseudoFriction = (0.05 + 0.005 * getSpeed()) * getSpeed();
3805 bool brakelightsOn = vNext < getSpeed() - ACCEL2SPEED(pseudoFriction);
3806
3807 if (vNext <= SUMO_const_haltingSpeed) {
3808 brakelightsOn = true;
3809 }
3810 if (brakelightsOn && !isStopped()) {
3812 } else {
3814 }
3815}
3816
3817
3818void
3823 } else {
3824 myWaitingTime = 0;
3826 }
3827}
3828
3829
3830void
3832 // update time loss (depends on the updated edge)
3833 if (!isStopped()) {
3834 const double vmax = myLane->getVehicleMaxSpeed(this);
3835 if (vmax > 0) {
3836 myTimeLoss += TS * (vmax - vNext) / vmax;
3837 }
3838 }
3839}
3840
3841
3842double
3843MSVehicle::checkReversal(bool& canReverse, double speedThreshold, double seen) const {
3844 const bool stopOk = (myStops.empty() || myStops.front().edge != myCurrEdge
3845 || (myStops.front().getSpeed() > 0 && myState.myPos > myStops.front().pars.endPos - 2 * POSITION_EPS));
3846#ifdef DEBUG_REVERSE_BIDI
3847 if (DEBUG_COND) std::cout << SIMTIME << " checkReversal lane=" << myLane->getID()
3848 << " pos=" << myState.myPos
3849 << " speed=" << std::setprecision(6) << getPreviousSpeed() << std::setprecision(gPrecision)
3850 << " speedThreshold=" << speedThreshold
3851 << " seen=" << seen
3852 << " isRail=" << ((getVClass() & SVC_RAIL_CLASSES) != 0)
3853 << " speedOk=" << (getPreviousSpeed() <= speedThreshold)
3854 << " posOK=" << (myState.myPos <= myLane->getLength())
3855 << " normal=" << !myLane->isInternal()
3856 << " routeOK=" << ((myCurrEdge + 1) != myRoute->end())
3857 << " bidi=" << (myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1))
3858 << " stopOk=" << stopOk
3859 << "\n";
3860#endif
3861 if ((getVClass() & SVC_RAIL_CLASSES) != 0
3862 && getPreviousSpeed() <= speedThreshold
3863 && myState.myPos <= myLane->getLength()
3864 && !myLane->isInternal()
3865 && (myCurrEdge + 1) != myRoute->end()
3866 && myLane->getEdge().getBidiEdge() == *(myCurrEdge + 1)
3867 // ensure there are no further stops on this edge
3868 && stopOk
3869 ) {
3870 //if (isSelected()) std::cout << " check1 passed\n";
3871
3872 // ensure that the vehicle is fully on bidi edges that allow reversal
3873 const int neededFutureRoute = 1 + (int)(MSGlobals::gUsingInternalLanes
3874 ? myFurtherLanes.size()
3875 : ceil((double)myFurtherLanes.size() / 2.0));
3876 const int remainingRoute = int(myRoute->end() - myCurrEdge) - 1;
3877 if (remainingRoute < neededFutureRoute) {
3878#ifdef DEBUG_REVERSE_BIDI
3879 if (DEBUG_COND) {
3880 std::cout << " fail: remainingEdges=" << ((int)(myRoute->end() - myCurrEdge)) << " further=" << myFurtherLanes.size() << "\n";
3881 }
3882#endif
3883 return getMaxSpeed();
3884 }
3885 //if (isSelected()) std::cout << " check2 passed\n";
3886
3887 // ensure that the turn-around connection exists from the current edge to it's bidi-edge
3888 const MSEdgeVector& succ = myLane->getEdge().getSuccessors();
3889 if (std::find(succ.begin(), succ.end(), myLane->getEdge().getBidiEdge()) == succ.end()) {
3890#ifdef DEBUG_REVERSE_BIDI
3891 if (DEBUG_COND) {
3892 std::cout << " noTurn (bidi=" << myLane->getEdge().getBidiEdge()->getID() << " succ=" << toString(succ) << "\n";
3893 }
3894#endif
3895 return getMaxSpeed();
3896 }
3897 //if (isSelected()) std::cout << " check3 passed\n";
3898
3899 // ensure that the vehicle front will not move past a stop on the bidi edge of the current edge
3900 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + 1)) {
3901 const double stopPos = myStops.front().getEndPos(*this);
3902 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
3903 const double newPos = myLane->getLength() - (getBackPositionOnLane() + brakeDist);
3904 if (newPos > stopPos) {
3905#ifdef DEBUG_REVERSE_BIDI
3906 if (DEBUG_COND) {
3907 std::cout << " reversal would go past stop on " << myLane->getBidiLane()->getID() << "\n";
3908 }
3909#endif
3910 if (seen > MAX2(brakeDist, 1.0)) {
3911 return getMaxSpeed();
3912 } else {
3913#ifdef DEBUG_REVERSE_BIDI
3914 if (DEBUG_COND) {
3915 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
3916 }
3917#endif
3918 }
3919 }
3920 }
3921 //if (isSelected()) std::cout << " check4 passed\n";
3922
3923 // ensure that bidi-edges exist for all further edges and that no stops will be skipped when reversing
3924 int view = 2;
3925 for (MSLane* further : myFurtherLanes) {
3926 if (!further->getEdge().isInternal()) {
3927 if (further->getEdge().getBidiEdge() != *(myCurrEdge + view)) {
3928#ifdef DEBUG_REVERSE_BIDI
3929 if (DEBUG_COND) {
3930 std::cout << " noBidi view=" << view << " further=" << further->getID() << " furtherBidi=" << Named::getIDSecure(further->getEdge().getBidiEdge()) << " future=" << (*(myCurrEdge + view))->getID() << "\n";
3931 }
3932#endif
3933 return getMaxSpeed();
3934 }
3935 if (!myStops.empty() && myStops.front().edge == (myCurrEdge + view)) {
3936 const double brakeDist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
3937 const double stopPos = myStops.front().getEndPos(*this);
3938 const double newPos = further->getLength() - (getBackPositionOnLane(further) + brakeDist);
3939 if (newPos > stopPos) {
3940#ifdef DEBUG_REVERSE_BIDI
3941 if (DEBUG_COND) {
3942 std::cout << " reversal would go past stop on further-opposite lane " << further->getBidiLane()->getID() << "\n";
3943 }
3944#endif
3945 if (seen > MAX2(brakeDist, 1.0)) {
3946 canReverse = false;
3947 return getMaxSpeed();
3948 } else {
3949#ifdef DEBUG_REVERSE_BIDI
3950 if (DEBUG_COND) {
3951 std::cout << " train is too long, skipping stop at " << stopPos << " cannot be avoided\n";
3952 }
3953#endif
3954 }
3955 }
3956 }
3957 view++;
3958 }
3959 }
3960 // reverse as soon as comfortably possible
3961 const double vMinComfortable = getCarFollowModel().minNextSpeed(getSpeed(), this);
3962#ifdef DEBUG_REVERSE_BIDI
3963 if (DEBUG_COND) {
3964 std::cout << SIMTIME << " seen=" << seen << " vReverseOK=" << vMinComfortable << "\n";
3965 }
3966#endif
3967 canReverse = true;
3968 return vMinComfortable;
3969 }
3970 return getMaxSpeed();
3971}
3972
3973
3974void
3975MSVehicle::processLaneAdvances(std::vector<MSLane*>& passedLanes, std::string& emergencyReason) {
3976 for (std::vector<MSLane*>::reverse_iterator i = myFurtherLanes.rbegin(); i != myFurtherLanes.rend(); ++i) {
3977 passedLanes.push_back(*i);
3978 }
3979 if (passedLanes.size() == 0 || passedLanes.back() != myLane) {
3980 passedLanes.push_back(myLane);
3981 }
3982 // let trains reverse direction
3983 bool reverseTrain = false;
3984 checkReversal(reverseTrain);
3985 if (reverseTrain) {
3986 // add some slack to ensure that the back of train does appear looped
3987 myState.myPos += 2 * (myLane->getLength() - myState.myPos) + myType->getLength() + NUMERICAL_EPS;
3988 myState.mySpeed = 0;
3989#ifdef DEBUG_REVERSE_BIDI
3990 if (DEBUG_COND) {
3991 std::cout << SIMTIME << " reversing train=" << getID() << " newPos=" << myState.myPos << "\n";
3992 }
3993#endif
3994 }
3995 // move on lane(s)
3996 if (myState.myPos > myLane->getLength()) {
3997 // The vehicle has moved at least to the next lane (maybe it passed even more than one)
3998 if (myCurrEdge != myRoute->end() - 1) {
3999 MSLane* approachedLane = myLane;
4000 // move the vehicle forward
4002 while (myNextDriveItem != myLFLinkLanes.end() && approachedLane != nullptr && myState.myPos > approachedLane->getLength()) {
4003 const MSLink* link = myNextDriveItem->myLink;
4004 const double linkDist = myNextDriveItem->myDistance;
4006 // check whether the vehicle was allowed to enter lane
4007 // otherwise it is decelerated and we do not need to test for it's
4008 // approach on the following lanes when a lane changing is performed
4009 // proceed to the next lane
4010 if (approachedLane->mustCheckJunctionCollisions()) {
4011 // vehicle moves past approachedLane within a single step, collision checking must still be done
4013 }
4014 if (link != nullptr) {
4015 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4016 && !myLane->isInternal()
4017 && myLane->getBidiLane() != nullptr
4018 && link->getLane()->getBidiLane() == myLane
4019 && !reverseTrain) {
4020 emergencyReason = " because it must reverse direction";
4021 approachedLane = nullptr;
4022 break;
4023 }
4024 if ((getVClass() & SVC_RAIL_CLASSES) != 0
4025 && myState.myPos < myLane->getLength() + NUMERICAL_EPS
4026 && hasStops() && getNextStop().edge == myCurrEdge) {
4027 // avoid skipping stop due to numerical instability
4028 // this is a special case for rail vehicles because they
4029 // continue myLFLinkLanes past stops
4030 approachedLane = myLane;
4032 break;
4033 }
4034 approachedLane = link->getViaLaneOrLane();
4036 bool beyondStopLine = linkDist < link->getLaneBefore()->getVehicleStopOffset(this);
4037 if (link->haveRed() && !ignoreRed(link, false) && !beyondStopLine && !reverseTrain) {
4038 emergencyReason = " because of a red traffic light";
4039 break;
4040 }
4041 }
4042 if (reverseTrain && approachedLane->isInternal()) {
4043 // avoid getting stuck on a slow turn-around internal lane
4044 myState.myPos += approachedLane->getLength();
4045 }
4046 } else if (myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4047 // avoid warning due to numerical instability
4048 approachedLane = myLane;
4050 } else if (reverseTrain) {
4051 approachedLane = (*(myCurrEdge + 1))->getLanes()[0];
4052 link = myLane->getLinkTo(approachedLane);
4053 assert(link != 0);
4054 while (link->getViaLane() != nullptr) {
4055 link = link->getViaLane()->getLinkCont()[0];
4056 }
4058 } else {
4059 emergencyReason = " because there is no connection to the next edge";
4060 approachedLane = nullptr;
4061 break;
4062 }
4063 if (approachedLane != myLane && approachedLane != nullptr) {
4066 assert(myState.myPos > 0);
4067 enterLaneAtMove(approachedLane);
4068 if (link->isEntryLink()) {
4071 }
4072 if (link->isConflictEntryLink()) {
4074 }
4075 if (link->isExitLink()) {
4076 // passed junction, reset for approaching the next one
4080 }
4081#ifdef DEBUG_PLAN_MOVE_LEADERINFO
4082 if (DEBUG_COND) {
4083 std::cout << "Update junctionTimes link=" << link->getViaLaneOrLane()->getID()
4084 << " entry=" << link->isEntryLink() << " conflict=" << link->isConflictEntryLink() << " exit=" << link->isExitLink()
4085 << " ET=" << myJunctionEntryTime
4086 << " ETN=" << myJunctionEntryTimeNeverYield
4087 << " CET=" << myJunctionConflictEntryTime
4088 << "\n";
4089 }
4090#endif
4091 if (hasArrivedInternal()) {
4092 break;
4093 }
4096 // abort lane change
4097 WRITE_WARNING("Vehicle '" + getID() + "' could not finish continuous lane change (turn lane) time=" +
4098 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4100 }
4101 }
4102 if (approachedLane->getEdge().isVaporizing()) {
4104 break;
4105 }
4106 passedLanes.push_back(approachedLane);
4107 }
4108 }
4109 // NOTE: Passed drive items will be erased in the next simstep's planMove()
4110
4111#ifdef DEBUG_ACTIONSTEPS
4112 if (DEBUG_COND && myNextDriveItem != myLFLinkLanes.begin()) {
4113 std::cout << "Updated drive items:" << std::endl;
4114 for (DriveItemVector::iterator i = myLFLinkLanes.begin(); i != myLFLinkLanes.end(); ++i) {
4115 std::cout
4116 << " vPass=" << (*i).myVLinkPass
4117 << " vWait=" << (*i).myVLinkWait
4118 << " linkLane=" << ((*i).myLink == 0 ? "NULL" : (*i).myLink->getViaLaneOrLane()->getID())
4119 << " request=" << (*i).mySetRequest
4120 << "\n";
4121 }
4122 }
4123#endif
4124 } else if (!hasArrivedInternal() && myState.myPos < myLane->getLength() + NUMERICAL_EPS) {
4125 // avoid warning due to numerical instability when stopping at the end of the route
4127 }
4128
4129 }
4130}
4131
4132
4133
4134bool
4136#ifdef DEBUG_EXEC_MOVE
4137 if (DEBUG_COND) {
4138 std::cout << "\nEXECUTE_MOVE\n"
4139 << SIMTIME
4140 << " veh=" << getID()
4141 << " speed=" << getSpeed() // toString(getSpeed(), 24)
4142 << std::endl;
4143 }
4144#endif
4145
4146
4147 // Maximum safe velocity
4148 double vSafe = std::numeric_limits<double>::max();
4149 // Minimum safe velocity (lower bound).
4150 double vSafeMin = -std::numeric_limits<double>::max();
4151 // The distance to a link, which should either be crossed this step
4152 // or in front of which we need to stop.
4153 double vSafeMinDist = 0;
4154
4155 if (myActionStep) {
4156 // Actuate control (i.e. choose bounds for safe speed in current simstep (euler), resp. after current sim step (ballistic))
4157 processLinkApproaches(vSafe, vSafeMin, vSafeMinDist);
4158#ifdef DEBUG_ACTIONSTEPS
4159 if (DEBUG_COND) {
4160 std::cout << SIMTIME << " vehicle '" << getID() << "'\n"
4161 " vsafe from processLinkApproaches(): vsafe " << vSafe << std::endl;
4162 }
4163#endif
4164 } else {
4165 // Continue with current acceleration
4166 vSafe = getSpeed() + ACCEL2SPEED(myAcceleration);
4167#ifdef DEBUG_ACTIONSTEPS
4168 if (DEBUG_COND) {
4169 std::cout << SIMTIME << " vehicle '" << getID() << "' skips processLinkApproaches()\n"
4170 " continues with constant accel " << myAcceleration << "...\n"
4171 << "speed: " << getSpeed() << " -> " << vSafe << std::endl;
4172 }
4173#endif
4174 }
4175
4176
4177//#ifdef DEBUG_EXEC_MOVE
4178// if (DEBUG_COND) {
4179// std::cout << "vSafe = " << toString(vSafe,12) << "\n" << std::endl;
4180// }
4181//#endif
4182
4183 // Determine vNext = speed after current sim step (ballistic), resp. in current simstep (euler)
4184 // Call to finalizeSpeed applies speed reduction due to dawdling / lane changing but ensures minimum safe speed
4185 double vNext = vSafe;
4186 const double rawAccel = SPEED2ACCEL(MAX2(vNext, 0.) - myState.mySpeed);
4187 if (vNext <= SUMO_const_haltingSpeed && myWaitingTime > MSGlobals::gStartupWaitThreshold && rawAccel <= accelThresholdForWaiting()) {
4189 } else if (isStopped()) {
4190 // do not apply startupDelay but signal that a stop has taken place
4192 } else {
4193 // identify potential startup (before other effects reduce the speed again)
4195 }
4196 if (myActionStep) {
4197 vNext = getCarFollowModel().finalizeSpeed(this, vSafe);
4198 if (vNext > 0) {
4199 vNext = MAX2(vNext, vSafeMin);
4200 }
4201 }
4202 // (Leo) to avoid tiny oscillations (< 1e-10) of vNext in a standing vehicle column (observed for ballistic update), we cap off vNext
4203 // (We assure to do this only for vNext<<NUMERICAL_EPS since otherwise this would nullify the workaround for #2995
4204 // (Jakob) We also need to make sure to reach a stop at the start of the next edge
4205 if (fabs(vNext) < NUMERICAL_EPS_SPEED && myStopDist > POSITION_EPS) {
4206 vNext = 0.;
4207 }
4208#ifdef DEBUG_EXEC_MOVE
4209 if (DEBUG_COND) {
4210 std::cout << SIMTIME << " finalizeSpeed vSafe=" << vSafe << " vSafeMin=" << (vSafeMin == -std::numeric_limits<double>::max() ? "-Inf" : toString(vSafeMin))
4211 << " vNext=" << vNext << " (i.e. accel=" << SPEED2ACCEL(vNext - getSpeed()) << ")" << std::endl;
4212 }
4213#endif
4214
4215 // vNext may be higher than vSafe without implying a bug:
4216 // - when approaching a green light that suddenly switches to yellow
4217 // - when using unregulated junctions
4218 // - when using tau < step-size
4219 // - when using unsafe car following models
4220 // - when using TraCI and some speedMode / laneChangeMode settings
4221 //if (vNext > vSafe + NUMERICAL_EPS) {
4222 // WRITE_WARNING("vehicle '" + getID() + "' cannot brake hard enough to reach safe speed "
4223 // + toString(vSafe, 4) + ", moving at " + toString(vNext, 4) + " instead. time="
4224 // + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
4225 //}
4226
4228 vNext = MAX2(vNext, 0.);
4229 } else {
4230 // (Leo) Ballistic: negative vNext can be used to indicate a stop within next step.
4231 }
4232
4233 // Check for speed advices from the traci client
4234 vNext = processTraCISpeedControl(vSafe, vNext);
4235
4236 // the acceleration of a vehicle equipped with the elecHybrid device is restricted by the maximal power of the electric drive as well
4237 MSDevice_ElecHybrid* elecHybridOfVehicle = dynamic_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid)));
4238 if (elecHybridOfVehicle != nullptr) {
4239 // this is the consumption given by the car following model-computed acceleration
4240 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4241 // but the maximum power of the electric motor may be lower
4242 // it needs to be converted from [W] to [Wh/s] (3600s / 1h) so that TS can be taken into account
4243 double maxPower = elecHybridOfVehicle->getParameterDouble(toString(SUMO_ATTR_MAXIMUMPOWER)) / 3600;
4244 if (elecHybridOfVehicle->getConsum() / TS > maxPower) {
4245 // no, we cannot accelerate that fast, recompute the maximum possible acceleration
4246 double accel = elecHybridOfVehicle->acceleration(*this, maxPower, this->getSpeed());
4247 // and update the speed of the vehicle
4248 vNext = MIN2(vNext, this->getSpeed() + accel * TS);
4249 vNext = MAX2(vNext, 0.);
4250 // and set the vehicle consumption to reflect this
4251 elecHybridOfVehicle->setConsum(elecHybridOfVehicle->consumption(*this, (vNext - this->getSpeed()) / TS, vNext));
4252 }
4253 }
4254
4255 setBrakingSignals(vNext);
4256
4257 // update position and speed
4258 int oldLaneOffset = myLane->getEdge().getNumLanes() - myLane->getIndex();
4259 const MSLane* oldLaneMaybeOpposite = myLane;
4261 // transform to the forward-direction lane, move and then transform back
4264 }
4265 updateState(vNext);
4266 updateWaitingTime(vNext);
4267
4268 // Lanes, which the vehicle touched at some moment of the executed simstep
4269 std::vector<MSLane*> passedLanes;
4270 // remember previous lane (myLane is updated in processLaneAdvances)
4271 const MSLane* oldLane = myLane;
4272 // Reason for a possible emergency stop
4273 std::string emergencyReason = TL(" for unknown reasons");
4274 processLaneAdvances(passedLanes, emergencyReason);
4275
4276 updateTimeLoss(vNext);
4278
4280 if (myState.myPos > myLane->getLength()) {
4281 WRITE_WARNINGF(TL("Vehicle '%' performs emergency stop at the end of lane '%'% (decel=%, offset=%), time=%."),
4282 getID(), myLane->getID(), emergencyReason, myAcceleration - myState.mySpeed,
4287 myState.mySpeed = 0;
4288 myAcceleration = 0;
4289 }
4290 const MSLane* oldBackLane = getBackLane();
4292 passedLanes.clear(); // ignore back occupation
4293 }
4294#ifdef DEBUG_ACTIONSTEPS
4295 if (DEBUG_COND) {
4296 std::cout << SIMTIME << " veh '" << getID() << "' updates further lanes." << std::endl;
4297 }
4298#endif
4300 // bestLanes need to be updated before lane changing starts. NOTE: This call is also a presumption for updateDriveItems()
4302 if (myLane != oldLane || oldBackLane != getBackLane()) {
4303 if (myLaneChangeModel->getShadowLane() != nullptr || getLateralOverlap() > POSITION_EPS) {
4304 // shadow lane must be updated if the front or back lane changed
4305 // either if we already have a shadowLane or if there is lateral overlap
4307 }
4309 // The vehicles target lane must be also be updated if the front or back lane changed
4311 }
4312 }
4313 setBlinkerInformation(); // needs updated bestLanes
4314 //change the blue light only for emergency vehicles SUMOVehicleClass
4316 setEmergencyBlueLight(MSNet::getInstance()->getCurrentTimeStep());
4317 }
4318 // State needs to be reset for all vehicles before the next call to MSEdgeControl::changeLanes
4319 if (myActionStep) {
4320 // check (#2681): Can this be skipped?
4322 } else {
4323#ifdef DEBUG_ACTIONSTEPS
4324 if (DEBUG_COND) {
4325 std::cout << SIMTIME << " veh '" << getID() << "' skips LCM->prepareStep()." << std::endl;
4326 }
4327#endif
4328 }
4330 }
4331
4332#ifdef DEBUG_EXEC_MOVE
4333 if (DEBUG_COND) {
4334 std::cout << SIMTIME << " executeMove finished veh=" << getID() << " lane=" << myLane->getID() << " myPos=" << getPositionOnLane() << " myPosLat=" << getLateralPositionOnLane() << "\n";
4335 gDebugFlag1 = false; // See MSLink_DEBUG_OPENED
4336 }
4337#endif
4339 // transform back to the opposite-direction lane
4340 MSLane* newOpposite = nullptr;
4341 const MSEdge* newOppositeEdge = myLane->getEdge().getOppositeEdge();
4342 if (newOppositeEdge != nullptr) {
4343 newOpposite = newOppositeEdge->getLanes()[newOppositeEdge->getNumLanes() - MAX2(1, oldLaneOffset)];
4344#ifdef DEBUG_EXEC_MOVE
4345 if (DEBUG_COND) {
4346 std::cout << SIMTIME << " newOppositeEdge=" << newOppositeEdge->getID() << " oldLaneOffset=" << oldLaneOffset << " leftMost=" << newOppositeEdge->getNumLanes() - 1 << " newOpposite=" << Named::getIDSecure(newOpposite) << "\n";
4347 }
4348#endif
4349 }
4350 if (newOpposite == nullptr) {
4352 // unusual overtaking at junctions is ok for emergency vehicles
4353 WRITE_WARNINGF(TL("Unexpected end of opposite lane for vehicle '%' at lane '%', time=%."),
4355 }
4357 if (myState.myPos < getLength()) {
4358 // further lanes is always cleared during opposite driving
4359 MSLane* oldOpposite = oldLane->getOpposite();
4360 if (oldOpposite != nullptr) {
4361 myFurtherLanes.push_back(oldOpposite);
4362 myFurtherLanesPosLat.push_back(0);
4363 // small value since the lane is going in the other direction
4366 } else {
4367#ifdef _MSC_VER
4368#pragma warning(push)
4369#pragma warning(disable: 4127) // do not warn about constant conditional expression
4370#endif
4371 SOFT_ASSERT(false);
4372#ifdef _MSC_VER
4373#pragma warning(pop)
4374#endif
4375 }
4376 }
4377 } else {
4379 myLane = newOpposite;
4380 oldLane = oldLaneMaybeOpposite;
4381 //std::cout << SIMTIME << " updated myLane=" << Named::getIDSecure(myLane) << " oldLane=" << oldLane->getID() << "\n";
4384 }
4385 }
4387 // Return whether the vehicle did move to another lane
4388 return myLane != oldLane;
4389}
4390
4391void
4393 myState.myPos += dist;
4396
4397 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(dist);
4399 for (int i = 0; i < (int)lanes.size(); i++) {
4400 MSLink* link = nullptr;
4401 if (i + 1 < (int)lanes.size()) {
4402 const MSLane* const to = lanes[i + 1];
4403 const bool internal = to->isInternal();
4404 for (MSLink* const l : lanes[i]->getLinkCont()) {
4405 if ((internal && l->getViaLane() == to) || (!internal && l->getLane() == to)) {
4406 link = l;
4407 break;
4408 }
4409 }
4410 }
4411 myLFLinkLanes.emplace_back(link, getSpeed(), getSpeed(), true, t, getSpeed(), 0, 0, dist);
4412 }
4413 // minimum execute move:
4414 std::vector<MSLane*> passedLanes;
4415 // Reason for a possible emergency stop
4416 std::string emergencyReason = " for unknown reasons";
4417 if (lanes.size() > 1) {
4419 }
4420 processLaneAdvances(passedLanes, emergencyReason);
4421#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
4422 if (DEBUG_COND) {
4423 std::cout << SIMTIME << " veh=" << getID() << " executeFractionalMove dist=" << dist
4424 << " passedLanes=" << toString(passedLanes) << " lanes=" << toString(lanes)
4425 << " finalPos=" << myState.myPos
4426 << " speed=" << getSpeed()
4427 << " myFurtherLanes=" << toString(myFurtherLanes)
4428 << "\n";
4429 }
4430#endif
4432 if (lanes.size() > 1) {
4433 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
4434#ifdef DEBUG_FURTHER
4435 if (DEBUG_COND) {
4436 std::cout << SIMTIME << " leaveLane \n";
4437 }
4438#endif
4439 (*i)->resetPartialOccupation(this);
4440 }
4441 myFurtherLanes.clear();
4442 myFurtherLanesPosLat.clear();
4444 }
4445}
4446
4447
4448void
4450 // update position and speed
4451 double deltaPos; // positional change
4453 // euler
4454 deltaPos = SPEED2DIST(vNext);
4455 } else {
4456 // ballistic
4457 deltaPos = getDeltaPos(SPEED2ACCEL(vNext - myState.mySpeed));
4458 }
4459
4460 // the *mean* acceleration during the next step (probably most appropriate for emission calculation)
4461 // NOTE: for the ballistic update vNext may be negative, indicating a stop.
4463
4464#ifdef DEBUG_EXEC_MOVE
4465 if (DEBUG_COND) {
4466 std::cout << SIMTIME << " updateState() for veh '" << getID() << "': deltaPos=" << deltaPos
4467 << " pos=" << myState.myPos << " newPos=" << myState.myPos + deltaPos << std::endl;
4468 }
4469#endif
4470 double decelPlus = -myAcceleration - getCarFollowModel().getMaxDecel() - NUMERICAL_EPS;
4471 if (decelPlus > 0) {
4472 const double previousAcceleration = SPEED2ACCEL(myState.mySpeed - myState.myPreviousSpeed);
4473 if (myAcceleration + NUMERICAL_EPS < previousAcceleration) {
4474 // vehicle brakes beyond wished maximum deceleration (only warn at the start of the braking manoeuvre)
4475 decelPlus += 2 * NUMERICAL_EPS;
4476 const double emergencyFraction = decelPlus / MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel());
4477 if (emergencyFraction >= MSGlobals::gEmergencyDecelWarningThreshold) {
4478 WRITE_WARNINGF(TL("Vehicle '%' performs emergency braking on lane '%' with decel=%, wished=%, severity=%, time=%."),
4479 //+ " decelPlus=" + toString(decelPlus)
4480 //+ " prevAccel=" + toString(previousAcceleration)
4481 //+ " reserve=" + toString(MAX2(NUMERICAL_EPS, getCarFollowModel().getEmergencyDecel() - getCarFollowModel().getMaxDecel()))
4482 getID(), myLane->getID(), -myAcceleration, getCarFollowModel().getMaxDecel(), emergencyFraction, time2string(SIMSTEP));
4483 }
4484 }
4485 }
4486
4488 myState.mySpeed = MAX2(vNext, 0.);
4489
4490 if (myInfluencer != nullptr && myInfluencer->isRemoteControlled()) {
4491 deltaPos = myInfluencer->implicitDeltaPosRemote(this);
4492 }
4493
4494 myState.myPos += deltaPos;
4495 myState.myLastCoveredDist = deltaPos;
4496 myNextTurn.first -= deltaPos;
4497
4499}
4500
4501void
4503 updateState(0);
4504 // deboard while parked
4505 if (myPersonDevice != nullptr) {
4507 }
4508 if (myContainerDevice != nullptr) {
4510 }
4511 for (MSVehicleDevice* const dev : myDevices) {
4512 dev->notifyParking();
4513 }
4514}
4515
4516
4517void
4520 delete myCFVariables;
4522}
4523
4524
4525const MSLane*
4527 if (myFurtherLanes.size() > 0) {
4528 return myFurtherLanes.back();
4529 } else {
4530 return myLane;
4531 }
4532}
4533
4534
4535double
4536MSVehicle::updateFurtherLanes(std::vector<MSLane*>& furtherLanes, std::vector<double>& furtherLanesPosLat,
4537 const std::vector<MSLane*>& passedLanes) {
4538#ifdef DEBUG_SETFURTHER
4539 if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID()
4540 << " updateFurtherLanes oldFurther=" << toString(furtherLanes)
4541 << " oldFurtherPosLat=" << toString(furtherLanesPosLat)
4542 << " passed=" << toString(passedLanes)
4543 << "\n";
4544#endif
4545 for (std::vector<MSLane*>::iterator i = furtherLanes.begin(); i != furtherLanes.end(); ++i) {
4546 (*i)->resetPartialOccupation(this);
4547 }
4548
4549 std::vector<MSLane*> newFurther;
4550 std::vector<double> newFurtherPosLat;
4551 double backPosOnPreviousLane = myState.myPos - getLength();
4552 bool widthShift = myFurtherLanesPosLat.size() > myFurtherLanes.size();
4553 if (passedLanes.size() > 1) {
4554 // There are candidates for further lanes. (passedLanes[-1] is the current lane, or current shadow lane in context of updateShadowLanes())
4555 std::vector<MSLane*>::const_iterator fi = furtherLanes.begin();
4556 std::vector<double>::const_iterator fpi = furtherLanesPosLat.begin();
4557 for (auto pi = passedLanes.rbegin() + 1; pi != passedLanes.rend() && backPosOnPreviousLane < 0; ++pi) {
4558 // As long as vehicle back reaches into passed lane, add it to the further lanes
4559 newFurther.push_back(*pi);
4560 backPosOnPreviousLane += (*pi)->setPartialOccupation(this);
4561 if (fi != furtherLanes.end() && *pi == *fi) {
4562 // Lateral position on this lane is already known. Assume constant and use old value.
4563 newFurtherPosLat.push_back(*fpi);
4564 ++fi;
4565 ++fpi;
4566 } else {
4567 // The lane *pi was not in furtherLanes before.
4568 // If it is downstream, we assume as lateral position the current position
4569 // If it is a new lane upstream (can appear as shadow further in case of LC-maneuvering, e.g.)
4570 // we assign the last known lateral position.
4571 if (newFurtherPosLat.size() == 0) {
4572 if (widthShift) {
4573 newFurtherPosLat.push_back(myFurtherLanesPosLat.back());
4574 } else {
4575 newFurtherPosLat.push_back(myState.myPosLat);
4576 }
4577 } else {
4578 newFurtherPosLat.push_back(newFurtherPosLat.back());
4579 }
4580 }
4581#ifdef DEBUG_SETFURTHER
4582 if (DEBUG_COND) {
4583 std::cout << SIMTIME << " updateFurtherLanes \n"
4584 << " further lane '" << (*pi)->getID() << "' backPosOnPreviousLane=" << backPosOnPreviousLane
4585 << std::endl;
4586 }
4587#endif
4588 }
4589 furtherLanes = newFurther;
4590 furtherLanesPosLat = newFurtherPosLat;
4591 } else {
4592 furtherLanes.clear();
4593 furtherLanesPosLat.clear();
4594 }
4595#ifdef DEBUG_SETFURTHER
4596 if (DEBUG_COND) std::cout
4597 << " newFurther=" << toString(furtherLanes)
4598 << " newFurtherPosLat=" << toString(furtherLanesPosLat)
4599 << " newBackPos=" << backPosOnPreviousLane
4600 << "\n";
4601#endif
4602 return backPosOnPreviousLane;
4603}
4604
4605
4606double
4607MSVehicle::getBackPositionOnLane(const MSLane* lane, bool calledByGetPosition) const {
4608#ifdef DEBUG_FURTHER
4609 if (DEBUG_COND) {
4610 std::cout << SIMTIME
4611 << " getBackPositionOnLane veh=" << getID()
4612 << " lane=" << Named::getIDSecure(lane)
4613 << " cbgP=" << calledByGetPosition
4614 << " pos=" << myState.myPos
4615 << " backPos=" << myState.myBackPos
4616 << " myLane=" << myLane->getID()
4617 << " myLaneBidi=" << Named::getIDSecure(myLane->getBidiLane())
4618 << " further=" << toString(myFurtherLanes)
4619 << " furtherPosLat=" << toString(myFurtherLanesPosLat)
4620 << "\n shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
4621 << " shadowFurther=" << toString(myLaneChangeModel->getShadowFurtherLanes())
4622 << " shadowFurtherPosLat=" << toString(myLaneChangeModel->getShadowFurtherLanesPosLat())
4623 << "\n targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
4624 << " furtherTargets=" << toString(myLaneChangeModel->getFurtherTargetLanes())
4625 << std::endl;
4626 }
4627#endif
4628 if (lane == myLane
4629 || lane == myLaneChangeModel->getShadowLane()
4630 || lane == myLaneChangeModel->getTargetLane()) {
4632 if (lane == myLaneChangeModel->getShadowLane()) {
4633 return lane->getLength() - myState.myPos - myType->getLength();
4634 } else {
4635 return myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
4636 }
4637 } else if (&lane->getEdge() != &myLane->getEdge()) {
4638 return lane->getLength() - myState.myPos + (calledByGetPosition ? -1 : 1) * myType->getLength();
4639 } else {
4640 // account for parallel lanes of different lengths in the most conservative manner (i.e. while turning)
4641 return myState.myPos - myType->getLength() + MIN2(0.0, lane->getLength() - myLane->getLength());
4642 }
4643 } else if (lane == myLane->getBidiLane()) {
4644 return lane->getLength() - myState.myPos + myType->getLength() * (calledByGetPosition ? -1 : 1);
4645 } else if (myFurtherLanes.size() > 0 && lane == myFurtherLanes.back()) {
4646 return myState.myBackPos;
4647 } else if ((myLaneChangeModel->getShadowFurtherLanes().size() > 0 && lane == myLaneChangeModel->getShadowFurtherLanes().back())
4648 || (myLaneChangeModel->getFurtherTargetLanes().size() > 0 && lane == myLaneChangeModel->getFurtherTargetLanes().back())) {
4649 assert(myFurtherLanes.size() > 0);
4650 if (lane->getLength() == myFurtherLanes.back()->getLength()) {
4651 return myState.myBackPos;
4652 } else {
4653 // interpolate
4654 //if (DEBUG_COND) {
4655 //if (myFurtherLanes.back()->getLength() != lane->getLength()) {
4656 // std::cout << SIMTIME << " veh=" << getID() << " lane=" << lane->getID() << " further=" << myFurtherLanes.back()->getID()
4657 // << " len=" << lane->getLength() << " fLen=" << myFurtherLanes.back()->getLength()
4658 // << " backPos=" << myState.myBackPos << " result=" << myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength() << "\n";
4659 //}
4660 return myState.myBackPos / myFurtherLanes.back()->getLength() * lane->getLength();
4661 }
4662 } else {
4663 if (lane->getBidiLane() != nullptr) {
4664 if (myLane == lane->getBidiLane()) {
4665 return lane->getLength() - (myState.myPos - myType->getLength());
4666 } else if (myFurtherLanes.size() > 0 && lane->getBidiLane() == myFurtherLanes.back()) {
4667 return lane->getLength() - myState.myBackPos;
4668 }
4669 }
4670 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherLanes=" << toString(myFurtherLanes) << "\n";
4671 double leftLength = myType->getLength() - myState.myPos;
4672
4673 std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin();
4674 while (leftLength > 0 && i != myFurtherLanes.end()) {
4675 leftLength -= (*i)->getLength();
4676 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
4677 if (*i == lane) {
4678 return -leftLength;
4679 }
4680 ++i;
4681 }
4682 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
4683 leftLength = myType->getLength() - myState.myPos;
4685 while (leftLength > 0 && i != myLaneChangeModel->getShadowFurtherLanes().end()) {
4686 leftLength -= (*i)->getLength();
4687 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
4688 if (*i == lane) {
4689 return -leftLength;
4690 }
4691 ++i;
4692 }
4693 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myFurtherTargetLanes=" << toString(myLaneChangeModel->getFurtherTargetLanes()) << "\n";
4694 leftLength = myType->getLength() - myState.myPos;
4695 i = getFurtherLanes().begin();
4696 const std::vector<MSLane*> furtherTargetLanes = myLaneChangeModel->getFurtherTargetLanes();
4697 auto j = furtherTargetLanes.begin();
4698 while (leftLength > 0 && j != furtherTargetLanes.end()) {
4699 leftLength -= (*i)->getLength();
4700 // if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
4701 if (*j == lane) {
4702 return -leftLength;
4703 }
4704 ++i;
4705 ++j;
4706 }
4707 WRITE_WARNING("Request backPos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane)
4708 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
4709#ifdef _MSC_VER
4710#pragma warning(push)
4711#pragma warning(disable: 4127) // do not warn about constant conditional expression
4712#endif
4713 SOFT_ASSERT(false);
4714#ifdef _MSC_VER
4715#pragma warning(pop)
4716#endif
4717 return myState.myBackPos;
4718 }
4719}
4720
4721
4722double
4724 return getBackPositionOnLane(lane, true) + myType->getLength();
4725}
4726
4727
4728bool
4730 return lane == myLane || lane == myLaneChangeModel->getShadowLane() || lane == myLane->getBidiLane();
4731}
4732
4733
4734void
4735MSVehicle::checkRewindLinkLanes(const double lengthsInFront, DriveItemVector& lfLinks) const {
4737 double seenSpace = -lengthsInFront;
4738#ifdef DEBUG_CHECKREWINDLINKLANES
4739 if (DEBUG_COND) {
4740 std::cout << "\nCHECK_REWIND_LINKLANES\n" << " veh=" << getID() << " lengthsInFront=" << lengthsInFront << "\n";
4741 };
4742#endif
4743 bool foundStopped = false;
4744 // compute available space until a stopped vehicle is found
4745 // this is the sum of non-interal lane length minus in-between vehicle lengths
4746 for (int i = 0; i < (int)lfLinks.size(); ++i) {
4747 // skip unset links
4748 DriveProcessItem& item = lfLinks[i];
4749#ifdef DEBUG_CHECKREWINDLINKLANES
4750 if (DEBUG_COND) std::cout << SIMTIME
4751 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
4752 << " foundStopped=" << foundStopped;
4753#endif
4754 if (item.myLink == nullptr || foundStopped) {
4755 if (!foundStopped) {
4756 item.availableSpace += seenSpace;
4757 } else {
4758 item.availableSpace = seenSpace;
4759 }
4760#ifdef DEBUG_CHECKREWINDLINKLANES
4761 if (DEBUG_COND) {
4762 std::cout << " avail=" << item.availableSpace << "\n";
4763 }
4764#endif
4765 continue;
4766 }
4767 // get the next lane, determine whether it is an internal lane
4768 const MSLane* approachedLane = item.myLink->getViaLane();
4769 if (approachedLane != nullptr) {
4770 if (keepClear(item.myLink)) {
4771 seenSpace = seenSpace - approachedLane->getBruttoVehLenSum();
4772 if (approachedLane == myLane) {
4773 seenSpace += getVehicleType().getLengthWithGap();
4774 }
4775 } else {
4776 seenSpace = seenSpace + approachedLane->getSpaceTillLastStanding(this, foundStopped);// - approachedLane->getBruttoVehLenSum() + approachedLane->getLength();
4777 }
4778 item.availableSpace = seenSpace;
4779#ifdef DEBUG_CHECKREWINDLINKLANES
4780 if (DEBUG_COND) std::cout
4781 << " approached=" << approachedLane->getID()
4782 << " approachedBrutto=" << approachedLane->getBruttoVehLenSum()
4783 << " avail=" << item.availableSpace
4784 << " seenSpace=" << seenSpace
4785 << " hadStoppedVehicle=" << item.hadStoppedVehicle
4786 << " lengthsInFront=" << lengthsInFront
4787 << "\n";
4788#endif
4789 continue;
4790 }
4791 approachedLane = item.myLink->getLane();
4792 const MSVehicle* last = approachedLane->getLastAnyVehicle();
4793 if (last == nullptr || last == this) {
4794 if (approachedLane->getLength() > getVehicleType().getLength()
4795 || keepClear(item.myLink)) {
4796 seenSpace += approachedLane->getLength();
4797 }
4798 item.availableSpace = seenSpace;
4799#ifdef DEBUG_CHECKREWINDLINKLANES
4800 if (DEBUG_COND) {
4801 std::cout << " last=" << Named::getIDSecure(last) << " laneLength=" << approachedLane->getLength() << " avail=" << item.availableSpace << "\n";
4802 }
4803#endif
4804 } else {
4805 bool foundStopped2 = false;
4806 const double spaceTillLastStanding = approachedLane->getSpaceTillLastStanding(this, foundStopped2);
4807 seenSpace += spaceTillLastStanding;
4808 if (foundStopped2) {
4809 foundStopped = true;
4810 item.hadStoppedVehicle = true;
4811 }
4812 item.availableSpace = seenSpace;
4813 if (last->myHaveToWaitOnNextLink || last->isStopped()) {
4814 foundStopped = true;
4815 item.hadStoppedVehicle = true;
4816 }
4817#ifdef DEBUG_CHECKREWINDLINKLANES
4818 if (DEBUG_COND) std::cout
4819 << " approached=" << approachedLane->getID()
4820 << " last=" << last->getID()
4821 << " lastHasToWait=" << last->myHaveToWaitOnNextLink
4822 << " lastBrakeLight=" << last->signalSet(VEH_SIGNAL_BRAKELIGHT)
4823 << " lastBrakeGap=" << last->getCarFollowModel().brakeGap(last->getSpeed())
4824 << " lastGap=" << (last->getBackPositionOnLane(approachedLane) + last->getCarFollowModel().brakeGap(last->getSpeed()) - last->getSpeed() * last->getCarFollowModel().getHeadwayTime()
4825 // gap of last up to the next intersection
4826 - last->getVehicleType().getMinGap())
4827 << " stls=" << spaceTillLastStanding
4828 << " avail=" << item.availableSpace
4829 << " seenSpace=" << seenSpace
4830 << " foundStopped=" << foundStopped
4831 << " foundStopped2=" << foundStopped2
4832 << "\n";
4833#endif
4834 }
4835 }
4836
4837 // check which links allow continuation and add pass available to the previous item
4838 for (int i = ((int)lfLinks.size() - 1); i > 0; --i) {
4839 DriveProcessItem& item = lfLinks[i - 1];
4840 DriveProcessItem& nextItem = lfLinks[i];
4841 const bool canLeaveJunction = item.myLink->getViaLane() == nullptr || nextItem.myLink == nullptr || nextItem.mySetRequest;
4842 const bool opened = (item.myLink != nullptr
4843 && (canLeaveJunction || (
4844 // indirect bicycle turn
4845 nextItem.myLink != nullptr && nextItem.myLink->isInternalJunctionLink() && nextItem.myLink->haveRed()))
4846 && (
4847 item.myLink->havePriority()
4848 || i == 1 // the upcoming link (item 0) is checked in executeMove anyway. No need to use outdata approachData here
4850 || item.myLink->opened(item.myArrivalTime, item.myArrivalSpeed,
4853 bool allowsContinuation = (item.myLink == nullptr || item.myLink->isCont() || opened) && !item.hadStoppedVehicle;
4854#ifdef DEBUG_CHECKREWINDLINKLANES
4855 if (DEBUG_COND) std::cout
4856 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
4857 << " canLeave=" << canLeaveJunction
4858 << " opened=" << opened
4859 << " allowsContinuation=" << allowsContinuation
4860 << " foundStopped=" << foundStopped
4861 << "\n";
4862#endif
4863 if (!opened && item.myLink != nullptr) {
4864 foundStopped = true;
4865 if (i > 1) {
4866 DriveProcessItem& item2 = lfLinks[i - 2];
4867 if (item2.myLink != nullptr && item2.myLink->isCont()) {
4868 allowsContinuation = true;
4869 }
4870 }
4871 }
4872 if (allowsContinuation) {
4873 item.availableSpace = nextItem.availableSpace;
4874#ifdef DEBUG_CHECKREWINDLINKLANES
4875 if (DEBUG_COND) std::cout
4876 << " link=" << (item.myLink == nullptr ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
4877 << " copy nextAvail=" << nextItem.availableSpace
4878 << "\n";
4879#endif
4880 }
4881 }
4882
4883 // find removalBegin
4884 int removalBegin = -1;
4885 for (int i = 0; foundStopped && i < (int)lfLinks.size() && removalBegin < 0; ++i) {
4886 // skip unset links
4887 const DriveProcessItem& item = lfLinks[i];
4888 if (item.myLink == nullptr) {
4889 continue;
4890 }
4891 /*
4892 double impatienceCorrection = MAX2(0., double(double(myWaitingTime)));
4893 if (seenSpace<getVehicleType().getLengthWithGap()-impatienceCorrection/10.&&nextSeenNonInternal!=0) {
4894 removalBegin = lastLinkToInternal;
4895 }
4896 */
4897
4898 const double leftSpace = item.availableSpace - getVehicleType().getLengthWithGap();
4899#ifdef DEBUG_CHECKREWINDLINKLANES
4900 if (DEBUG_COND) std::cout
4901 << SIMTIME
4902 << " veh=" << getID()
4903 << " link=" << (item.myLink == 0 ? "NULL" : item.myLink->getViaLaneOrLane()->getID())
4904 << " avail=" << item.availableSpace
4905 << " leftSpace=" << leftSpace
4906 << "\n";
4907#endif
4908 if (leftSpace < 0/* && item.myLink->willHaveBlockedFoe()*/) {
4909 double impatienceCorrection = 0;
4910 /*
4911 if(item.myLink->getState()==LINKSTATE_MINOR) {
4912 impatienceCorrection = MAX2(0., STEPS2TIME(myWaitingTime));
4913 }
4914 */
4915 // may ignore keepClear rules
4916 if (leftSpace < -impatienceCorrection / 10. && keepClear(item.myLink)) {
4917 removalBegin = i;
4918 }
4919 //removalBegin = i;
4920 }
4921 }
4922 // abort requests
4923 if (removalBegin != -1 && !(removalBegin == 0 && myLane->getEdge().isInternal())) {
4924 const double brakeGap = getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0.);
4925 while (removalBegin < (int)(lfLinks.size())) {
4926 DriveProcessItem& dpi = lfLinks[removalBegin];
4927 if (dpi.myLink == nullptr) {
4928 break;
4929 }
4930 dpi.myVLinkPass = dpi.myVLinkWait;
4931#ifdef DEBUG_CHECKREWINDLINKLANES
4932 if (DEBUG_COND) {
4933 std::cout << " removalBegin=" << removalBegin << " brakeGap=" << brakeGap << " dist=" << dpi.myDistance << " speed=" << myState.mySpeed << " a2s=" << ACCEL2SPEED(getCarFollowModel().getMaxDecel()) << "\n";
4934 }
4935#endif
4936 if (dpi.myDistance >= brakeGap + POSITION_EPS) {
4937 // always leave junctions after requesting to enter
4938 if (!dpi.myLink->isExitLink() || !lfLinks[removalBegin - 1].mySetRequest) {
4939 dpi.mySetRequest = false;
4940 }
4941 }
4942 ++removalBegin;
4943 }
4944 }
4945 }
4946}
4947
4948
4949void
4951 if (!checkActionStep(t)) {
4952 return;
4953 }
4955 for (DriveProcessItem& dpi : myLFLinkLanes) {
4956 if (dpi.myLink != nullptr) {
4957 if (dpi.myLink->getState() == LINKSTATE_ALLWAY_STOP) {
4958 dpi.myArrivalTime += (SUMOTime)RandHelper::rand((int)2, getRNG()); // tie braker
4959 }
4960 dpi.myLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
4961 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance, getLateralPositionOnLane());
4962 }
4963 }
4964 if (myLaneChangeModel->getShadowLane() != nullptr) {
4965 // register on all shadow links
4966 for (const DriveProcessItem& dpi : myLFLinkLanes) {
4967 if (dpi.myLink != nullptr) {
4968 MSLink* parallelLink = dpi.myLink->getParallelLink(myLaneChangeModel->getShadowDirection());
4969 if (parallelLink == nullptr && getLaneChangeModel().isOpposite() && dpi.myLink->isEntryLink()) {
4970 // register on opposite direction entry link to warn foes at minor side road
4971 parallelLink = dpi.myLink->getOppositeDirectionLink();
4972 }
4973 if (parallelLink != nullptr) {
4974 const double latOffset = getLane()->getRightSideOnEdge() - myLaneChangeModel->getShadowLane()->getRightSideOnEdge();
4975 parallelLink->setApproaching(this, dpi.myArrivalTime, dpi.myArrivalSpeed, dpi.getLeaveSpeed(),
4976 dpi.mySetRequest, dpi.myArrivalSpeedBraking, getWaitingTime(), dpi.myDistance,
4977 latOffset);
4979 }
4980 }
4981 }
4982 }
4983#ifdef DEBUG_PLAN_MOVE
4984 if (DEBUG_COND) {
4985 std::cout << SIMTIME
4986 << " veh=" << getID()
4987 << " after checkRewindLinkLanes\n";
4988 for (DriveProcessItem& dpi : myLFLinkLanes) {
4989 std::cout
4990 << " vPass=" << dpi.myVLinkPass
4991 << " vWait=" << dpi.myVLinkWait
4992 << " linkLane=" << (dpi.myLink == 0 ? "NULL" : dpi.myLink->getViaLaneOrLane()->getID())
4993 << " request=" << dpi.mySetRequest
4994 << " atime=" << dpi.myArrivalTime
4995 << "\n";
4996 }
4997 }
4998#endif
4999}
5000
5001
5002void
5004 DriveProcessItem dpi(0, dist);
5005 dpi.myLink = link;
5006 const double arrivalSpeedBraking = getCarFollowModel().getMinimalArrivalSpeedEuler(dist, getSpeed());
5007 link->setApproaching(this, SUMOTime_MAX, 0, 0, false, arrivalSpeedBraking, 0, dpi.myDistance, 0);
5008 // ensure cleanup in the next step
5009 myLFLinkLanes.push_back(dpi);
5010}
5011
5012
5013void
5015 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5016 // skip the reminder if it is a lane reminder but not for my lane (indicated by rem->second > 0.)
5017 if (rem->first->getLane() != nullptr && rem->second > 0.) {
5018#ifdef _DEBUG
5019 if (myTraceMoveReminders) {
5020 traceMoveReminder("notifyEnter_skipped", rem->first, rem->second, true);
5021 }
5022#endif
5023 ++rem;
5024 } else {
5025 if (rem->first->notifyEnter(*this, reason, enteredLane)) {
5026#ifdef _DEBUG
5027 if (myTraceMoveReminders) {
5028 traceMoveReminder("notifyEnter", rem->first, rem->second, true);
5029 }
5030#endif
5031 ++rem;
5032 } else {
5033#ifdef _DEBUG
5034 if (myTraceMoveReminders) {
5035 traceMoveReminder("notifyEnter", rem->first, rem->second, false);
5036 }
5037// std::cout << SIMTIME << " Vehicle '" << getID() << "' erases MoveReminder (with offset " << rem->second << ")" << std::endl;
5038#endif
5039 rem = myMoveReminders.erase(rem);
5040 }
5041 }
5042 }
5043}
5044
5045
5046void
5047MSVehicle::enterLaneAtMove(MSLane* enteredLane, bool onTeleporting) {
5048 myAmOnNet = !onTeleporting;
5049 // vaporizing edge?
5050 /*
5051 if (enteredLane->getEdge().isVaporizing()) {
5052 // yep, let's do the vaporization...
5053 myLane = enteredLane;
5054 return true;
5055 }
5056 */
5057 // Adjust MoveReminder offset to the next lane
5058 adaptLaneEntering2MoveReminder(*enteredLane);
5059 // set the entered lane as the current lane
5060 MSLane* oldLane = myLane;
5061 myLane = enteredLane;
5062 myLastBestLanesEdge = nullptr;
5063
5064 // internal edges are not a part of the route...
5065 if (!enteredLane->getEdge().isInternal()) {
5066 ++myCurrEdge;
5068 }
5069 if (myInfluencer != nullptr) {
5071 }
5072 if (!onTeleporting) {
5075 // transform lateral position when the lane width changes
5076 assert(oldLane != nullptr);
5077 const MSLink* const link = oldLane->getLinkTo(myLane);
5078 if (link != nullptr) {
5080 myState.myPosLat += link->getLateralShift();
5081 }
5082 } else if (fabs(myState.myPosLat) > NUMERICAL_EPS) {
5083 const double overlap = MAX2(0.0, getLateralOverlap(myState.myPosLat, oldLane));
5084 const double range = (oldLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5085 const double range2 = (myLane->getWidth() - getVehicleType().getWidth()) * 0.5 + overlap;
5086 myState.myPosLat *= range2 / range;
5087 }
5088 if (!isRailway(getVClass()) && myLane->getBidiLane() != nullptr) {
5089 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
5091 }
5092 } else {
5093 // normal move() isn't called so reset position here. must be done
5094 // before calling reminders
5095 myState.myPos = 0;
5098 }
5099 // update via
5100 if (myParameter->via.size() > 0 && myLane->getEdge().getID() == myParameter->via.front()) {
5101 myParameter->via.erase(myParameter->via.begin());
5102 }
5103}
5104
5105
5106void
5108 myAmOnNet = true;
5109 myLane = enteredLane;
5111 // need to update myCurrentLaneInBestLanes
5113 // switch to and activate the new lane's reminders
5114 // keep OldLaneReminders
5115 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5116 addReminder(*rem);
5117 }
5119 MSLane* lane = myLane;
5120 double leftLength = getVehicleType().getLength() - myState.myPos;
5121 int deleteFurther = 0;
5122 for (int i = 0; i < (int)myFurtherLanes.size(); i++) {
5123 if (lane != nullptr) {
5125 }
5126 if (lane != nullptr) {
5127#ifdef DEBUG_SETFURTHER
5128 if (DEBUG_COND) {
5129 std::cout << SIMTIME << " enterLaneAtLaneChange \n";
5130 }
5131#endif
5132 myFurtherLanes[i]->resetPartialOccupation(this);
5133 // lane changing onto longer lanes may reduce the number of
5134 // remaining further lanes
5135 if (leftLength > 0) {
5136 myFurtherLanes[i] = lane;
5138 leftLength -= (lane)->setPartialOccupation(this);
5139 myState.myBackPos = -leftLength;
5140#ifdef DEBUG_SETFURTHER
5141 if (DEBUG_COND) {
5142 std::cout << SIMTIME << " newBackPos=" << myState.myBackPos << "\n";
5143 }
5144#endif
5145 } else {
5146 deleteFurther++;
5147 }
5148 } else {
5149 // keep the old values, but ensure there is no shadow
5152 }
5153 if (myState.myBackPos < 0) {
5154 myState.myBackPos += myFurtherLanes[i]->getLength();
5155 }
5156#ifdef DEBUG_SETFURTHER
5157 if (DEBUG_COND) {
5158 std::cout << SIMTIME << " i=" << i << " further=" << myFurtherLanes[i]->getID() << " newBackPos=" << myState.myBackPos << "\n";
5159 }
5160#endif
5161 }
5162 }
5163 if (deleteFurther > 0) {
5164#ifdef DEBUG_SETFURTHER
5165 if (DEBUG_COND) {
5166 std::cout << SIMTIME << " veh=" << getID() << " shortening myFurtherLanes by " << deleteFurther << "\n";
5167 }
5168#endif
5169 myFurtherLanes.erase(myFurtherLanes.end() - 1);
5171 }
5172#ifdef DEBUG_SETFURTHER
5173 if (DEBUG_COND) {
5174 std::cout << SIMTIME << " enterLaneAtLaneChange new furtherLanes=" << toString(myFurtherLanes)
5175 << " furterLanesPosLat=" << toString(myFurtherLanesPosLat) << "\n";
5176 }
5177#endif
5179}
5180
5181
5182void
5183MSVehicle::computeFurtherLanes(MSLane* enteredLane, double pos, bool collision) {
5184 // build the list of lanes the vehicle is lapping into
5185 if (!myLaneChangeModel->isOpposite()) {
5186 double leftLength = myType->getLength() - pos;
5187 MSLane* clane = enteredLane;
5188 int routeIndex = getRoutePosition();
5189 while (leftLength > 0) {
5190 if (routeIndex > 0 && clane->getEdge().isNormal()) {
5191 // get predecessor lane that corresponds to prior route
5192 routeIndex--;
5193 const MSEdge* fromRouteEdge = myRoute->getEdges()[routeIndex];
5194 MSLane* target = clane;
5195 clane = nullptr;
5196 for (auto ili : target->getIncomingLanes()) {
5197 if (ili.lane->getEdge().getNormalBefore() == fromRouteEdge) {
5198 clane = ili.lane;
5199 break;
5200 }
5201 }
5202 } else {
5203 clane = clane->getLogicalPredecessorLane();
5204 }
5205 if (clane == nullptr || clane == myLane || clane == myLane->getBidiLane()
5206 || (clane->isInternal() && (
5207 clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN
5208 || clane->getLinkCont()[0]->getDirection() == LinkDirection::TURN_LEFTHAND))) {
5209 break;
5210 }
5211 if (!collision || std::find(myFurtherLanes.begin(), myFurtherLanes.end(), clane) == myFurtherLanes.end()) {
5212 myFurtherLanes.push_back(clane);
5214 clane->setPartialOccupation(this);
5215 }
5216 leftLength -= clane->getLength();
5217 }
5218 myState.myBackPos = -leftLength;
5219#ifdef DEBUG_SETFURTHER
5220 if (DEBUG_COND) {
5221 std::cout << SIMTIME << " computeFurtherLanes veh=" << getID() << " pos=" << pos << " myFurtherLanes=" << toString(myFurtherLanes) << " backPos=" << myState.myBackPos << "\n";
5222 }
5223#endif
5224 } else {
5225 // clear partial occupation
5226 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
5227#ifdef DEBUG_SETFURTHER
5228 if (DEBUG_COND) {
5229 std::cout << SIMTIME << " opposite: resetPartialOccupation " << (*i)->getID() << " \n";
5230 }
5231#endif
5232 (*i)->resetPartialOccupation(this);
5233 }
5234 myFurtherLanes.clear();
5235 myFurtherLanesPosLat.clear();
5236 }
5237}
5238
5239
5240void
5241MSVehicle::enterLaneAtInsertion(MSLane* enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification) {
5242 myState = State(pos, speed, posLat, pos - getVehicleType().getLength(), hasDeparted() ? myState.myPreviousSpeed : speed);
5244 onDepart();
5245 }
5247 assert(myState.myPos >= 0);
5248 assert(myState.mySpeed >= 0);
5249 myLane = enteredLane;
5250 myAmOnNet = true;
5251 // schedule action for the next timestep
5253 if (notification != MSMoveReminder::NOTIFICATION_TELEPORT) {
5254 // set and activate the new lane's reminders, teleports already did that at enterLaneAtMove
5255 for (std::vector< MSMoveReminder* >::const_iterator rem = enteredLane->getMoveReminders().begin(); rem != enteredLane->getMoveReminders().end(); ++rem) {
5256 addReminder(*rem);
5257 }
5258 activateReminders(notification, enteredLane);
5259 } else {
5260 myLastBestLanesEdge = nullptr;
5263 }
5264 computeFurtherLanes(enteredLane, pos);
5268 } else if (MSGlobals::gLaneChangeDuration > 0) {
5270 }
5271 if (notification != MSMoveReminder::NOTIFICATION_LOAD_STATE) {
5274 myAngle += M_PI;
5275 }
5276 }
5277}
5278
5279
5280void
5281MSVehicle::leaveLane(const MSMoveReminder::Notification reason, const MSLane* approachedLane) {
5282 for (MoveReminderCont::iterator rem = myMoveReminders.begin(); rem != myMoveReminders.end();) {
5283 if (rem->first->notifyLeave(*this, myState.myPos + rem->second, reason, approachedLane)) {
5284#ifdef _DEBUG
5285 if (myTraceMoveReminders) {
5286 traceMoveReminder("notifyLeave", rem->first, rem->second, true);
5287 }
5288#endif
5289 ++rem;
5290 } else {
5291#ifdef _DEBUG
5292 if (myTraceMoveReminders) {
5293 traceMoveReminder("notifyLeave", rem->first, rem->second, false);
5294 }
5295#endif
5296 rem = myMoveReminders.erase(rem);
5297 }
5298 }
5299 if ((reason == MSMoveReminder::NOTIFICATION_JUNCTION || reason == MSMoveReminder::NOTIFICATION_TELEPORT) && myLane != nullptr) {
5301 }
5302 if (myLane != nullptr && myLane->getBidiLane() != nullptr && myAmOnNet && !isRailway(getVClass())) {
5304 }
5306 // @note. In case of lane change, myFurtherLanes and partial occupation
5307 // are handled in enterLaneAtLaneChange()
5308 for (std::vector<MSLane*>::iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
5309#ifdef DEBUG_FURTHER
5310 if (DEBUG_COND) {
5311 std::cout << SIMTIME << " leaveLane \n";
5312 }
5313#endif
5314 (*i)->resetPartialOccupation(this);
5315 }
5316 myFurtherLanes.clear();
5317 myFurtherLanesPosLat.clear();
5318 }
5320 myAmOnNet = false;
5321 myWaitingTime = 0;
5322 }
5324 myStopDist = std::numeric_limits<double>::max();
5325 if (myPastStops.back().speed <= 0) {
5326 WRITE_WARNING("Vehicle '" + getID() + "' aborts stop.");
5327 }
5328 }
5330 while (!myStops.empty() && myStops.front().edge == myCurrEdge && &myStops.front().lane->getEdge() == &myLane->getEdge()) {
5331 if (myStops.front().getSpeed() <= 0) {
5332 WRITE_WARNING("Vehicle '" + getID() + "' skips stop on lane '" + myStops.front().lane->getID()
5333 + "' time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".")
5334 myStops.pop_front();
5335 } else {
5336 MSStop& stop = myStops.front();
5337 // passed waypoint at the end of the lane
5338 if (!stop.reached) {
5339 if (MSStopOut::active()) {
5341 }
5342 stop.reached = true;
5343 // enter stopping place so leaveFrom works as expected
5344 if (stop.busstop != nullptr) {
5345 // let the bus stop know the vehicle
5346 stop.busstop->enter(this, stop.pars.parking == ParkingType::OFFROAD);
5347 }
5348 if (stop.containerstop != nullptr) {
5349 // let the container stop know the vehicle
5351 }
5352 // do not enter parkingarea!
5353 if (stop.chargingStation != nullptr) {
5354 // let the container stop know the vehicle
5356 }
5357 }
5359 }
5360 myStopDist = std::numeric_limits<double>::max();
5361 }
5362 }
5363}
5364
5365
5368 return *myLaneChangeModel;
5369}
5370
5371
5374 return *myLaneChangeModel;
5375}
5376
5377bool
5379 return (lane->isInternal()
5380 ? & (lane->getLinkCont()[0]->getLane()->getEdge()) != *(myCurrEdge + 1)
5381 : &lane->getEdge() != *myCurrEdge);
5382}
5383
5384const std::vector<MSVehicle::LaneQ>&
5386 return *myBestLanes.begin();
5387}
5388
5389
5390void
5391MSVehicle::updateBestLanes(bool forceRebuild, const MSLane* startLane) {
5392#ifdef DEBUG_BESTLANES
5393 if (DEBUG_COND) {
5394 std::cout << SIMTIME << " updateBestLanes veh=" << getID() << " force=" << forceRebuild << " startLane1=" << Named::getIDSecure(startLane) << " myLane=" << Named::getIDSecure(myLane) << "\n";
5395 }
5396#endif
5397 if (startLane == nullptr) {
5398 startLane = myLane;
5399 }
5400 assert(startLane != 0);
5402 // depending on the calling context, startLane might be the forward lane
5403 // or the reverse-direction lane. In the latter case we need to
5404 // transform it to the forward lane.
5405 if (isOppositeLane(startLane)) {
5406 // use leftmost lane of forward edge
5407 startLane = startLane->getEdge().getOppositeEdge()->getLanes().back();
5408 assert(startLane != 0);
5409#ifdef DEBUG_BESTLANES
5410 if (DEBUG_COND) {
5411 std::cout << " startLaneIsOpposite newStartLane=" << startLane->getID() << "\n";
5412 }
5413#endif
5414 }
5415 }
5416 if (forceRebuild) {
5417 myLastBestLanesEdge = nullptr;
5419 }
5420 if (myBestLanes.size() > 0 && !forceRebuild && myLastBestLanesEdge == &startLane->getEdge()) {
5422#ifdef DEBUG_BESTLANES
5423 if (DEBUG_COND) {
5424 std::cout << " only updateOccupancyAndCurrentBestLane\n";
5425 }
5426#endif
5427 return;
5428 }
5429 if (startLane->getEdge().isInternal()) {
5430 if (myBestLanes.size() == 0 || forceRebuild) {
5431 // rebuilt from previous non-internal lane (may backtrack twice if behind an internal junction)
5432 updateBestLanes(true, startLane->getLogicalPredecessorLane());
5433 }
5434 if (myLastBestLanesInternalLane == startLane && !forceRebuild) {
5435#ifdef DEBUG_BESTLANES
5436 if (DEBUG_COND) {
5437 std::cout << " nothing to do on internal\n";
5438 }
5439#endif
5440 return;
5441 }
5442 // adapt best lanes to fit the current internal edge:
5443 // keep the entries that are reachable from this edge
5444 const MSEdge* nextEdge = startLane->getNextNormal();
5445 assert(!nextEdge->isInternal());
5446 for (std::vector<std::vector<LaneQ> >::iterator it = myBestLanes.begin(); it != myBestLanes.end();) {
5447 std::vector<LaneQ>& lanes = *it;
5448 assert(lanes.size() > 0);
5449 if (&(lanes[0].lane->getEdge()) == nextEdge) {
5450 // keep those lanes which are successors of internal lanes from the edge of startLane
5451 std::vector<LaneQ> oldLanes = lanes;
5452 lanes.clear();
5453 const std::vector<MSLane*>& sourceLanes = startLane->getEdge().getLanes();
5454 for (std::vector<MSLane*>::const_iterator it_source = sourceLanes.begin(); it_source != sourceLanes.end(); ++it_source) {
5455 for (std::vector<LaneQ>::iterator it_lane = oldLanes.begin(); it_lane != oldLanes.end(); ++it_lane) {
5456 if ((*it_source)->getLinkCont()[0]->getLane() == (*it_lane).lane) {
5457 lanes.push_back(*it_lane);
5458 break;
5459 }
5460 }
5461 }
5462 assert(lanes.size() == startLane->getEdge().getLanes().size());
5463 // patch invalid bestLaneOffset and updated myCurrentLaneInBestLanes
5464 for (int i = 0; i < (int)lanes.size(); ++i) {
5465 if (i + lanes[i].bestLaneOffset < 0) {
5466 lanes[i].bestLaneOffset = -i;
5467 }
5468 if (i + lanes[i].bestLaneOffset >= (int)lanes.size()) {
5469 lanes[i].bestLaneOffset = (int)lanes.size() - i - 1;
5470 }
5471 assert(i + lanes[i].bestLaneOffset >= 0);
5472 assert(i + lanes[i].bestLaneOffset < (int)lanes.size());
5473 if (lanes[i].bestContinuations[0] != 0) {
5474 // patch length of bestContinuation to match expectations (only once)
5475 lanes[i].bestContinuations.insert(lanes[i].bestContinuations.begin(), (MSLane*)nullptr);
5476 }
5477 if (startLane->getLinkCont()[0]->getLane() == lanes[i].lane) {
5478 myCurrentLaneInBestLanes = lanes.begin() + i;
5479 }
5480 assert(&(lanes[i].lane->getEdge()) == nextEdge);
5481 }
5482 myLastBestLanesInternalLane = startLane;
5484#ifdef DEBUG_BESTLANES
5485 if (DEBUG_COND) {
5486 std::cout << " updated for internal\n";
5487 }
5488#endif
5489 return;
5490 } else {
5491 // remove passed edges
5492 it = myBestLanes.erase(it);
5493 }
5494 }
5495 assert(false); // should always find the next edge
5496 }
5497 // start rebuilding
5498 myLastBestLanesEdge = &startLane->getEdge();
5499 myBestLanes.clear();
5500
5501 // get information about the next stop
5502 MSRouteIterator nextStopEdge = myRoute->end();
5503 const MSLane* nextStopLane = nullptr;
5504 double nextStopPos = 0;
5505 bool nextStopIsWaypoint = false;
5506 if (!myStops.empty()) {
5507 const MSStop& nextStop = myStops.front();
5508 nextStopLane = nextStop.lane;
5509 if (nextStop.isOpposite) {
5510 // target leftmost lane in forward direction
5511 nextStopLane = nextStopLane->getEdge().getOppositeEdge()->getLanes().back();
5512 }
5513 nextStopEdge = nextStop.edge;
5514 nextStopPos = nextStop.pars.startPos;
5515 nextStopIsWaypoint = nextStop.getSpeed() > 0;
5516 }
5517 // myArrivalTime = -1 in the context of validating departSpeed with departLane=best
5519 nextStopEdge = (myRoute->end() - 1);
5520 nextStopLane = (*nextStopEdge)->getLanes()[myArrivalLane];
5521 nextStopPos = myArrivalPos;
5522 }
5523 if (nextStopEdge != myRoute->end()) {
5524 // make sure that the "wrong" lanes get a penalty. (penalty needs to be
5525 // large enough to overcome a magic threshold in MSLaneChangeModel::DK2004.cpp:383)
5526 nextStopPos = MAX2(POSITION_EPS, MIN2((double)nextStopPos, (double)(nextStopLane->getLength() - 2 * POSITION_EPS)));
5527 if (nextStopLane->isInternal()) {
5528 // switch to the correct lane before entering the intersection
5529 nextStopPos = (*nextStopEdge)->getLength();
5530 }
5531 }
5532
5533 // go forward along the next lanes;
5534 // trains do not have to deal with lane-changing for stops but their best
5535 // lanes lookahead is needed for rail signal control
5536 const bool continueAfterStop = nextStopIsWaypoint || isRailway(getVClass());
5537 int seen = 0;
5538 double seenLength = 0;
5539 bool progress = true;
5540 // bestLanes must cover the braking distance even when at the very end of the current lane to avoid unecessary slow down
5541 const double maxBrakeDist = startLane->getLength() + getCarFollowModel().getHeadwayTime() * getMaxSpeed() + getCarFollowModel().brakeGap(getMaxSpeed()) + getVehicleType().getMinGap();
5542 for (MSRouteIterator ce = myCurrEdge; progress;) {
5543 std::vector<LaneQ> currentLanes;
5544 const std::vector<MSLane*>* allowed = nullptr;
5545 const MSEdge* nextEdge = nullptr;
5546 if (ce != myRoute->end() && ce + 1 != myRoute->end()) {
5547 nextEdge = *(ce + 1);
5548 allowed = (*ce)->allowedLanes(*nextEdge, myType->getVehicleClass());
5549 }
5550 const std::vector<MSLane*>& lanes = (*ce)->getLanes();
5551 for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
5552 LaneQ q;
5553 MSLane* cl = *i;
5554 q.lane = cl;
5555 q.bestContinuations.push_back(cl);
5556 q.bestLaneOffset = 0;
5558 q.currentLength = q.length;
5559 q.allowsContinuation = allowed == nullptr || std::find(allowed->begin(), allowed->end(), cl) != allowed->end();
5560 q.occupation = 0;
5561 q.nextOccupation = 0;
5562 currentLanes.push_back(q);
5563 }
5564 //
5565 if (nextStopEdge == ce
5566 // already past the stop edge
5567 && !(ce == myCurrEdge && myLane != nullptr && myLane->isInternal())) {
5568 if (!nextStopLane->isInternal() && !continueAfterStop) {
5569 progress = false;
5570 }
5571 const MSLane* normalStopLane = nextStopLane->getNormalPredecessorLane();
5572 for (std::vector<LaneQ>::iterator q = currentLanes.begin(); q != currentLanes.end(); ++q) {
5573 if (nextStopLane != nullptr && normalStopLane != (*q).lane) {
5574 (*q).allowsContinuation = false;
5575 (*q).length = nextStopPos;
5576 (*q).currentLength = (*q).length;
5577 }
5578 }
5579 }
5580
5581 myBestLanes.push_back(currentLanes);
5582 ++seen;
5583 seenLength += currentLanes[0].lane->getLength();
5584 ++ce;
5585 progress &= (seen <= 4 || seenLength < MAX2(maxBrakeDist, 3000.0)); // motorway
5586 progress &= (seen <= 8 || seenLength < MAX2(maxBrakeDist, 200.0) || isRailway(getVClass())); // urban
5587 progress &= ce != myRoute->end();
5588 /*
5589 if(progress) {
5590 progress &= (currentLanes.size()!=1||(*ce)->getLanes().size()!=1);
5591 }
5592 */
5593 }
5594
5595 // we are examining the last lane explicitly
5596 if (myBestLanes.size() != 0) {
5597 double bestLength = -1;
5598 // minimum and maximum lane index with best length
5599 int bestThisIndex = 0;
5600 int bestThisMaxIndex = 0;
5601 int index = 0;
5602 std::vector<LaneQ>& last = myBestLanes.back();
5603 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
5604 if ((*j).length > bestLength) {
5605 bestLength = (*j).length;
5606 bestThisIndex = index;
5607 bestThisMaxIndex = index;
5608 } else if ((*j).length == bestLength) {
5609 bestThisMaxIndex = index;
5610 }
5611 }
5612 index = 0;
5613 bool requiredChangeRightForbidden = false;
5614 int requireChangeToLeftForbidden = -1;
5615 for (std::vector<LaneQ>::iterator j = last.begin(); j != last.end(); ++j, ++index) {
5616 if ((*j).length < bestLength) {
5617 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
5618 (*j).bestLaneOffset = bestThisIndex - index;
5619 } else {
5620 (*j).bestLaneOffset = bestThisMaxIndex - index;
5621 }
5622 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
5623 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
5624 || requiredChangeRightForbidden)) {
5625 // this lane and all further lanes to the left cannot be used
5626 requiredChangeRightForbidden = true;
5627 (*j).length -= (*j).currentLength;
5628 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
5629 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
5630 // this lane and all previous lanes to the right cannot be used
5631 requireChangeToLeftForbidden = (*j).lane->getIndex();
5632 }
5633 }
5634 }
5635 for (int i = requireChangeToLeftForbidden; i >= 0; i--) {
5636 last[i].length -= last[i].currentLength;
5637 }
5638#ifdef DEBUG_BESTLANES
5639 if (DEBUG_COND) {
5640 std::cout << " last edge=" << last.front().lane->getEdge().getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
5641 std::vector<LaneQ>& laneQs = myBestLanes.back();
5642 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
5643 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
5644 }
5645 }
5646#endif
5647 }
5648 // go backward through the lanes
5649 // track back best lane and compute the best prior lane(s)
5650 for (std::vector<std::vector<LaneQ> >::reverse_iterator i = myBestLanes.rbegin() + 1; i != myBestLanes.rend(); ++i) {
5651 std::vector<LaneQ>& nextLanes = (*(i - 1));
5652 std::vector<LaneQ>& clanes = (*i);
5653 MSEdge& cE = clanes[0].lane->getEdge();
5654 int index = 0;
5655 double bestConnectedLength = -1;
5656 double bestLength = -1;
5657 for (std::vector<LaneQ>::iterator j = nextLanes.begin(); j != nextLanes.end(); ++j, ++index) {
5658 if ((*j).lane->isApproachedFrom(&cE) && bestConnectedLength < (*j).length) {
5659 bestConnectedLength = (*j).length;
5660 }
5661 if (bestLength < (*j).length) {
5662 bestLength = (*j).length;
5663 }
5664 }
5665 // compute index of the best lane (highest length and least offset from the best next lane)
5666 int bestThisIndex = 0;
5667 int bestThisMaxIndex = 0;
5668 if (bestConnectedLength > 0) {
5669 index = 0;
5670 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
5671 LaneQ bestConnectedNext;
5672 bestConnectedNext.length = -1;
5673 if ((*j).allowsContinuation) {
5674 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m) {
5675 if (((*m).lane->allowsVehicleClass(getVClass()) || (*m).lane->hadPermissionChanges())
5676 && (*m).lane->isApproachedFrom(&cE, (*j).lane)) {
5677 if (bestConnectedNext.length < (*m).length || (bestConnectedNext.length == (*m).length && abs(bestConnectedNext.bestLaneOffset) > abs((*m).bestLaneOffset))) {
5678 bestConnectedNext = *m;
5679 }
5680 }
5681 }
5682 if (bestConnectedNext.length == bestConnectedLength && abs(bestConnectedNext.bestLaneOffset) < 2) {
5683 (*j).length += bestLength;
5684 } else {
5685 (*j).length += bestConnectedNext.length;
5686 }
5687 (*j).bestLaneOffset = bestConnectedNext.bestLaneOffset;
5688 }
5689 copy(bestConnectedNext.bestContinuations.begin(), bestConnectedNext.bestContinuations.end(), back_inserter((*j).bestContinuations));
5690 if (clanes[bestThisIndex].length < (*j).length
5691 || (clanes[bestThisIndex].length == (*j).length && abs(clanes[bestThisIndex].bestLaneOffset) > abs((*j).bestLaneOffset))
5692 || (clanes[bestThisIndex].length == (*j).length && abs(clanes[bestThisIndex].bestLaneOffset) == abs((*j).bestLaneOffset) &&
5693 nextLinkPriority(clanes[bestThisIndex].bestContinuations) < nextLinkPriority((*j).bestContinuations))
5694 ) {
5695 bestThisIndex = index;
5696 bestThisMaxIndex = index;
5697 } else if (clanes[bestThisIndex].length == (*j).length
5698 && abs(clanes[bestThisIndex].bestLaneOffset) == abs((*j).bestLaneOffset)
5699 && nextLinkPriority(clanes[bestThisIndex].bestContinuations) == nextLinkPriority((*j).bestContinuations)) {
5700 bestThisMaxIndex = index;
5701 }
5702 }
5703
5704 //vehicle with elecHybrid device prefers running under an overhead wire
5705 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
5706 index = 0;
5707 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
5708 std::string overheadWireSegmentID = MSNet::getInstance()->getStoppingPlaceID((*j).lane, ((*j).currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
5709 if (overheadWireSegmentID != "") {
5710 bestThisIndex = index;
5711 bestThisMaxIndex = index;
5712 }
5713 }
5714 }
5715
5716 } else {
5717 // only needed in case of disconnected routes
5718 int bestNextIndex = 0;
5719 int bestDistToNeeded = (int) clanes.size();
5720 index = 0;
5721 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
5722 if ((*j).allowsContinuation) {
5723 int nextIndex = 0;
5724 for (std::vector<LaneQ>::const_iterator m = nextLanes.begin(); m != nextLanes.end(); ++m, ++nextIndex) {
5725 if ((*m).lane->isApproachedFrom(&cE, (*j).lane)) {
5726 if (bestDistToNeeded > abs((*m).bestLaneOffset)) {
5727 bestDistToNeeded = abs((*m).bestLaneOffset);
5728 bestThisIndex = index;
5729 bestThisMaxIndex = index;
5730 bestNextIndex = nextIndex;
5731 }
5732 }
5733 }
5734 }
5735 }
5736 clanes[bestThisIndex].length += nextLanes[bestNextIndex].length;
5737 copy(nextLanes[bestNextIndex].bestContinuations.begin(), nextLanes[bestNextIndex].bestContinuations.end(), back_inserter(clanes[bestThisIndex].bestContinuations));
5738
5739 }
5740 // set bestLaneOffset for all lanes
5741 index = 0;
5742 bool requiredChangeRightForbidden = false;
5743 int requireChangeToLeftForbidden = -1;
5744 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
5745 if ((*j).length < clanes[bestThisIndex].length
5746 || ((*j).length == clanes[bestThisIndex].length && abs((*j).bestLaneOffset) > abs(clanes[bestThisIndex].bestLaneOffset))
5747 || (nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)
5748 ) {
5749 if (abs(bestThisIndex - index) < abs(bestThisMaxIndex - index)) {
5750 (*j).bestLaneOffset = bestThisIndex - index;
5751 } else {
5752 (*j).bestLaneOffset = bestThisMaxIndex - index;
5753 }
5754 if ((nextLinkPriority((*j).bestContinuations)) < nextLinkPriority(clanes[bestThisIndex].bestContinuations)) {
5755 // try to move away from the lower-priority lane before it ends
5756 (*j).length = (*j).currentLength;
5757 }
5758 if ((*j).bestLaneOffset < 0 && (!(*j).lane->allowsChangingRight(getVClass())
5759 || !(*j).lane->getParallelLane(-1, false)->allowsVehicleClass(getVClass())
5760 || requiredChangeRightForbidden)) {
5761 // this lane and all further lanes to the left cannot be used
5762 requiredChangeRightForbidden = true;
5763 (*j).length -= (*j).currentLength;
5764 } else if ((*j).bestLaneOffset > 0 && (!(*j).lane->allowsChangingLeft(getVClass())
5765 || !(*j).lane->getParallelLane(1, false)->allowsVehicleClass(getVClass()))) {
5766 // this lane and all previous lanes to the right cannot be used
5767 requireChangeToLeftForbidden = (*j).lane->getIndex();
5768 }
5769 } else {
5770 (*j).bestLaneOffset = 0;
5771 }
5772 }
5773 for (int idx = requireChangeToLeftForbidden; idx >= 0; idx--) {
5774 clanes[idx].length -= clanes[idx].currentLength;
5775 }
5776
5777 //vehicle with elecHybrid device prefers running under an overhead wire
5778 if (static_cast<MSDevice_ElecHybrid*>(getDevice(typeid(MSDevice_ElecHybrid))) != 0) {
5779 index = 0;
5780 std::string overheadWireID = MSNet::getInstance()->getStoppingPlaceID(clanes[bestThisIndex].lane, (clanes[bestThisIndex].currentLength) / 2, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
5781 if (overheadWireID != "") {
5782 for (std::vector<LaneQ>::iterator j = clanes.begin(); j != clanes.end(); ++j, ++index) {
5783 (*j).bestLaneOffset = bestThisIndex - index;
5784 }
5785 }
5786 }
5787
5788#ifdef DEBUG_BESTLANES
5789 if (DEBUG_COND) {
5790 std::cout << " edge=" << cE.getID() << " (bestIndex=" << bestThisIndex << " bestMaxIndex=" << bestThisMaxIndex << "):\n";
5791 std::vector<LaneQ>& laneQs = clanes;
5792 for (std::vector<LaneQ>::iterator j = laneQs.begin(); j != laneQs.end(); ++j) {
5793 std::cout << " lane=" << (*j).lane->getID() << " length=" << (*j).length << " bestOffset=" << (*j).bestLaneOffset << "\n";
5794 }
5795 }
5796#endif
5797
5798 }
5800#ifdef DEBUG_BESTLANES
5801 if (DEBUG_COND) {
5802 std::cout << SIMTIME << " veh=" << getID() << " bestCont=" << toString(getBestLanesContinuation()) << "\n";
5803 }
5804#endif
5805 return;
5806}
5807
5808
5809int
5810MSVehicle::nextLinkPriority(const std::vector<MSLane*>& conts) {
5811 if (conts.size() < 2) {
5812 return -1;
5813 } else {
5814 const MSLink* const link = conts[0]->getLinkTo(conts[1]);
5815 if (link != nullptr) {
5816 return link->havePriority() ? 1 : 0;
5817 } else {
5818 // disconnected route
5819 return -1;
5820 }
5821 }
5822}
5823
5824
5825void
5827 std::vector<LaneQ>& currLanes = *myBestLanes.begin();
5828 std::vector<LaneQ>::iterator i;
5829 for (i = currLanes.begin(); i != currLanes.end(); ++i) {
5830 double nextOccupation = 0;
5831 for (std::vector<MSLane*>::const_iterator j = (*i).bestContinuations.begin() + 1; j != (*i).bestContinuations.end(); ++j) {
5832 nextOccupation += (*j)->getBruttoVehLenSum();
5833 }
5834 (*i).nextOccupation = nextOccupation;
5835#ifdef DEBUG_BESTLANES
5836 if (DEBUG_COND) {
5837 std::cout << " lane=" << (*i).lane->getID() << " nextOccupation=" << nextOccupation << "\n";
5838 }
5839#endif
5840 if ((*i).lane == startLane) {
5842 }
5843 }
5844}
5845
5846
5847const std::vector<MSLane*>&
5849 if (myBestLanes.empty() || myBestLanes[0].empty()) {
5850 return myEmptyLaneVector;
5851 }
5852 return (*myCurrentLaneInBestLanes).bestContinuations;
5853}
5854
5855
5856const std::vector<MSLane*>&
5858 const MSLane* lane = l;
5859 // XXX: shouldn't this be a "while" to cover more than one internal lane? (Leo) Refs. #2575
5860 if (lane->getEdge().isInternal()) {
5861 // internal edges are not kept inside the bestLanes structure
5862 lane = lane->getLinkCont()[0]->getLane();
5863 }
5864 if (myBestLanes.size() == 0) {
5865 return myEmptyLaneVector;
5866 }
5867 for (std::vector<LaneQ>::const_iterator i = myBestLanes[0].begin(); i != myBestLanes[0].end(); ++i) {
5868 if ((*i).lane == lane) {
5869 return (*i).bestContinuations;
5870 }
5871 }
5872 return myEmptyLaneVector;
5873}
5874
5875const std::vector<const MSLane*>
5876MSVehicle::getUpcomingLanesUntil(double distance) const {
5877 std::vector<const MSLane*> lanes;
5878
5879 if (distance <= 0.) {
5880 // WRITE_WARNINGF(TL("MSVehicle::getUpcomingLanesUntil(): distance ('%') should be greater than 0."), distance);
5881 return lanes;
5882 }
5883
5884 if (!myLaneChangeModel->isOpposite()) {
5885 distance += getPositionOnLane();
5886 } else {
5887 distance += myLane->getOppositePos(getPositionOnLane());
5888 }
5890 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
5891 lanes.insert(lanes.end(), lane);
5892 distance -= lane->getLength();
5893 lane = lane->getLinkCont().front()->getViaLaneOrLane();
5894 }
5895
5896 const std::vector<MSLane*>& contLanes = getBestLanesContinuation();
5897 if (contLanes.empty()) {
5898 return lanes;
5899 }
5900 auto contLanesIt = contLanes.begin();
5901 MSRouteIterator routeIt = myCurrEdge; // keep track of covered edges in myRoute
5902 while (distance > 0.) {
5903 MSLane* l = nullptr;
5904 if (contLanesIt != contLanes.end()) {
5905 l = *contLanesIt;
5906 if (l != nullptr) {
5907 assert(l->getEdge().getID() == (*routeIt)->getLanes().front()->getEdge().getID());
5908 }
5909 ++contLanesIt;
5910 if (l != nullptr || myLane->isInternal()) {
5911 ++routeIt;
5912 }
5913 if (l == nullptr) {
5914 continue;
5915 }
5916 } else if (routeIt != myRoute->end()) { // bestLanes didn't get us far enough
5917 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
5918 l = (*routeIt)->getLanes().back();
5919 ++routeIt;
5920 } else { // the search distance goes beyond our route
5921 break;
5922 }
5923
5924 assert(l != nullptr);
5925
5926 // insert internal lanes if applicable
5927 const MSLane* internalLane = lanes.size() > 0 ? lanes.back()->getInternalFollowingLane(l) : nullptr;
5928 while ((internalLane != nullptr) && internalLane->isInternal() && (distance > 0.)) {
5929 lanes.insert(lanes.end(), internalLane);
5930 distance -= internalLane->getLength();
5931 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
5932 }
5933 if (distance <= 0.) {
5934 break;
5935 }
5936
5937 lanes.insert(lanes.end(), l);
5938 distance -= l->getLength();
5939 }
5940
5941 return lanes;
5942}
5943
5944const std::vector<const MSLane*>
5945MSVehicle::getPastLanesUntil(double distance) const {
5946 std::vector<const MSLane*> lanes;
5947
5948 if (distance <= 0.) {
5949 // WRITE_WARNINGF(TL("MSVehicle::getPastLanesUntil(): distance ('%') should be greater than 0."), distance);
5950 return lanes;
5951 }
5952
5953 MSRouteIterator routeIt = myCurrEdge;
5954 if (!myLaneChangeModel->isOpposite()) {
5955 distance += myLane->getLength() - getPositionOnLane();
5956 } else {
5958 }
5960 while (lane->isInternal() && (distance > 0.)) { // include initial internal lanes
5961 lanes.insert(lanes.end(), lane);
5962 distance -= lane->getLength();
5963 lane = lane->getLogicalPredecessorLane();
5964 }
5965
5966 while (distance > 0.) {
5967 // choose left-most lane as default (avoid sidewalks, bike lanes etc)
5968 MSLane* l = (*routeIt)->getLanes().back();
5969
5970 // insert internal lanes if applicable
5971 const MSEdge* internalEdge = lanes.size() > 0 ? (*routeIt)->getInternalFollowingEdge(&(lanes.back()->getEdge()), getVClass()) : nullptr;
5972 const MSLane* internalLane = internalEdge != nullptr ? internalEdge->getLanes().front() : nullptr;
5973 std::vector<const MSLane*> internalLanes;
5974 while ((internalLane != nullptr) && internalLane->isInternal()) { // collect all internal successor lanes
5975 internalLanes.insert(internalLanes.begin(), internalLane);
5976 internalLane = internalLane->getLinkCont().front()->getViaLaneOrLane();
5977 }
5978 for (auto it = internalLanes.begin(); (it != internalLanes.end()) && (distance > 0.); ++it) { // check remaining distance in correct order
5979 lanes.insert(lanes.end(), *it);
5980 distance -= (*it)->getLength();
5981 }
5982 if (distance <= 0.) {
5983 break;
5984 }
5985
5986 lanes.insert(lanes.end(), l);
5987 distance -= l->getLength();
5988
5989 // NOTE: we're going backwards with the (bi-directional) Iterator
5990 // TODO: consider make reverse_iterator() when moving on to C++14 or later
5991 if (routeIt != myRoute->begin()) {
5992 --routeIt;
5993 } else { // we went backwards to begin() and already processed the first and final element
5994 break;
5995 }
5996 }
5997
5998 return lanes;
5999}
6000
6001
6002const std::vector<MSLane*>
6004 const std::vector<const MSLane*> routeLanes = getPastLanesUntil(myLane->getMaximumBrakeDist());
6005 std::vector<MSLane*> result;
6006 for (const MSLane* lane : routeLanes) {
6007 MSLane* opposite = lane->getOpposite();
6008 if (opposite != nullptr) {
6009 result.push_back(opposite);
6010 } else {
6011 break;
6012 }
6013 }
6014 return result;
6015}
6016
6017
6018int
6020 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6021 return 0;
6022 } else {
6023 return (*myCurrentLaneInBestLanes).bestLaneOffset;
6024 }
6025}
6026
6027double
6029 if (myBestLanes.empty() || myBestLanes[0].empty()) {
6030 return -1;
6031 } else {
6032 return (*myCurrentLaneInBestLanes).length;
6033 }
6034}
6035
6036
6037
6038void
6039MSVehicle::adaptBestLanesOccupation(int laneIndex, double density) {
6040 std::vector<MSVehicle::LaneQ>& preb = myBestLanes.front();
6041 assert(laneIndex < (int)preb.size());
6042 preb[laneIndex].occupation = density + preb[laneIndex].nextOccupation;
6043}
6044
6045
6046void
6049 myState.myPosLat = 0;
6050 }
6051}
6052
6053std::pair<const MSLane*, double>
6054MSVehicle::getLanePosAfterDist(double distance) const {
6055 if (distance == 0) {
6056 return std::make_pair(myLane, getPositionOnLane());
6057 }
6058 const std::vector<const MSLane*> lanes = getUpcomingLanesUntil(distance);
6059 distance += getPositionOnLane();
6060 for (const MSLane* lane : lanes) {
6061 if (lane->getLength() > distance) {
6062 return std::make_pair(lane, distance);
6063 }
6064 distance -= lane->getLength();
6065 }
6066 return std::make_pair(nullptr, -1);
6067}
6068
6069
6070double
6071MSVehicle::getDistanceToPosition(double destPos, const MSEdge* destEdge) const {
6072 double distance = std::numeric_limits<double>::max();
6073 if (isOnRoad() && destEdge != nullptr) {
6074 if (myLane->isInternal()) {
6075 // vehicle is on inner junction edge
6076 distance = myLane->getLength() - getPositionOnLane();
6077 distance += myRoute->getDistanceBetween(0, destPos, *(myCurrEdge + 1), destEdge);
6078 } else {
6079 // vehicle is on a normal edge
6080 distance = myRoute->getDistanceBetween(getPositionOnLane(), destPos, *myCurrEdge, destEdge);
6081 }
6082 }
6083 return distance;
6084}
6085
6086
6087std::pair<const MSVehicle* const, double>
6088MSVehicle::getLeader(double dist) const {
6089 if (myLane == nullptr) {
6090 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6091 }
6092 if (dist == 0) {
6094 }
6095 const MSVehicle* lead = nullptr;
6096 const MSLane* lane = myLane; // ensure lane does not change between getVehiclesSecure and releaseVehicles;
6097 const MSLane::VehCont& vehs = lane->getVehiclesSecure();
6098 // vehicle might be outside the road network
6099 MSLane::VehCont::const_iterator it = std::find(vehs.begin(), vehs.end(), this);
6100 if (it != vehs.end() && it + 1 != vehs.end()) {
6101 lead = *(it + 1);
6102 }
6103 if (lead != nullptr) {
6104 std::pair<const MSVehicle* const, double> result(
6105 lead, lead->getBackPositionOnLane(myLane) - getPositionOnLane() - getVehicleType().getMinGap());
6106 lane->releaseVehicles();
6107 return result;
6108 }
6109 const double seen = myLane->getLength() - getPositionOnLane();
6110 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(myLane);
6111 std::pair<const MSVehicle* const, double> result = myLane->getLeaderOnConsecutive(dist, seen, getSpeed(), *this, bestLaneConts);
6112 lane->releaseVehicles();
6113 return result;
6114}
6115
6116
6117std::pair<const MSVehicle* const, double>
6118MSVehicle::getFollower(double dist) const {
6119 if (myLane == nullptr) {
6120 return std::make_pair(static_cast<const MSVehicle*>(nullptr), -1);
6121 }
6122 if (dist == 0) {
6123 dist = getCarFollowModel().brakeGap(myLane->getEdge().getSpeedLimit() * 2, 4.5, 0);
6124 }
6125 return myLane->getFollower(this, getPositionOnLane(), dist, MSLane::MinorLinkMode::FOLLOW_NEVER);
6126}
6127
6128
6129double
6131 // calling getLeader with 0 would induce a dist calculation but we only want to look for the leaders on the current lane
6132 std::pair<const MSVehicle* const, double> leaderInfo = getLeader(-1);
6133 if (leaderInfo.first == nullptr || getSpeed() == 0) {
6134 return -1;
6135 }
6136 return (leaderInfo.second + getVehicleType().getMinGap()) / getSpeed();
6137}
6138
6139
6140void
6142 MSBaseVehicle::addTransportable(transportable);
6143 if (myStops.size() > 0 && myStops.front().reached) {
6144 if (transportable->isPerson()) {
6145 if (myStops.front().triggered && myStops.front().numExpectedPerson > 0) {
6146 myStops.front().numExpectedPerson -= (int)myStops.front().pars.awaitedPersons.count(transportable->getID());
6147 }
6148 } else {
6149 if (myStops.front().pars.containerTriggered && myStops.front().numExpectedContainer > 0) {
6150 myStops.front().numExpectedContainer -= (int)myStops.front().pars.awaitedContainers.count(transportable->getID());
6151 }
6152 }
6153 }
6154}
6155
6156
6157void
6160 int state = myLaneChangeModel->getOwnState();
6161 // do not set blinker for sublane changes or when blocked from changing to the right
6162 const bool blinkerManoeuvre = (((state & LCA_SUBLANE) == 0) && (
6163 (state & LCA_KEEPRIGHT) == 0 || (state & LCA_BLOCKED) == 0));
6167 // lane indices increase from left to right
6168 std::swap(left, right);
6169 }
6170 if ((state & LCA_LEFT) != 0 && blinkerManoeuvre) {
6171 switchOnSignal(left);
6172 } else if ((state & LCA_RIGHT) != 0 && blinkerManoeuvre) {
6173 switchOnSignal(right);
6174 } else if (myLaneChangeModel->isChangingLanes()) {
6176 switchOnSignal(left);
6177 } else {
6178 switchOnSignal(right);
6179 }
6180 } else {
6181 const MSLane* lane = getLane();
6182 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, 1, *lane, getBestLanesContinuation());
6183 if (link != lane->getLinkCont().end() && lane->getLength() - getPositionOnLane() < lane->getVehicleMaxSpeed(this) * (double) 7.) {
6184 switch ((*link)->getDirection()) {
6189 break;
6193 break;
6194 default:
6195 break;
6196 }
6197 }
6198 }
6199 // stopping related signals
6200 if (hasStops()
6201 && (myStops.begin()->reached ||
6203 && myStopDist < getCarFollowModel().brakeGap(myLane->getVehicleMaxSpeed(this), getCarFollowModel().getMaxDecel(), 3)))) {
6204 if (myStops.begin()->lane->getIndex() > 0 && myStops.begin()->lane->getParallelLane(-1)->allowsVehicleClass(getVClass())) {
6205 // not stopping on the right. Activate emergency blinkers
6207 } else if (!myStops.begin()->reached && (myStops.begin()->pars.parking == ParkingType::OFFROAD)) {
6208 // signal upcoming parking stop on the current lane when within braking distance (~2 seconds before braking)
6210 }
6211 }
6212 if (myInfluencer != nullptr && myInfluencer->getSignals() >= 0) {
6214 myInfluencer->setSignals(-1); // overwrite computed signals only once
6215 }
6216}
6217
6218void
6220
6221 //TODO look if timestep ist SIMSTEP
6222 if (currentTime % 1000 == 0) {
6225 } else {
6227 }
6228 }
6229}
6230
6231
6232int
6234 return myLane == nullptr ? -1 : myLane->getIndex();
6235}
6236
6237
6238void
6239MSVehicle::setTentativeLaneAndPosition(MSLane* lane, double pos, double posLat) {
6240 myLane = lane;
6241 myState.myPos = pos;
6242 myState.myPosLat = posLat;
6244}
6245
6246
6247double
6249 return myState.myPosLat + 0.5 * myLane->getWidth() - 0.5 * getVehicleType().getWidth();
6250}
6251
6252
6253double
6255 return myState.myPosLat + 0.5 * myLane->getWidth() + 0.5 * getVehicleType().getWidth();
6256}
6257
6258
6259double
6261 return myState.myPosLat + 0.5 * lane->getWidth() - 0.5 * getVehicleType().getWidth();
6262}
6263
6264
6265double
6267 return myState.myPosLat + 0.5 * lane->getWidth() + 0.5 * getVehicleType().getWidth();
6268}
6269
6270
6271double
6273 return getCenterOnEdge(lane) - 0.5 * getVehicleType().getWidth();
6274}
6275
6276
6277double
6279 if (lane == nullptr || &lane->getEdge() == &myLane->getEdge()) {
6281 } else if (lane == myLaneChangeModel->getShadowLane()) {
6282 if (myLaneChangeModel->isOpposite() && &lane->getEdge() != &myLane->getEdge()) {
6283 return lane->getRightSideOnEdge() + lane->getWidth() - myState.myPosLat + 0.5 * myLane->getWidth();
6284 }
6286 return lane->getRightSideOnEdge() + lane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6287 } else {
6288 return lane->getRightSideOnEdge() - myLane->getWidth() + myState.myPosLat + 0.5 * myLane->getWidth();
6289 }
6290 } else if (lane == myLane->getBidiLane()) {
6291 return lane->getRightSideOnEdge() - myState.myPosLat + 0.5 * lane->getWidth();
6292 } else {
6293 assert(myFurtherLanes.size() == myFurtherLanesPosLat.size());
6294 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6295 if (myFurtherLanes[i] == lane) {
6296#ifdef DEBUG_FURTHER
6297 if (DEBUG_COND) std::cout << " getCenterOnEdge veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " furtherLat=" << myFurtherLanesPosLat[i]
6298 << " result=" << lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth()
6299 << "\n";
6300#endif
6301 return lane->getRightSideOnEdge() + myFurtherLanesPosLat[i] + 0.5 * lane->getWidth();
6302 }
6303 }
6304 //if (DEBUG_COND) std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6305 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6306 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6307 //if (DEBUG_COND) std::cout << " comparing i=" << (*i)->getID() << " lane=" << lane->getID() << "\n";
6308 if (shadowFurther[i] == lane) {
6309 assert(myLaneChangeModel->getShadowLane() != 0);
6310 return (lane->getRightSideOnEdge() + myLaneChangeModel->getShadowFurtherLanesPosLat()[i] + 0.5 * lane->getWidth()
6312 }
6313 }
6314 assert(false);
6315 throw ProcessError("Request lateral pos of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6316 }
6317}
6318
6319
6320double
6322 assert(lane != 0);
6323 if (&lane->getEdge() == &myLane->getEdge()) {
6324 return myLane->getRightSideOnEdge() - lane->getRightSideOnEdge();
6325 } else if (myLane->getParallelOpposite() == lane) {
6326 return (myLane->getWidth() + lane->getWidth()) * 0.5 - 2 * getLateralPositionOnLane();
6327 } else if (myLane->getBidiLane() == lane) {
6328 return -2 * getLateralPositionOnLane();
6329 } else {
6330 // Check whether the lane is a further lane for the vehicle
6331 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6332 if (myFurtherLanes[i] == lane) {
6333#ifdef DEBUG_FURTHER
6334 if (DEBUG_COND) {
6335 std::cout << " getLatOffset veh=" << getID() << " lane=" << lane->getID() << " i=" << i << " posLat=" << myState.myPosLat << " furtherLat=" << myFurtherLanesPosLat[i] << "\n";
6336 }
6337#endif
6339 }
6340 }
6341#ifdef DEBUG_FURTHER
6342 if (DEBUG_COND) {
6343 std::cout << SIMTIME << " veh=" << getID() << " myShadowFurtherLanes=" << toString(myLaneChangeModel->getShadowFurtherLanes()) << "\n";
6344 }
6345#endif
6346 // Check whether the lane is a "shadow further lane" for the vehicle
6347 const std::vector<MSLane*>& shadowFurther = myLaneChangeModel->getShadowFurtherLanes();
6348 for (int i = 0; i < (int)shadowFurther.size(); ++i) {
6349 if (shadowFurther[i] == lane) {
6350#ifdef DEBUG_FURTHER
6351 if (DEBUG_COND) std::cout << " getLatOffset veh=" << getID()
6352 << " shadowLane=" << Named::getIDSecure(myLaneChangeModel->getShadowLane())
6353 << " lane=" << lane->getID()
6354 << " i=" << i
6355 << " posLat=" << myState.myPosLat
6356 << " shadowPosLat=" << getLatOffset(myLaneChangeModel->getShadowLane())
6357 << " shadowFurtherLat=" << myLaneChangeModel->getShadowFurtherLanesPosLat()[i]
6358 << "\n";
6359#endif
6361 }
6362 }
6363 // Check whether the vehicle issued a maneuverReservation on the lane.
6364 const std::vector<MSLane*>& furtherTargets = myLaneChangeModel->getFurtherTargetLanes();
6365 for (int i = 0; i < (int)myFurtherLanes.size(); ++i) {
6366 // Further target lanes are just neighboring lanes of the vehicle's further lanes, @see MSAbstractLaneChangeModel::updateTargetLane()
6367 MSLane* targetLane = furtherTargets[i];
6368 if (targetLane == lane) {
6369 const double targetDir = myLaneChangeModel->getManeuverDist() < 0 ? -1. : 1.;
6370 const double latOffset = myFurtherLanesPosLat[i] - myState.myPosLat + targetDir * 0.5 * (myFurtherLanes[i]->getWidth() + targetLane->getWidth());
6371#ifdef DEBUG_TARGET_LANE
6372 if (DEBUG_COND) {
6373 std::cout << " getLatOffset veh=" << getID()
6374 << " wrt targetLane=" << Named::getIDSecure(myLaneChangeModel->getTargetLane())
6375 << "\n i=" << i
6376 << " posLat=" << myState.myPosLat
6377 << " furtherPosLat=" << myFurtherLanesPosLat[i]
6378 << " maneuverDist=" << myLaneChangeModel->getManeuverDist()
6379 << " targetDir=" << targetDir
6380 << " latOffset=" << latOffset
6381 << std::endl;
6382 }
6383#endif
6384 return latOffset;
6385 }
6386 }
6387 assert(false);
6388 throw ProcessError("Request lateral offset of vehicle '" + getID() + "' for invalid lane '" + Named::getIDSecure(lane) + "'");
6389 }
6390}
6391
6392
6393double
6394MSVehicle::lateralDistanceToLane(const int offset) const {
6395 // compute the distance when changing to the neighboring lane
6396 // (ensure we do not lap into the line behind neighLane since there might be unseen blockers)
6397 assert(offset == 0 || offset == 1 || offset == -1);
6398 assert(myLane != nullptr);
6399 assert(myLane->getParallelLane(offset) != nullptr || myLane->getParallelOpposite() != nullptr);
6400 const double halfCurrentLaneWidth = 0.5 * myLane->getWidth();
6401 const double halfVehWidth = 0.5 * (getWidth() + NUMERICAL_EPS);
6402 const double latPos = getLateralPositionOnLane();
6403 const double oppositeSign = getLaneChangeModel().isOpposite() ? -1 : 1;
6404 double leftLimit = halfCurrentLaneWidth - halfVehWidth - oppositeSign * latPos;
6405 double rightLimit = -halfCurrentLaneWidth + halfVehWidth - oppositeSign * latPos;
6406 double latLaneDist = 0; // minimum distance to move the vehicle fully onto the new lane
6407 if (offset == 0) {
6408 if (latPos + halfVehWidth > halfCurrentLaneWidth) {
6409 // correct overlapping left
6410 latLaneDist = halfCurrentLaneWidth - latPos - halfVehWidth;
6411 } else if (latPos - halfVehWidth < -halfCurrentLaneWidth) {
6412 // correct overlapping right
6413 latLaneDist = -halfCurrentLaneWidth - latPos + halfVehWidth;
6414 }
6415 latLaneDist *= oppositeSign;
6416 } else if (offset == -1) {
6417 latLaneDist = rightLimit - (getWidth() + NUMERICAL_EPS);
6418 } else if (offset == 1) {
6419 latLaneDist = leftLimit + (getWidth() + NUMERICAL_EPS);
6420 }
6421#ifdef DEBUG_ACTIONSTEPS
6422 if (DEBUG_COND) {
6423 std::cout << SIMTIME
6424 << " veh=" << getID()
6425 << " halfCurrentLaneWidth=" << halfCurrentLaneWidth
6426 << " halfVehWidth=" << halfVehWidth
6427 << " latPos=" << latPos
6428 << " latLaneDist=" << latLaneDist
6429 << " leftLimit=" << leftLimit
6430 << " rightLimit=" << rightLimit
6431 << "\n";
6432 }
6433#endif
6434 return latLaneDist;
6435}
6436
6437
6438double
6439MSVehicle::getLateralOverlap(double posLat, const MSLane* lane) const {
6440 return (fabs(posLat) + 0.5 * getVehicleType().getWidth()
6441 - 0.5 * lane->getWidth());
6442}
6443
6444double
6447}
6448
6449double
6452}
6453
6454
6455void
6457 for (const DriveProcessItem& dpi : lfLinks) {
6458 if (dpi.myLink != nullptr) {
6459 dpi.myLink->removeApproaching(this);
6460 }
6461 }
6462 // unregister on all shadow links
6464}
6465
6466
6467bool
6469 // the following links are unsafe:
6470 // - zipper links if they are close enough and have approaching vehicles in the relevant time range
6471 // - unprioritized links if the vehicle is currently approaching a prioritzed link and unable to stop in time
6472 double seen = myLane->getLength() - getPositionOnLane();
6473 const double dist = getCarFollowModel().brakeGap(getSpeed(), getCarFollowModel().getMaxDecel(), 0);
6474 if (seen < dist) {
6475 const std::vector<MSLane*>& bestLaneConts = getBestLanesContinuation(lane);
6476 int view = 1;
6477 std::vector<MSLink*>::const_iterator link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
6478 DriveItemVector::const_iterator di = myLFLinkLanes.begin();
6479 while (!lane->isLinkEnd(link) && seen <= dist) {
6480 if (!lane->getEdge().isInternal()
6481 && (((*link)->getState() == LINKSTATE_ZIPPER && seen < (*link)->getFoeVisibilityDistance())
6482 || !(*link)->havePriority())) {
6483 // find the drive item corresponding to this link
6484 bool found = false;
6485 while (di != myLFLinkLanes.end() && !found) {
6486 if ((*di).myLink != nullptr) {
6487 const MSLane* diPredLane = (*di).myLink->getLaneBefore();
6488 if (diPredLane != nullptr) {
6489 if (&diPredLane->getEdge() == &lane->getEdge()) {
6490 found = true;
6491 }
6492 }
6493 }
6494 if (!found) {
6495 di++;
6496 }
6497 }
6498 if (found) {
6499 const SUMOTime leaveTime = (*link)->getLeaveTime((*di).myArrivalTime, (*di).myArrivalSpeed,
6500 (*di).getLeaveSpeed(), getVehicleType().getLength());
6501 if ((*link)->hasApproachingFoe((*di).myArrivalTime, leaveTime, (*di).myArrivalSpeed, getCarFollowModel().getMaxDecel())) {
6502 //std::cout << SIMTIME << " veh=" << getID() << " aborting changeTo=" << Named::getIDSecure(bestLaneConts.front()) << " linkState=" << toString((*link)->getState()) << " seen=" << seen << " dist=" << dist << "\n";
6503 return true;
6504 }
6505 }
6506 // no drive item is found if the vehicle aborts it's request within dist
6507 }
6508 lane = (*link)->getViaLaneOrLane();
6509 if (!lane->getEdge().isInternal()) {
6510 view++;
6511 }
6512 seen += lane->getLength();
6513 link = MSLane::succLinkSec(*this, view, *lane, bestLaneConts);
6514 }
6515 }
6516 return false;
6517}
6518
6519
6521MSVehicle::getBoundingBox(double offset) const {
6522 PositionVector centerLine;
6523 centerLine.push_back(getPosition());
6524 switch (myType->getGuiShape()) {
6531 for (MSLane* lane : myFurtherLanes) {
6532 centerLine.push_back(lane->getShape().back());
6533 }
6534 break;
6535 }
6536 default:
6537 break;
6538 }
6539 centerLine.push_back(getBackPosition());
6540 if (offset != 0) {
6541 centerLine.extrapolate2D(offset);
6542 }
6543 PositionVector result = centerLine;
6544 result.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
6545 centerLine.move2side(MIN2(0.0, -0.5 * myType->getWidth() - offset));
6546 result.append(centerLine.reverse(), POSITION_EPS);
6547 return result;
6548}
6549
6550
6552MSVehicle::getBoundingPoly(double offset) const {
6553 switch (myType->getGuiShape()) {
6559 // box with corners cut off
6560 PositionVector result;
6561 PositionVector centerLine;
6562 centerLine.push_back(getPosition());
6563 centerLine.push_back(getBackPosition());
6564 if (offset != 0) {
6565 centerLine.extrapolate2D(offset);
6566 }
6567 PositionVector line1 = centerLine;
6568 PositionVector line2 = centerLine;
6569 line1.move2side(MAX2(0.0, 0.3 * myType->getWidth() + offset));
6570 line2.move2side(MAX2(0.0, 0.5 * myType->getWidth() + offset));
6571 line2.scaleRelative(0.8);
6572 result.push_back(line1[0]);
6573 result.push_back(line2[0]);
6574 result.push_back(line2[1]);
6575 result.push_back(line1[1]);
6576 line1.move2side(MIN2(0.0, -0.6 * myType->getWidth() - offset));
6577 line2.move2side(MIN2(0.0, -1.0 * myType->getWidth() - offset));
6578 result.push_back(line1[1]);
6579 result.push_back(line2[1]);
6580 result.push_back(line2[0]);
6581 result.push_back(line1[0]);
6582 return result;
6583 }
6584 default:
6585 return getBoundingBox();
6586 }
6587}
6588
6589
6590bool
6592 for (std::vector<MSLane*>::const_iterator i = myFurtherLanes.begin(); i != myFurtherLanes.end(); ++i) {
6593 if (&(*i)->getEdge() == edge) {
6594 return true;
6595 }
6596 }
6597 return false;
6598}
6599
6600bool
6601MSVehicle::rerouteParkingArea(const std::string& parkingAreaID, std::string& errorMsg) {
6602 // this function is based on MSTriggeredRerouter::rerouteParkingArea in order to keep
6603 // consistency in the behaviour.
6604
6605 // get vehicle params
6606 MSParkingArea* destParkArea = getNextParkingArea();
6607 const MSRoute& route = getRoute();
6608 const MSEdge* lastEdge = route.getLastEdge();
6609
6610 if (destParkArea == nullptr) {
6611 // not driving towards a parking area
6612 errorMsg = "Vehicle " + getID() + " is not driving to a parking area so it cannot be rerouted.";
6613 return false;
6614 }
6615
6616 // if the current route ends at the parking area, the new route will also and at the new area
6617 bool newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
6618 && getArrivalPos() >= destParkArea->getBeginLanePosition()
6619 && getArrivalPos() <= destParkArea->getEndLanePosition());
6620
6621 // retrieve info on the new parking area
6623 parkingAreaID, SumoXMLTag::SUMO_TAG_PARKING_AREA);
6624
6625 if (newParkingArea == nullptr) {
6626 errorMsg = "Parking area ID " + toString(parkingAreaID) + " not found in the network.";
6627 return false;
6628 }
6629
6630 const MSEdge* newEdge = &(newParkingArea->getLane().getEdge());
6632
6633 // Compute the route from the current edge to the parking area edge
6634 ConstMSEdgeVector edgesToPark;
6635 router.compute(getEdge(), newEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
6636
6637 // Compute the route from the parking area edge to the end of the route
6638 ConstMSEdgeVector edgesFromPark;
6639 if (!newDestination) {
6640 router.compute(newEdge, lastEdge, this, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
6641 } else {
6642 // adapt plans of any riders
6643 for (MSTransportable* p : getPersons()) {
6644 p->rerouteParkingArea(getNextParkingArea(), newParkingArea);
6645 }
6646 }
6647
6648 // we have a new destination, let's replace the vehicle route
6649 ConstMSEdgeVector edges = edgesToPark;
6650 if (edgesFromPark.size() > 0) {
6651 edges.insert(edges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
6652 }
6653
6654 if (newDestination) {
6655 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
6656 *newParameter = getParameter();
6658 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
6659 replaceParameter(newParameter);
6660 }
6661 const double routeCost = router.recomputeCosts(edges, this, MSNet::getInstance()->getCurrentTimeStep());
6662 ConstMSEdgeVector prevEdges(myCurrEdge, myRoute->end());
6663 const double savings = router.recomputeCosts(prevEdges, this, MSNet::getInstance()->getCurrentTimeStep());
6664 if (replaceParkingArea(newParkingArea, errorMsg)) {
6665 const bool onInit = myLane == nullptr;
6666 replaceRouteEdges(edges, routeCost, savings, "TraCI:" + toString(SUMO_TAG_PARKING_AREA_REROUTE), onInit, false, false);
6667 } else {
6668 WRITE_WARNING("Vehicle '" + getID() + "' could not reroute to new parkingArea '" + newParkingArea->getID()
6669 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
6670 return false;
6671 }
6672 return true;
6673}
6674
6675
6676bool
6678 const int numStops = (int)myStops.size();
6679 const bool result = MSBaseVehicle::addTraciStop(stop, errorMsg);
6680 if (myLane != nullptr && numStops != (int)myStops.size()) {
6681 updateBestLanes(true);
6682 }
6683 return result;
6684}
6685
6686
6687bool
6688MSVehicle::handleCollisionStop(MSStop& stop, const double distToStop) {
6689 if (myCurrEdge == stop.edge && distToStop + POSITION_EPS < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getMaxDecel(), 0)) {
6690 if (distToStop < getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)) {
6691 double vNew = getCarFollowModel().maximumSafeStopSpeed(distToStop, getCarFollowModel().getMaxDecel(), getSpeed(), false, 0);
6692 //std::cout << SIMTIME << " veh=" << getID() << " v=" << myState.mySpeed << " distToStop=" << distToStop
6693 // << " vMinNex=" << getCarFollowModel().minNextSpeed(getSpeed(), this)
6694 // << " bg1=" << getCarFollowModel().brakeGap(myState.mySpeed)
6695 // << " bg2=" << getCarFollowModel().brakeGap(myState.mySpeed, getCarFollowModel().getEmergencyDecel(), 0)
6696 // << " vNew=" << vNew
6697 // << "\n";
6698 myState.mySpeed = MIN2(myState.mySpeed, vNew + ACCEL2SPEED(getCarFollowModel().getEmergencyDecel()));
6701 if (myState.myPos < myType->getLength()) {
6705 myAngle += M_PI;
6706 }
6707 }
6708 }
6709 }
6710 return true;
6711}
6712
6713
6714bool
6716 if (isStopped()) {
6720 }
6721 MSStop& stop = myStops.front();
6722 // we have waited long enough and fulfilled any passenger-requirements
6723 if (stop.busstop != nullptr) {
6724 // inform bus stop about leaving it
6725 stop.busstop->leaveFrom(this);
6726 }
6727 // we have waited long enough and fulfilled any container-requirements
6728 if (stop.containerstop != nullptr) {
6729 // inform container stop about leaving it
6730 stop.containerstop->leaveFrom(this);
6731 }
6732 if (stop.parkingarea != nullptr && stop.getSpeed() <= 0) {
6733 // inform parking area about leaving it
6734 stop.parkingarea->leaveFrom(this);
6735 }
6736 if (stop.chargingStation != nullptr) {
6737 // inform charging station about leaving it
6738 stop.chargingStation->leaveFrom(this);
6739 }
6740 // the current stop is no longer valid
6741 myLane->getEdge().removeWaiting(this);
6743 for (const auto& rem : myMoveReminders) {
6744 rem.first->notifyStopEnded();
6745 }
6746 if (MSStopOut::active()) {
6747 MSStopOut::getInstance()->stopEnded(this, stop.pars, stop.lane->getID());
6748 }
6750 myCollisionImmunity = TIME2STEPS(5); // leave the conflict area
6751 }
6753 // reset lateral position to default
6754 myState.myPosLat = 0;
6755 }
6756 myPastStops.push_back(stop.pars);
6757 myStops.pop_front();
6758 // do not count the stopping time towards gridlock time.
6759 // Other outputs use an independent counter and are not affected.
6760 myWaitingTime = 0;
6761 // maybe the next stop is on the same edge; let's rebuild best lanes
6762 updateBestLanes(true);
6763 // continue as wished...
6766 return true;
6767 }
6768 return false;
6769}
6770
6771
6774 if (myInfluencer == nullptr) {
6775 myInfluencer = new Influencer();
6776 }
6777 return *myInfluencer;
6778}
6779
6782 return getInfluencer();
6783}
6784
6785
6788 return myInfluencer;
6789}
6790
6793 return myInfluencer;
6794}
6795
6796
6797double
6799 if (myInfluencer != nullptr && myInfluencer->getOriginalSpeed() >= 0) {
6800 // influencer original speed is -1 on initialization
6802 }
6803 return myState.mySpeed;
6804}
6805
6806
6807int
6809 if (hasInfluencer()) {
6811 MSNet::getInstance()->getCurrentTimeStep(),
6812 myLane->getEdge(),
6813 getLaneIndex(),
6814 state);
6815 }
6816 return state;
6817}
6818
6819
6820void
6822 myCachedPosition = xyPos;
6823}
6824
6825
6826bool
6828 return myInfluencer != nullptr && myInfluencer->isRemoteControlled();
6829}
6830
6831
6832bool
6834 return myInfluencer != nullptr && myInfluencer->getLastAccessTimeStep() + lookBack >= MSNet::getInstance()->getCurrentTimeStep();
6835}
6836
6837
6838bool
6839MSVehicle::keepClear(const MSLink* link) const {
6840 if (link->hasFoes() && link->keepClear() /* && item.myLink->willHaveBlockedFoe()*/) {
6841 const double keepClearTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_IGNORE_KEEPCLEAR_TIME, -1);
6842 //std::cout << SIMTIME << " veh=" << getID() << " keepClearTime=" << keepClearTime << " accWait=" << getAccumulatedWaitingSeconds() << " keepClear=" << (keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime) << "\n";
6843 return keepClearTime < 0 || getAccumulatedWaitingSeconds() < keepClearTime;
6844 } else {
6845 return false;
6846 }
6847}
6848
6849
6850bool
6851MSVehicle::ignoreRed(const MSLink* link, bool canBrake) const {
6852 if ((myInfluencer != nullptr && !myInfluencer->getEmergencyBrakeRedLight())) {
6853 return true;
6854 }
6855 const double ignoreRedTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
6856#ifdef DEBUG_IGNORE_RED
6857 if (DEBUG_COND) {
6858 std::cout << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID() << " state=" << toString(link->getState()) << "\n";
6859 }
6860#endif
6861 if (ignoreRedTime < 0) {
6862 const double ignoreYellowTime = getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, 0);
6863 if (ignoreYellowTime > 0 && link->haveYellow()) {
6864 assert(link->getTLLogic() != 0);
6865 const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
6866 // when activating ignoreYellow behavior, vehicles will drive if they cannot brake
6867 return !canBrake || ignoreYellowTime > yellowDuration;
6868 } else {
6869 return false;
6870 }
6871 } else if (link->haveYellow()) {
6872 // always drive at yellow when ignoring red
6873 return true;
6874 } else if (link->haveRed()) {
6875 assert(link->getTLLogic() != 0);
6876 const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
6877#ifdef DEBUG_IGNORE_RED
6878 if (DEBUG_COND) {
6879 std::cout
6880 // << SIMTIME << " veh=" << getID() << " link=" << link->getViaLaneOrLane()->getID()
6881 << " ignoreRedTime=" << ignoreRedTime
6882 << " spentRed=" << redDuration
6883 << " canBrake=" << canBrake << "\n";
6884 }
6885#endif
6886 // when activating ignoreRed behavior, vehicles will always drive if they cannot brake
6887 return !canBrake || ignoreRedTime > redDuration;
6888 } else {
6889 return false;
6890 }
6891}
6892
6893
6894bool
6896 // either on an internal lane that was entered via minor link
6897 // or on approach to minor link below visibility distance
6898 if (myLane == nullptr) {
6899 return false;
6900 }
6901 if (myLane->getEdge().isInternal()) {
6902 return !myLane->getIncomingLanes().front().viaLink->havePriority();
6903 } else if (myLFLinkLanes.size() > 0 && myLFLinkLanes.front().myLink != nullptr) {
6904 MSLink* link = myLFLinkLanes.front().myLink;
6905 return !link->havePriority() && myLFLinkLanes.front().myDistance <= link->getFoeVisibilityDistance();
6906 }
6907 return false;
6908}
6909
6910bool
6911MSVehicle::isLeader(const MSLink* link, const MSVehicle* veh, const double gap) const {
6912 assert(link->fromInternalLane());
6913 if (veh == nullptr) {
6914 return false;
6915 }
6916 if (!myLane->isInternal() || myLane->getEdge().getToJunction() != link->getJunction()) {
6917 // if this vehicle is not yet on the junction, every vehicle is a leader
6918 return true;
6919 }
6920 if (veh->getLaneChangeModel().hasBlueLight()) {
6921 // blue light device automatically gets right of way
6922 return true;
6923 }
6924 const MSLane* foeLane = veh->getLane();
6925 if (foeLane->isInternal()) {
6926 if (foeLane->getEdge().getFromJunction() == link->getJunction()) {
6928 SUMOTime foeET = veh->myJunctionEntryTime;
6929 // check relationship between link and foeLane
6931 // we are entering the junction from the same lane
6933 foeET = veh->myJunctionEntryTimeNeverYield;
6936 }
6937 } else {
6938 const MSLink* foeLink = foeLane->getIncomingLanes()[0].viaLink;
6939 const MSJunctionLogic* logic = link->getJunction()->getLogic();
6940 assert(logic != nullptr);
6941 // determine who has right of way
6942 bool response; // ego response to foe
6943 bool response2; // foe response to ego
6944 // attempt 1: tlLinkState
6945 const MSLink* entry = link->getCorrespondingEntryLink();
6946 const MSLink* foeEntry = foeLink->getCorrespondingEntryLink();
6947 if (entry->haveRed() || foeEntry->haveRed()) {
6948 // ensure that vehicles which are stuck on the intersection may exit
6949 if (!foeEntry->haveRed() && veh->getSpeed() > SUMO_const_haltingSpeed && gap < 0) {
6950 // foe might be oncoming, don't drive unless foe can still brake safely
6951 const double foeGap = -gap - veh->getLength();
6952#ifdef DEBUG_PLAN_MOVE_LEADERINFO
6953 if (DEBUG_COND) {
6954 std::cout << " foeGap=" << foeGap << " foeBGap=" << veh->getBrakeGap(true) << "\n";
6955
6956 }
6957#endif
6958 if (foeGap < veh->getBrakeGap(true)) {
6959 response = true;
6960 response2 = false;
6961 } else {
6962 response = false;
6963 response2 = true;
6964 }
6965 } else {
6966 // brake for stuck foe
6967 response = foeEntry->haveRed();
6968 response2 = entry->haveRed();
6969 }
6970 } else if (entry->havePriority() != foeEntry->havePriority()) {
6971 response = !entry->havePriority();
6972 response2 = !foeEntry->havePriority();
6973 } else if (entry->haveYellow() && foeEntry->haveYellow()) {
6974 // let the faster vehicle keep moving
6975 response = veh->getSpeed() >= getSpeed();
6976 response2 = getSpeed() >= veh->getSpeed();
6977 } else {
6978 // fallback if pedestrian crossings are involved
6979 response = logic->getResponseFor(link->getIndex()).test(foeLink->getIndex());
6980 response2 = logic->getResponseFor(foeLink->getIndex()).test(link->getIndex());
6981 }
6982#ifdef DEBUG_PLAN_MOVE_LEADERINFO
6983 if (DEBUG_COND) {
6984 std::cout << SIMTIME
6985 << " foeLane=" << foeLane->getID()
6986 << " foeLink=" << foeLink->getViaLaneOrLane()->getID()
6987 << " linkIndex=" << link->getIndex()
6988 << " foeLinkIndex=" << foeLink->getIndex()
6989 << " entryState=" << toString(entry->getState())
6990 << " entryState2=" << toString(foeEntry->getState())
6991 << " response=" << response
6992 << " response2=" << response2
6993 << "\n";
6994 }
6995#endif
6996 if (!response) {
6997 // if we have right of way over the foe, entryTime does not matter
6998 foeET = veh->myJunctionConflictEntryTime;
6999 egoET = myJunctionEntryTime;
7000 } else if (response && response2) {
7001 // in a mutual conflict scenario, use entry time to avoid deadlock
7002 foeET = veh->myJunctionConflictEntryTime;
7004 }
7005 }
7006 if (egoET == foeET) {
7007 // try to use speed as tie braker
7008 if (getSpeed() == veh->getSpeed()) {
7009 // use ID as tie braker
7010#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7011 if (DEBUG_COND) {
7012 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7013 << " foeIsLeaderByID=" << (getID() < veh->getID()) << "\n";
7014 }
7015#endif
7016 return getID() < veh->getID();
7017 } else {
7018#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7019 if (DEBUG_COND) {
7020 std::cout << SIMTIME << " veh=" << getID() << " equal ET " << egoET << " with foe " << veh->getID()
7021 << " foeIsLeaderBySpeed=" << (getSpeed() < veh->getSpeed())
7022 << " v=" << getSpeed() << " foeV=" << veh->getSpeed()
7023 << "\n";
7024 }
7025#endif
7026 return getSpeed() < veh->getSpeed();
7027 }
7028 } else {
7029 // leader was on the junction first
7030#ifdef DEBUG_PLAN_MOVE_LEADERINFO
7031 if (DEBUG_COND) {
7032 std::cout << SIMTIME << " veh=" << getID() << " egoET " << egoET << " with foe " << veh->getID()
7033 << " foeET=" << foeET << " isLeader=" << (egoET > foeET) << "\n";
7034 }
7035#endif
7036 return egoET > foeET;
7037 }
7038 } else {
7039 // vehicle can only be partially on the junction. Must be a leader
7040 return true;
7041 }
7042 } else {
7043 // vehicle can only be partially on the junction. Must be a leader
7044 return true;
7045 }
7046}
7047
7048void
7051 // here starts the vehicle internal part (see loading)
7052 std::vector<std::string> internals;
7053 internals.push_back(toString(myParameter->parametersSet));
7054 internals.push_back(toString(myDeparture));
7055 internals.push_back(toString(distance(myRoute->begin(), myCurrEdge)));
7056 internals.push_back(toString(myDepartPos));
7057 internals.push_back(toString(myWaitingTime));
7058 internals.push_back(toString(myTimeLoss));
7059 internals.push_back(toString(myLastActionTime));
7060 internals.push_back(toString(isStopped()));
7061 internals.push_back(toString(myPastStops.size()));
7062 out.writeAttr(SUMO_ATTR_STATE, internals);
7064 out.writeAttr(SUMO_ATTR_SPEED, std::vector<double> { myState.mySpeed, myState.myPreviousSpeed });
7069 // save past stops
7071 stop.write(out, false);
7072 // do not write started and ended twice
7073 if ((stop.parametersSet & STOP_STARTED_SET) == 0) {
7074 out.writeAttr(SUMO_ATTR_STARTED, time2string(stop.started));
7075 }
7076 if ((stop.parametersSet & STOP_ENDED_SET) == 0) {
7077 out.writeAttr(SUMO_ATTR_ENDED, time2string(stop.ended));
7078 }
7079 out.closeTag();
7080 }
7081 // save upcoming stops
7082 for (MSStop& stop : myStops) {
7083 stop.write(out);
7084 }
7085 // save parameters and device states
7087 for (MSVehicleDevice* const dev : myDevices) {
7088 dev->saveState(out);
7089 }
7090 out.closeTag();
7091}
7092
7093void
7095 if (!attrs.hasAttribute(SUMO_ATTR_POSITION)) {
7096 throw ProcessError("Error: Invalid vehicles in state (may be a meso state)!");
7097 }
7098 int routeOffset;
7099 bool stopped;
7100 int pastStops;
7101 std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
7102 bis >> myParameter->parametersSet;
7103 bis >> myDeparture;
7104 bis >> routeOffset;
7105 bis >> myDepartPos;
7106 bis >> myWaitingTime;
7107 bis >> myTimeLoss;
7108 bis >> myLastActionTime;
7109 bis >> stopped;
7110 bis >> pastStops;
7111 if (hasDeparted()) {
7112 myCurrEdge = myRoute->begin() + routeOffset;
7113 myDeparture -= offset;
7114 // fix stops
7115 while (pastStops > 0) {
7116 myPastStops.push_back(myStops.front().pars);
7117 myStops.pop_front();
7118 pastStops--;
7119 }
7120 // see MSBaseVehicle constructor
7123 }
7124 }
7125 std::istringstream pis(attrs.getString(SUMO_ATTR_POSITION));
7127 std::istringstream sis(attrs.getString(SUMO_ATTR_SPEED));
7132 std::istringstream dis(attrs.getString(SUMO_ATTR_DISTANCE));
7133 dis >> myOdometer >> myNumberReroutes;
7135 if (stopped) {
7136 myStopDist = 0;
7137 }
7139 // no need to reset myCachedPosition here since state loading happens directly after creation
7140}
7141
7142void
7144 SUMOTime arrivalTime, double arrivalSpeed,
7145 double arrivalSpeedBraking,
7146 double dist, double leaveSpeed) {
7147 // ensure that approach information is reset on the next call to setApproachingForAllLinks
7148 myLFLinkLanes.push_back(DriveProcessItem(link, 0, 0, setRequest,
7149 arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed));
7150
7151}
7152
7153
7154std::shared_ptr<MSSimpleDriverState>
7156 return myDriverState->getDriverState();
7157}
7158
7159
7160double
7162 return myFrictionDevice == nullptr ? 1. : myFrictionDevice->getMeasuredFriction();
7163}
7164
7165
7166void
7167MSVehicle::setPreviousSpeed(double prevSpeed, double prevAcceleration) {
7168 myState.mySpeed = MAX2(0., prevSpeed);
7169 // also retcon acceleration
7170 if (prevAcceleration != std::numeric_limits<double>::min()) {
7171 myAcceleration = prevAcceleration;
7172 } else {
7174 }
7175}
7176
7177
7178double
7180 //return MAX2(-myAcceleration, getCarFollowModel().getApparentDecel());
7182}
7183
7184/****************************************************************************/
7185bool
7187 return (myManoeuvre.configureExitManoeuvre(this));
7188}
7189
7190/* -------------------------------------------------------------------------
7191 * methods of MSVehicle::manoeuvre
7192 * ----------------------------------------------------------------------- */
7193
7194MSVehicle::Manoeuvre::Manoeuvre() : myManoeuvreStop(""), myManoeuvreStartTime(0), myManoeuvreCompleteTime(0), myManoeuvreType(MSVehicle::MANOEUVRE_NONE), myGUIIncrement(0) {}
7195
7197 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7198 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7199 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7200 myManoeuvreType = manoeuvre.myManoeuvreType;
7201 myGUIIncrement = manoeuvre.myGUIIncrement;
7202}
7203
7206 myManoeuvreStop = manoeuvre.myManoeuvreStop;
7207 myManoeuvreStartTime = manoeuvre.myManoeuvreStartTime;
7208 myManoeuvreCompleteTime = manoeuvre.myManoeuvreCompleteTime;
7209 myManoeuvreType = manoeuvre.myManoeuvreType;
7210 myGUIIncrement = manoeuvre.myGUIIncrement;
7211 return *this;
7212}
7213
7214bool
7216 return (myManoeuvreStop != manoeuvre.myManoeuvreStop ||
7217 myManoeuvreStartTime != manoeuvre.myManoeuvreStartTime ||
7218 myManoeuvreCompleteTime != manoeuvre.myManoeuvreCompleteTime ||
7219 myManoeuvreType != manoeuvre.myManoeuvreType ||
7220 myGUIIncrement != manoeuvre.myGUIIncrement
7221 );
7222}
7223
7224double
7226 return (myGUIIncrement);
7227}
7228
7231 return (myManoeuvreType);
7232}
7233
7236 return (myManoeuvre.getManoeuvreType());
7237}
7238
7239
7240void
7243}
7244
7245void
7247 myManoeuvreType = mType;
7248}
7249
7250
7251bool
7253 if (!veh->hasStops()) {
7254 return false; // should never happen - checked before call
7255 }
7256
7257 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7258 const MSStop& stop = veh->getNextStop();
7259
7260 int manoeuverAngle = stop.parkingarea->getLastFreeLotAngle();
7261 double GUIAngle = stop.parkingarea->getLastFreeLotGUIAngle();
7262 if (abs(GUIAngle) < 0.1) {
7263 GUIAngle = -0.1; // Wiggle vehicle on parallel entry
7264 }
7265 myManoeuvreVehicleID = veh->getID();
7266 myManoeuvreStop = stop.parkingarea->getID();
7267 myManoeuvreType = MSVehicle::MANOEUVRE_ENTRY;
7268 myManoeuvreStartTime = currentTime;
7269 myManoeuvreCompleteTime = currentTime + veh->myType->getEntryManoeuvreTime(manoeuverAngle);
7270 myGUIIncrement = GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7271
7272#ifdef DEBUG_STOPS
7273 if (veh->isSelected()) {
7274 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 <<
7275 " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7276 }
7277#endif
7278
7279 return (true);
7280}
7281
7282bool
7284 // At the moment we only want to set for parking areas
7285 if (!veh->hasStops()) {
7286 return true;
7287 }
7288 if (veh->getNextStop().parkingarea == nullptr) {
7289 return true;
7290 }
7291
7292 if (myManoeuvreType != MSVehicle::MANOEUVRE_NONE) {
7293 return (false);
7294 }
7295
7296 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
7297
7298 int manoeuverAngle = veh->getCurrentParkingArea()->getManoeuverAngle(*veh);
7299 double GUIAngle = veh->getCurrentParkingArea()->getGUIAngle(*veh);
7300 if (abs(GUIAngle) < 0.1) {
7301 GUIAngle = 0.1; // Wiggle vehicle on parallel exit
7302 }
7303
7304 myManoeuvreVehicleID = veh->getID();
7305 myManoeuvreStop = veh->getCurrentParkingArea()->getID();
7306 myManoeuvreType = MSVehicle::MANOEUVRE_EXIT;
7307 myManoeuvreStartTime = currentTime;
7308 myManoeuvreCompleteTime = currentTime + veh->myType->getExitManoeuvreTime(manoeuverAngle);
7309 myGUIIncrement = -GUIAngle / (STEPS2TIME(myManoeuvreCompleteTime - myManoeuvreStartTime) / TS);
7310 if (veh->remainingStopDuration() > 0) {
7311 myManoeuvreCompleteTime += veh->remainingStopDuration();
7312 }
7313
7314#ifdef DEBUG_STOPS
7315 if (veh->isSelected()) {
7316 std::cout << "EXIT manoeuvre start: vehicle=" << veh->getID() << " Manoeuvre Angle=" << manoeuverAngle << " increment=" << RAD2DEG(myGUIIncrement) << " currentTime=" << currentTime
7317 << " endTime=" << myManoeuvreCompleteTime << " manoeuvre time=" << myManoeuvreCompleteTime - currentTime << " parkArea=" << myManoeuvreStop << std::endl;
7318 }
7319#endif
7320
7321 return (true);
7322}
7323
7324bool
7326 // At the moment we only want to consider parking areas - need to check because we could be setting up a manoeuvre
7327 if (!veh->hasStops()) {
7328 return (true);
7329 }
7330 MSStop* currentStop = &veh->myStops.front();
7331 if (currentStop->parkingarea == nullptr) {
7332 return true;
7333 } else if (currentStop->parkingarea->getID() != myManoeuvreStop || MSVehicle::MANOEUVRE_ENTRY != myManoeuvreType) {
7334 if (configureEntryManoeuvre(veh)) {
7336 return (false);
7337 } else { // cannot configure entry so stop trying
7338 return true;
7339 }
7340 } else if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7341 return false;
7342 } else { // manoeuvre complete
7343 myManoeuvreType = MSVehicle::MANOEUVRE_NONE;
7344 return true;
7345 }
7346}
7347
7348
7349bool
7351 if (checkType != myManoeuvreType) {
7352 return true; // we're not manoeuvering / wrong manoeuvre
7353 }
7354
7355 if (MSNet::getInstance()->getCurrentTimeStep() < myManoeuvreCompleteTime) {
7356 return false;
7357 } else {
7358 return true;
7359 }
7360}
7361
7362
7363bool
7365 return (MSNet::getInstance()->getCurrentTimeStep() >= myManoeuvreCompleteTime);
7366}
7367bool
7370}
7371
7372double
7374 if (hasStops()) {
7375 MSLane* lane = myLane;
7376 if (lane == nullptr) {
7377 // not in network
7378 lane = getEdge()->getLanes()[0];
7379 }
7380 const MSStop& stop = myStops.front();
7381 auto it = myCurrEdge + 1;
7382 // drive to end of current edge
7383 double dist = (lane->getLength() - getPositionOnLane());
7384 double travelTime = lane->getEdge().getMinimumTravelTime(this) * dist / lane->getLength();
7385 // drive until stop edge
7386 while (it != myRoute->end() && it < stop.edge) {
7387 travelTime += (*it)->getMinimumTravelTime(this);
7388 dist += (*it)->getLength();
7389 it++;
7390 }
7391 // drive up to the stop position
7392 const double stopEdgeDist = stop.pars.endPos - (lane == stop.lane ? lane->getLength() : 0);
7393 dist += stopEdgeDist;
7394 travelTime += stop.lane->getEdge().getMinimumTravelTime(this) * (stopEdgeDist / stop.lane->getLength());
7395 // estimate time loss due to acceleration and deceleration
7396 // maximum speed is limited by available distance:
7397 const double a = getCarFollowModel().getMaxAccel();
7398 const double b = getCarFollowModel().getMaxDecel();
7399 const double c = getSpeed();
7400 const double d = dist;
7401 const double len = getVehicleType().getLength();
7402 const double vs = MIN2(MAX2(stop.getSpeed(), 0.0), stop.lane->getVehicleMaxSpeed(this));
7403 // distAccel = (v - c)^2 / (2a)
7404 // distDecel = (v + vs)*(v - vs) / 2b = (v^2 - vs^2) / (2b)
7405 // distAccel + distDecel < d
7406 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))))
7407 + pow((a * vs), 2))))) * 0.5) + (c * b)) / (b + a));
7408 it = myCurrEdge;
7409 double v0 = c;
7410 bool v0Stable = getAcceleration() == 0 && v0 > 0;
7411 double timeLossAccel = 0;
7412 double timeLossDecel = 0;
7413 double timeLossLength = 0;
7414 while (it != myRoute->end() && it <= stop.edge) {
7415 double v = MIN2(maxVD, (*it)->getVehicleMaxSpeed(this));
7416 double edgeLength = (it == stop.edge ? stop.pars.endPos : (*it)->getLength()) - (it == myCurrEdge ? getPositionOnLane() : 0);
7417 if (edgeLength <= len && v0Stable && v0 < v) {
7418 const double lengthDist = MIN2(len, edgeLength);
7419 const double dTL = lengthDist / v0 - lengthDist / v;
7420 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " el=" << edgeLength << " lDist=" << lengthDist << " newTLL=" << dTL<< "\n";
7421 timeLossLength += dTL;
7422 }
7423 if (edgeLength > len) {
7424 const double dv = v - v0;
7425 if (dv > 0) {
7426 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
7427 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
7428 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
7429 timeLossAccel += dTA;
7430 // time loss from vehicle length
7431 } else if (dv < 0) {
7432 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
7433 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
7434 //std::cout << " e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
7435 timeLossDecel += dTD;
7436 }
7437 v0 = v;
7438 v0Stable = true;
7439 }
7440 it++;
7441 }
7442 // final deceleration to stop (may also be acceleration or deceleration to waypoint speed)
7443 double v = vs;
7444 const double dv = v - v0;
7445 if (dv > 0) {
7446 // timeLossAccel = timeAccel - timeMaxspeed = dv / a - distAccel / v
7447 const double dTA = dv / a - dv * (v + v0) / (2 * a * v);
7448 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLA=" << dTA << "\n";
7449 timeLossAccel += dTA;
7450 // time loss from vehicle length
7451 } else if (dv < 0) {
7452 // timeLossDecel = timeDecel - timeMaxspeed = dv / b - distDecel / v
7453 const double dTD = -dv / b + dv * (v + v0) / (2 * b * v0);
7454 //std::cout << " final e=" << (*it)->getID() << " v0=" << v0 << " v=" << v << " newTLD=" << dTD << "\n";
7455 timeLossDecel += dTD;
7456 }
7457 const double result = travelTime + timeLossAccel + timeLossDecel + timeLossLength;
7458 //std::cout << SIMTIME << " v=" << c << " a=" << a << " b=" << b << " maxVD=" << maxVD << " tt=" << travelTime
7459 // << " ta=" << timeLossAccel << " td=" << timeLossDecel << " tl=" << timeLossLength << " res=" << result << "\n";
7460 return MAX2(0.0, result);
7461 } else {
7462 return INVALID_DOUBLE;
7463 }
7464}
7465
7466double
7468 if (hasStops() && myStops.front().pars.until >= 0) {
7469 const MSStop& stop = myStops.front();
7470 SUMOTime estimatedDepart = MSNet::getInstance()->getCurrentTimeStep() - DELTA_T;
7471 if (stop.reached) {
7472 return STEPS2TIME(estimatedDepart + stop.duration - stop.pars.until);
7473 }
7474 if (stop.pars.duration > 0) {
7475 estimatedDepart += stop.pars.duration;
7476 }
7477 estimatedDepart += TIME2STEPS(estimateTimeToNextStop());
7478 const double result = MAX2(0.0, STEPS2TIME(estimatedDepart - stop.pars.until));
7479 return result;
7480 } else {
7481 // vehicles cannot drive before 'until' so stop delay can never be
7482 // negative and we can use -1 to signal "undefined"
7483 return -1;
7484 }
7485}
7486
7487double
7489 if (hasStops() && myStops.front().pars.arrival >= 0) {
7490 const MSStop& stop = myStops.front();
7491 if (stop.reached) {
7492 return STEPS2TIME(stop.pars.started - stop.pars.arrival);
7493 } else {
7494 return STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()) + estimateTimeToNextStop() - STEPS2TIME(stop.pars.arrival);
7495 }
7496 } else {
7497 // vehicles can arrival earlier than planned so arrival delay can be negative
7498 return INVALID_DOUBLE;
7499 }
7500}
7501
7502
7503const MSEdge*
7505 return myLane != nullptr ? &myLane->getEdge() : getEdge();
7506}
7507
7508const MSEdge*
7510 if (myLane == nullptr || (myCurrEdge + 1) == myRoute->end()) {
7511 return nullptr;
7512 }
7513 if (myLane->isInternal()) {
7515 } else {
7516 const MSEdge* nextNormal = succEdge(1);
7517 const MSEdge* nextInternal = myLane->getEdge().getInternalFollowingEdge(nextNormal, getVClass());
7518 return nextInternal ? nextInternal : nextNormal;
7519 }
7520}
7521
7522/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define RAD2DEG(x)
Definition: GeomHelper.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:73
std::pair< const MSVehicle *, double > CLeaderDist
Definition: MSLeaderInfo.h:38
std::pair< const MSPerson *, double > PersonDist
Definition: MSPModel.h:41
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition: MSRoute.h:54
#define NUMERICAL_EPS_SPEED
Definition: MSVehicle.cpp:121
#define STOPPING_PLACE_OFFSET
Definition: MSVehicle.cpp:112
#define JUNCTION_BLOCKAGE_TIME
Definition: MSVehicle.cpp:116
#define DEBUG_COND
Definition: MSVehicle.cpp:105
#define DIST_TO_STOPLINE_EXPECT_PRIORITY
Definition: MSVehicle.cpp:119
#define DEBUG_COND2(obj)
Definition: MSVehicle.cpp:107
#define CRLL_LOOK_AHEAD
Definition: MSVehicle.cpp:114
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:274
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define TL(string)
Definition: MsgHandler.h:282
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define SPEED2DIST(x)
Definition: SUMOTime.h:44
#define SIMSTEP
Definition: SUMOTime.h:60
#define ACCEL2SPEED(x)
Definition: SUMOTime.h:50
#define SUMOTime_MAX
Definition: SUMOTime.h:33
#define TS
Definition: SUMOTime.h:41
#define SIMTIME
Definition: SUMOTime.h:61
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
#define DIST2SPEED(x)
Definition: SUMOTime.h:46
#define SPEED2ACCEL(x)
Definition: SUMOTime.h:52
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
@ 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_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_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:25
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:33
const double INVALID_DOUBLE
Definition: StdDefs.h:60
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN3(T a, T b, T c)
Definition: StdDefs.h:84
T MIN2(T a, T b)
Definition: StdDefs.h:71
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:77
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)
Definition: GeomHelper.cpp:192
static double fromNaviDegree(const double angle)
Definition: GeomHelper.cpp:209
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.
const std::vector< MSLane * > & getFurtherTargetLanes() const
double getAngleOffset() const
return the angle offset during a continuous change maneuver
const std::vector< MSLane * > & getShadowFurtherLanes() const
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc) const
The base class for microscopic and mesoscopic vehicles.
Definition: MSBaseVehicle.h:55
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 or 0.
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)
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.
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()
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.
const MSRoute * myRoute
This vehicle's route.
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
@ ROUTE_START_INVALID_LANE
Definition: MSBaseVehicle.h:78
@ ROUTE_START_INVALID_PERMISSIONS
Definition: MSBaseVehicle.h:76
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
virtual bool replaceRoute(const MSRoute *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 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.
bool haveValidStopEdges() const
check whether all stop.edge MSRouteIterators are valid and in order
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
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
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
Definition: MSCFModel.cpp:743
virtual double maxNextSpeed(double speed, const MSVehicle *const veh) const
Returns the maximum speed given the current speed.
Definition: MSCFModel.cpp:270
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 ...
Definition: MSCFModel.cpp:287
virtual VehicleVariables * createVehicleVariables() const
Returns model specific values which are stored inside a vehicle and must be used with casting.
Definition: MSCFModel.h:245
double maximumSafeStopSpeed(double gap, double decel, double currentSpeed, bool onInsertion=false, double headway=-1) const
Returns the maximum next velocity for stopping within gap.
Definition: MSCFModel.cpp:752
double getEmergencyDecel() const
Get the vehicle type's maximal phisically possible deceleration [m/s^2].
Definition: MSCFModel.h:270
SUMOTime getStartupDelay() const
Get the vehicle type's startupDelay.
Definition: MSCFModel.h:285
double getMinimalArrivalSpeed(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance.
Definition: MSCFModel.cpp:516
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.
Definition: MSCFModel.cpp:299
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...
Definition: MSCFModel.cpp:276
SUMOTime getMinimalArrivalTime(double dist, double currentSpeed, double arrivalSpeed) const
Computes the minimal time needed to cover a distance given the desired speed at arrival.
Definition: MSCFModel.cpp:407
virtual double finalizeSpeed(MSVehicle *const veh, double vPos) const
Applies interaction with stops and lane changing model influences. Called at most once per simulation...
Definition: MSCFModel.cpp:165
virtual double maximumLaneSpeedCF(double maxSpeed, double maxSpeedLane) const
Returns the maximum velocity the CF-model wants to achieve in the next step.
Definition: MSCFModel.h:224
double getApparentDecel() const
Get the vehicle type's apparent deceleration [m/s^2] (the one regarded by its followers.
Definition: MSCFModel.h:278
double getMaxAccel() const
Get the vehicle type's maximum acceleration [m/s^2].
Definition: MSCFModel.h:254
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition: MSCFModel.h:373
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:262
double getMinimalArrivalSpeedEuler(double dist, double currentSpeed) const
Computes the minimal possible arrival speed after covering a given distance for Euler update.
Definition: MSCFModel.cpp:523
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:309
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.
double getMeasuredFriction()
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
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:1236
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:1303
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:1312
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:1155
static bool gModelParkingManoeuver
whether parking simulation includes manoeuver time and any associated lane blocking
Definition: MSGlobals.h:156
static bool gUseMesoSim
Definition: MSGlobals.h:103
static SUMOTime gStartupWaitThreshold
The minimum waiting time before applying startupDelay.
Definition: MSGlobals.h:174
static double gTLSYellowMinDecel
The minimum deceleration at a yellow traffic light (only overruled by emergencyDecel)
Definition: MSGlobals.h:165
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:168
static bool gSublane
whether sublane simulation is enabled (sublane model or continuous lanechanging)
Definition: MSGlobals.h:159
static SUMOTime gLaneChangeDuration
Definition: MSGlobals.h:94
static double gEmergencyDecelWarningThreshold
treshold for warning about strong deceleration
Definition: MSGlobals.h:148
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:138
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:1209
const std::vector< MSMoveReminder * > & getMoveReminders() const
Return the list of this lane's move reminders.
Definition: MSLane.h:296
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:4022
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:4178
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:2521
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition: MSLane.cpp:2503
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition: MSLane.h:429
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2365
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition: MSLane.cpp:2451
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition: MSLane.h:437
double getBruttoVehLenSum() const
Returns the sum of lengths of vehicles, including their minGaps, which were on the lane during the la...
Definition: MSLane.h:1082
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition: MSLane.cpp:2379
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition: MSLane.cpp:2428
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition: MSLane.cpp:1259
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition: MSLane.cpp:3421
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition: MSLane.h:561
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:2175
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition: MSLane.h:879
MSLane * getCanonicalPredecessorLane() const
Definition: MSLane.cpp:2912
double getLength() const
Returns the lane's length.
Definition: MSLane.h:575
const PositionVector & getShape() const
Returns this lane's shape.
Definition: MSLane.h:506
double getMaximumBrakeDist() const
compute maximum braking distance on this lane
Definition: MSLane.cpp:2578
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:2440
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:1303
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition: MSLane.h:802
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition: MSLane.h:856
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition: MSLane.cpp:336
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition: MSLane.h:547
double getRightSideOnEdge() const
Definition: MSLane.h:1118
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition: MSLane.cpp:4171
int getIndex() const
Returns the lane's index.
Definition: MSLane.h:597
MSLane * getCanonicalSuccessorLane() const
Definition: MSLane.cpp:2936
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition: MSLane.cpp:4017
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:2866
double getCenterOnEdge() const
Definition: MSLane.h:1126
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition: MSLane.cpp:2351
bool isInternal() const
Definition: MSLane.cpp:2330
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition: MSLane.cpp:355
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition: MSLane.cpp:4005
virtual const VehCont & getVehiclesSecure() const
Returns the vehicles container; locks it for microsimulation.
Definition: MSLane.h:456
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition: MSLane.h:486
bool mustCheckJunctionCollisions() const
whether this lane must check for junction collisions
Definition: MSLane.cpp:4265
double interpolateLanePosToGeometryPos(double lanePos) const
Definition: MSLane.h:527
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition: MSLane.cpp:4252
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:2661
@ COLLISION_ACTION_WARN
Definition: MSLane.h:203
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition: MSLane.cpp:4011
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:713
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:4271
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition: MSLane.cpp:2891
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:3446
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:590
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:675
const Position geometryPositionAtOffset(double offset, double lateralOffset=0) const
Definition: MSLane.h:533
static CollisionAction getCollisionAction()
Definition: MSLane.h:1276
saves leader/follower vehicles and their distances relative to an ego vehicle
Definition: MSLeaderInfo.h:144
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
Definition: MSLeaderInfo.h:86
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
int getSublaneOffset() const
Definition: MSLeaderInfo.h:102
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_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:636
The simulated network and simulation perfomer.
Definition: MSNet.h:88
void removeVehicleStateListener(VehicleStateListener *listener)
Removes a vehicle states listener.
Definition: MSNet.cpp:1172
VehicleState
Definition of a vehicle state.
Definition: MSNet.h:603
@ 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:1105
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:1296
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:321
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:1287
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition: MSNet.cpp:1164
bool hasContainers() const
Returns whether containers are simulated.
Definition: MSNet.h:412
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:1181
bool hasPersons() const
Returns whether persons are simulated.
Definition: MSNet.h:396
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition: MSNet.h:432
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:379
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition: MSNet.cpp:1096
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition: MSNet.h:422
A lane area vehicles can halt at.
Definition: MSParkingArea.h:58
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
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition: MSRoute.cpp:80
const MSEdge * getLastEdge() const
returns the destination edge
Definition: MSRoute.cpp:92
double getDistanceBetween(double fromPos, double toPos, const MSEdge *fromEdge, const MSEdge *toEdge, bool includeInternal=true, int routePosition=0) const
Compute the distance between 2 given edges on this route, including the length of internal lanes....
Definition: MSRoute.cpp:316
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition: MSRoute.cpp:74
Definition: MSStop.h:44
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:156
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:133
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
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:150
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)
Definition: MSStopOut.cpp:102
static MSStopOut * getInstance()
Definition: MSStopOut.h:60
A lane area vehicles can halt at.
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:1366
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to, const std::string &info="")
Called if a vehicle changes its state.
Definition: MSVehicle.cpp:261
Changes the wished vehicle speed / lanes.
Definition: MSVehicle.h:1361
void setLaneChangeMode(int value)
Sets lane changing behavior.
Definition: MSVehicle.cpp:781
TraciLaneChangePriority myTraciLaneChangePriority
flags for determining the priority of traci lane change requests
Definition: MSVehicle.h:1671
bool getEmergencyBrakeRedLight() const
Returns whether red lights shall be a reason to brake.
Definition: MSVehicle.h:1533
SUMOTime getLaneTimeLineEnd()
Definition: MSVehicle.cpp:470
void adaptLaneTimeLine(int indexShift)
Adapts lane timeline when moving to a new lane and the lane index changes.
Definition: MSVehicle.cpp:422
void setRemoteControlled(Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector &route, SUMOTime t)
Definition: MSVehicle.cpp:792
bool isRemoteAffected(SUMOTime t) const
Definition: MSVehicle.cpp:811
int getSpeedMode() const
return the current speed mode
Definition: MSVehicle.cpp:435
void deactivateGapController()
Deactivates the gap control.
Definition: MSVehicle.cpp:409
Influencer()
Constructor.
Definition: MSVehicle.cpp:360
void setSpeedMode(int speedMode)
Sets speed-constraining behaviors.
Definition: MSVehicle.cpp:770
std::shared_ptr< GapControlState > myGapControlState
The gap control state.
Definition: MSVehicle.h:1619
bool considerSafeVelocity() const
Returns whether safe velocities shall be considered.
Definition: MSVehicle.h:1547
int getSignals() const
Definition: MSVehicle.h:1595
bool myConsiderMaxDeceleration
Whether the maximum deceleration shall be regarded.
Definition: MSVehicle.h:1637
void setLaneTimeLine(const std::vector< std::pair< SUMOTime, int > > &laneTimeLine)
Sets a new lane timeline.
Definition: MSVehicle.cpp:416
bool myRespectJunctionLeaderPriority
Whether the junction priority rules are respected (within)
Definition: MSVehicle.h:1646
void setOriginalSpeed(double speed)
Stores the originally longitudinal speed.
Definition: MSVehicle.cpp:661
double myOriginalSpeed
The velocity before influence.
Definition: MSVehicle.h:1622
double implicitDeltaPosRemote(const MSVehicle *veh)
return the change in longitudinal position that is implicit in the new remote position
Definition: MSVehicle.cpp:928
double implicitSpeedRemote(const MSVehicle *veh, double oldSpeed)
return the speed that is implicit in the new remote position
Definition: MSVehicle.cpp:901
void postProcessRemoteControl(MSVehicle *v)
update position from remote control
Definition: MSVehicle.cpp:832
double gapControlSpeed(SUMOTime currentTime, const SUMOVehicle *veh, double speed, double vSafe, double vMin, double vMax)
Applies gap control logic on the speed.
Definition: MSVehicle.cpp:509
void setSublaneChange(double latDist)
Sets a new sublane-change request.
Definition: MSVehicle.cpp:430
double getOriginalSpeed() const
Returns the originally longitudinal speed to use.
Definition: MSVehicle.cpp:656
SUMOTime myLastRemoteAccess
Definition: MSVehicle.h:1655
bool getRespectJunctionLeaderPriority() const
Returns whether junction priority rules within the junction shall be respected (concerns vehicles wit...
Definition: MSVehicle.h:1541
LaneChangeMode myStrategicLC
lane changing which is necessary to follow the current route
Definition: MSVehicle.h:1660
LaneChangeMode mySpeedGainLC
lane changing to travel with higher speed
Definition: MSVehicle.h:1664
static void init()
Static initalization.
Definition: MSVehicle.cpp:385
LaneChangeMode mySublaneLC
changing to the prefered lateral alignment
Definition: MSVehicle.h:1668
bool getRespectJunctionPriority() const
Returns whether junction priority rules shall be respected (concerns approaching vehicles outside the...
Definition: MSVehicle.h:1525
static void cleanup()
Static cleanup.
Definition: MSVehicle.cpp:390
int getLaneChangeMode() const
return the current lane change mode
Definition: MSVehicle.cpp:447
SUMOTime getLaneTimeLineDuration()
Definition: MSVehicle.cpp:457
double influenceSpeed(SUMOTime currentTime, double speed, double vSafe, double vMin, double vMax)
Applies stored velocity information on the speed to use.
Definition: MSVehicle.cpp:480
double changeRequestRemainingSeconds(const SUMOTime currentTime) const
Return the remaining number of seconds of the current laneTimeLine assuming one exists.
Definition: MSVehicle.cpp:762
bool myConsiderSafeVelocity
Whether the safe velocity shall be regarded.
Definition: MSVehicle.h:1631
bool mySpeedAdaptationStarted
Whether influencing the speed has already started.
Definition: MSVehicle.h:1628
~Influencer()
Destructor.
Definition: MSVehicle.cpp:382
void setSignals(int signals)
Definition: MSVehicle.h:1591
double myLatDist
The requested lateral change.
Definition: MSVehicle.h:1625
bool myEmergencyBrakeRedLight
Whether red lights are a reason to brake.
Definition: MSVehicle.h:1643
LaneChangeMode myRightDriveLC
changing to the rightmost lane
Definition: MSVehicle.h:1666
void setSpeedTimeLine(const std::vector< std::pair< SUMOTime, double > > &speedTimeLine)
Sets a new velocity timeline.
Definition: MSVehicle.cpp:395
void updateRemoteControlRoute(MSVehicle *v)
update route if provided by remote control
Definition: MSVehicle.cpp:817
SUMOTime getLastAccessTimeStep() const
Definition: MSVehicle.h:1571
bool myConsiderMaxAcceleration
Whether the maximum acceleration shall be regarded.
Definition: MSVehicle.h:1634
LaneChangeMode myCooperativeLC
lane changing with the intent to help other vehicles
Definition: MSVehicle.h:1662
bool isRemoteControlled() const
Definition: MSVehicle.cpp:805
bool myRespectJunctionPriority
Whether the junction priority rules are respected (approaching)
Definition: MSVehicle.h:1640
int influenceChangeDecision(const SUMOTime currentTime, const MSEdge &currentEdge, const int currentLaneIndex, int state)
Applies stored LaneChangeMode information and laneTimeLine.
Definition: MSVehicle.cpp:667
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,.
Definition: MSVehicle.cpp:401
Container for manouevering time associated with stopping.
Definition: MSVehicle.h:1285
SUMOTime myManoeuvreCompleteTime
Time at which this manoeuvre should complete.
Definition: MSVehicle.h:1337
MSVehicle::ManoeuvreType getManoeuvreType() const
Accessor (get) for manoeuvre type.
Definition: MSVehicle.cpp:7230
std::string myManoeuvreStop
The name of the stop associated with the Manoeuvre - for debug output.
Definition: MSVehicle.h:1331
bool manoeuvreIsComplete() const
Check if any manoeuver is ongoing and whether the completion time is beyond currentTime.
Definition: MSVehicle.cpp:7364
bool configureExitManoeuvre(MSVehicle *veh)
Setup the myManoeuvre for exiting (Sets completion time and manoeuvre type)
Definition: MSVehicle.cpp:7283
void setManoeuvreType(const MSVehicle::ManoeuvreType mType)
Accessor (set) for manoeuvre type.
Definition: MSVehicle.cpp:7246
Manoeuvre & operator=(const Manoeuvre &manoeuvre)
Assignment operator.
Definition: MSVehicle.cpp:7205
Manoeuvre()
Constructor.
Definition: MSVehicle.cpp:7194
ManoeuvreType myManoeuvreType
Manoeuvre type - currently entry, exit or none.
Definition: MSVehicle.h:1340
double getGUIIncrement() const
Accessor for GUI rotation step when parking (radians)
Definition: MSVehicle.cpp:7225
SUMOTime myManoeuvreStartTime
Time at which the Manoeuvre for this stop started.
Definition: MSVehicle.h:1334
bool operator!=(const Manoeuvre &manoeuvre)
Operator !=.
Definition: MSVehicle.cpp:7215
bool entryManoeuvreIsComplete(MSVehicle *veh)
Configure an entry manoeuvre if nothing is configured - otherwise check if complete.
Definition: MSVehicle.cpp:7325
bool manoeuvreIsComplete(const ManoeuvreType checkType) const
Check if specific manoeuver is ongoing and whether the completion time is beyond currentTime.
Definition: MSVehicle.cpp:7350
bool configureEntryManoeuvre(MSVehicle *veh)
Setup the entry manoeuvre for this vehicle (Sets completion time and manoeuvre type)
Definition: MSVehicle.cpp:7252
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.
Definition: MSVehicle.cpp:168
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 !=.
Definition: MSVehicle.cpp:158
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.
Definition: MSVehicle.cpp:146
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)
Definition: MSVehicle.cpp:202
const std::string getState() const
Definition: MSVehicle.cpp:234
SUMOTime cumulatedWaitingTime(SUMOTime memory=-1) const
Definition: MSVehicle.cpp:180
void setState(const std::string &state)
Definition: MSVehicle.cpp:245
WaitingTimeCollector(SUMOTime memory=MSGlobals::gWaitingTimeMemory)
Constructor.
Definition: MSVehicle.cpp:176
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 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
Definition: MSVehicle.cpp:7241
TraciLaneChangePriority
modes for prioritizing traci lane change requests
Definition: MSVehicle.h:1163
@ LCP_NOOVERLAP
Definition: MSVehicle.h:1165
@ LCP_OPPORTUNISTIC
Definition: MSVehicle.h:1167
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)
Definition: MSVehicle.cpp:6272
bool wasRemoteControlled(SUMOTime lookBack=DELTA_T) const
Returns the information whether the vehicle is fully controlled via TraCI within the lookBack time.
Definition: MSVehicle.cpp:6833
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...
Definition: MSVehicle.cpp:3298
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
Definition: MSVehicle.cpp:3147
void checkRewindLinkLanes(const double lengthsInFront, DriveItemVector &lfLinks) const
runs heuristic for keeping the intersection clear in case of downstream jamming
Definition: MSVehicle.cpp:4735
bool willStop() const
Returns whether the vehicle will stop on the current edge.
Definition: MSVehicle.cpp:1550
bool hasDriverState() const
Whether this vehicle is equipped with a MSDriverState.
Definition: MSVehicle.h:1009
static int nextLinkPriority(const std::vector< MSLane * > &conts)
get a numerical value for the priority of the upcoming link
Definition: MSVehicle.cpp:5810
double getTimeGapOnLane() const
Returns the time gap in seconds to the leader of the vehicle on the same lane.
Definition: MSVehicle.cpp:6130
void updateBestLanes(bool forceRebuild=false, const MSLane *startLane=0)
computes the best lanes to use in order to continue the route
Definition: MSVehicle.cpp:5391
bool myAmIdling
Whether the vehicle is trying to enter the network (eg after parking so engine is running)
Definition: MSVehicle.h:1919
SUMOTime myWaitingTime
The time the vehicle waits (is not faster than 0.1m/s) in seconds.
Definition: MSVehicle.h:1855
double getStopDelay() const
Returns the public transport stop delay in seconds.
Definition: MSVehicle.cpp:7467
double computeAngle() const
compute the current vehicle angle
Definition: MSVehicle.cpp:1399
double myTimeLoss
the time loss in seconds due to driving with less than maximum speed
Definition: MSVehicle.h:1859
SUMOTime myLastActionTime
Action offset (actions are taken at time myActionOffset + N*getActionStepLength()) Initialized to 0,...
Definition: MSVehicle.h:1874
bool hasArrivedInternal(bool oppositeTransformed=true) const
Returns whether this vehicle has already arived (reached the arrivalPosition on its final edge) metho...
Definition: MSVehicle.cpp:1076
double getFriction() const
Returns the current friction on the road as perceived by the friction device.
Definition: MSVehicle.cpp:7161
bool replaceParkingArea(MSParkingArea *parkingArea, std::string &errorMsg)
replace the current parking area stop with a new stop with merge duration
Definition: MSVehicle.cpp:1489
void boardTransportables(MSStop &stop)
board persons and load transportables at the given stop
Definition: MSVehicle.cpp:1838
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...
Definition: MSVehicle.cpp:5876
bool isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
Definition: MSVehicle.h:599
void adaptLaneEntering2MoveReminder(const MSLane &enteredLane)
Adapts the vehicle's entering of a new lane.
Definition: MSVehicle.cpp:1159
void addTransportable(MSTransportable *transportable)
Adds a person or container to this vehicle.
Definition: MSVehicle.cpp:6141
MSParkingArea * getNextParkingArea()
get the upcoming parking area stop or nullptr
Definition: MSVehicle.cpp:1526
SUMOTime myJunctionConflictEntryTime
Definition: MSVehicle.h:1937
PositionVector getBoundingPoly(double offset=0) const
get bounding polygon
Definition: MSVehicle.cpp:6552
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...
Definition: MSVehicle.cpp:6239
SUMOTime getWaitingTime() const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition: MSVehicle.h:663
void workOnMoveReminders(double oldPos, double newPos, double newSpeed)
Processes active move reminder.
Definition: MSVehicle.cpp:1100
bool isStoppedOnLane() const
Definition: MSVehicle.cpp:1555
double myAcceleration
The current acceleration after dawdling in m/s.
Definition: MSVehicle.h:1901
void registerInsertionApproach(MSLink *link, double dist)
register approach on insertion
Definition: MSVehicle.cpp:5003
void adaptToLeaders(const MSLeaderInfo &ahead, double latOffset, const double seen, DriveProcessItem *const lastLink, const MSLane *const lane, double &v, double &vLinkPass) const
Definition: MSVehicle.cpp:2844
const MSLane * getBackLane() const
Definition: MSVehicle.cpp:4526
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.
Definition: MSVehicle.cpp:5241
std::pair< double, LinkDirection > myNextTurn
the upcoming turn for the vehicle
Definition: MSVehicle.h:1905
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.
Definition: MSVehicle.cpp:7167
SUMOTime getArrivalTime(SUMOTime t, double seen, double v, double arrivalSpeed) const
Definition: MSVehicle.cpp:2825
double getAccumulatedWaitingSeconds() const
Returns the number of seconds waited (speed was lesser than 0.1m/s) within the last millisecs.
Definition: MSVehicle.h:708
bool isFrontOnLane(const MSLane *lane) const
Returns the information whether the front of the vehicle is on the given lane.
Definition: MSVehicle.cpp:4729
virtual ~MSVehicle()
Destructor.
Definition: MSVehicle.cpp:991
bool stopsAt(MSStoppingPlace *stop) const
Returns whether the vehicle stops at the given stopping place.
Definition: MSVehicle.cpp:1947
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...
Definition: MSVehicle.cpp:3975
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5367
void setEmergencyBlueLight(SUMOTime currentTime)
sets the blue flashing light for emergency vehicles
Definition: MSVehicle.cpp:6219
bool isActionStep(SUMOTime t) const
Returns whether the next simulation step will be an action point for the vehicle.
Definition: MSVehicle.h:629
MSAbstractLaneChangeModel * myLaneChangeModel
Definition: MSVehicle.h:1881
Position getPositionAlongBestLanes(double offset) const
Return the (x,y)-position, which the vehicle would reach if it continued along its best continuation ...
Definition: MSVehicle.cpp:1241
bool hasValidRouteStart(std::string &msg)
checks wether the vehicle can depart on the first edge
Definition: MSVehicle.cpp:1038
double getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
Definition: MSVehicle.cpp:6254
std::vector< MSLane * > myFurtherLanes
The information into which lanes the vehicle laps into.
Definition: MSVehicle.h:1908
bool signalSet(int which) const
Returns whether the given signal is on.
Definition: MSVehicle.h:1199
MSCFModel::VehicleVariables * myCFVariables
The per vehicle variables of the car following model.
Definition: MSVehicle.h:2120
bool addTraciStop(SUMOVehicleParameter::Stop stop, std::string &errorMsg)
Definition: MSVehicle.cpp:6677
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)
Definition: MSVehicle.cpp:3131
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
Definition: MSVehicle.cpp:6808
double getMaxSpeedOnLane() const
Returns the maximal speed for the vehicle on its current lane (including speed factor and deviation,...
Definition: MSVehicle.cpp:1307
bool isRemoteControlled() const
Returns the information whether the vehicle is fully controlled via TraCI.
Definition: MSVehicle.cpp:6827
bool myAmOnNet
Whether the vehicle is on the network (not parking, teleported, vaporized, or arrived)
Definition: MSVehicle.h:1916
void enterLaneAtMove(MSLane *enteredLane, bool onTeleporting=false)
Update when the vehicle enters a new lane in the move step.
Definition: MSVehicle.cpp:5047
void adaptBestLanesOccupation(int laneIndex, double density)
update occupation from MSLaneChanger
Definition: MSVehicle.cpp:6039
double accelThresholdForWaiting() const
maximum acceleration to consider a vehicle as 'waiting' at low speed
Definition: MSVehicle.h:2114
void setAngle(double angle, bool straightenFurther=false)
Set a custom vehicle angle in rad, optionally updates furtherLanePosLat.
Definition: MSVehicle.cpp:1353
std::vector< LaneQ >::iterator myCurrentLaneInBestLanes
Definition: MSVehicle.h:1896
double getDeltaPos(const double accel) const
calculates the distance covered in the next integration step given an acceleration and assuming the c...
Definition: MSVehicle.cpp:3276
const MSLane * myLastBestLanesInternalLane
Definition: MSVehicle.h:1884
void updateOccupancyAndCurrentBestLane(const MSLane *startLane)
updates LaneQ::nextOccupation and myCurrentLaneInBestLanes
Definition: MSVehicle.cpp:5826
const std::vector< MSLane * > getUpstreamOppositeLanes() const
Returns the sequence of opposite lanes corresponding to past lanes.
Definition: MSVehicle.cpp:6003
WaitingTimeCollector myWaitingTimeCollector
Definition: MSVehicle.h:1856
void setRemoteState(Position xyPos)
sets position outside the road network
Definition: MSVehicle.cpp:6821
void fixPosition()
repair errors in vehicle position after changing between internal edges
Definition: MSVehicle.cpp:6047
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:510
double getSpeedWithoutTraciInfluence() const
Returns the uninfluenced velocity.
Definition: MSVehicle.cpp:6798
PositionVector getBoundingBox(double offset=0) const
get bounding rectangle
Definition: MSVehicle.cpp:6521
ManoeuvreType
flag identifying which, if any, manoeuvre is in progress
Definition: MSVehicle.h:1258
@ MANOEUVRE_ENTRY
Manoeuvre into stopping place.
Definition: MSVehicle.h:1260
@ MANOEUVRE_NONE
not manouevring
Definition: MSVehicle.h:1264
@ MANOEUVRE_EXIT
Manoeuvre out of stopping place.
Definition: MSVehicle.h:1262
const MSEdge * getNextEdgePtr() const
returns the next edge (possibly an internal edge)
Definition: MSVehicle.cpp:7509
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
Definition: MSVehicle.cpp:1208
void setBrakingSignals(double vNext)
sets the braking lights on/off
Definition: MSVehicle.cpp:3800
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
Definition: MSVehicle.cpp:5848
double estimateTimeToNextStop() const
Definition: MSVehicle.cpp:7373
MSParkingArea * getCurrentParkingArea()
get the current parking area stop or nullptr
Definition: MSVehicle.cpp:1540
const MSEdge * myLastBestLanesEdge
Definition: MSVehicle.h:1883
bool ignoreCollision() const
whether this vehicle is except from collision checks
Definition: MSVehicle.cpp:1587
Influencer * myInfluencer
An instance of a velocity/lane influencing instance; built in "getInfluencer".
Definition: MSVehicle.h:2123
void saveState(OutputDevice &out)
Saves the states of a vehicle.
Definition: MSVehicle.cpp:7049
bool replaceRoute(const MSRoute *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.
Definition: MSVehicle.cpp:1085
void onRemovalFromNet(const MSMoveReminder::Notification reason)
Called when the vehicle is removed from the network.
Definition: MSVehicle.cpp:1015
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....
Definition: MSVehicle.cpp:2014
bool resumeFromStopping()
Definition: MSVehicle.cpp:6715
int getBestLaneOffset() const
Definition: MSVehicle.cpp:6019
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
Definition: MSVehicle.cpp:3034
double lateralDistanceToLane(const int offset) const
Get the minimal lateral distance required to move fully onto the lane at given offset.
Definition: MSVehicle.cpp:6394
bool stopsAtEdge(const MSEdge *edge) const
Returns whether the vehicle stops at the given edge.
Definition: MSVehicle.cpp:1963
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.
Definition: MSVehicle.cpp:1989
std::vector< DriveProcessItem > DriveItemVector
Container for used Links/visited Lanes during planMove() and executeMove.
Definition: MSVehicle.h:2000
void setBlinkerInformation()
sets the blue flashing light for emergency vehicles
Definition: MSVehicle.cpp:6158
const MSEdge * getCurrentEdge() const
Returns the edge the vehicle is currently at (possibly an internal edge or nullptr)
Definition: MSVehicle.cpp:7504
void adaptToLeaderDistance(const MSLeaderDistanceInfo &ahead, double latOffset, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
Definition: MSVehicle.cpp:2923
DriveItemVector::iterator myNextDriveItem
iterator pointing to the next item in myLFLinkLanes
Definition: MSVehicle.h:2013
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.
Definition: MSVehicle.cpp:5281
bool isIdling() const
Returns whether a sim vehicle is waiting to enter a lane (after parking has completed)
Definition: MSVehicle.h:615
std::shared_ptr< MSSimpleDriverState > getDriverState() const
Returns the vehicle driver's state.
Definition: MSVehicle.cpp:7155
void removeApproachingInformation(const DriveItemVector &lfLinks) const
unregister approach from all upcoming links
Definition: MSVehicle.cpp:6456
void replaceVehicleType(MSVehicleType *type)
Replaces the current vehicle type by the one given.
Definition: MSVehicle.cpp:4518
SUMOTime myJunctionEntryTimeNeverYield
Definition: MSVehicle.h:1936
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
Definition: MSVehicle.cpp:6321
bool rerouteParkingArea(const std::string &parkingAreaID, std::string &errorMsg)
Definition: MSVehicle.cpp:6601
bool hasArrived() const
Returns whether this vehicle has already arived (reached the arrivalPosition on its final edge)
Definition: MSVehicle.cpp:1070
const MSEdge * getRerouteOrigin() const
Returns the starting point for reroutes (usually the current edge)
Definition: MSVehicle.cpp:1337
void switchOffSignal(int signal)
Switches the given signal off.
Definition: MSVehicle.h:1182
void updateState(double vNext)
updates the vehicles state, given a next value for its speed. This value can be negative in case of t...
Definition: MSVehicle.cpp:4449
double getStopArrivalDelay() const
Returns the estimated public transport stop arrival delay in seconds.
Definition: MSVehicle.cpp:7488
int mySignals
State of things of the vehicle that can be on or off.
Definition: MSVehicle.h:1913
bool setExitManoeuvre()
accessor function to myManoeuvre equivalent
Definition: MSVehicle.cpp:7186
bool isOppositeLane(const MSLane *lane) const
whether the give lane is reverse direction of the current route or not
Definition: MSVehicle.cpp:5378
double myStopDist
distance to the next stop or doubleMax if there is none
Definition: MSVehicle.h:1927
Signalling
Some boolean values which describe the state of some vehicle parts.
Definition: MSVehicle.h:1117
@ VEH_SIGNAL_BLINKER_RIGHT
Right blinker lights are switched on.
Definition: MSVehicle.h:1121
@ VEH_SIGNAL_BRAKELIGHT
The brake lights are on.
Definition: MSVehicle.h:1127
@ VEH_SIGNAL_EMERGENCY_BLUE
A blue emergency light is on.
Definition: MSVehicle.h:1143
@ VEH_SIGNAL_BLINKER_LEFT
Left blinker lights are switched on.
Definition: MSVehicle.h:1123
SUMOTime getActionStepLength() const
Returns the vehicle's action step length in millisecs, i.e. the interval between two action points.
Definition: MSVehicle.h:521
bool myHaveToWaitOnNextLink
Definition: MSVehicle.h:1921
SUMOTime collisionStopTime() const
Returns the remaining time a vehicle needs to stop due to a collision. A negative value indicates tha...
Definition: MSVehicle.cpp:1581
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...
Definition: MSVehicle.cpp:5945
double getBestLaneDist() const
returns the distance that can be driven without lane change
Definition: MSVehicle.cpp:6028
std::pair< const MSVehicle *const, double > getLeader(double dist=0) const
Returns the leader of the vehicle looking for a fixed distance.
Definition: MSVehicle.cpp:6088
bool executeMove()
Executes planned vehicle movements with regards to right-of-way.
Definition: MSVehicle.cpp:4135
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:577
std::pair< const MSVehicle *const, double > getFollower(double dist=0) const
Returns the follower of the vehicle looking for a fixed distance.
Definition: MSVehicle.cpp:6118
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
Definition: MSVehicle.cpp:6911
void computeFurtherLanes(MSLane *enteredLane, double pos, bool collision=false)
updates myFurtherLanes on lane insertion or after collision
Definition: MSVehicle.cpp:5183
MSLane * getMutableLane() const
Returns the lane the vehicle is on Non const version indicates that something volatile is going on.
Definition: MSVehicle.h:585
std::pair< const MSLane *, double > getLanePosAfterDist(double distance) const
return lane and position along bestlanes at the given distance
Definition: MSVehicle.cpp:6054
SUMOTime myCollisionImmunity
amount of time for which the vehicle is immune from collisions
Definition: MSVehicle.h:1930
bool passingMinor() const
decide whether the vehicle is passing a minor link or has comitted to do so
Definition: MSVehicle.cpp:6895
void updateWaitingTime(double vNext)
Updates the vehicle's waiting time counters (accumulated and consecutive)
Definition: MSVehicle.cpp:3819
void enterLaneAtLaneChange(MSLane *enteredLane)
Update when the vehicle enters a new lane in the laneChange step.
Definition: MSVehicle.cpp:5107
BaseInfluencer & getBaseInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:6781
Influencer & getInfluencer()
Definition: MSVehicle.cpp:6773
double getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
Definition: MSVehicle.cpp:6248
bool unsafeLinkAhead(const MSLane *lane) const
whether the vehicle may safely move to the given lane with regard to upcoming links
Definition: MSVehicle.cpp:6468
double getCurrentApparentDecel() const
get apparent deceleration based on vType parameters and current acceleration
Definition: MSVehicle.cpp:7179
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
Definition: MSVehicle.cpp:4536
DriveItemVector myLFLinkLanesPrev
planned speeds from the previous step for un-registering from junctions after the new container is fi...
Definition: MSVehicle.h:2006
std::vector< std::vector< LaneQ > > myBestLanes
Definition: MSVehicle.h:1891
void setActionStepLength(double actionStepLength, bool resetActionOffset=true)
Sets the action steplength of the vehicle.
Definition: MSVehicle.cpp:1376
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.
Definition: MSVehicle.cpp:1181
bool myActionStep
The flag myActionStep indicates whether the current time step is an action point for the vehicle.
Definition: MSVehicle.h:1871
const Position getBackPosition() const
Definition: MSVehicle.cpp:1456
bool congested() const
Definition: MSVehicle.cpp:1393
void loadState(const SUMOSAXAttributes &attrs, const SUMOTime offset)
Loads the state of this vehicle from the given description.
Definition: MSVehicle.cpp:7094
SUMOTime myTimeSinceStartup
duration of driving (speed > SUMO_const_haltingSpeed) after the last halting eposide
Definition: MSVehicle.h:1940
double getSpeed() const
Returns the vehicle's current speed.
Definition: MSVehicle.h:486
void setApproachingForAllLinks(const SUMOTime t)
Register junction approaches for all link items in the current plan.
Definition: MSVehicle.cpp:4950
SUMOTime remainingStopDuration() const
Returns the remaining stop duration for a stopped vehicle or 0.
Definition: MSVehicle.cpp:1572
bool keepStopping(bool afterProcessing=false) const
Returns whether the vehicle is stopped and must continue to do so.
Definition: MSVehicle.cpp:1560
void workOnIdleReminders()
cycle through vehicle devices invoking notifyIdle
Definition: MSVehicle.cpp:1143
static std::vector< MSLane * > myEmptyLaneVector
Definition: MSVehicle.h:1898
Position myCachedPosition
Definition: MSVehicle.h:1932
MSVehicle::ManoeuvreType getManoeuvreType() const
accessor function to myManoeuvre equivalent
Definition: MSVehicle.cpp:7235
double checkReversal(bool &canReverse, double speedThreshold=SUMO_const_haltingSpeed, double seen=0) const
Definition: MSVehicle.cpp:3843
void removePassedDriveItems()
Erase passed drive items from myLFLinkLanes (and unregister approaching information for corresponding...
Definition: MSVehicle.cpp:3586
const std::vector< MSLane * > & getFurtherLanes() const
Definition: MSVehicle.h:838
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
Definition: MSVehicle.cpp:5385
std::vector< double > myFurtherLanesPosLat
lateral positions on further lanes
Definition: MSVehicle.h:1910
bool checkActionStep(const SUMOTime t)
Returns whether the vehicle is supposed to take action in the current simulation step Updates myActio...
Definition: MSVehicle.cpp:1979
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition: MSVehicle.h:966
Position validatePosition(Position result, double offset=0) const
ensure that a vehicle-relative position is not invalid
Definition: MSVehicle.cpp:1316
void loadPreviousApproaching(MSLink *link, bool setRequest, SUMOTime arrivalTime, double arrivalSpeed, double arrivalSpeedBraking, double dist, double leaveSpeed)
Definition: MSVehicle.cpp:7143
bool keepClear(const MSLink *link) const
decide whether the given link must be kept clear
Definition: MSVehicle.cpp:6839
bool manoeuvreIsComplete() const
accessor function to myManoeuvre equivalent
Definition: MSVehicle.cpp:7368
double processNextStop(double currentVelocity)
Processes stops, returns the velocity needed to reach the stop.
Definition: MSVehicle.cpp:1593
double myAngle
the angle in radians (
Definition: MSVehicle.h:1924
bool ignoreRed(const MSLink *link, bool canBrake) const
decide whether a red (or yellow light) may be ignore
Definition: MSVehicle.cpp:6851
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.
Definition: MSVehicle.cpp:3831
MSDevice_DriverState * myDriverState
This vehicle's driver state.
Definition: MSVehicle.h:1865
bool joinTrainPart(MSVehicle *veh)
try joining the given vehicle to the rear of this one (to resolve joinTriggered)
Definition: MSVehicle.cpp:1893
MSLane * myLane
The lane the vehicle is on.
Definition: MSVehicle.h:1879
bool onFurtherEdge(const MSEdge *edge) const
whether this vehicle has its back (and no its front) on the given edge
Definition: MSVehicle.cpp:6591
double processTraCISpeedControl(double vSafe, double vNext)
Check for speed advices from the traci client and adjust the speed vNext in the current (euler) / aft...
Definition: MSVehicle.cpp:3557
Manoeuvre myManoeuvre
Definition: MSVehicle.h:1347
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it's primary lane
Definition: MSVehicle.cpp:6450
double getAngle() const
Returns the vehicle's direction in radians.
Definition: MSVehicle.h:729
bool handleCollisionStop(MSStop &stop, const double distToStop)
Definition: MSVehicle.cpp:6688
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition: MSVehicle.h:1690
MSDevice_Friction * myFrictionDevice
This vehicle's friction perception.
Definition: MSVehicle.h:1868
double getPreviousSpeed() const
Returns the vehicle's speed before the previous time step.
Definition: MSVehicle.h:494
MSVehicle()
invalidated default constructor
bool joinTrainPartFront(MSVehicle *veh)
try joining the given vehicle to the front of this one (to resolve joinTriggered)
Definition: MSVehicle.cpp:1910
void updateActionOffset(const SUMOTime oldActionStepLength, const SUMOTime newActionStepLength)
Process an updated action step length value (only affects the vehicle's action offset,...
Definition: MSVehicle.cpp:1995
double getBrakeGap(bool delayed=false) const
get distance for coming to a stop (used for rerouting checks)
Definition: MSVehicle.cpp:1973
void executeFractionalMove(double dist)
move vehicle forward by the given distance during insertion
Definition: MSVehicle.cpp:4392
LaneChangeMode
modes for resolving conflicts between external control (traci) and vehicle control over lane changing...
Definition: MSVehicle.h:1155
@ LC_NOCONFLICT
Definition: MSVehicle.h:1157
virtual void drawOutsideNetwork(bool)
register vehicle for drawing while outside the network
Definition: MSVehicle.h:1841
void initDevices()
Definition: MSVehicle.cpp:1028
State myState
This Vehicles driving state (pos and speed)
Definition: MSVehicle.h:1862
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)
Definition: MSVehicle.cpp:6278
void adaptToLeader(const std::pair< const MSVehicle *, double > leaderInfo, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass) const
Definition: MSVehicle.cpp:2955
void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
Definition: MSVehicle.cpp:5014
double getDistanceToPosition(double destPos, const MSEdge *destEdge) const
Definition: MSVehicle.cpp:6071
void planMoveInternal(const SUMOTime t, MSLeaderInfo ahead, DriveItemVector &lfLinks, double &myStopDist, std::pair< double, LinkDirection > &myNextTurn) const
Definition: MSVehicle.cpp:2083
void switchOnSignal(int signal)
Switches the given signal on.
Definition: MSVehicle.h:1174
static bool overlap(const MSVehicle *veh1, const MSVehicle *veh2)
Definition: MSVehicle.h:757
int getLaneIndex() const
Definition: MSVehicle.cpp:6233
void updateParkingState()
update state while parking
Definition: MSVehicle.cpp:4502
DriveItemVector myLFLinkLanes
container for the planned speeds in the current step
Definition: MSVehicle.h:2003
void updateDriveItems()
Check whether the drive items (myLFLinkLanes) are up to date, and update them if required.
Definition: MSVehicle.cpp:3640
SUMOTime myJunctionEntryTime
time at which the current junction was entered
Definition: MSVehicle.h:1935
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.
Definition: MSVehicleType.h:63
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.
Definition: MSVehicleType.h:91
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.
Definition: OutputDevice.h:61
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:251
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:267
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:298
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:252
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:262
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)
Definition: RandHelper.cpp:94
double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
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...
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.
virtual double getSpeed() const =0
Returns the object's current speed.
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:60
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
std::string lane
The lane to stop at.
SUMOTime extension
The maximum time extension for boarding / loading.
std::string parkingarea
(Optional) parking area if one is assigned to the stop
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...
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:1947
double getLeaveSpeed() const
Definition: MSVehicle.h:1993
void adaptLeaveSpeed(const double v)
Definition: MSVehicle.h:1986
static std::map< const MSVehicle *, GapControlState * > refVehMap
stores reference vehicles currently in use by a gapController
Definition: MSVehicle.h:1420
static GapControlVehStateListener vehStateListener
Definition: MSVehicle.h:1423
void activate(double tauOriginal, double tauTarget, double additionalGap, double duration, double changeRate, double maxDecel, const MSVehicle *refVeh)
Start gap control with given params.
Definition: MSVehicle.cpp:317
static void cleanup()
Static cleanup (removes vehicle state listener)
Definition: MSVehicle.cpp:311
void deactivate()
Stop gap control.
Definition: MSVehicle.cpp:347
static void init()
Static initalization (adds vehicle state listener)
Definition: MSVehicle.cpp:300
A structure representing the best lanes for continuing the current route starting at 'lane'.
Definition: MSVehicle.h:857
double length
The overall length which may be driven when using this lane without a lane change.
Definition: MSVehicle.h:861
bool allowsContinuation
Whether this lane allows to continue the drive.
Definition: MSVehicle.h:871
double nextOccupation
As occupation, but without the first lane.
Definition: MSVehicle.h:867
std::vector< MSLane * > bestContinuations
Definition: MSVehicle.h:877
MSLane * lane
The described lane.
Definition: MSVehicle.h:859
double currentLength
The length which may be driven on this lane.
Definition: MSVehicle.h:863
int bestLaneOffset
The (signed) number of lanes to be crossed to get to the lane which allows to continue the drive.
Definition: MSVehicle.h:869
double occupation
The overall vehicle sum on consecutive lanes which can be passed without a lane change.
Definition: MSVehicle.h:865