Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSLaneChangerSublane.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2002-2024 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 const double updatedSpeedLat = vehicle->getLaneChangeModel().getSpeedLat() != 0;
282 vehicle->getLaneChangeModel().setSpeedLat(0);
283 vehicle->getLaneChangeModel().setManeuverDist(0.);
285 if (updatedSpeedLat) {
286 // update angle after having reset lateral speed
287 vehicle->setAngle(vehicle->computeAngle());
288 }
289}
290
291
294 StateAndDist result = StateAndDist(0, 0, 0, 0);
295 if (mayChange(laneOffset)) {
296 if (laneOffset != 0 && vehicle->getLaneChangeModel().isOpposite()) {
297 return result;
298 }
299 const std::vector<MSVehicle::LaneQ>& preb = (vehicle->getLaneChangeModel().isOpposite()
300 ? getBestLanesOpposite(vehicle, nullptr, 1000)
301 : vehicle->getBestLanes());
302 result.state = checkChangeSublane(laneOffset, alternatives, preb, result.latDist, result.maneuverDist);
303 result.dir = laneOffset;
304 if ((result.state & LCA_WANTS_LANECHANGE) != 0 && (result.state & LCA_URGENT) != 0 && (result.state & LCA_BLOCKED) != 0) {
305 (myCandi + laneOffset)->lastBlocked = vehicle;
306 if ((myCandi + laneOffset)->firstBlocked == nullptr) {
307 (myCandi + laneOffset)->firstBlocked = vehicle;
308 }
309 }
310 }
311 return result;
312}
313
314
316// (used to continue sublane changing in non-action steps).
317bool
319 // lateral distance to complete maneuver
320 double remLatDist = vehicle->getLaneChangeModel().getManeuverDist();
321 if (remLatDist == 0) {
322 return false;
323 }
324 const bool urgent = (vehicle->getLaneChangeModel().getOwnState() & LCA_URGENT) != 0;
325 const double nextLatDist = SPEED2DIST(vehicle->getLaneChangeModel().computeSpeedLat(remLatDist, remLatDist, urgent));
326#ifdef DEBUG_MANEUVER
327 if (DEBUG_COND) {
328 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' continueChangeSublane()"
329 << " remLatDist=" << remLatDist << " nextLatDist=" << nextLatDist
330 << std::endl;
331 }
332#endif
333
334 const bool changed = startChangeSublane(vehicle, from, nextLatDist, remLatDist);
335 return changed;
336}
337
338
339bool
340MSLaneChangerSublane::startChangeSublane(MSVehicle* vehicle, ChangerIt& from, double latDist, double maneuverDist) {
341 if (vehicle->isRemoteControlled()) {
342 return false;
343 }
344 MSLane* source = from->lane;
345 // Prevent continuation of LC beyond lane borders if change is not allowed
346 double distToRightLaneBorder = vehicle->getLane()->getWidth() * 0.5 + vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
347 double distToLeftLaneBorder = vehicle->getLane()->getWidth() * 0.5 - vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
348 if (vehicle->getLaneChangeModel().isOpposite()) {
349 std::swap(distToRightLaneBorder, distToLeftLaneBorder);
350 }
351 // determine direction of LC
352 int direction = 0;
353 if (latDist > 0 && latDist > distToLeftLaneBorder) {
354 direction = 1;
355 } else if (latDist < 0 && -latDist > distToRightLaneBorder) {
356 direction = -1;
357 }
358 const int changerDirection = vehicle->getLaneChangeModel().isOpposite() ? -direction : direction;
359 ChangerIt to = from;
360#ifdef DEBUG_MANEUVER
361 if (DEBUG_COND) {
362 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' latDist=" << latDist << " maneuverDist=" << maneuverDist
363 << " distRight=" << distToRightLaneBorder << " distLeft=" << distToLeftLaneBorder
364 << " dir=" << direction << " cDir=" << changerDirection << " mayChange=" << mayChange(changerDirection) << "\n";
365 }
366#endif
367 if (mayChange(changerDirection)) {
368 to = from + changerDirection;
369 } else if (changerDirection == 1 && source->getOpposite() != nullptr) {
370 // change to the opposite direction lane
371 to = (source->getOpposite()->getEdge().myLaneChanger->getChanger().end() - 1);
372 } else {
373 // This may occur during maneuver continuation in non-actionsteps.
374 // TODO: Understand better why and test later if additional sublane actionstep debugging resolves this
375 // (XXX: perhaps one should try to extrapolate check for this case before to avoid maneuver initialization
376 // similar as for continuous LC in MSLaneChanger::checkChange())
377 //assert(false);
378 abortLCManeuver(vehicle);
379 return false;
380 }
381
382 // The following does:
383 // 1) update vehicles lateral position according to latDist and target lane
384 // 2) distinguish several cases
385 // a) vehicle moves completely within the same lane
386 // b) vehicle intersects another lane
387 // - vehicle must be moved to the lane where its midpoint is (either old or new)
388 // - shadow vehicle must be created/moved to the other lane if the vehicle intersects it
389 // 3) updated dens of all lanes that hold the vehicle or its shadow
390
391 vehicle->myState.myPosLat += latDist * (vehicle->getLaneChangeModel().isOpposite() ? -1 : 1);
392 for (int i = 0; i < (int)vehicle->myFurtherLanesPosLat.size(); i++) {
393 vehicle->myFurtherLanesPosLat[i] += latDist * (vehicle->getLaneChangeModel().isOpposite() ? -1 : 1);
394 }
396 vehicle->getLaneChangeModel().setSpeedLat(DIST2SPEED(latDist));
397#ifdef DEBUG_MANEUVER
398 if (DEBUG_COND) {
399 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' with maneuverDist=" << maneuverDist
400 << " and committedSpeed=" << vehicle->getLaneChangeModel().getCommittedSpeed()
401 << " increments lateral position by latDist=" << latDist << std::endl;
402 }
403#endif
404#ifdef DEBUG_SURROUNDING
405 if (DEBUG_COND) {
406 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "'\n to->ahead=" << to->ahead.toString()
407 << "'\n to->aheadNext=" << to->aheadNext.toString()
408 << std::endl;
409 }
410#endif
411 const bool completedPriorManeuver = fabs(vehicle->getLaneChangeModel().getPreviousManeuverDist()) < NUMERICAL_EPS;
412 const bool completedManeuver = fabs(maneuverDist - latDist) < NUMERICAL_EPS;
413 vehicle->getLaneChangeModel().updateSafeLatDist(latDist);
414
415 // current maneuver is aborted when direction or reason changes
416 const int priorReason = vehicle->getLaneChangeModel().getPrevState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
417 const int reason = vehicle->getLaneChangeModel().getOwnState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
418#ifdef DEBUG_MANEUVER
419 if (DEBUG_COND) {
420 std::cout << SIMTIME << " vehicle '" << vehicle->getID()
421 << "' completedPriorManeuver=" << completedPriorManeuver
422 << " completedManeuver=" << completedManeuver
423 << " priorReason=" << toString((LaneChangeAction)priorReason)
424 << " reason=" << toString((LaneChangeAction)reason)
425 << " priorManeuverDist=" << vehicle->getLaneChangeModel().getPreviousManeuverDist()
426 << " maneuverDist=" << maneuverDist
427 << " latDist=" << latDist
428 << std::endl;
429 }
430#endif
431 if (!completedManeuver && !completedPriorManeuver && priorReason != 0 &&
432 (vehicle->getLaneChangeModel().getPreviousManeuverDist() * latDist < 0
433 || priorReason != reason)) {
434 const int priorDirection = vehicle->getLaneChangeModel().getPreviousManeuverDist() > 0 ? 1 : -1;
435 // original from cannot be reconstructed
436#ifdef DEBUG_MANEUVER
437 if (DEBUG_COND) {
438 std::cout << SIMTIME << " startChangeSublane abort priorReason=" << toString((LaneChangeAction)priorReason)
439 << " reason=" << toString((LaneChangeAction)reason) << " veh=" << vehicle->getID() << "\n";
440 }
441#endif
442 outputLCEnded(vehicle, from, from, priorDirection);
443 }
444
445 outputLCStarted(vehicle, from, to, direction, maneuverDist);
446 vehicle->getLaneChangeModel().setManeuverDist(maneuverDist - latDist);
447 const bool changedToNewLane = checkChangeToNewLane(vehicle, direction, from, to);
448
449 MSLane* oldShadowLane = vehicle->getLaneChangeModel().getShadowLane();
451 MSLane* shadowLane = vehicle->getLaneChangeModel().getShadowLane();
452 if (shadowLane != nullptr && shadowLane != oldShadowLane
453 && &shadowLane->getEdge() == &source->getEdge()) {
454 assert(oldShadowLane == 0 || vehicle->getLaneChangeModel().isOpposite() || to != from);
455 const double latOffset = vehicle->getLane()->getRightSideOnEdge() - shadowLane->getRightSideOnEdge();
456 (myChanger.begin() + shadowLane->getIndex())->ahead.addLeader(vehicle, false, latOffset);
457 }
458 if (completedManeuver) {
459 outputLCEnded(vehicle, from, to, direction);
460 }
461
462 // Update maneuver reservations on target lanes
463 MSLane* targetLane = vehicle->getLaneChangeModel().updateTargetLane();
464 if (!changedToNewLane && targetLane != nullptr
465 && vehicle->getActionStepLength() > DELTA_T
466 && &targetLane->getEdge() == &source->getEdge()
467 ) {
468 const int dir = (vehicle->getLaneChangeModel().getManeuverDist() > 0 ? 1 : -1);
469 ChangerIt target = from + dir;
470 const double actionStepDist = dir * vehicle->getVehicleType().getMaxSpeedLat() * vehicle->getActionStepLengthSecs();
471 const double latOffset = vehicle->getLatOffset(targetLane) + actionStepDist;
472 target->ahead.addLeader(vehicle, false, latOffset);
473 //std::cout << SIMTIME << " veh=" << vehicle->getID() << " target=" << targetLane->getID()
474 // << " actionStepDist=" << actionStepDist << " latOffset=" << latOffset
475 // << " targetAhead=" << target->ahead.toString() << "\n";
476 }
477
478 // compute new angle of the vehicle from the x- and y-distances travelled within last time step
479 // (should happen last because primaryLaneChanged() also triggers angle computation)
480 // this part of the angle comes from the orientation of our current lane
481 double laneAngle = vehicle->computeAngle();
482 if (vehicle->getLaneChangeModel().isOpposite()) {
483 // reverse lane angle
484 laneAngle += M_PI;
485 }
486#ifdef DEBUG_MANEUVER
487 if (DEBUG_COND) {
488 std::cout << SIMTIME << " startChangeSublane"
489 << " oldLane=" << from->lane->getID()
490 << " newLane=" << to->lane->getID()
491 << " shadowLane=" << (shadowLane != nullptr ? shadowLane->getID() : "NULL")
492 << " targetLane=" << (targetLane != nullptr ? targetLane->getID() : "NULL")
493 << " maneuverDist=" << vehicle->getLaneChangeModel().getManeuverDist()
494 << " latDist=" << latDist
495 << " oldShadowLane=" << Named::getIDSecure(oldShadowLane)
496 << " newShadowLane=" << Named::getIDSecure(vehicle->getLaneChangeModel().getShadowLane())
497 << " laneA=" << RAD2DEG(laneAngle)
498 << " oldA=" << RAD2DEG(vehicle->getAngle())
499 << " oppposite=" << vehicle->getLaneChangeModel().isOpposite()
500 << " changedToNewLane=" << changedToNewLane
501 << "\n";
502 }
503#endif
504 vehicle->setAngle(laneAngle, completedManeuver);
505
506 // check if a traci maneuver must continue
507 // getOwnState is reset to 0 when changing lanes so we use the stored reason
508 if ((reason & LCA_TRACI) != 0) {
509#ifdef DEBUG_MANEUVER
510 if (DEBUG_COND) {
511 std::cout << SIMTIME << " continue TraCI-maneuver remainingLatDist=" << vehicle->getLaneChangeModel().getManeuverDist() << "\n";
512 }
513#endif
515 }
516 from->lane->requireCollisionCheck();
517 to->lane->requireCollisionCheck();
518 return changedToNewLane;
519}
520
521bool
523 const int oppositeSign = vehicle->getLaneChangeModel().isOpposite() ? -1 : 1;
524 const bool opposite = (&from->lane->getEdge() != &to->lane->getEdge());
525 const bool changedToNewLane = (to->lane != from->lane
526 && fabs(vehicle->getLateralPositionOnLane()) > 0.5 * vehicle->getLane()->getWidth()
527 && (mayChange(direction * oppositeSign) || opposite));
528 if (changedToNewLane) {
529 vehicle->myState.myPosLat -= direction * 0.5 * (from->lane->getWidth() + to->lane->getWidth()) * oppositeSign;
530 if (!opposite) {
531 to->lane->myTmpVehicles.insert(to->lane->myTmpVehicles.begin(), vehicle);
532 to->dens += vehicle->getVehicleType().getLengthWithGap();
533 }
535 if (!vehicle->isActive()) {
536 // update leaders beyond the current edge for all lanes
537 // @note to->aheadNext and from->aheadNext are only needed for output in non-action steps.
538 to->aheadNext = getLeaders(to, vehicle);
539 from->aheadNext = getLeaders(from, vehicle);
540 }
541 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
542 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
543 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
544 }
545 vehicle->getLaneChangeModel().startLaneChangeManeuver(from->lane, to->lane, direction);
546 if (!opposite) {
547 to->ahead.addLeader(vehicle, false, 0);
548 }
549 } else {
550 from->ahead.addLeader(vehicle, false, 0);
551 }
552 return changedToNewLane;
553}
554
555void
556MSLaneChangerSublane::outputLCStarted(MSVehicle* vehicle, ChangerIt& from, ChangerIt& to, int direction, double maneuverDist) {
558 // non-sublane change started
559 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)
560 && ((vehicle->getLaneChangeModel().getOwnState() & LCA_STAY) == 0)
561 // no changing for the same reason in previous step (either not wanted or blocked)
564 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_STAY) != 0)
565 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_BLOCKED) != 0))
566 ) {
567#ifdef DEBUG_STATE
568 if (DEBUG_COND) {
569 std::cout << SIMTIME << " veh=" << vehicle->getID() << " laneChangeStarted state=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getOwnState())
570 << " prevState=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getPrevState())
573 << "\n";
574 }
575#endif
576 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
577 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
578 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
579 vehicle->getLaneChangeModel().laneChangeOutput("changeStarted", from->lane, to->lane, direction, maneuverDist);
580 }
581}
582
583void
586 // non-sublane change ended
587 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)) {
588 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
589 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
590 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
591 vehicle->getLaneChangeModel().laneChangeOutput("changeEnded", from->lane, to->lane, direction);
592 }
593}
594
595
597MSLaneChangerSublane::getLeaders(const ChangerIt& target, const MSVehicle* vehicle) const {
598 // get the leading vehicle on the lane to change to
599#ifdef DEBUG_SURROUNDING
600 if (DEBUG_COND) {
601 std::cout << SIMTIME << " getLeaders lane=" << target->lane->getID() << " ego=" << vehicle->getID() << " ahead=" << target->ahead.toString() << "\n";
602 }
603#endif
604 MSLeaderDistanceInfo result(target->lane->getWidth(), nullptr, 0);
605 int sublaneShift = 0;
606 if (target->lane == vehicle->getLane()) {
608 sublaneShift = int(-vehicle->getLeftSideOnLane() / MSGlobals::gLateralResolution);
609 } else if (vehicle->getRightSideOnLane() > target->lane->getWidth() + MSGlobals::gLateralResolution) {
610 sublaneShift = -int((vehicle->getRightSideOnLane() - target->lane->getWidth()) / MSGlobals::gLateralResolution);
611 }
612 result.setSublaneOffset(sublaneShift);
613 }
614 for (int i = 0; i < target->ahead.numSublanes(); ++i) {
615 const MSVehicle* veh = target->ahead[i];
616 if (veh != nullptr) {
617 const double gap = veh->getBackPositionOnLane(target->lane) - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
618#ifdef DEBUG_SURROUNDING
619 if (DEBUG_COND) {
620 std::cout << " ahead lead=" << veh->getID() << " leadBack=" << veh->getBackPositionOnLane() << " gap=" << gap << " sublaneShift=" << sublaneShift << "\n";
621 }
622#endif
623 if (i + sublaneShift >= 0 && i + sublaneShift < result.numSublanes()) {
624 result.addLeader(veh, gap, 0, i + sublaneShift);
625 }
626 }
627 }
628 if (sublaneShift != 0) {
629 for (MSVehicle* cand : target->outsideBounds) {
630 const double gap = cand->getBackPositionOnLane() - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
631 result.addLeader(cand, gap);
632 }
633 }
634#ifdef DEBUG_SURROUNDING
635 if (DEBUG_COND) {
636 std::cout << " outsideBounds=" << toString(target->outsideBounds) << " result=" << result.toString() << "\n";
637 }
638#endif
639 target->lane->addLeaders(vehicle, vehicle->getPositionOnLane(), result);
640 return result;
641}
642
643
644int
646 int laneOffset,
647 LaneChangeAction alternatives,
648 const std::vector<MSVehicle::LaneQ>& preb,
649 double& latDist,
650 double& maneuverDist) const {
651
652 ChangerIt target = myCandi + laneOffset;
653 MSVehicle* vehicle = veh(myCandi);
654 const MSLane& neighLane = *(target->lane);
655 int blocked = 0;
656
657 MSLeaderDistanceInfo neighLeaders = target->aheadNext;
658 MSLeaderDistanceInfo neighFollowers = target->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
659 MSLeaderDistanceInfo neighBlockers(neighLane.getWidth(), vehicle, vehicle->getLane()->getRightSideOnEdge() - neighLane.getRightSideOnEdge());
660 MSLeaderDistanceInfo leaders = myCandi->aheadNext;
661 addOutsideLeaders(vehicle, leaders);
662 MSLeaderDistanceInfo followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
663 MSLeaderDistanceInfo blockers(vehicle->getLane()->getWidth(), vehicle, 0);
664
665 // consider sibling lanes of the origin and target lane
666 for (int offset : myCandi->siblings) {
667 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
668 ChangerIt ceSib = myCandi + offset;
669 MSLeaderDistanceInfo sibFollowers = ceSib->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
670 if (sibFollowers.hasVehicles()) {
671 followers.addLeaders(sibFollowers);
672 }
673 if (ceSib->aheadNext.hasVehicles()) {
674 leaders.addLeaders(ceSib->aheadNext);
675 }
676#ifdef DEBUG_SURROUNDING
677 if (DEBUG_COND) {
678 std::cout << SIMTIME << " ego=" << vehicle->getID() << " ahead=" << myCandi->aheadNext.toString() << " sib=" << ceSib->lane->getID() << " sibAhead=" << ceSib->aheadNext.toString() << " leaders=" << leaders.toString() << "\n";
679 }
680#endif
681 }
682 for (int offset : target->siblings) {
683 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
684 ChangerIt ceSib = target + offset;
685 MSLeaderDistanceInfo sibFollowers = ceSib->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
686 if (sibFollowers.hasVehicles()) {
687 neighFollowers.addLeaders(sibFollowers);
688 }
689 if (ceSib->aheadNext.hasVehicles()) {
690 neighLeaders.addLeaders(ceSib->aheadNext);
691 }
692#ifdef DEBUG_SURROUNDING
693 if (DEBUG_COND) {
694 std::cout << SIMTIME << " ego=" << vehicle->getID() << " neighAhead=" << target->aheadNext.toString() << " sib=" << ceSib->lane->getID() << " sibAhead=" << ceSib->aheadNext.toString() << " neighLeaders=" << neighLeaders.toString() << "\n";
695 }
696#endif
697 }
698
699 // break leader symmetry
700 if (laneOffset == -1 && neighLeaders.hasVehicles()) {
701 neighLeaders.moveSamePosTo(vehicle, neighFollowers);
702 }
703
704#ifdef DEBUG_SURROUNDING
705 if (DEBUG_COND) std::cout << SIMTIME
706 << " checkChangeSublane: veh=" << vehicle->getID()
707 << " laneOffset=" << laneOffset
708 << "\n leaders=" << leaders.toString()
709 << "\n neighLeaders=" << neighLeaders.toString()
710 << "\n followers=" << followers.toString()
711 << "\n neighFollowers=" << neighFollowers.toString()
712 << "\n";
713#endif
714
715
716 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
717 laneOffset, alternatives,
718 leaders, followers, blockers,
719 neighLeaders, neighFollowers, neighBlockers,
720 neighLane, preb,
721 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
722 int state = blocked | wish;
723
724 // XXX
725 // do are more careful (but expensive) check to ensure that a
726 // safety-critical leader is not being overlooked
727
728 // XXX
729 // ensure that a continuous lane change manoeuvre can be completed
730 // before the next turning movement
731
732 // let TraCI influence the wish to change lanes and the security to take
733 const int oldstate = state;
734 state = vehicle->influenceChangeDecision(state);
735#ifdef DEBUG_STATE
736 if (DEBUG_COND && state != oldstate) {
737 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
738 }
739#endif
740 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
741 if (laneOffset != 0) {
742 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
743 }
744 return state;
745}
746
747
748bool
750 MSVehicle* vehicle,
751 int laneOffset,
752 MSLane* targetLane,
753 const std::pair<MSVehicle* const, double>& leader,
754 const std::pair<MSVehicle* const, double>& neighLead,
755 const std::pair<MSVehicle* const, double>& neighFollow,
756 const std::vector<MSVehicle::LaneQ>& preb) {
758
759 UNUSED_PARAMETER(leader);
760 UNUSED_PARAMETER(neighLead);
761 UNUSED_PARAMETER(neighFollow);
762
763 const MSLane& neighLane = *targetLane;
764 MSLane* curLane = myCandi->lane;
765
766 MSLeaderDistanceInfo neighLeaders(targetLane->getWidth(), nullptr, 0);
767 MSLeaderDistanceInfo neighFollowers(targetLane->getWidth(), nullptr, 0);
768 MSLeaderDistanceInfo neighBlockers(targetLane->getWidth(), nullptr, 0);
769 MSLeaderDistanceInfo leaders(curLane->getWidth(), nullptr, 0);
770 MSLeaderDistanceInfo followers(curLane->getWidth(), nullptr, 0);
771 MSLeaderDistanceInfo blockers(curLane->getWidth(), nullptr, 0);
772
773 const double backPosOnTarget = vehicle->getLane()->getOppositePos(vehicle->getBackPositionOnLane());
774 if (vehicle->getLaneChangeModel().isOpposite()) {
775 leaders = curLane->getFollowersOnConsecutive(vehicle, vehicle->getPositionOnLane(), true, -1, MSLane::MinorLinkMode::FOLLOW_ONCOMING);
776 leaders.fixOppositeGaps(false);
777 curLane->addLeaders(vehicle, vehicle->getBackPositionOnLane(), followers);
778 followers.fixOppositeGaps(true);
779 neighFollowers = targetLane->getFollowersOnConsecutive(vehicle, backPosOnTarget, true);
780 neighFollowers.fixOppositeGaps(false);
781 // artificially increase the position to ensure that ego is not added as a leader
782 const double posOnTarget = backPosOnTarget + vehicle->getVehicleType().getLength() + POSITION_EPS;
783 targetLane->addLeaders(vehicle, posOnTarget, neighLeaders);
784 neighLeaders.patchGaps(2 * POSITION_EPS);
785 int sublaneIndex = 0;
786 for (int i = 0; i < targetLane->getIndex(); i++) {
787 sublaneIndex += MSLeaderInfo(targetLane->getEdge().getLanes()[i]->getWidth()).numSublanes();
788 }
789 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(neighLeaders, sublaneIndex, targetLane->getIndex());
790 } else {
791 leaders = myCandi->aheadNext;
792 followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
793 const double posOnTarget = backPosOnTarget - vehicle->getVehicleType().getLength();
794 targetLane->addLeaders(vehicle, backPosOnTarget, neighFollowers, true);
795 neighFollowers.fixOppositeGaps(true);
796 neighLeaders = targetLane->getFollowersOnConsecutive(vehicle, posOnTarget, true);
797 neighLeaders.fixOppositeGaps(false);
798 }
799
800
801#ifdef DEBUG_CHANGE_OPPOSITE
802 if (DEBUG_COND) std::cout << SIMTIME
803 << " checkChangeOppositeSublane: veh=" << vehicle->getID()
804 << " isOpposite=" << vehicle->getLaneChangeModel().isOpposite()
805 << " laneOffset=" << laneOffset
806 << "\n leaders=" << leaders.toString()
807 << "\n neighLeaders=" << neighLeaders.toString()
808 << "\n followers=" << followers.toString()
809 << "\n neighFollowers=" << neighFollowers.toString()
810 << "\n";
811#endif
812
814 | (mayChange(1) ? LCA_LEFT : LCA_NONE));
815
816 int blocked = 0;
817 double latDist = 0;
818 double maneuverDist = 0;
819 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
820 laneOffset, alternatives,
821 leaders, followers, blockers,
822 neighLeaders, neighFollowers, neighBlockers,
823 neighLane, preb,
824 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
825 int state = blocked | wish;
826
827 const int oldstate = state;
828 state = vehicle->influenceChangeDecision(state);
829#ifdef DEBUG_CHANGE_OPPOSITE
830 if (DEBUG_COND && state != oldstate) {
831 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
832 }
833#endif
834 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
835 if (laneOffset != 0) {
836 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
837 }
838
839 if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) == 0) {
840 // change if the vehicle wants to and is allowed to change
841#ifdef DEBUG_CHANGE_OPPOSITE
842 if (DEBUG_COND) {
843 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' performing sublane change latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
844 }
845#endif
846 vehicle->getLaneChangeModel().setOwnState(state);
847 return startChangeSublane(vehicle, myCandi, latDist, maneuverDist);
848 } else {
849 vehicle->getLaneChangeModel().setSpeedLat(0);
850 return false;
851 }
852}
853
854std::pair<MSVehicle*, double>
856 const double egoWidth = vehicle->getVehicleType().getWidth() + vehicle->getVehicleType().getMinGapLat();
857 std::pair<MSVehicle*, double> leader(nullptr, std::numeric_limits<double>::max());
858 for (int i = 0; i < leaders.numSublanes(); ++i) {
859 CLeaderDist cand = leaders[i];
860 if (cand.first != nullptr) {
861 const double rightSide = cand.first->getRightSideOnLane();
862 if (cand.second < leader.second
863 && rightSide < egoWidth
864 && vehicle->getLane()->getWidth() - rightSide - cand.first->getVehicleType().getWidth() < egoWidth) {
865 leader.first = const_cast<MSVehicle*>(cand.first);
866 leader.second = cand.second;
867 }
868 }
869 }
870 return leader;
871}
872
873
874void
876 if (vehicle->getLaneChangeModel().getShadowLane() == nullptr) {
877 const MSLane* lane = vehicle->getLane();
878 const double rightOL = vehicle->getRightSideOnLane(lane);
879 const double leftOL = vehicle->getLeftSideOnLane(lane);
880 const bool outsideLeft = rightOL > lane->getWidth();
881#ifdef DEBUG_SURROUNDING
882 if (DEBUG_COND) {
883 std::cout << SIMTIME << " addOutsideLeaders veh=" << vehicle->getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
884 }
885#endif
886 if (leftOL < 0 || outsideLeft) {
887 int sublaneOffset = 0;
888 if (outsideLeft) {
889 sublaneOffset = MIN2(0, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution) + 1);
890 } else {
891 sublaneOffset = MAX2(0, (int)ceil(-rightOL / MSGlobals::gLateralResolution) - 1);
892 }
893 if (sublaneOffset != 0) {
894 leaders.setSublaneOffset(sublaneOffset);
895#ifdef DEBUG_SURROUNDING
896 if (DEBUG_COND) {
897 std::cout << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
898 }
899#endif
900 for (const MSVehicle* cand : lane->myTmpVehicles) {
901#ifdef DEBUG_SURROUNDING
902 if (DEBUG_COND) {
903 std::cout << " cand=" << cand->getID() << " cLOE=" << cand->getLeftSideOnEdge() << " cROE=" << cand->getRightSideOnEdge() << "\n";
904 }
905#endif
906 if (cand->getPositionOnLane() > vehicle->getPositionOnLane()
907 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
908 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
909 const double gap = cand->getPositionOnLane() - vehicle->getPositionOnLane() - cand->getLength() - vehicle->getVehicleType().getMinGap();
910 leaders.addLeader(cand, gap);
911#ifdef DEBUG_SURROUNDING
912 if (DEBUG_COND) {
913 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << leaders.toString() << "\n";
914 }
915#endif
916 }
917 }
918 }
919 }
920 }
921}
922
923/****************************************************************************/
#define RAD2DEG(x)
Definition GeomHelper.h:36
std::pair< const MSVehicle *, double > CLeaderDist
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
#define SPEED2DIST(x)
Definition SUMOTime.h:45
#define SIMTIME
Definition SUMOTime.h:62
#define DIST2SPEED(x)
Definition SUMOTime.h:47
@ SVC_EMERGENCY
public emergency vehicles
LaneChangeAction
The state of a vehicle's lane-change behavior.
@ LCA_BLOCKED
blocked in all directions
@ LCA_URGENT
The action is urgent (to be defined by lc-model)
@ LCA_STAY
Needs to stay on the current lane.
@ LCA_SUBLANE
used by the sublane model
@ LCA_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
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
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:906
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:656
static double gLateralResolution
Definition MSGlobals.h:100
Performs lane changing of vehicles.
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
void addOutsideLeaders(const MSVehicle *vehicle, MSLeaderDistanceInfo &leaders) const
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
VehCont myTmpVehicles
Container for lane-changing vehicles. After completion of lane-change- process, the containers will b...
Definition MSLane.h:1474
void addLeaders(const MSVehicle *vehicle, double vehPos, MSLeaderDistanceInfo &result, bool oppositeDirection=false)
get leaders for ego on the given lane
Definition MSLane.cpp:4064
double getRightSideOnEdge() const
Definition MSLane.h:1194
int getIndex() const
Returns the lane's index.
Definition MSLane.h:642
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4311
@ FOLLOW_ONCOMING
Definition MSLane.h:976
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4299
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
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:3725
double getWidth() const
Returns the lane's width.
Definition MSLane.h:635
saves leader/follower vehicles and their distances relative to an ego vehicle
virtual void addLeaders(MSLeaderDistanceInfo &other)
updatd empty sublanes with vehicles and gaps from other
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
bool hasVehicles() const
void setSublaneChange(double latDist)
Sets a new sublane-change request.
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
double computeAngle() const
compute the current vehicle angle
bool isStoppedOnLane() const
bool isActive() const
Returns whether the current simulation step is an action point for the vehicle.
Definition MSVehicle.h:628
MSAbstractLaneChangeModel & getLaneChangeModel()
double getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
double getActionStepLengthSecs() const
Returns the vehicle's action step length in secs, i.e. the interval between two action points.
Definition MSVehicle.h:533
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
bool isRemoteControlled() const
Returns the information whether the vehicle is fully controlled via TraCI.
void adaptBestLanesOccupation(int laneIndex, double density)
update occupation from MSLaneChanger
void setAngle(double angle, bool straightenFurther=false)
Set a custom vehicle angle in rad, optionally updates furtherLanePosLat.
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
SUMOTime getActionStepLength() const
Returns the vehicle's action step length in millisecs, i.e. the interval between two action points.
Definition MSVehicle.h:525
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
Influencer & getInfluencer()
double getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
Position myCachedPosition
Definition MSVehicle.h:1929
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
std::vector< double > myFurtherLanesPosLat
lateral positions on further lanes
Definition MSVehicle.h:1907
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
double getAngle() const
Returns the vehicle's direction in radians.
Definition MSVehicle.h:731
State myState
This Vehicles driving state (pos and speed)
Definition MSVehicle.h:1859
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:322
#define DEBUG_COND
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