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