Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSAbstractLaneChangeModel.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
23// Interface for lane-change models
24/****************************************************************************/
25
26// ===========================================================================
27// DEBUG
28// ===========================================================================
29//#define DEBUG_TARGET_LANE
30//#define DEBUG_SHADOWLANE
31//#define DEBUG_OPPOSITE
32//#define DEBUG_MANEUVER
33#define DEBUG_COND (myVehicle.isSelected())
34
35#include <config.h>
36
40#include <microsim/MSNet.h>
41#include <microsim/MSEdge.h>
42#include <microsim/MSLane.h>
43#include <microsim/MSLink.h>
44#include <microsim/MSStop.h>
47#include <microsim/MSGlobals.h>
49#include "MSLCM_DK2008.h"
50#include "MSLCM_LC2013.h"
51#include "MSLCM_LC2013_CC.h"
52#include "MSLCM_SL2015.h"
54
55/* -------------------------------------------------------------------------
56 * static members
57 * ----------------------------------------------------------------------- */
63const double MSAbstractLaneChangeModel::NO_NEIGHBOR(std::numeric_limits<double>::max());
65
66#define LC_ASSUMED_DECEL 1.0 // the minimal constant deceleration assumed to estimate the duration of a continuous lane-change at its initiation.
67
68/* -------------------------------------------------------------------------
69 * MSAbstractLaneChangeModel-methods
70 * ----------------------------------------------------------------------- */
71
72void
74 myAllowOvertakingRight = oc.getBool("lanechange.overtake-right");
75 myLCOutput = oc.isSet("lanechange-output");
76 myLCStartedOutput = oc.getBool("lanechange-output.started");
77 myLCEndedOutput = oc.getBool("lanechange-output.ended");
78 myLCXYOutput = oc.getBool("lanechange-output.xy");
79}
80
81
85 throw ProcessError(TLF("Lane change model '%' is not compatible with sublane simulation", toString(lcm)));
86 }
87 switch (lcm) {
89 return new MSLCM_DK2008(v);
91 return new MSLCM_LC2013(v);
93 return new MSLCM_LC2013_CC(v);
95 return new MSLCM_SL2015(v);
98 return new MSLCM_LC2013(v);
99 } else {
100 return new MSLCM_SL2015(v);
101 }
102 default:
103 throw ProcessError(TLF("Lane change model '%' not implemented", toString(lcm)));
104 }
105}
106
107
109 myVehicle(v),
110 myOwnState(0),
111 myPreviousState(0),
112 myPreviousState2(0),
113 myCanceledStateRight(LCA_NONE),
114 myCanceledStateCenter(LCA_NONE),
115 myCanceledStateLeft(LCA_NONE),
116 mySpeedLat(0),
117 myAccelerationLat(0),
118 myAngleOffset(0),
119 myPreviousAngleOffset(0),
120 myCommittedSpeed(0),
121 myLaneChangeCompletion(1.0),
122 myLaneChangeDirection(0),
123 myAlreadyChanged(false),
124 myShadowLane(nullptr),
125 myTargetLane(nullptr),
126 myModel(model),
127 myLastLateralGapLeft(0.),
128 myLastLateralGapRight(0.),
129 myLastLeaderGap(0.),
130 myLastFollowerGap(0.),
131 myLastLeaderSecureGap(0.),
132 myLastFollowerSecureGap(0.),
133 myLastOrigLeaderGap(0.),
134 myLastOrigLeaderSecureGap(0.),
135 myLastLeaderSpeed(0),
136 myLastFollowerSpeed(0),
137 myLastOrigLeaderSpeed(0),
138 myDontResetLCGaps(false),
139 myStrategicLookahead(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD, UNDEFINED_LOOKAHEAD)),
140 myMaxSpeedLatStanding(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING, v.getVehicleType().getMaxSpeedLat())),
141 myMaxSpeedLatFactor(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR, 1)),
142 myMaxDistLatStanding(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_MAXDISTLATSTANDING,
143 // prevent lateral sliding for cars but permit for two-wheelers due to better maneuverability
144 (v.getVClass() & (SVC_BICYCLE | SVC_MOTORCYCLE | SVC_MOPED)) != 0 ? std::numeric_limits<double>::max() : 1.6)),
145 mySigma(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_SIGMA, 0.0)),
146 myOvertakeRightParam(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_OVERTAKE_RIGHT, 0)),
147 myAssertive(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_ASSERTIVE, 1)),
148 myCooperativeHelpTime(TIME2STEPS(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_HELPTIME, 60))),
149 myCooperativeHelpThreshold(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_HELPTHRESHOLD, -1)),
150 myCooperativeMinSpeed(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_COOPERATIVE_MINSPEED, 0)),
151 myHaveBlueLight(v.getDevice(typeid(MSDevice_Bluelight)) != nullptr), // see MSVehicle::initDevices
152 myLastLaneChangeOffset(0),
153 myAmOpposite(false),
154 myManeuverDist(0.),
155 myPreviousManeuverDist(0.) {
159}
160
161
164
165void
168 myOwnState = state;
169 myPreviousState = state; // myOwnState is modified in prepareStep so we make a backup
170}
171
172void
173MSAbstractLaneChangeModel::updateSafeLatDist(const double travelledLatDist) {
174 UNUSED_PARAMETER(travelledLatDist);
175}
176
177
178void
180#ifdef DEBUG_MANEUVER
181 if (DEBUG_COND) {
182 std::cout << SIMTIME
183 << " veh=" << myVehicle.getID()
184 << " setManeuverDist() old=" << myManeuverDist << " new=" << dist
185 << std::endl;
186 }
187#endif
188 myManeuverDist = fabs(dist) < NUMERICAL_EPS ? 0. : dist;
189 // store value which may be modified by the model during the next step
191}
192
193
194double
198
199double
203
204void
206 if (dir == -1) {
207 myLeftFollowers = std::make_shared<MSLeaderDistanceInfo>(followers);
208 myLeftLeaders = std::make_shared<MSLeaderDistanceInfo>(leaders);
209 } else if (dir == 1) {
210 myRightFollowers = std::make_shared<MSLeaderDistanceInfo>(followers);
211 myRightLeaders = std::make_shared<MSLeaderDistanceInfo>(leaders);
212 } else {
213 // dir \in {-1,1} !
214 assert(false);
215 }
216}
217
218
219void
220MSAbstractLaneChangeModel::saveNeighbors(const int dir, const std::pair<MSVehicle* const, double>& follower, const std::pair<MSVehicle* const, double>& leader) {
221 if (dir == -1) {
222 myLeftFollowers = std::make_shared<MSLeaderDistanceInfo>(follower, myVehicle.getLane()->getWidth());
223 myLeftLeaders = std::make_shared<MSLeaderDistanceInfo>(leader, myVehicle.getLane()->getWidth());
224 } else if (dir == 1) {
225 myRightFollowers = std::make_shared<MSLeaderDistanceInfo>(follower, myVehicle.getLane()->getWidth());
226 myRightLeaders = std::make_shared<MSLeaderDistanceInfo>(leader, myVehicle.getLane()->getWidth());
227 } else {
228 // dir \in {-1,1} !
229 assert(false);
230 }
231}
232
233
234void
236 myLeftFollowers = nullptr;
237 myLeftLeaders = nullptr;
238 myRightFollowers = nullptr;
239 myRightLeaders = nullptr;
240}
241
242
243const std::shared_ptr<MSLeaderDistanceInfo>
245 if (dir == -1) {
246 return myLeftFollowers;
247 } else if (dir == 1) {
248 return myRightFollowers;
249 } else {
250 // dir \in {-1,1} !
251 assert(false);
252 }
253 return nullptr;
254}
255
256const std::shared_ptr<MSLeaderDistanceInfo>
258 if (dir == -1) {
259 return myLeftLeaders;
260 } else if (dir == 1) {
261 return myRightLeaders;
262 } else {
263 // dir \in {-1,1} !
264 assert(false);
265 }
266 return nullptr;
267}
268
269
270bool
272 if (neighLeader == nullptr) {
273 return false;
274 }
275 // Congested situation are relevant only on highways (maxSpeed > 70km/h)
276 // and congested on German Highways means that the vehicles have speeds
277 // below 60km/h. Overtaking on the right is allowed then.
278 if ((myVehicle.getLane()->getSpeedLimit() <= 70.0 / 3.6) || (neighLeader->getLane()->getSpeedLimit() <= 70.0 / 3.6)) {
279
280 return false;
281 }
282 if (myVehicle.congested() && neighLeader->congested()) {
283 return true;
284 }
285 return false;
286}
287
288
289bool
290MSAbstractLaneChangeModel::avoidOvertakeRight(const MSVehicle* const neighLeader, const bool allowProb) const {
291 return (!myAllowOvertakingRight // the highway case
292 && !myVehicle.congested()
295 (neighLeader != nullptr && neighLeader->isStopped() // the bus stop case
296 && neighLeader->getStops().front().busstop != nullptr
297 && !StringUtils::toBool(neighLeader->getStops().front().busstop->getParameter("allowOvertakeRight", "true")));
298}
299
300bool
301MSAbstractLaneChangeModel::predInteraction(const std::pair<MSVehicle*, double>& leader) {
302 if (leader.first == 0) {
303 return false;
304 }
305 // let's check it on highways only
306 if (leader.first->getSpeed() < (80.0 / 3.6)) {
307 return false;
308 }
309 return leader.second < getCarFollowModel().interactionGap(&myVehicle, leader.first->getSpeed());
310}
311
312
313bool
317 myLaneChangeDirection = direction;
318 setManeuverDist((target->getWidth() + source->getWidth()) * 0.5 * direction);
321 if (myLCOutput) {
323 }
324 return true;
325 } else {
326 primaryLaneChanged(source, target, direction);
327 return false;
328 }
329}
330
331void
335
336void
340
341void
343 initLastLaneChangeOffset(direction);
345 source->leftByLaneChange(&myVehicle);
346 laneChangeOutput("change", source, target, direction); // record position on the source edge in case of opposite change
347 if (&source->getEdge() != &target->getEdge()) {
349#ifdef DEBUG_OPPOSITE
350 if (debugVehicle()) {
351 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " primaryLaneChanged source=" << source->getID() << " target=" << target->getID() << " nowOpposite=" << myAmOpposite << "\n";
352 }
353#endif
356 } else if (myAmOpposite) {
357#ifdef DEBUG_OPPOSITE
358 if (debugVehicle()) {
359 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " primaryLaneChanged source=" << source->getID() << " target=" << target->getID() << " stayOpposite\n";
360 }
361#endif
362 myAlreadyChanged = true;
364 if (!MSGlobals::gSublane) {
365 // in the continous case, the vehicle is added to the target lane via MSLaneChanger::continueChange / registerHop
366 // in the sublane case, the vehicle is added to the target lane via MSLaneChangerSublane::checkChangeOppositeSublane / MSLane::myTmpVehicles
368 }
369 } else {
372 }
373 // Assure that the drive items are up to date (even if the following step is no actionstep for the vehicle).
374 // This is necessary because the lane advance uses the target lane from the corresponding drive item.
376 changed();
377}
378
379void
380MSAbstractLaneChangeModel::laneChangeOutput(const std::string& tag, MSLane* source, MSLane* target, int direction, double maneuverDist) {
381 if (myLCOutput) {
382 OutputDevice& of = OutputDevice::getDeviceByOption("lanechange-output");
383 of.openTag(tag);
386 of.writeAttr(SUMO_ATTR_TIME, time2string(MSNet::getInstance()->getCurrentTimeStep()));
387 of.writeAttr(SUMO_ATTR_FROM, source->getID());
388 of.writeAttr(SUMO_ATTR_TO, target->getID());
389 of.writeAttr(SUMO_ATTR_DIR, direction);
407 const double latGap = direction < 0 ? myLastLateralGapRight : myLastLateralGapLeft;
408 of.writeAttr("latGap", latGap == NO_NEIGHBOR ? "None" : toString(latGap), latGap == NO_NEIGHBOR);
409 if (maneuverDist != 0) {
410 of.writeAttr("maneuverDistance", toString(maneuverDist));
411 }
412 }
413 if (myLCXYOutput) {
416 }
417 of.closeTag();
420 }
421 }
422}
423
424
425double
426MSAbstractLaneChangeModel::computeSpeedLat(double /*latDist*/, double& maneuverDist, bool /*urgent*/) const {
428 int stepsToChange = (int)ceil(fabs(maneuverDist) / SPEED2DIST(myVehicle.getVehicleType().getMaxSpeedLat()));
429 return DIST2SPEED(maneuverDist / stepsToChange);
430 } else {
431 return maneuverDist / STEPS2TIME(MSGlobals::gLaneChangeDuration);
432 }
433}
434
435
436double
440
441void
444 mySpeedLat = speedLat;
445}
446
447
448void
454
455
456bool
458 const bool pastBefore = pastMidpoint();
459 // maneuverDist is not updated in the context of continuous lane changing but represents the full LC distance
460 double maneuverDist = getManeuverDist();
461 setSpeedLat(computeSpeedLat(0, maneuverDist, (myOwnState & LCA_URGENT) != 0));
463 return !pastBefore && pastMidpoint();
464}
465
466
467void
469 UNUSED_PARAMETER(reason);
478 // opposite driving continues after parking
479 } else {
480 // aborted maneuver
481#ifdef DEBUG_OPPOSITE
482 if (debugVehicle()) {
483 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " aborted maneuver (no longer opposite)\n";
484 }
485#endif
487 }
488 }
489}
490
491
492MSLane*
493MSAbstractLaneChangeModel::getShadowLane(const MSLane* lane, double posLat) const {
495 // initialize shadow lane
496 const double overlap = myVehicle.getLateralOverlap(posLat, lane);
497#ifdef DEBUG_SHADOWLANE
498 if (debugVehicle()) {
499 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " posLat=" << posLat << " overlap=" << overlap << "\n";
500 }
501#endif
502 if (myAmOpposite) {
503 // return the neigh-lane in forward direction
504 return lane->getParallelLane(1);
505 } else if (overlap > NUMERICAL_EPS) {
506 const int shadowDirection = posLat < 0 ? -1 : 1;
507 return lane->getParallelLane(shadowDirection);
508 } else if (isChangingLanes() && myLaneChangeCompletion < 0.5) {
509 // "reserve" target lane even when there is no overlap yet
511 } else {
512 return nullptr;
513 }
514 } else {
515 return nullptr;
516 }
517}
518
519
520MSLane*
524
525
526void
528 if (myShadowLane != nullptr) {
529 if (debugVehicle()) {
530 std::cout << SIMTIME << " cleanupShadowLane\n";
531 }
533 myShadowLane = nullptr;
534 }
535 for (MSLane* further : myShadowFurtherLanes) {
536 if (debugVehicle()) {
537 std::cout << SIMTIME << " cleanupShadowLane2\n";
538 }
540 if (further->getBidiLane() != nullptr) {
541 further->getBidiLane()->resetPartialOccupation(&myVehicle);
542 }
543 }
544 myShadowFurtherLanes.clear();
546}
547
548void
550 if (myTargetLane != nullptr) {
551 if (debugVehicle()) {
552 std::cout << SIMTIME << " cleanupTargetLane\n";
553 }
555 myTargetLane = nullptr;
556 }
557 for (std::vector<MSLane*>::const_iterator it = myFurtherTargetLanes.begin(); it != myFurtherTargetLanes.end(); ++it) {
558 if (debugVehicle()) {
559 std::cout << SIMTIME << " cleanupTargetLane\n";
560 }
561 if (*it != nullptr) {
563 }
564 }
565 myFurtherTargetLanes.clear();
566// myNoPartiallyOccupatedByShadow.clear();
567}
568
569
570bool
572 // store request before canceling
573 getCanceledState(laneOffset) |= state;
574 int ret = myVehicle.influenceChangeDecision(state);
575 return ret != state;
576}
577
578double
582
583void
585 if (dir > 0) {
587 } else if (dir < 0) {
589 }
590}
591
592void
594 if (!MSGlobals::gSublane) {
595 // assume each vehicle drives at the center of its lane and act as if it fits
596 return;
597 }
598 if (myShadowLane != nullptr) {
599#ifdef DEBUG_SHADOWLANE
600 if (debugVehicle()) {
601 std::cout << SIMTIME << " updateShadowLane()\n";
602 }
603#endif
605 }
607 std::vector<MSLane*> passed;
608 if (myShadowLane != nullptr) {
610 const std::vector<MSLane*>& further = myVehicle.getFurtherLanes();
611 if (myAmOpposite) {
612 assert(further.size() == 0);
613 } else {
614 const std::vector<double>& furtherPosLat = myVehicle.getFurtherLanesPosLat();
615 assert(further.size() == furtherPosLat.size());
616 passed.push_back(myShadowLane);
617 for (int i = 0; i < (int)further.size(); ++i) {
618 MSLane* shadowFurther = getShadowLane(further[i], furtherPosLat[i]);
619#ifdef DEBUG_SHADOWLANE
620 if (debugVehicle()) {
621 std::cout << SIMTIME << " further=" << further[i]->getID() << " (posLat=" << furtherPosLat[i] << ") shadowFurther=" << Named::getIDSecure(shadowFurther) << "\n";
622 }
623#endif
624 if (shadowFurther != nullptr && shadowFurther->getLinkTo(passed.back()) != nullptr) {
625 passed.push_back(shadowFurther);
626 }
627 }
628 std::reverse(passed.begin(), passed.end());
629 }
630 } else {
631 if (isChangingLanes() && myVehicle.getLateralOverlap() > NUMERICAL_EPS) {
632 WRITE_WARNING("Vehicle '" + myVehicle.getID() + "' could not finish continuous lane change (lane disappeared) time=" +
633 time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
635 }
636 }
637#ifdef DEBUG_SHADOWLANE
638 if (debugVehicle()) {
639 std::cout << SIMTIME << " updateShadowLane() veh=" << myVehicle.getID()
640 << " newShadowLane=" << Named::getIDSecure(myShadowLane)
641 << "\n before:" << " myShadowFurtherLanes=" << toString(myShadowFurtherLanes) << " further=" << toString(myVehicle.getFurtherLanes()) << " passed=" << toString(passed);
642 std::cout << std::endl;
643 }
644#endif
646#ifdef DEBUG_SHADOWLANE
647 if (debugVehicle()) std::cout
648 << "\n after:" << " myShadowFurtherLanes=" << toString(myShadowFurtherLanes) << "\n";
649#endif
650}
651
652
653int
655 if (isChangingLanes()) {
656 if (pastMidpoint()) {
657 return -myLaneChangeDirection;
658 } else {
660 }
661 } else if (myShadowLane == nullptr) {
662 return 0;
663 } else if (myAmOpposite) {
664 // return neigh-lane in forward direction
665 return 1;
666 } else if (&myShadowLane->getEdge() == &myVehicle.getLane()->getEdge()) {
668 } else {
669 // overlap with opposite direction lane
670 return 1;
671 }
672}
673
674
675MSLane*
677#ifdef DEBUG_TARGET_LANE
678 MSLane* oldTarget = myTargetLane;
679 std::vector<MSLane*> oldFurtherTargets = myFurtherTargetLanes;
680 if (debugVehicle()) {
681 std::cout << SIMTIME << " veh '" << myVehicle.getID() << "' (lane=" << myVehicle.getLane()->getID() << ") updateTargetLane()"
682 << "\n oldTarget: " << (oldTarget == nullptr ? "NULL" : oldTarget->getID())
683 << " oldFurtherTargets: " << toString(oldFurtherTargets);
684 }
685#endif
686 if (myTargetLane != nullptr) {
688 }
689 // Clear old further target lanes
690 for (MSLane* oldTargetLane : myFurtherTargetLanes) {
691 if (oldTargetLane != nullptr) {
692 oldTargetLane->resetManeuverReservation(&myVehicle);
693 }
694 }
695 myFurtherTargetLanes.clear();
696
697 // Get new target lanes and issue a maneuver reservation.
698 int targetDir;
700 if (myTargetLane != nullptr) {
702 // further targets are just the target lanes corresponding to the vehicle's further lanes
703 // @note In a neglectable amount of situations we might add a reservation for a shadow further lane.
704 for (MSLane* furtherLane : myVehicle.getFurtherLanes()) {
705 MSLane* furtherTargetLane = furtherLane->getParallelLane(targetDir);
706 myFurtherTargetLanes.push_back(furtherTargetLane);
707 if (furtherTargetLane != nullptr) {
708 furtherTargetLane->setManeuverReservation(&myVehicle);
709 }
710 }
711 }
712#ifdef DEBUG_TARGET_LANE
713 if (debugVehicle()) {
714 std::cout << "\n newTarget (maneuverDist=" << myManeuverDist << " offset=" << targetDir << "): " << (myTargetLane == nullptr ? "NULL" : myTargetLane->getID())
715 << " newFurtherTargets: " << toString(myFurtherTargetLanes)
716 << std::endl;
717 }
718#endif
719 return myTargetLane;
720}
721
722
723MSLane*
725 targetDir = 0;
726 if (myManeuverDist == 0) {
727 return nullptr;
728 }
729 // Current lateral boundaries of the vehicle
730 const double vehRight = myVehicle.getLateralPositionOnLane() - 0.5 * myVehicle.getWidth();
731 const double vehLeft = myVehicle.getLateralPositionOnLane() + 0.5 * myVehicle.getWidth();
732 const double halfLaneWidth = 0.5 * myVehicle.getLane()->getWidth();
733
734 if (vehRight + myManeuverDist < -halfLaneWidth) {
735 // Vehicle intends to traverse the right lane boundary
736 targetDir = -1;
737 } else if (vehLeft + myManeuverDist > halfLaneWidth) {
738 // Vehicle intends to traverse the left lane boundary
739 targetDir = 1;
740 }
741 if (targetDir == 0) {
742 // Presently, no maneuvering into another lane is begun.
743 return nullptr;
744 }
745 MSLane* target = myVehicle.getLane()->getParallelLane(targetDir);
746 if (target == nullptr || target == myShadowLane) {
747 return nullptr;
748 } else {
749 return target;
750 }
751}
752
753
754
755double
757 double result = 0.;
758 if (!(fabs(mySpeedLat) < NUMERICAL_EPS && fabs(myPreviousAngleOffset * 180 / M_PI) < NUMERICAL_EPS)) {
760 result = atan2(mySpeedLat, myVehicle.getSpeed());
761 } else {
763 }
764 }
765
766 myAngleOffset = result;
767 return result;
768}
769
770
771double
772MSAbstractLaneChangeModel::estimateLCDuration(const double speed, const double remainingManeuverDist, const double decel, bool urgent) const {
773
775 if (lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING) == lcParams.end() && lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR) == lcParams.end()) {
777 // no dependency of lateral speed on longitudinal speed. (Only called prior to LC initialization to determine whether it could be completed)
779 } else {
780 return remainingManeuverDist / myVehicle.getVehicleType().getMaxSpeedLat();
781 }
782 }
783
784 if (remainingManeuverDist == 0) {
785 return 0;
786 }
787
788 // Check argument assumptions
789 assert(speed >= 0);
790 assert(remainingManeuverDist >= 0);
791 assert(decel > 0);
794 assert(myMaxSpeedLatStanding >= 0);
795
796 // for brevity
797 const double v0 = speed;
798 const double D = remainingManeuverDist;
799 const double b = decel;
800 const double wmin = myMaxSpeedLatStanding;
801 const double f = myMaxSpeedLatFactor;
802 const double wmax = myVehicle.getVehicleType().getMaxSpeedLat();
803
804 /* Here's the approach for the calculation of the required time for the LC:
805 * To obtain the maximal LC-duration, for v(t) we assume that v(t)=max(0, v0-b*t),
806 * Where v(t)=0 <=> t >= ts:=v0/b
807 * For the lateral speed w(t) this gives:
808 * w(t) = min(wmax, wmin + f*v(t))
809 * The lateral distance covered until t is
810 * d(t) = int_0^t w(s) ds
811 * We distinguish three possibilities for the solution d(T)=D, where T is the time of the LC completion.
812 * 1) w(T) = wmax, i.e. v(T)>(wmax-wmin)/f
813 * 2) wmin < w(T) < wmax, i.e. (wmax-wmin)/f > v(T) > 0
814 * 3) w(T) = wmin, i.e., v(T)=0
815 */
816 const double vm = (wmax - wmin) / f;
817 double distSoFar = 0.;
818 double timeSoFar = 0.;
819 double v = v0;
820 if (v > vm) {
821 const double wmaxTime = (v0 - vm) / b;
822 const double d1 = wmax * wmaxTime;
823 if (d1 >= D) {
824 return D / wmax;
825 } else {
826 distSoFar += d1;
827 timeSoFar += wmaxTime;
828 v = vm;
829 }
830 }
831 if (v > 0) {
832 /* Here, w(t1+t) = wmin + f*v(t1+t) = wmin + f*(v - b*t)
833 * Thus, the additional lateral distance covered after time t is:
834 * d2 = (wmin + f*v)*t - 0.5*f*b*t^2
835 * and the additional lateral distance covered until v=0 at t=v/b is:
836 * d2 = (wmin + 0.5*f*v)*t
837 */
838 const double t = v / b; // stop time
839 const double d2 = (wmin + 0.5 * f * v) * t; // lateral distance covered until stop
840 assert(d2 > 0);
841 if (distSoFar + d2 >= D) {
842 // LC is completed during this phase
843 const double x = 0.5 * f * b;
844 const double y = wmin + f * v;
845 /* Solve D - distSoFar = y*t - x*t^2.
846 * 0 = x*t^2 - y*t/x + (D - distSoFar)/x
847 */
848 const double p = 0.5 * y / x;
849 const double q = (D - distSoFar) / x;
850 assert(p * p - q > 0);
851 const double t2 = p + sqrt(p * p - q);
852 return timeSoFar + t2;
853 } else {
854 distSoFar += d2;
855 timeSoFar += t;
856 //v = 0;
857 }
858 }
859 // If we didn't return yet this means the LC was not completed until the vehicle stops (if braking with rate b)
860 if (wmin == 0) {
861 // LC won't be completed if vehicle stands
862 double maneuverDist = remainingManeuverDist;
863 const double vModel = computeSpeedLat(maneuverDist, maneuverDist, urgent);
864 double result = D / vModel;
865 // make sure that the vehicle isn't braking to a stop during the manuever
866 if (vModel > SUMO_const_haltingSpeed && (vModel + myVehicle.getAcceleration() * result) > SUMO_const_haltingSpeed) {
867 // unless the model tells us something different
868 return result;
869 } else {
870 return -1;
871 }
872 } else {
873 // complete LC with lateral speed wmin
874 return timeSoFar + (D - distSoFar) / wmin;
875 }
876}
877
880 assert(isChangingLanes()); // Only to be called during ongoing lane change
882 if (lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING) == lcParams.end() && lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR) == lcParams.end()) {
885 } else {
887 }
888 }
889 // Using maxSpeedLat(Factor/Standing)
890 const bool urgent = (myOwnState & LCA_URGENT) != 0;
894}
895
896
897void
899 //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " @=" << &myVehicle << " set shadow approaching=" << link->getViaLaneOrLane()->getID() << "\n";
900 myApproachedByShadow.push_back(link);
901}
902
903void
905 for (std::vector<MSLink*>::iterator it = myApproachedByShadow.begin(); it != myApproachedByShadow.end(); ++it) {
906 //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " @=" << &myVehicle << " remove shadow approaching=" << (*it)->getViaLaneOrLane()->getID() << "\n";
907 (*it)->removeApproaching(&myVehicle);
908 }
909 myApproachedByShadow.clear();
910}
911
912
913
914void
917 int oldstate = myVehicle.getLaneChangeModel().getOwnState();
918 if (myOwnState != newstate) {
920 // Calculate and set the lateral maneuver distance corresponding to the change request
921 // to induce a corresponding sublane change.
922 const int dir = (newstate & LCA_RIGHT) != 0 ? -1 : ((newstate & LCA_LEFT) != 0 ? 1 : 0);
923 // minimum distance to move the vehicle fully onto the lane at offset dir
924 const double latLaneDist = myVehicle.lateralDistanceToLane(dir);
925 if ((newstate & LCA_TRACI) != 0) {
926 if ((newstate & LCA_STAY) != 0) {
927 setManeuverDist(0.);
928 } else if (((newstate & LCA_RIGHT) != 0 && dir < 0)
929 || ((newstate & LCA_LEFT) != 0 && dir > 0)) {
930 setManeuverDist(latLaneDist);
931 }
932 }
933 if (myVehicle.hasInfluencer()) {
934 // lane change requests override sublane change requests
936 }
937
938 }
939 setOwnState(newstate);
940 } else {
941 // Check for sublane change requests
943 const double maneuverDist = myVehicle.getInfluencer().getLatDist();
946 newstate |= LCA_TRACI;
947 if (myOwnState != newstate) {
948 setOwnState(newstate);
949 }
950 if (gDebugFlag2) {
951 std::cout << " traci influenced maneuverDist=" << maneuverDist << "\n";
952 }
953 }
954 }
955 if (gDebugFlag2) {
956 std::cout << SIMTIME << " veh=" << myVehicle.getID() << " stateAfterTraCI=" << toString((LaneChangeAction)newstate) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
957 }
958}
959
960void
965
966void
968 if (follower.first != 0) {
969 myLastFollowerGap = follower.second + follower.first->getVehicleType().getMinGap();
971 myLastFollowerSpeed = follower.first->getSpeed();
972 }
973}
974
975void
977 if (leader.first != 0) {
979 myLastLeaderSecureGap = secGap;
980 myLastLeaderSpeed = leader.first->getSpeed();
981 }
982}
983
984void
986 if (leader.first != 0) {
989 myLastOrigLeaderSpeed = leader.first->getSpeed();
990 }
991}
992
993void
1016
1017void
1019 int rightmost;
1020 int leftmost;
1021 vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
1022 for (int i = rightmost; i <= leftmost; ++i) {
1023 CLeaderDist vehDist = vehicles[i];
1024 if (vehDist.first != 0) {
1025 const MSVehicle* leader = &myVehicle;
1026 const MSVehicle* follower = vehDist.first;
1027 const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
1028 if (netGap < myLastFollowerGap && netGap >= 0) {
1029 myLastFollowerGap = netGap;
1030 myLastFollowerSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
1031 myLastFollowerSpeed = follower->getSpeed();
1032 }
1033 }
1034 }
1035}
1036
1037void
1039 int rightmost;
1040 int leftmost;
1041 vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
1042 for (int i = rightmost; i <= leftmost; ++i) {
1043 CLeaderDist vehDist = vehicles[i];
1044 if (vehDist.first != 0) {
1045 const MSVehicle* leader = vehDist.first;
1046 const MSVehicle* follower = &myVehicle;
1047 const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
1048 if (netGap < myLastLeaderGap && netGap >= 0) {
1049 myLastLeaderGap = netGap;
1050 myLastLeaderSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
1051 myLastLeaderSpeed = leader->getSpeed();
1052 }
1053 }
1054 }
1055}
1056
1057void
1059 int rightmost;
1060 int leftmost;
1061 vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
1062 for (int i = rightmost; i <= leftmost; ++i) {
1063 CLeaderDist vehDist = vehicles[i];
1064 if (vehDist.first != 0) {
1065 const MSVehicle* leader = vehDist.first;
1066 const MSVehicle* follower = &myVehicle;
1067 const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
1068 if (netGap < myLastOrigLeaderGap && netGap >= 0) {
1069 myLastOrigLeaderGap = netGap;
1070 myLastOrigLeaderSecureGap = follower->getCarFollowModel().getSecureGap(follower, leader, follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
1071 myLastOrigLeaderSpeed = leader->getSpeed();
1072 }
1073 }
1074 }
1075}
1076
1077
1078bool
1080 const int stateRight = mySavedStateRight.second;
1081 if (
1082 (stateRight & LCA_STRATEGIC) != 0
1083 && (stateRight & LCA_RIGHT) != 0
1084 && (stateRight & LCA_BLOCKED) != 0) {
1085 return true;
1086 }
1087 const int stateLeft = mySavedStateLeft.second;
1088 if (
1089 (stateLeft & LCA_STRATEGIC) != 0
1090 && (stateLeft & LCA_LEFT) != 0
1091 && (stateLeft & LCA_BLOCKED) != 0) {
1092 return true;
1093 }
1094 return false;
1095}
1096
1097double
1101
1102
1103int
1105 const int i = myVehicle.getLane()->getIndex();
1106 if (myAmOpposite) {
1108 } else {
1109 return i;
1110 }
1111}
1112
1113void
1114MSAbstractLaneChangeModel::addLCSpeedAdvice(const double vSafe, bool ownAdvice) {
1115 const double accel = SPEED2ACCEL(vSafe - myVehicle.getSpeed());
1116 myLCAccelerationAdvices.push_back({accel, ownAdvice});
1117}
1118
1119
1120bool
1121MSAbstractLaneChangeModel::canOvertakeRight(const MSVehicle* const nv, const double dist, const double maxSpeedDiff, const double helpOvertakeSpeed, double& vSafe, double& deltaV) const {
1122 deltaV = MAX2(maxSpeedDiff, myVehicle.getSpeed() - nv->getSpeed());
1123 if (deltaV > 0) {
1124 const double vMaxDecel = getCarFollowModel().getSpeedAfterMaxDecel(myVehicle.getSpeed());
1125 const double vSafeFollow = getCarFollowModel().followSpeed(
1127 const double vStayBehind = nv->getSpeed() - helpOvertakeSpeed;
1128 if (vSafeFollow >= vMaxDecel) {
1129 vSafe = vSafeFollow;
1130 } else {
1131 vSafe = MAX2(vMaxDecel, vStayBehind);
1132 }
1133 return true;
1134 }
1135 return false;
1136}
1137
1138
1139void
1141 std::vector<double> lcState;
1142 lcState.push_back((double)myOwnState);
1143 for (const auto& item : myLCAccelerationAdvices) {
1144 lcState.push_back(item.first);
1145 lcState.push_back((double)item.second);
1146 }
1147 out.writeAttr(SUMO_ATTR_LCSTATE_BASE, lcState);
1148
1151 }
1152}
1153
1154void
1157 std::istringstream bis(attrs.getString(SUMO_ATTR_LCSTATE_BASE));
1158 double token;
1159 bis >> token;
1160 myOwnState = (int)token; // double is suffciently precise
1161 double prev = std::numeric_limits<double>::max();
1162 while (bis >> token) {
1163 if (prev != std::numeric_limits<double>::max()) {
1164 myLCAccelerationAdvices.push_back(std::make_pair(prev, (bool)token));
1165 prev = std::numeric_limits<double>::max();
1166 }
1167 prev = token;
1168 }
1169 }
1170 if (attrs.hasAttribute(SUMO_ATTR_LCSTATE)) {
1171 std::istringstream bis(attrs.getString(SUMO_ATTR_LCSTATE));
1172 bis >> mySpeedLat;
1174 bis >> myLaneChangeDirection;
1175 }
1176}
1177
1178
1179double
1180MSAbstractLaneChangeModel::getExtraReservation(int bestLaneOffset, double neighExtraDist) const {
1181 if (neighExtraDist > myVehicle.getVehicleType().getLengthWithGap()) {
1182 return 0;
1183 }
1184 if (bestLaneOffset < -1) {
1185 return 20;
1186 } else if (bestLaneOffset > 1) {
1187 return 40;
1188 }
1189 return 0;
1190}
1191
1192
1193double
1194MSAbstractLaneChangeModel::getCooperativeHelpSpeed(const MSLane* lane, double distToLaneEnd) const {
1195 if (myCooperativeHelpTime >= 0) {
1196 std::pair<double, SUMOTime> backAndWaiting = lane->getEdge().getLastBlocked(lane->getIndex());
1197 if (backAndWaiting.second >= myCooperativeHelpTime) {
1198 double gap = distToLaneEnd - lane->getLength() + backAndWaiting.first - myVehicle.getVehicleType().getMinGap() - NUMERICAL_EPS;
1199 if (backAndWaiting.first < 0) {
1200 if (myVehicle.getLane()->getToJunction() == lane->getFromJunction()) {
1201 if (myVehicle.getLane()->isInternal()) {
1202 // already on the junction, potentially blocking lane change, do not stop
1203 gap = -1;
1204 } else {
1205 // stop before entering the junction
1207 }
1208 }
1209 }
1210 if (gap > 0) {
1211 double stopSpeed = myVehicle.getCarFollowModel().stopSpeed(&myVehicle, myVehicle.getSpeed(), gap);
1212 //if (myVehicle.isSelected() && stopSpeed < myVehicle.getSpeed()) {
1213 // std::cout << SIMTIME << " veh=" << myVehicle.getID() << " lane=" << lane->getID() << " dte=" << distToLaneEnd << " gap=" << gap << " backPos=" << backAndWaiting.first << " waiting=" << backAndWaiting.second << " helpTime=" << myCooperativeHelpTime << " stopSpeed=" << stopSpeed << " minNext=" << myVehicle.getCarFollowModel().minNextSpeed(myVehicle.getSpeed(), &myVehicle) << "\n";
1214 //}
1216 // regular braking is helpful
1217 return stopSpeed;
1218 }
1219 }
1220 }
1221 }
1222 // do not restrict speed
1223 return std::numeric_limits<double>::max();
1224}
long long int SUMOTime
Definition GUI.h:36
#define LC_ASSUMED_DECEL
std::pair< const MSVehicle *, double > CLeaderDist
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TLF(string,...)
Definition MsgHandler.h:306
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define SIMTIME
Definition SUMOTime.h:65
#define TIME2STEPS(x)
Definition SUMOTime.h:60
#define DIST2SPEED(x)
Definition SUMOTime.h:50
#define SPEED2ACCEL(x)
Definition SUMOTime.h:56
const long long int VTYPEPARS_MAXSPEED_LAT_SET
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_MOTORCYCLE
vehicle is a motorcycle
@ SVC_EMERGENCY
public emergency vehicles
@ SVC_MOPED
vehicle is a moped
LaneChangeAction
The state of a vehicle's lane-change behavior.
@ LCA_UNKNOWN
The action has not been determined.
@ 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_AMBACKBLOCKER
@ LCA_AMBLOCKINGLEADER
@ LCA_LEFT
Wants go to the left.
@ LCA_STRATEGIC
The action is needed to follow the route (navigational lc)
@ LCA_AMBACKBLOCKER_STANDING
@ LCA_TRACI
The action is due to a TraCI request.
@ LCA_RIGHT
Wants go to the right.
@ LCA_AMBLOCKINGFOLLOWER
@ SUMO_ATTR_SPEED
@ SUMO_ATTR_LCA_ASSERTIVE
@ SUMO_ATTR_Y
@ SUMO_ATTR_LCA_COOPERATIVE_MINSPEED
@ SUMO_ATTR_X
@ SUMO_ATTR_LCA_MAXDISTLATSTANDING
@ SUMO_ATTR_LCA_COOPERATIVE_HELPTIME
@ SUMO_ATTR_LCA_MAXSPEEDLATFACTOR
@ SUMO_ATTR_LCA_MAXSPEEDLATSTANDING
@ SUMO_ATTR_LCA_STRATEGIC_LOOKAHEAD
@ SUMO_ATTR_TO
@ SUMO_ATTR_FROM
@ SUMO_ATTR_LCA_SIGMA
@ SUMO_ATTR_LCSTATE_BASE
@ SUMO_ATTR_TYPE
@ SUMO_ATTR_LCA_COOPERATIVE_HELPTHRESHOLD
@ SUMO_ATTR_ID
@ SUMO_ATTR_LCSTATE
The state of the lanechange model.
@ SUMO_ATTR_LCA_OVERTAKE_RIGHT
@ SUMO_ATTR_DIR
The abstract direction of a link.
@ SUMO_ATTR_POSITION
@ SUMO_ATTR_TIME
trigger: the time of the step
bool gDebugFlag2
Definition StdDefs.cpp:45
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
Interface for lane-change models.
double getForwardPos() const
get vehicle position relative to the forward direction lane
double myAccelerationLat
the current lateral acceleration
void setFollowerGaps(CLeaderDist follower, double secGap)
virtual double getExtraReservation(int bestLaneOffset, double neighExtraDist=0) const
std::vector< MSLane * > myFurtherTargetLanes
bool myAlreadyChanged
whether the vehicle has already moved this step
bool myAmOpposite
whether the vehicle is driving in the opposite direction
std::shared_ptr< MSLeaderDistanceInfo > myRightFollowers
std::shared_ptr< MSLeaderDistanceInfo > myRightLeaders
virtual void setOwnState(const int state)
bool pastMidpoint() const
return whether the vehicle passed the midpoint of a continuous lane change maneuver
double myPreviousAngleOffset
the angle offset of the previous time step resulting from lane change and sigma
virtual double getAssumedDecelForLaneChangeDuration() const
Returns a deceleration value which is used for the estimation of the duration of a lane change.
virtual double computeSpeedLat(double latDist, double &maneuverDist, bool urgent) const
decides the next lateral speed depending on the remaining lane change distance to be covered and upda...
virtual double estimateLCDuration(const double speed, const double remainingManeuverDist, const double decel, bool urgent) const
Calculates the maximal time needed to complete a lane change maneuver if lcMaxSpeedLatFactor and lcMa...
std::shared_ptr< MSLeaderDistanceInfo > myLeftLeaders
int myPreviousState
lane changing state from the previous simulation step
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model)
int myOwnState
The current state of the vehicle.
double myLastOrigLeaderGap
acutal and secure distance to closest leader vehicle on the original when performing lane change
virtual bool predInteraction(const std::pair< MSVehicle *, double > &leader)
void laneChangeOutput(const std::string &tag, MSLane *source, MSLane *target, int direction, double maneuverDist=0)
called once the vehicle ends a lane change manoeuvre (non-instant)
bool myDontResetLCGaps
Flag to prevent resetting the memorized values for LC relevant gaps until the LC output is triggered ...
int myPreviousState2
lane changing state from step before the previous simulation step
MSLane * getShadowLane() const
Returns the lane the vehicle's shadow is on during continuous/sublane lane change.
const std::shared_ptr< MSLeaderDistanceInfo > getFollowers(const int dir)
Returns the neighboring, lc-relevant followers for the last step in the requested direction.
double myCommittedSpeed
the speed when committing to a change maneuver
std::shared_ptr< MSLeaderDistanceInfo > myLeftFollowers
Cached info on lc-relevant neighboring vehicles.
static bool myLCOutput
whether to record lane-changing
bool startLaneChangeManeuver(MSLane *source, MSLane *target, int direction)
start the lane change maneuver and return whether it continues
virtual void saveState(OutputDevice &out) const
Save the state of the laneChangeModel.
std::pair< int, int > mySavedStateRight
double myLastLeaderSecureGap
the minimum longitudinal distances to vehicles on the target lane that would be necessary for stringe...
void endLaneChangeManeuver(const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_LANE_CHANGE)
void saveLCState(const int dir, int stateWithoutTraCI, const int state)
static bool myAllowOvertakingRight
whether overtaking on the right is permitted
std::vector< MSLink * > myApproachedByShadow
links which are approached by the shadow vehicle
bool canOvertakeRight(const MSVehicle *const nv, const double dist, const double maxSpeedDiff, const double helpOvertakeSpeed, double &vSafe, double &deltaV) const
void addLCSpeedAdvice(const double vSafe, bool ownAdvice=true)
Takes a vSafe (speed advice for speed in the next simulation step), converts it into an acceleration ...
void setLeaderGaps(CLeaderDist, double secGap)
const std::shared_ptr< MSLeaderDistanceInfo > getLeaders(const int dir)
Returns the neighboring, lc-relevant leaders for the last step in the requested direction.
std::vector< MSLane * > myNoPartiallyOccupatedByShadow
bool cancelRequest(int state, int laneOffset)
whether the influencer cancels the given request
double myLastLeaderGap
the actual minimum longitudinal distances to vehicles on the target lane
SUMOTime remainingTime() const
Compute the remaining time until LC completion.
void setOrigLeaderGaps(CLeaderDist, double secGap)
void setManeuverDist(const double dist)
Updates the remaining distance for the current maneuver while it is continued within non-action steps...
std::vector< std::pair< double, bool > > myLCAccelerationAdvices
void setShadowApproachingInformation(MSLink *link) const
set approach information for the shadow vehicle
double getCooperativeHelpSpeed(const MSLane *lane, double distToLaneEnd) const
return speed for helping a vehicle that is blocked from changing
virtual bool avoidOvertakeRight(const MSVehicle *const neighLeader, const bool allowProb=false) const
int getNormalizedLaneIndex()
brief return lane index that treats opposite lanes like normal lanes to the left of the forward lanes
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
void setSpeedLat(double speedLat)
set the lateral speed and update lateral acceleraton
MSLane * myTargetLane
The target lane for the vehicle's current maneuver.
MSLane * determineTargetLane(int &targetDir) const
double myPreviousManeuverDist
Maneuver distance from the previous simulation step.
double getMaxSpeedLat2() const
return the max of maxSpeedLat and lcMaxSpeedLatStanding
std::vector< double > myShadowFurtherLanesPosLat
const MSCFModel & getCarFollowModel() const
The vehicle's car following model.
MSLane * myShadowLane
A lane that is partially occupied by the front of the vehicle but that is not the primary lane.
double mySpeedLat
the current lateral speed
virtual void updateSafeLatDist(const double travelledLatDist)
Updates the value of safe lateral distances (in SL2015) during maneuver continuation in non-action st...
void checkTraCICommands()
Check for commands issued for the vehicle via TraCI and apply the appropriate state changes For the s...
double myManeuverDist
The complete lateral distance the vehicle wants to travel to finish its maneuver Only used by sublane...
int myLaneChangeDirection
direction of the lane change maneuver -1 means right, 1 means left
void primaryLaneChanged(MSLane *source, MSLane *target, int direction)
called once when the vehicles primary lane changes
int getShadowDirection() const
return the direction in which the current shadow lane lies
double myLastLeaderSpeed
speeds of surrounding vehicles at the time of lane change
virtual void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the laneChangeModel from the given attributes.
MSAbstractLaneChangeModel(MSVehicle &v, const LaneChangeModel model)
Constructor.
MSVehicle & myVehicle
The vehicle this lane-changer belongs to.
double calcAngleOffset()
return the angle offset during a continuous change maneuver
double myAngleOffset
the current angle offset resulting from lane change and sigma
double myLastLateralGapLeft
the minimum lateral gaps to other vehicles that were found when last changing to the left and right
virtual ~MSAbstractLaneChangeModel()
Destructor.
static void initGlobalOptions(const OptionsCont &oc)
init global model parameters
void memorizeGapsAtLCInit()
Control for resetting the memorized values for LC relevant gaps until the LC output is triggered in t...
double myLaneChangeCompletion
progress of the lane change maneuver 0:started, 1:complete
virtual bool debugVehicle() const
whether the current vehicles shall be debugged
virtual void changed()=0
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
std::vector< MSLane * > myShadowFurtherLanes
virtual bool congested(const MSVehicle *const neighLeader)
void clearNeighbors()
Clear info on neighboring vehicle from previous step.
void saveNeighbors(const int dir, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &leaders)
Saves the lane change relevant vehicles, which are currently on neighboring lanes in the given direct...
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
double getLength() const
Returns the vehicle's length.
double getWidth() const
Returns the vehicle's width.
const std::list< MSStop > & getStops() const
SumoRNG * getRNG() const
const MSStop & getNextStop() const
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
bool isStopped() const
Returns whether the vehicle is at a stop.
virtual double interactionGap(const MSVehicle *const veh, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
virtual double minNextSpeed(double speed, const MSVehicle *const veh=0) const
Returns the minimum speed given the current speed (depends on the numerical update scheme and its ste...
virtual double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:285
virtual double getSpeedAfterMaxDecel(double v) const
Returns the velocity after maximum deceleration.
Definition MSCFModel.h:447
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:189
A device which collects info on the vehicle trip (mainly on departure and arrival)
std::pair< double, SUMOTime > getLastBlocked(int index) const
retrieve properties of a blocked vehicle that wants to chane to the lane with the given index
Definition MSEdge.cpp:1718
int getNumLanes() const
Definition MSEdge.h:172
static double gLateralResolution
Definition MSGlobals.h:100
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition MSGlobals.h:177
static bool gSublane
whether sublane simulation is enabled (sublane model or continuous lanechanging)
Definition MSGlobals.h:168
static SUMOTime gLaneChangeDuration
Definition MSGlobals.h:97
A lane change model developed by D. Krajzewicz between 2004 and 2010.
A lane change model developed by D. Krajzewicz, J. Erdmann et al. between 2004 and 2013,...
A lane change model developed by D. Krajzewicz, J. Erdmann et al. between 2004 and 2013.
A lane change model developed by J. Erdmann.
Representation of a lane in the micro simulation.
Definition MSLane.h:84
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:2888
virtual void resetManeuverReservation(MSVehicle *v)
Unregisters a vehicle, which previously registered for maneuvering into this lane.
Definition MSLane.cpp:438
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2784
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1424
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:602
void enteredByLaneChange(MSVehicle *v)
Definition MSLane.cpp:3397
const MSJunction * getToJunction() const
Definition MSLane.cpp:4770
double getLength() const
Returns the lane's length.
Definition MSLane.h:632
const MSJunction * getFromJunction() const
Definition MSLane.cpp:4764
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition MSLane.cpp:385
int getIndex() const
Returns the lane's index.
Definition MSLane.h:668
void leftByLaneChange(MSVehicle *v)
Definition MSLane.cpp:3390
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4435
bool isInternal() const
Definition MSLane.cpp:2652
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition MSLane.cpp:404
virtual void setManeuverReservation(MSVehicle *v)
Registers the lane change intentions (towards this lane) for the given vehicle.
Definition MSLane.cpp:427
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4429
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
double getWidth() const
Returns the lane's width.
Definition MSLane.h:661
saves leader/follower vehicles and their distances relative to an ego vehicle
void getSubLanes(const MSVehicle *veh, double latOffset, int &rightmost, int &leftmost) const
Notification
Definition of a vehicle state.
@ NOTIFICATION_LANE_CHANGE
The vehicle changes lanes (micro only)
@ NOTIFICATION_PARKING
The vehicle starts or ends parking.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:199
bool isOpposite
whether this an opposite-direction stop
Definition MSStop.h:87
double getLatDist() const
Definition MSVehicle.h:1607
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
const std::vector< double > & getFurtherLanesPosLat() const
Definition MSVehicle.h:843
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...
MSAbstractLaneChangeModel & getLaneChangeModel()
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
void fixPosition()
repair errors in vehicle position after changing between internal edges
double getAcceleration() const
Returns the vehicle's acceleration in m/s (this is computed as the last step's mean acceleration in c...
Definition MSVehicle.h:514
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
double lateralDistanceToLane(const int offset) const
Get the minimal lateral distance required to move fully onto the lane at given offset.
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.
void switchOffSignal(int signal)
Switches the given signal off.
Definition MSVehicle.h:1177
@ VEH_SIGNAL_BLINKER_RIGHT
Right blinker lights are switched on.
Definition MSVehicle.h:1116
@ VEH_SIGNAL_BLINKER_LEFT
Left blinker lights are switched on.
Definition MSVehicle.h:1118
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
void enterLaneAtLaneChange(MSLane *enteredLane)
Update when the vehicle enters a new lane in the laneChange step.
Influencer & getInfluencer()
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
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
bool congested() const
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const std::vector< MSLane * > & getFurtherLanes() const
Definition MSVehicle.h:839
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:973
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it's primary lane
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition MSVehicle.h:1706
void switchOnSignal(int signal)
Switches the given signal on.
Definition MSVehicle.h:1169
void updateDriveItems()
Check whether the drive items (myLFLinkLanes) are up to date, and update them if required.
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
SUMOVehicleClass getVehicleClass() const
Get this vehicle type's vehicle class.
const std::string & getID() const
Returns the name of the vehicle type.
double getMinGap() const
Get the free space in front of vehicles of this class.
bool wasSet(long long int what) const
Returns whether the given parameter was set.
double getMaxSpeedLat() const
Get vehicle's maximum lateral speed [m/s].
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:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false, const bool escape=false)
writes a named attribute
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
double x() const
Returns the x-position.
Definition Position.h:52
double y() const
Returns the y-position.
Definition Position.h:57
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
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.
std::map< SumoXMLAttr, std::string > SubParams
sub-model parameters
const SubParams & getLCParams() const
Returns the LC parameter.
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
#define UNUSED_PARAMETER(x)
#define DEBUG_COND
Definition json.hpp:4471
#define M_PI
Definition odrSpiral.cpp:45