Eclipse SUMO - Simulation of Urban MObility
MSLaneChangerSublane.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2002-2022 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
19// Performs sub-lane changing of vehicles
20/****************************************************************************/
21#include <config.h>
22
24#include "MSNet.h"
25#include "MSVehicle.h"
26#include "MSVehicleType.h"
27#include "MSVehicleTransfer.h"
28#include "MSGlobals.h"
29#include <cassert>
30#include <iterator>
31#include <cstdlib>
32#include <cmath>
36
37
38// ===========================================================================
39// DEBUG constants
40// ===========================================================================
41#define DEBUG_COND (vehicle->getLaneChangeModel().debugVehicle())
42//#define DEBUG_COND (vehicle->getID() == "disabled")
43//#define DEBUG_COND true
44//#define DEBUG_DECISION
45//#define DEBUG_ACTIONSTEPS
46//#define DEBUG_STATE
47//#define DEBUG_MANEUVER
48//#define DEBUG_SURROUNDING
49//#define DEBUG_CHANGE_OPPOSITE
50
51// ===========================================================================
52// member method definitions
53// ===========================================================================
54MSLaneChangerSublane::MSLaneChangerSublane(const std::vector<MSLane*>* lanes, bool allowChanging) :
55 MSLaneChanger(lanes, allowChanging) {
56 // initialize siblings
57 if (myChanger.front().lane->isInternal()) {
58 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
59 for (ChangerIt ce2 = myChanger.begin(); ce2 != myChanger.end(); ++ce2) {
60 if (ce != ce2 && ce->lane->getIncomingLanes().front().lane == ce2->lane->getIncomingLanes().front().lane) {
61 //std::cout << "addSibling lane=" << ce->lane->getID() << " offset=" << ce2->lane->getIndex() - ce->lane->getIndex() << "\n";
62 ce->siblings.push_back(ce2->lane->getIndex() - ce->lane->getIndex());
63 }
64 }
65 }
66 }
67}
68
69
71
72void
75 // Prepare myChanger with a safe state.
76 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
77 ce->ahead = ce->lane->getPartialBeyond();
78 ce->outsideBounds.clear();
79// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " vehicles=" << toString(ce->lane->myVehicles) << "\n";
80// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " partial vehicles=" << toString(ce->lane->myPartialVehicles) << "\n";
81// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " partial vehicles beyond=" << toString(ce->ahead.toString()) << "\n";
82 }
83}
84
85
86
87void
89 MSLaneChanger::updateChanger(vehHasChanged);
90 if (!vehHasChanged) {
91 MSVehicle* lead = myCandi->lead;
92 //std::cout << SIMTIME << " updateChanger lane=" << myCandi->lane->getID() << " lead=" << Named::getIDSecure(lead) << " lsol=" << lead->getLeftSideOnLane() << " rsol=" << lead->getRightSideOnLane() << "\n";
93 if (lead->getLeftSideOnLane() < 0 || lead->getRightSideOnLane() > myCandi->lane->getWidth()) {
94 myCandi->outsideBounds.push_back(lead);
95 } else {
96 myCandi->ahead.addLeader(lead, false, 0);
97 }
98 MSLane* shadowLane = lead->getLaneChangeModel().getShadowLane();
99 if (shadowLane != nullptr && &shadowLane->getEdge() == &lead->getLane()->getEdge()) {
100 assert(shadowLane->getIndex() < (int)myChanger.size());
101 const double latOffset = lead->getLane()->getRightSideOnEdge() - shadowLane->getRightSideOnEdge();
102 //std::cout << SIMTIME << " updateChanger shadowLane=" << shadowLane->getID() << " lead=" << Named::getIDSecure(lead) << "\n";
103 (myChanger.begin() + shadowLane->getIndex())->ahead.addLeader(lead, false, latOffset);
104 }
105 }
106 //std::cout << SIMTIME << " updateChanger: lane=" << myCandi->lane->getID() << " lead=" << Named::getIDSecure(myCandi->lead) << " ahead=" << myCandi->ahead.toString() << " vehHasChanged=" << vehHasChanged << "\n";
107 //for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
108 // std::cout << " lane=" << ce->lane->getID() << " vehicles=" << toString(ce->lane->myVehicles) << "\n";
109 //}
110}
111
112
113bool
115 // variant of change() for the sublane case
117 MSVehicle* vehicle = veh(myCandi);
119#ifdef DEBUG_ACTIONSTEPS
120 if (DEBUG_COND) {
121 std::cout << "\n" << SIMTIME << " CHANGE veh=" << vehicle->getID() << " lane=" << vehicle->getLane()->getID() << "\n";
122 }
123#endif
124 assert(vehicle->getLane() == (*myCandi).lane);
125 assert(!vehicle->getLaneChangeModel().isChangingLanes());
126 if ( vehicle->getLaneChangeModel().alreadyChanged() || vehicle->isStoppedOnLane()) {
127 registerUnchanged(vehicle);
128 if (vehicle->isStoppedOnLane()) {
129 myCandi->lastStopped = vehicle;
130 }
131 return false;
132 }
133 if (!vehicle->isActive()) {
134#ifdef DEBUG_ACTIONSTEPS
135 if (DEBUG_COND) {
136 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' skips regular change checks." << std::endl;
137 }
138#endif
139
140 bool changed;
141 // let TraCI influence the wish to change lanes during non-actionsteps
142 checkTraCICommands(vehicle);
143
144 // Resume change
145 changed = continueChangeSublane(vehicle, myCandi);
146#ifdef DEBUG_ACTIONSTEPS
147 if (DEBUG_COND) {
148 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' lcm->maneuverDist=" << vehicle->getLaneChangeModel().getManeuverDist()
149 << " lcm->speedLat=" << vehicle->getLaneChangeModel().getSpeedLat() << std::endl;
150 }
151#endif
152 if (!changed) {
153 registerUnchanged(vehicle);
154 }
155 return changed;
156 }
157
158#ifdef DEBUG_ACTIONSTEPS
159 if (DEBUG_COND) {
160 std::cout << "\n" << SIMTIME << " veh '" << vehicle->getID() << "' plans lanechange maneuver." << std::endl;
161 }
162#endif
163 vehicle->updateBestLanes(); // needed?
164 const bool isOpposite = vehicle->getLaneChangeModel().isOpposite();
165 if (!isOpposite) {
166 for (int i = 0; i < (int) myChanger.size(); ++i) {
167 vehicle->adaptBestLanesOccupation(i, myChanger[i].dens);
168 }
169 }
170 // update leaders beyond the current edge for all lanes
171 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
172 ce->aheadNext = getLeaders(ce, vehicle);
173 }
174 // update expected speeds
175 int sublaneIndex = 0;
176 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
177 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(ce->aheadNext, sublaneIndex, ce->lane->getIndex());
178 for (int offset : ce->siblings) {
179 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
180 ChangerIt ceSib = ce + offset;
181 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(ceSib->aheadNext, sublaneIndex, ceSib->lane->getIndex());
182 }
183 sublaneIndex += ce->ahead.numSublanes();
184 }
185
186 // Check for changes to the opposite lane if vehicle is active
187#ifdef DEBUG_ACTIONSTEPS
188 if (DEBUG_COND) {
189 std::cout << " myChangeToOpposite=" << myChangeToOpposite << " isOpposite=" << isOpposite << " mayChangeRight=" << mayChange(-1) << " mayChangeLeft=" << mayChange(1) << "\n";
190 }
191#endif
192
193 const bool stopOpposite = hasOppositeStop(vehicle);
194 const int traciState = vehicle->influenceChangeDecision(0);
195 const bool traciRequestOpposite = !mayChange(1) && (traciState & LCA_LEFT) != 0;
196
197 if (myChangeToOpposite && (
198 // cannot overtake since there is only one usable lane (or emergency)
199 ((!mayChange(-1) && !mayChange(1)) || vehicle->getVClass() == SVC_EMERGENCY)
200 || traciRequestOpposite
201 || stopOpposite
202 // can alway come back from the opposite side
203 || isOpposite)) {
204 const MSLeaderDistanceInfo& leaders = myCandi->aheadNext;
205 if (leaders.hasVehicles() || isOpposite || stopOpposite || traciRequestOpposite) {
206 std::pair<MSVehicle*, double> leader = findClosestLeader(leaders, vehicle);
208 if ((leader.first != nullptr || isOpposite || stopOpposite || traciRequestOpposite)
209 && changeOpposite(vehicle, leader, myCandi->lastStopped)) {
210 return true;
211 } else if (myCheckedChangeOpposite) {
212 registerUnchanged(vehicle);
213 return false;
214 }
215 // try sublane change within current lane otherwise
216 }
217 }
218
220 | (mayChange(1) ? LCA_LEFT : LCA_NONE));
221
222 StateAndDist right = checkChangeHelper(vehicle, -1, alternatives);
223 StateAndDist left = checkChangeHelper(vehicle, 1, alternatives);
224 StateAndDist current = checkChangeHelper(vehicle, 0, alternatives);
225
226 StateAndDist decision = vehicle->getLaneChangeModel().decideDirection(current,
227 vehicle->getLaneChangeModel().decideDirection(right, left));
228#ifdef DEBUG_DECISION
229 if (vehicle->getLaneChangeModel().debugVehicle()) {
230 std::cout << "\n" << SIMTIME << " decision=" << toString((LaneChangeAction)decision.state) << " dir=" << decision.dir << " latDist=" << decision.latDist << " maneuverDist=" << decision.maneuverDist << "\n";
231 }
232#endif
233 vehicle->getLaneChangeModel().setOwnState(decision.state);
234 if ((decision.state & LCA_WANTS_LANECHANGE) != 0 && (decision.state & LCA_BLOCKED) == 0) {
235 // change if the vehicle wants to and is allowed to change
236#ifdef DEBUG_MANEUVER
237 if (DEBUG_COND) {
238 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' performing sublane change..." << std::endl;
239 }
240#endif
241 const bool changed = startChangeSublane(vehicle, myCandi, decision.latDist, decision.maneuverDist);
242 if (!changed) {
243 registerUnchanged(vehicle);
244 }
245 return changed;
246 }
247 // @note this assumes vehicles can instantly abort any maneuvre in case of emergency
248 abortLCManeuver(vehicle);
249 registerUnchanged(vehicle);
250
251 if ((right.state & (LCA_URGENT)) != 0 && (left.state & (LCA_URGENT)) != 0) {
252 // ... wants to go to the left AND to the right
253 // just let them go to the right lane...
254 left.state = 0;
255 }
256 return false;
257}
258
259
260void
262#ifdef DEBUG_MANEUVER
263 if (DEBUG_COND) {
264 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' aborts LC-continuation."
265 << std::endl;
266 }
267#endif
268 const int priorReason = vehicle->getLaneChangeModel().getPrevState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
269 const int reason = vehicle->getLaneChangeModel().getOwnState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
270 if (priorReason != 0 && priorReason != reason && vehicle->getLaneChangeModel().getPreviousManeuverDist() != 0) {
271 // original from cannot be reconstructed
272 const int priorDirection = vehicle->getLaneChangeModel().getPreviousManeuverDist() > 0 ? 1 : -1;
273#ifdef DEBUG_MANEUVER
274 if (DEBUG_COND) {
275 std::cout << SIMTIME << " abortLCManeuver priorReason=" << toString((LaneChangeAction)priorReason)
276 << " reason=" << toString((LaneChangeAction)reason) << " veh=" << vehicle->getID() << "\n";
277 }
278#endif
279 outputLCEnded(vehicle, myCandi, myCandi, priorDirection);
280 }
281 vehicle->getLaneChangeModel().setSpeedLat(0);
282 vehicle->getLaneChangeModel().setManeuverDist(0.);
284}
285
286
289 StateAndDist result = StateAndDist(0, 0, 0, 0);
290 if (mayChange(laneOffset)) {
291 if (laneOffset != 0 && vehicle->getLaneChangeModel().isOpposite()) {
292 return result;
293 }
294 const std::vector<MSVehicle::LaneQ>& preb = (vehicle->getLaneChangeModel().isOpposite()
295 ? getBestLanesOpposite(vehicle, nullptr, 1000)
296 : vehicle->getBestLanes());
297 result.state = checkChangeSublane(laneOffset, alternatives, preb, result.latDist, result.maneuverDist);
298 result.dir = laneOffset;
299 if ((result.state & LCA_WANTS_LANECHANGE) != 0 && (result.state & LCA_URGENT) != 0 && (result.state & LCA_BLOCKED) != 0) {
300 (myCandi + laneOffset)->lastBlocked = vehicle;
301 if ((myCandi + laneOffset)->firstBlocked == nullptr) {
302 (myCandi + laneOffset)->firstBlocked = vehicle;
303 }
304 }
305 }
306 return result;
307}
308
309
311// (used to continue sublane changing in non-action steps).
312bool
314 // lateral distance to complete maneuver
315 double remLatDist = vehicle->getLaneChangeModel().getManeuverDist();
316 if (remLatDist == 0) {
317 return false;
318 }
319 const bool urgent = (vehicle->getLaneChangeModel().getOwnState() & LCA_URGENT) != 0;
320 const double nextLatDist = SPEED2DIST(vehicle->getLaneChangeModel().computeSpeedLat(remLatDist, remLatDist, urgent));
321#ifdef DEBUG_MANEUVER
322 if (DEBUG_COND) {
323 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' continueChangeSublane()"
324 << " remLatDist=" << remLatDist << " nextLatDist=" << nextLatDist
325 << std::endl;
326 }
327#endif
328
329 const bool changed = startChangeSublane(vehicle, from, nextLatDist, remLatDist);
330 return changed;
331}
332
333
334bool
335MSLaneChangerSublane::startChangeSublane(MSVehicle* vehicle, ChangerIt& from, double latDist, double maneuverDist) {
336 if (vehicle->isRemoteControlled()) {
337 return false;
338 }
339 MSLane* source = from->lane;
340 // Prevent continuation of LC beyond lane borders if change is not allowed
341 double distToRightLaneBorder = vehicle->getLane()->getWidth() * 0.5 + vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
342 double distToLeftLaneBorder = vehicle->getLane()->getWidth() * 0.5 - vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
343 if (vehicle->getLaneChangeModel().isOpposite()) {
344 std::swap(distToRightLaneBorder, distToLeftLaneBorder);
345 }
346 // determine direction of LC
347 int direction = 0;
348 if (latDist > 0 && latDist > distToLeftLaneBorder) {
349 direction = 1;
350 } else if (latDist < 0 && -latDist > distToRightLaneBorder) {
351 direction = -1;
352 }
353 const int changerDirection = vehicle->getLaneChangeModel().isOpposite() ? -direction : direction;
354 ChangerIt to = from;
355#ifdef DEBUG_MANEUVER
356 if (DEBUG_COND) {
357 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' latDist=" << latDist << " maneuverDist=" << maneuverDist
358 << " distRight=" << distToRightLaneBorder << " distLeft=" << distToLeftLaneBorder
359 << " dir=" << direction << " cDir=" << changerDirection << " mayChange=" << mayChange(changerDirection) << "\n";
360 }
361#endif
362 if (mayChange(changerDirection)) {
363 to = from + changerDirection;
364 } else if (changerDirection == 1 && source->getOpposite() != nullptr) {
365 // change to the opposite direction lane
366 to = (source->getOpposite()->getEdge().myLaneChanger->getChanger().end() - 1);
367 } else {
368 // This may occur during maneuver continuation in non-actionsteps.
369 // TODO: Understand better why and test later if additional sublane actionstep debugging resolves this
370 // (XXX: perhaps one should try to extrapolate check for this case before to avoid maneuver initialization
371 // similar as for continuous LC in MSLaneChanger::checkChange())
372 //assert(false);
373 abortLCManeuver(vehicle);
374 return false;
375 }
376
377 // The following does:
378 // 1) update vehicles lateral position according to latDist and target lane
379 // 2) distinguish several cases
380 // a) vehicle moves completely within the same lane
381 // b) vehicle intersects another lane
382 // - vehicle must be moved to the lane where it's midpoint is (either old or new)
383 // - shadow vehicle must be created/moved to the other lane if the vehicle intersects it
384 // 3) updated dens of all lanes that hold the vehicle or its shadow
385
386 vehicle->myState.myPosLat += latDist * (vehicle->getLaneChangeModel().isOpposite() ? -1 : 1);
388 vehicle->getLaneChangeModel().setSpeedLat(DIST2SPEED(latDist));
389#ifdef DEBUG_MANEUVER
390 if (DEBUG_COND) {
391 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' with maneuverDist=" << maneuverDist
392 << " and committedSpeed=" << vehicle->getLaneChangeModel().getCommittedSpeed()
393 << " increments lateral position by latDist=" << latDist << std::endl;
394 }
395#endif
396#ifdef DEBUG_SURROUNDING
397 if (DEBUG_COND) {
398 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "'\n to->ahead=" << to->ahead.toString()
399 << "'\n to->aheadNext=" << to->aheadNext.toString()
400 << std::endl;
401 }
402#endif
403 const bool completedPriorManeuver = fabs(vehicle->getLaneChangeModel().getPreviousManeuverDist()) < NUMERICAL_EPS;
404 const bool completedManeuver = fabs(maneuverDist - latDist) < NUMERICAL_EPS;
405 vehicle->getLaneChangeModel().updateSafeLatDist(latDist);
406
407 // current maneuver is aborted when direction or reason changes
408 const int priorReason = vehicle->getLaneChangeModel().getPrevState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
409 const int reason = vehicle->getLaneChangeModel().getOwnState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
410#ifdef DEBUG_MANEUVER
411 if (DEBUG_COND) {
412 std::cout << SIMTIME << " vehicle '" << vehicle->getID()
413 << "' completedPriorManeuver=" << completedPriorManeuver
414 << " completedManeuver=" << completedManeuver
415 << " priorReason=" << toString((LaneChangeAction)priorReason)
416 << " reason=" << toString((LaneChangeAction)reason)
417 << " priorManeuverDist=" << vehicle->getLaneChangeModel().getPreviousManeuverDist()
418 << " maneuverDist=" << maneuverDist
419 << " latDist=" << latDist
420 << std::endl;
421 }
422#endif
423 if (!completedManeuver && !completedPriorManeuver && priorReason != 0 &&
424 (vehicle->getLaneChangeModel().getPreviousManeuverDist() * latDist < 0
425 || priorReason != reason)) {
426 const int priorDirection = vehicle->getLaneChangeModel().getPreviousManeuverDist() > 0 ? 1 : -1;
427 // original from cannot be reconstructed
428#ifdef DEBUG_MANEUVER
429 if (DEBUG_COND) {
430 std::cout << SIMTIME << " startChangeSublane abort priorReason=" << toString((LaneChangeAction)priorReason)
431 << " reason=" << toString((LaneChangeAction)reason) << " veh=" << vehicle->getID() << "\n";
432 }
433#endif
434 outputLCEnded(vehicle, from, from, priorDirection);
435 }
436
437 outputLCStarted(vehicle, from, to, direction, maneuverDist);
438 vehicle->getLaneChangeModel().setManeuverDist(maneuverDist - latDist);
439 const bool changedToNewLane = checkChangeToNewLane(vehicle, direction, from, to);
440
441 MSLane* oldShadowLane = vehicle->getLaneChangeModel().getShadowLane();
443 MSLane* shadowLane = vehicle->getLaneChangeModel().getShadowLane();
444 if (shadowLane != nullptr && shadowLane != oldShadowLane
445 && &shadowLane->getEdge() == &source->getEdge()) {
446 assert(oldShadowLane == 0 || vehicle->getLaneChangeModel().isOpposite() || to != from);
447 const double latOffset = vehicle->getLane()->getRightSideOnEdge() - shadowLane->getRightSideOnEdge();
448 (myChanger.begin() + shadowLane->getIndex())->ahead.addLeader(vehicle, false, latOffset);
449 }
450 if (completedManeuver) {
451 outputLCEnded(vehicle, from, to, direction);
452 }
453
454 // Update maneuver reservations on target lanes
455 MSLane* targetLane = vehicle->getLaneChangeModel().updateTargetLane();
456 if (!changedToNewLane && targetLane != nullptr
457 && vehicle->getActionStepLength() > DELTA_T
458 && &targetLane->getEdge() == &source->getEdge()
459 ) {
460 const int dir = (vehicle->getLaneChangeModel().getManeuverDist() > 0 ? 1 : -1);
461 ChangerIt target = from + dir;
462 const double actionStepDist = dir * vehicle->getVehicleType().getMaxSpeedLat() * vehicle->getActionStepLengthSecs();
463 const double latOffset = vehicle->getLatOffset(targetLane) + actionStepDist;
464 target->ahead.addLeader(vehicle, false, latOffset);
465 //std::cout << SIMTIME << " veh=" << vehicle->getID() << " target=" << targetLane->getID()
466 // << " actionStepDist=" << actionStepDist << " latOffset=" << latOffset
467 // << " targetAhead=" << target->ahead.toString() << "\n";
468 }
469
470 // compute new angle of the vehicle from the x- and y-distances travelled within last time step
471 // (should happen last because primaryLaneChanged() also triggers angle computation)
472 // this part of the angle comes from the orientation of our current lane
473 double laneAngle = vehicle->getLane()->getShape().rotationAtOffset(vehicle->getLane()->interpolateLanePosToGeometryPos(vehicle->getPositionOnLane())) ;
474 if (vehicle->getLane()->getShape().length2D() == 0) {
475 if (vehicle->getFurtherLanes().size() == 0) {
476 laneAngle = vehicle->getAngle();
477 } else {
478 laneAngle = vehicle->getFurtherLanes().front()->getShape().rotationAtOffset(-NUMERICAL_EPS);
479 }
480 }
481 // this part of the angle comes from the vehicle's lateral movement
482 double changeAngle = 0;
483 // avoid flicker
484 if (fabs(latDist) > NUMERICAL_EPS) {
485 // angle is between vehicle front and vehicle back (and depending on travelled distance)
486 changeAngle = atan2(DIST2SPEED(latDist), vehicle->getVehicleType().getLength() + vehicle->getSpeed());
488 changeAngle *= -1;
489 }
490 }
491 if (vehicle->getLaneChangeModel().isOpposite()) {
492 // reverse lane angle
493 laneAngle += M_PI;
494 }
495#ifdef DEBUG_MANEUVER
496 if (DEBUG_COND) {
497 std::cout << SIMTIME << " startChangeSublane"
498 << " oldLane=" << from->lane->getID()
499 << " newLane=" << to->lane->getID()
500 << " shadowLane=" << (shadowLane != nullptr ? shadowLane->getID() : "NULL")
501 << " targetLane=" << (targetLane != nullptr ? targetLane->getID() : "NULL")
502 << " maneuverDist=" << vehicle->getLaneChangeModel().getManeuverDist()
503 << " latDist=" << latDist
504 << " oldShadowLane=" << Named::getIDSecure(oldShadowLane)
505 << " newShadowLane=" << Named::getIDSecure(vehicle->getLaneChangeModel().getShadowLane())
506 << " laneA=" << RAD2DEG(laneAngle)
507 << " changeA=" << RAD2DEG(changeAngle)
508 << " oldA=" << RAD2DEG(vehicle->getAngle())
509 << " newA=" << RAD2DEG(laneAngle + changeAngle)
510 << " oppposite=" << vehicle->getLaneChangeModel().isOpposite()
511 << " changedToNewLane=" << changedToNewLane
512 << "\n";
513 }
514#endif
515 vehicle->setAngle(laneAngle + changeAngle, completedManeuver);
516
517 // check if a traci maneuver must continue
518 // getOwnState is reset to 0 when changing lanes so we use the stored reason
519 if ((reason & LCA_TRACI) != 0) {
520#ifdef DEBUG_MANEUVER
521 if (DEBUG_COND) {
522 std::cout << SIMTIME << " continue TraCI-maneuver remainingLatDist=" << vehicle->getLaneChangeModel().getManeuverDist() << "\n";
523 }
524#endif
526 }
527 from->lane->requireCollisionCheck();
528 to->lane->requireCollisionCheck();
529 return changedToNewLane;
530}
531
532bool
534 const int oppositeSign = vehicle->getLaneChangeModel().isOpposite() ? -1 : 1;
535 const bool opposite = (&from->lane->getEdge() != &to->lane->getEdge());
536 const bool changedToNewLane = (to->lane != from->lane
537 && fabs(vehicle->getLateralPositionOnLane()) > 0.5 * vehicle->getLane()->getWidth()
538 && (mayChange(direction * oppositeSign) || opposite));
539 if (changedToNewLane) {
540 vehicle->myState.myPosLat -= direction * 0.5 * (from->lane->getWidth() + to->lane->getWidth()) * oppositeSign;
541 if (!opposite) {
542 to->lane->myTmpVehicles.insert(to->lane->myTmpVehicles.begin(), vehicle);
543 to->dens += vehicle->getVehicleType().getLengthWithGap();
544 }
546 if (!vehicle->isActive()) {
547 // update leaders beyond the current edge for all lanes
548 // @note to->aheadNext and from->aheadNext are only needed for output in non-action steps.
549 to->aheadNext = getLeaders(to, vehicle);
550 from->aheadNext = getLeaders(from, vehicle);
551 }
552 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
553 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
554 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
555 }
556 vehicle->getLaneChangeModel().startLaneChangeManeuver(from->lane, to->lane, direction);
557 if (!opposite) {
558 to->ahead.addLeader(vehicle, false, 0);
559 }
560 } else {
561 from->ahead.addLeader(vehicle, false, 0);
562 }
563 return changedToNewLane;
564}
565
566void
567MSLaneChangerSublane::outputLCStarted(MSVehicle* vehicle, ChangerIt& from, ChangerIt& to, int direction, double maneuverDist) {
569 // non-sublane change started
570 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)
571 && ((vehicle->getLaneChangeModel().getOwnState() & LCA_STAY) == 0)
572 // no changing for the same reason in previous step (either not wanted or blocked)
575 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_STAY) != 0)
576 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_BLOCKED) != 0))
577 ) {
578#ifdef DEBUG_STATE
579 if (DEBUG_COND) {
580 std::cout << SIMTIME << " veh=" << vehicle->getID() << " laneChangeStarted state=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getOwnState())
581 << " prevState=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getPrevState())
584 << "\n";
585 }
586#endif
587 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
588 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
589 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
590 vehicle->getLaneChangeModel().laneChangeOutput("changeStarted", from->lane, to->lane, direction, maneuverDist);
591 }
592}
593
594void
597 // non-sublane change ended
598 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)) {
599 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
600 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
601 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
602 vehicle->getLaneChangeModel().laneChangeOutput("changeEnded", from->lane, to->lane, direction);
603 }
604}
605
606
608MSLaneChangerSublane::getLeaders(const ChangerIt& target, const MSVehicle* vehicle) const {
609 // get the leading vehicle on the lane to change to
610#ifdef DEBUG_SURROUNDING
611 if (DEBUG_COND) {
612 std::cout << SIMTIME << " getLeaders lane=" << target->lane->getID() << " ego=" << vehicle->getID() << " ahead=" << target->ahead.toString() << "\n";
613 }
614#endif
615 MSLeaderDistanceInfo result(target->lane->getWidth(), nullptr, 0);
616 if (target->lane == vehicle->getLane()) {
619 } else if (vehicle->getRightSideOnLane() > target->lane->getWidth() + MSGlobals::gLateralResolution) {
620 result.setSublaneOffset(-int((vehicle->getRightSideOnLane() - target->lane->getWidth()) / MSGlobals::gLateralResolution));
621 }
622 }
623 const int sublaneShift = result.getSublaneOffset();
624 for (int i = 0; i < target->ahead.numSublanes(); ++i) {
625 const MSVehicle* veh = target->ahead[i];
626 if (veh != nullptr) {
627 const double gap = veh->getBackPositionOnLane(target->lane) - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
628#ifdef DEBUG_SURROUNDING
629 if (DEBUG_COND) {
630 std::cout << " ahead lead=" << veh->getID() << " leadBack=" << veh->getBackPositionOnLane() << " gap=" << gap << " sublaneShift=" << sublaneShift << "\n";
631 }
632#endif
633 if (i + sublaneShift >= 0 && i + sublaneShift < result.numSublanes()) {
634 result.addLeader(veh, gap, 0, i + sublaneShift);
635 }
636 }
637 }
638 if (sublaneShift != 0) {
639 for (MSVehicle* cand : target->outsideBounds) {
640 const double gap = cand->getBackPositionOnLane() - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
641 result.addLeader(cand, gap);
642 }
643 }
644#ifdef DEBUG_SURROUNDING
645 if (DEBUG_COND) {
646 std::cout << " outsideBounds=" << toString(target->outsideBounds) << " result=" << result.toString() << "\n";
647 }
648#endif
649 target->lane->addLeaders(vehicle, vehicle->getPositionOnLane(), result);
650 return result;
651}
652
653
654int
656 int laneOffset,
657 LaneChangeAction alternatives,
658 const std::vector<MSVehicle::LaneQ>& preb,
659 double& latDist,
660 double& maneuverDist) const {
661
662 ChangerIt target = myCandi + laneOffset;
663 MSVehicle* vehicle = veh(myCandi);
664 const MSLane& neighLane = *(target->lane);
665 int blocked = 0;
666
667 MSLeaderDistanceInfo neighLeaders = target->aheadNext;
668 MSLeaderDistanceInfo neighFollowers = target->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
669 MSLeaderDistanceInfo neighBlockers(neighLane.getWidth(), vehicle, vehicle->getLane()->getRightSideOnEdge() - neighLane.getRightSideOnEdge());
670 MSLeaderDistanceInfo leaders = myCandi->aheadNext;
671 MSLeaderDistanceInfo followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
672 MSLeaderDistanceInfo blockers(vehicle->getLane()->getWidth(), vehicle, 0);
673
674 // break leader symmetry
675 if (laneOffset == -1 && neighLeaders.hasVehicles()) {
676 neighLeaders.moveSamePosTo(vehicle, neighFollowers);
677 }
678
679#ifdef DEBUG_SURROUNDING
680 if (DEBUG_COND) std::cout << SIMTIME
681 << " checkChangeSublane: veh=" << vehicle->getID()
682 << " laneOffset=" << laneOffset
683 << "\n leaders=" << leaders.toString()
684 << "\n neighLeaders=" << neighLeaders.toString()
685 << "\n followers=" << followers.toString()
686 << "\n neighFollowers=" << neighFollowers.toString()
687 << "\n";
688#endif
689
690
691 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
692 laneOffset, alternatives,
693 leaders, followers, blockers,
694 neighLeaders, neighFollowers, neighBlockers,
695 neighLane, preb,
696 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
697 int state = blocked | wish;
698
699 // XXX
700 // do are more careful (but expensive) check to ensure that a
701 // safety-critical leader is not being overlooked
702
703 // XXX
704 // ensure that a continuous lane change manoeuvre can be completed
705 // before the next turning movement
706
707 // let TraCI influence the wish to change lanes and the security to take
708 const int oldstate = state;
709 state = vehicle->influenceChangeDecision(state);
710#ifdef DEBUG_STATE
711 if (DEBUG_COND && state != oldstate) {
712 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
713 }
714#endif
715 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
716 if (laneOffset != 0) {
717 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
718 }
719 return state;
720}
721
722
723bool
725 MSVehicle* vehicle,
726 int laneOffset,
727 MSLane* targetLane,
728 const std::pair<MSVehicle* const, double>& leader,
729 const std::pair<MSVehicle* const, double>& neighLead,
730 const std::pair<MSVehicle* const, double>& neighFollow,
731 const std::vector<MSVehicle::LaneQ>& preb) {
733
734 UNUSED_PARAMETER(leader);
735 UNUSED_PARAMETER(neighLead);
736 UNUSED_PARAMETER(neighFollow);
737
738 const MSLane& neighLane = *targetLane;
739 MSLane* curLane = myCandi->lane;
740
741 MSLeaderDistanceInfo neighLeaders(targetLane->getWidth(), nullptr, 0);
742 MSLeaderDistanceInfo neighFollowers(targetLane->getWidth(), nullptr, 0);
743 MSLeaderDistanceInfo neighBlockers(targetLane->getWidth(), nullptr, 0);
744 MSLeaderDistanceInfo leaders(curLane->getWidth(), nullptr, 0);
745 MSLeaderDistanceInfo followers(curLane->getWidth(), nullptr, 0);
746 MSLeaderDistanceInfo blockers(curLane->getWidth(), nullptr, 0);
747
748 const double backPosOnTarget = vehicle->getLane()->getOppositePos(vehicle->getBackPositionOnLane());
749 if (vehicle->getLaneChangeModel().isOpposite()) {
750 leaders = curLane->getFollowersOnConsecutive(vehicle, vehicle->getPositionOnLane(), true, -1, MSLane::MinorLinkMode::FOLLOW_ONCOMING);
751 leaders.fixOppositeGaps(false);
752 curLane->addLeaders(vehicle, vehicle->getBackPositionOnLane(), followers);
753 followers.fixOppositeGaps(true);
754 neighFollowers = targetLane->getFollowersOnConsecutive(vehicle, backPosOnTarget, true);
755 neighFollowers.fixOppositeGaps(false);
756 // artificially increase the position to ensure that ego is not added as a leader
757 const double posOnTarget = backPosOnTarget + vehicle->getVehicleType().getLength() + POSITION_EPS;
758 targetLane->addLeaders(vehicle, posOnTarget, neighLeaders);
759 neighLeaders.patchGaps(2 * POSITION_EPS);
760 int sublaneIndex = 0;
761 for (int i = 0; i < targetLane->getIndex(); i++) {
762 sublaneIndex += MSLeaderInfo(targetLane->getEdge().getLanes()[i]->getWidth()).numSublanes();
763 }
764 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(neighLeaders, sublaneIndex, targetLane->getIndex());
765 } else {
766 leaders = myCandi->aheadNext;
767 followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
768 const double posOnTarget = backPosOnTarget - vehicle->getVehicleType().getLength();
769 targetLane->addLeaders(vehicle, backPosOnTarget, neighFollowers, true);
770 neighFollowers.fixOppositeGaps(true);
771 neighLeaders = targetLane->getFollowersOnConsecutive(vehicle, posOnTarget, true);
772 neighLeaders.fixOppositeGaps(false);
773 }
774
775
776#ifdef DEBUG_CHANGE_OPPOSITE
777 if (DEBUG_COND) std::cout << SIMTIME
778 << " checkChangeOppositeSublane: veh=" << vehicle->getID()
779 << " isOpposite=" << vehicle->getLaneChangeModel().isOpposite()
780 << " laneOffset=" << laneOffset
781 << "\n leaders=" << leaders.toString()
782 << "\n neighLeaders=" << neighLeaders.toString()
783 << "\n followers=" << followers.toString()
784 << "\n neighFollowers=" << neighFollowers.toString()
785 << "\n";
786#endif
787
789 | (mayChange(1) ? LCA_LEFT : LCA_NONE));
790
791 int blocked = 0;
792 double latDist = 0;
793 double maneuverDist = 0;
794 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
795 laneOffset, alternatives,
796 leaders, followers, blockers,
797 neighLeaders, neighFollowers, neighBlockers,
798 neighLane, preb,
799 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
800 int state = blocked | wish;
801
802 const int oldstate = state;
803 state = vehicle->influenceChangeDecision(state);
804#ifdef DEBUG_CHANGE_OPPOSITE
805 if (DEBUG_COND && state != oldstate) {
806 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
807 }
808#endif
809 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
810 if (laneOffset != 0) {
811 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
812 }
813
814 if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) == 0) {
815 // change if the vehicle wants to and is allowed to change
816#ifdef DEBUG_CHANGE_OPPOSITE
817 if (DEBUG_COND) {
818 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' performing sublane change latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
819 }
820#endif
821 vehicle->getLaneChangeModel().setOwnState(state);
822 return startChangeSublane(vehicle, myCandi, latDist, maneuverDist);
823 } else {
824 vehicle->getLaneChangeModel().setSpeedLat(0);
825 return false;
826 }
827}
828
829std::pair<MSVehicle*, double>
831 const double egoWidth = vehicle->getVehicleType().getWidth() + vehicle->getVehicleType().getMinGapLat();
832 std::pair<MSVehicle*, double> leader(nullptr, std::numeric_limits<double>::max());
833 for (int i = 0; i < leaders.numSublanes(); ++i) {
834 CLeaderDist cand = leaders[i];
835 if (cand.first != nullptr) {
836 const double rightSide = cand.first->getRightSideOnLane();
837 if (cand.second < leader.second
838 && rightSide < egoWidth
839 && vehicle->getLane()->getWidth() - rightSide - cand.first->getVehicleType().getWidth() < egoWidth) {
840 leader.first = const_cast<MSVehicle*>(cand.first);
841 leader.second = cand.second;
842 }
843 }
844 }
845 return leader;
846}
847
848/****************************************************************************/
#define RAD2DEG(x)
Definition: GeomHelper.h:36
#define DEBUG_COND
std::pair< const MSVehicle *, double > CLeaderDist
Definition: MSLeaderInfo.h:38
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
#define SPEED2DIST(x)
Definition: SUMOTime.h:44
#define SIMTIME
Definition: SUMOTime.h:61
#define DIST2SPEED(x)
Definition: SUMOTime.h:46
@ SVC_EMERGENCY
public emergency vehicles
LaneChangeAction
The state of a vehicle's lane-change behavior.
@ LCA_BLOCKED
blocked in all directions
@ LCA_NONE
@ 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_LEFT
Wants go to the left.
@ LCA_CHANGE_REASONS
reasons of lane change
@ LCA_TRACI
The action is due to a TraCI request.
@ LCA_WANTS_LANECHANGE
lane can change
@ LCA_RIGHT
Wants go to the right.
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
void setFollowerGaps(CLeaderDist follower, double secGap)
virtual void setOwnState(const int state)
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...
static bool outputLCEnded()
whether start of maneuvers shall be recorede
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model)
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)
MSLane * getShadowLane() const
Returns the lane the vehicle's shadow is on during continuous/sublane lane change.
bool startLaneChangeManeuver(MSLane *source, MSLane *target, int direction)
start the lane change maneuver and return whether it continues
void saveLCState(const int dir, int stateWithoutTraCI, const int state)
static bool haveLCOutput()
whether lanechange-output is active
virtual void updateExpectedSublaneSpeeds(const MSLeaderDistanceInfo &ahead, int sublaneOffset, int laneIndex)
update expected speeds for each sublane of the current edge
void setLeaderGaps(CLeaderDist, double secGap)
void setOrigLeaderGaps(CLeaderDist, double secGap)
virtual int wantsChangeSublane(int laneOffset, LaneChangeAction alternatives, const MSLeaderDistanceInfo &leaders, const MSLeaderDistanceInfo &followers, const MSLeaderDistanceInfo &blockers, const MSLeaderDistanceInfo &neighLeaders, const MSLeaderDistanceInfo &neighFollowers, const MSLeaderDistanceInfo &neighBlockers, const MSLane &neighLane, const std::vector< MSVehicle::LaneQ > &preb, MSVehicle **lastBlocked, MSVehicle **firstBlocked, double &latDist, double &targetDistLat, int &blocked)
void setManeuverDist(const double dist)
Updates the remaining distance for the current maneuver while it is continued within non-action steps...
void setSpeedLat(double speedLat)
set the lateral speed and update lateral acceleraton
virtual void updateSafeLatDist(const double travelledLatDist)
Updates the value of safe lateral distances (in SL2015) during maneuver continuation in non-action st...
double getSpeedLat() const
return the lateral speed of the current lane change maneuver
bool alreadyChanged() const
reset the flag whether a vehicle already moved to false
virtual StateAndDist decideDirection(StateAndDist sd1, StateAndDist sd2) const
decide in which direction to move in case both directions are desirable
static bool outputLCStarted()
whether start of maneuvers shall be recorede
virtual bool debugVehicle() const
whether the current vehicles shall be debugged
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
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...
double getWidth() const
Returns the vehicle's width.
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
MSLaneChanger * myLaneChanger
This member will do the lane-change.
Definition: MSEdge.h:876
static double gLateralResolution
Definition: MSGlobals.h:97
static bool gLefthand
Whether lefthand-drive is being simulated.
Definition: MSGlobals.h:168
Performs lane changing of vehicles.
Definition: MSLaneChanger.h:45
const bool myChangeToOpposite
whether this edge allows changing to the opposite direction edge
bool changeOpposite(MSVehicle *vehicle, std::pair< MSVehicle *, double > leader, MSVehicle *lastStopped)
static bool hasOppositeStop(MSVehicle *vehicle)
whether vehicle has an opposite-direction stop within relevant range
void checkTraCICommands(MSVehicle *vehicle)
Take into account traci LC-commands.
virtual void initChanger()
Initialize the changer before looping over all vehicles.
MSVehicle * veh(ConstChangerIt ce) const
Changer myChanger
Container for ChangeElemements, one for every lane in the edge.
ChangerIt findCandidate()
Find current candidate. If there is none, myChanger.end() is returned.
bool mayChange(int direction) const
whether changing to the lane in the given direction should be considered
void registerUnchanged(MSVehicle *vehicle)
ChangerIt myCandi
Changer & getChanger()
return changer (only to be used by MSLaneChangerSublane from another instance)
Changer::iterator ChangerIt
the iterator moving over the ChangeElems
static std::vector< MSVehicle::LaneQ > getBestLanesOpposite(MSVehicle *vehicle, const MSLane *stopLane, double oppositeLength)
add LaneQ for opposite lanes
virtual void updateChanger(bool vehHasChanged)
bool startChangeSublane(MSVehicle *vehicle, ChangerIt &from, double latDist, double maneuverDist)
change by the specified amount and return whether a new lane was entered
bool checkChangeToNewLane(MSVehicle *vehicle, const int direction, ChangerIt from, ChangerIt to)
check whether the given vehicle has entered the new lane 'to->lane' during a sublane LC-step
void outputLCStarted(MSVehicle *vehicle, ChangerIt &from, ChangerIt &to, int direction, double maneuverDist)
optional output for start of lane-change maneuvre
MSLeaderDistanceInfo getLeaders(const ChangerIt &target, const MSVehicle *ego) const
get leaders for ego on the given lane
StateAndDist checkChangeHelper(MSVehicle *vehicle, int laneOffset, LaneChangeAction alternatives)
helper function that calls checkChangeSublane and sets blocker information
static std::pair< MSVehicle *, double > findClosestLeader(const MSLeaderDistanceInfo &leaders, const MSVehicle *vehicle)
find the closest leader that prevents ego vehicle from passing on the current lane
bool myCheckedChangeOpposite
whether checkChangeOpposite was called for the current vehicle
virtual void initChanger()
Initialize the changer before looping over all vehicles.
bool checkChangeOpposite(MSVehicle *vehicle, int laneOffset, MSLane *targetLane, const std::pair< MSVehicle *const, double > &leader, const std::pair< MSVehicle *const, double > &neighLead, const std::pair< MSVehicle *const, double > &neighFollow, const std::vector< MSVehicle::LaneQ > &preb)
virtual void updateChanger(bool vehHasChanged)
void abortLCManeuver(MSVehicle *vehicle)
immediately stop lane-changing and register vehicle as unchanged
MSLaneChangerSublane()
Default constructor.
void outputLCEnded(MSVehicle *vehicle, ChangerIt &from, ChangerIt &to, int direction)
optional output for end of lane-change maneuvre
MSAbstractLaneChangeModel::StateAndDist StateAndDist
int checkChangeSublane(int laneOffset, LaneChangeAction alternatives, const std::vector< MSVehicle::LaneQ > &preb, double &latDist, double &maneuverDist) const
check whether sub-lane changing in the given direction is desirable and possible
bool continueChangeSublane(MSVehicle *vehicle, ChangerIt &from)
Continue a sublane-lane change maneuver and return whether the midpoint was passed in this step.
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
void addLeaders(const MSVehicle *vehicle, double vehPos, MSLeaderDistanceInfo &result, bool oppositeDirection=false)
get leaders for ego on the given lane
Definition: MSLane.cpp:3771
const PositionVector & getShape() const
Returns this lane's shape.
Definition: MSLane.h:506
double getRightSideOnEdge() const
Definition: MSLane.h:1118
int getIndex() const
Returns the lane's index.
Definition: MSLane.h:597
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition: MSLane.cpp:4017
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition: MSLane.cpp:4005
double interpolateLanePosToGeometryPos(double lanePos) const
Definition: MSLane.h:527
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:713
MSLeaderDistanceInfo getFollowersOnConsecutive(const MSVehicle *ego, double backOffset, bool allSublanes, double searchDist=-1, MinorLinkMode mLinkMode=FOLLOW_ALWAYS) const
return the sublane followers with the largest missing rear gap among all predecessor lanes (within di...
Definition: MSLane.cpp:3446
double getWidth() const
Returns the lane's width.
Definition: MSLane.h:590
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
void patchGaps(double amount)
add given value to all gaps
virtual int addLeader(const MSVehicle *veh, double gap, double latOffset=0, int sublane=-1)
void moveSamePosTo(const MSVehicle *ego, MSLeaderDistanceInfo &other)
void setSublaneOffset(int offset)
set number of sublanes by which to shift positions
int numSublanes() const
Definition: MSLeaderInfo.h:86
bool hasVehicles() const
Definition: MSLeaderInfo.h:94
int getSublaneOffset() const
Definition: MSLeaderInfo.h:102
void setSublaneChange(double latDist)
Sets a new sublane-change request.
Definition: MSVehicle.cpp:430
double myPosLat
the stored lateral position
Definition: MSVehicle.h:140
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:77
void updateBestLanes(bool forceRebuild=false, const MSLane *startLane=0)
computes the best lanes to use in order to continue the route
Definition: MSVehicle.cpp:5391
bool isStoppedOnLane() const
Definition: MSVehicle.cpp:1555
bool isActive() const
Returns whether the current simulation step is an action point for the vehicle.
Definition: MSVehicle.h:622
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:5367
double getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
Definition: MSVehicle.cpp:6254
double getActionStepLengthSecs() const
Returns the vehicle's action step length in secs, i.e. the interval between two action points.
Definition: MSVehicle.h:529
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
Definition: MSVehicle.cpp:6808
bool isRemoteControlled() const
Returns the information whether the vehicle is fully controlled via TraCI.
Definition: MSVehicle.cpp:6827
void adaptBestLanesOccupation(int laneIndex, double density)
update occupation from MSLaneChanger
Definition: MSVehicle.cpp:6039
void setAngle(double angle, bool straightenFurther=false)
Set a custom vehicle angle in rad, optionally updates furtherLanePosLat.
Definition: MSVehicle.cpp:1353
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition: MSVehicle.h:401
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
Definition: MSVehicle.cpp:6321
SUMOTime getActionStepLength() const
Returns the vehicle's action step length in millisecs, i.e. the interval between two action points.
Definition: MSVehicle.h:521
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:577
Influencer & getInfluencer()
Definition: MSVehicle.cpp:6773
double getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
Definition: MSVehicle.cpp:6248
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition: MSVehicle.h:416
double getSpeed() const
Returns the vehicle's current speed.
Definition: MSVehicle.h:486
Position myCachedPosition
Definition: MSVehicle.h:1932
const std::vector< MSLane * > & getFurtherLanes() const
Definition: MSVehicle.h:838
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
Definition: MSVehicle.cpp:5385
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition: MSVehicle.h:377
double getAngle() const
Returns the vehicle's direction in radians.
Definition: MSVehicle.h:729
State myState
This Vehicles driving state (pos and speed)
Definition: MSVehicle.h:1862
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
double getMinGapLat() const
Get the minimum lateral gap that vehicles of this type maintain.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getMinGap() const
Get the free space in front of vehicles of this class.
double getMaxSpeedLat() const
Get vehicle's maximum lateral speed [m/s].
double getLength() const
Get vehicle's length [m].
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 const Position INVALID
used to indicate that a position is valid
Definition: Position.h:298
double length2D() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
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