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-2025 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 "MSLink.h"
26#include "MSVehicle.h"
27#include "MSVehicleType.h"
28#include "MSVehicleTransfer.h"
29#include "MSGlobals.h"
30#include <cassert>
31#include <iterator>
32#include <cstdlib>
33#include <cmath>
37
38
39// ===========================================================================
40// DEBUG constants
41// ===========================================================================
42#define DEBUG_COND (vehicle->getLaneChangeModel().debugVehicle())
43//#define DEBUG_COND (vehicle->getID() == "disabled")
44//#define DEBUG_COND true
45//#define DEBUG_DECISION
46//#define DEBUG_ACTIONSTEPS
47//#define DEBUG_STATE
48//#define DEBUG_MANEUVER
49//#define DEBUG_SURROUNDING
50//#define DEBUG_CHANGE_OPPOSITE
51
52// ===========================================================================
53// member method definitions
54// ===========================================================================
55MSLaneChangerSublane::MSLaneChangerSublane(const std::vector<MSLane*>* lanes, bool allowChanging) :
56 MSLaneChanger(lanes, allowChanging) {
57 // initialize siblings
58 if (myChanger.front().lane->isInternal()) {
59 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
60 for (ChangerIt ce2 = myChanger.begin(); ce2 != myChanger.end(); ++ce2) {
61 if (ce != ce2 && ce->lane->getIncomingLanes().front().lane == ce2->lane->getIncomingLanes().front().lane) {
62 //std::cout << "addSibling lane=" << ce->lane->getID() << " offset=" << ce2->lane->getIndex() - ce->lane->getIndex() << "\n";
63 ce->siblings.push_back(ce2->lane->getIndex() - ce->lane->getIndex());
64 }
65 }
66 }
67 }
68}
69
70
72
73void
76 // Prepare myChanger with a safe state.
77 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
78 ce->ahead = ce->lane->getPartialBeyond();
79 ce->outsideBounds.clear();
80// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " vehicles=" << toString(ce->lane->myVehicles) << "\n";
81// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " partial vehicles=" << toString(ce->lane->myPartialVehicles) << "\n";
82// std::cout << SIMTIME << " initChanger lane=" << ce->lane->getID() << " partial vehicles beyond=" << toString(ce->ahead.toString()) << "\n";
83 }
84}
85
86
87
88void
90 MSLaneChanger::updateChanger(vehHasChanged);
91 if (!vehHasChanged) {
92 MSVehicle* lead = myCandi->lead;
93 //std::cout << SIMTIME << " updateChanger lane=" << myCandi->lane->getID() << " lead=" << Named::getIDSecure(lead) << " lsol=" << lead->getLeftSideOnLane() << " rsol=" << lead->getRightSideOnLane() << "\n";
94 if (lead->getLeftSideOnLane() < 0 || lead->getRightSideOnLane() > myCandi->lane->getWidth()) {
95 myCandi->outsideBounds.push_back(lead);
96 } else {
97 myCandi->ahead.addLeader(lead, false, 0);
98 }
99 MSLane* shadowLane = lead->getLaneChangeModel().getShadowLane();
100 if (shadowLane != nullptr && &shadowLane->getEdge() == &lead->getLane()->getEdge()) {
101 assert(shadowLane->getIndex() < (int)myChanger.size());
102 const double latOffset = lead->getLane()->getRightSideOnEdge() - shadowLane->getRightSideOnEdge();
103 //std::cout << SIMTIME << " updateChanger shadowLane=" << shadowLane->getID() << " lead=" << Named::getIDSecure(lead) << "\n";
104 (myChanger.begin() + shadowLane->getIndex())->ahead.addLeader(lead, false, latOffset);
105 }
106 }
107 //std::cout << SIMTIME << " updateChanger: lane=" << myCandi->lane->getID() << " lead=" << Named::getIDSecure(myCandi->lead) << " ahead=" << myCandi->ahead.toString() << " vehHasChanged=" << vehHasChanged << "\n";
108 //for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
109 // std::cout << " lane=" << ce->lane->getID() << " vehicles=" << toString(ce->lane->myVehicles) << "\n";
110 //}
111}
112
113
114bool
116 // variant of change() for the sublane case
118 MSVehicle* vehicle = veh(myCandi);
120#ifdef DEBUG_ACTIONSTEPS
121 if (DEBUG_COND) {
122 std::cout << "\n" << SIMTIME << " CHANGE veh=" << vehicle->getID() << " lane=" << vehicle->getLane()->getID() << "\n";
123 }
124#endif
125 assert(vehicle->getLane() == (*myCandi).lane);
126 assert(!vehicle->getLaneChangeModel().isChangingLanes());
127 if ( vehicle->getLaneChangeModel().alreadyChanged() || vehicle->isStoppedOnLane()) {
128 registerUnchanged(vehicle);
129 if (vehicle->isStoppedOnLane()) {
130 myCandi->lastStopped = vehicle;
131 }
132 return false;
133 }
134 if (!vehicle->isActive()) {
135#ifdef DEBUG_ACTIONSTEPS
136 if (DEBUG_COND) {
137 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' skips regular change checks." << std::endl;
138 }
139#endif
140
141 bool changed;
142 // let TraCI influence the wish to change lanes during non-actionsteps
143 checkTraCICommands(vehicle);
144
145 // Resume change
146 changed = continueChangeSublane(vehicle, myCandi);
147#ifdef DEBUG_ACTIONSTEPS
148 if (DEBUG_COND) {
149 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' lcm->maneuverDist=" << vehicle->getLaneChangeModel().getManeuverDist()
150 << " lcm->speedLat=" << vehicle->getLaneChangeModel().getSpeedLat() << std::endl;
151 }
152#endif
153 if (!changed) {
154 registerUnchanged(vehicle);
155 }
156 return changed;
157 }
158
159#ifdef DEBUG_ACTIONSTEPS
160 if (DEBUG_COND) {
161 std::cout << "\n" << SIMTIME << " veh '" << vehicle->getID() << "' plans lanechange maneuver." << std::endl;
162 }
163#endif
164 vehicle->updateBestLanes(); // needed?
165 const bool isOpposite = vehicle->getLaneChangeModel().isOpposite();
166 if (!isOpposite) {
167 for (int i = 0; i < (int) myChanger.size(); ++i) {
168 vehicle->adaptBestLanesOccupation(i, myChanger[i].dens);
169 }
170 }
171 // update leaders beyond the current edge for all lanes
172 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
173 ce->aheadNext = getLeaders(ce, vehicle);
174 }
175 // update expected speeds
176 int sublaneIndex = 0;
177 for (ChangerIt ce = myChanger.begin(); ce != myChanger.end(); ++ce) {
178 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(ce->aheadNext, sublaneIndex, ce->lane->getIndex());
179 for (int offset : ce->siblings) {
180 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
181 ChangerIt ceSib = ce + offset;
182 if (ceSib->lane->allowsVehicleClass(vehicle->getVClass())) {
183 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(ceSib->aheadNext, sublaneIndex, ceSib->lane->getIndex());
184 }
185 }
186 sublaneIndex += ce->ahead.numSublanes();
187 }
188
189 // Check for changes to the opposite lane if vehicle is active
190#ifdef DEBUG_ACTIONSTEPS
191 if (DEBUG_COND) {
192 std::cout << " myChangeToOpposite=" << myChangeToOpposite << " isOpposite=" << isOpposite << " mayChangeRight=" << mayChange(-1) << " mayChangeLeft=" << mayChange(1) << "\n";
193 }
194#endif
195
196 const bool stopOpposite = hasOppositeStop(vehicle);
197 const int traciState = vehicle->influenceChangeDecision(0);
198 const bool traciRequestOpposite = !mayChange(1) && (traciState & LCA_LEFT) != 0;
199
200 if (myChangeToOpposite && (
201 // cannot overtake since there is only one usable lane (or emergency)
202 ((!mayChange(-1) && !mayChange(1)) || vehicle->getVClass() == SVC_EMERGENCY)
203 || traciRequestOpposite
204 || stopOpposite
205 // can alway come back from the opposite side
206 || isOpposite)) {
207 const MSLeaderDistanceInfo& leaders = myCandi->aheadNext;
208 if (leaders.hasVehicles() || isOpposite || stopOpposite || traciRequestOpposite) {
209 std::pair<MSVehicle*, double> leader = findClosestLeader(leaders, vehicle);
211 if ((leader.first != nullptr || isOpposite || stopOpposite || traciRequestOpposite)
212 && changeOpposite(vehicle, leader, myCandi->lastStopped)) {
213 return true;
214 } else if (myCheckedChangeOpposite) {
215 registerUnchanged(vehicle);
216 return false;
217 }
218 // try sublane change within current lane otherwise
219 }
220 }
221
223 | (mayChange(1) ? LCA_LEFT : LCA_NONE));
224
225 StateAndDist right = checkChangeHelper(vehicle, -1, alternatives);
226 StateAndDist left = checkChangeHelper(vehicle, 1, alternatives);
227 StateAndDist current = checkChangeHelper(vehicle, 0, alternatives);
228
229 StateAndDist decision = vehicle->getLaneChangeModel().decideDirection(current,
230 vehicle->getLaneChangeModel().decideDirection(right, left));
231#ifdef DEBUG_DECISION
232 if (vehicle->getLaneChangeModel().debugVehicle()) {
233 std::cout << "\n" << SIMTIME << " decision=" << toString((LaneChangeAction)decision.state) << " dir=" << decision.dir << " latDist=" << decision.latDist << " maneuverDist=" << decision.maneuverDist << "\n";
234 }
235#endif
236 vehicle->getLaneChangeModel().setOwnState(decision.state);
237 if ((decision.state & LCA_WANTS_LANECHANGE) != 0 && (decision.state & LCA_BLOCKED) == 0) {
238 // change if the vehicle wants to and is allowed to change
239#ifdef DEBUG_MANEUVER
240 if (DEBUG_COND) {
241 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' performing sublane change..." << std::endl;
242 }
243#endif
244 const bool changed = startChangeSublane(vehicle, myCandi, decision.latDist, decision.maneuverDist);
245 if (!changed) {
246 registerUnchanged(vehicle);
247 }
248 return changed;
249 }
250 // @note this assumes vehicles can instantly abort any maneuvre in case of emergency
251 abortLCManeuver(vehicle);
252 registerUnchanged(vehicle);
253
254 if ((right.state & (LCA_URGENT)) != 0 && (left.state & (LCA_URGENT)) != 0) {
255 // ... wants to go to the left AND to the right
256 // just let them go to the right lane...
257 left.state = 0;
258 }
259 return false;
260}
261
262
263void
265#ifdef DEBUG_MANEUVER
266 if (DEBUG_COND) {
267 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' aborts LC-continuation."
268 << std::endl;
269 }
270#endif
271 const int priorReason = vehicle->getLaneChangeModel().getPrevState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
272 const int reason = vehicle->getLaneChangeModel().getOwnState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
273 if (priorReason != 0 && priorReason != reason && vehicle->getLaneChangeModel().getPreviousManeuverDist() != 0) {
274 // original from cannot be reconstructed
275 const int priorDirection = vehicle->getLaneChangeModel().getPreviousManeuverDist() > 0 ? 1 : -1;
276#ifdef DEBUG_MANEUVER
277 if (DEBUG_COND) {
278 std::cout << SIMTIME << " abortLCManeuver priorReason=" << toString((LaneChangeAction)priorReason)
279 << " reason=" << toString((LaneChangeAction)reason) << " veh=" << vehicle->getID() << "\n";
280 }
281#endif
282 outputLCEnded(vehicle, myCandi, myCandi, priorDirection);
283 }
284 const double updatedSpeedLat = vehicle->getLaneChangeModel().getSpeedLat() != 0;
285 vehicle->getLaneChangeModel().setSpeedLat(0);
286 vehicle->getLaneChangeModel().setManeuverDist(0.);
288 if (updatedSpeedLat) {
289 // update angle after having reset lateral speed
290 vehicle->setAngle(vehicle->computeAngle());
291 }
292}
293
294
297 StateAndDist result = StateAndDist(0, 0, 0, 0);
298 if (mayChange(laneOffset)) {
299 if (laneOffset != 0 && vehicle->getLaneChangeModel().isOpposite()) {
300 return result;
301 }
302 const std::vector<MSVehicle::LaneQ>& preb = (vehicle->getLaneChangeModel().isOpposite()
303 ? getBestLanesOpposite(vehicle, nullptr, 1000)
304 : vehicle->getBestLanes());
305 result.state = checkChangeSublane(laneOffset, alternatives, preb, result.latDist, result.maneuverDist);
306 result.dir = laneOffset;
307 if ((result.state & LCA_WANTS_LANECHANGE) != 0 && (result.state & LCA_URGENT) != 0 && (result.state & LCA_BLOCKED) != 0) {
308 (myCandi + laneOffset)->lastBlocked = vehicle;
309 if ((myCandi + laneOffset)->firstBlocked == nullptr) {
310 (myCandi + laneOffset)->firstBlocked = vehicle;
311 }
312 }
313 }
314 return result;
315}
316
317
319// (used to continue sublane changing in non-action steps).
320bool
322 // lateral distance to complete maneuver
323 double remLatDist = vehicle->getLaneChangeModel().getManeuverDist();
324 if (remLatDist == 0) {
325 return false;
326 }
327 const bool urgent = (vehicle->getLaneChangeModel().getOwnState() & LCA_URGENT) != 0;
328 const double nextLatDist = SPEED2DIST(vehicle->getLaneChangeModel().computeSpeedLat(remLatDist, remLatDist, urgent));
329#ifdef DEBUG_MANEUVER
330 if (DEBUG_COND) {
331 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' continueChangeSublane()"
332 << " remLatDist=" << remLatDist << " nextLatDist=" << nextLatDist
333 << std::endl;
334 }
335#endif
336
337 const bool changed = startChangeSublane(vehicle, from, nextLatDist, remLatDist);
338 return changed;
339}
340
341
342bool
343MSLaneChangerSublane::startChangeSublane(MSVehicle* vehicle, ChangerIt& from, double latDist, double maneuverDist) {
344 if (vehicle->isRemoteControlled()) {
345 return false;
346 }
347 MSLane* source = from->lane;
348 // Prevent continuation of LC beyond lane borders if change is not allowed
349 double distToRightLaneBorder = vehicle->getLane()->getWidth() * 0.5 + vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
350 double distToLeftLaneBorder = vehicle->getLane()->getWidth() * 0.5 - vehicle->getLateralPositionOnLane() - vehicle->getWidth() * 0.5;
351 if (vehicle->getLaneChangeModel().isOpposite()) {
352 std::swap(distToRightLaneBorder, distToLeftLaneBorder);
353 }
354 // determine direction of LC
355 int direction = 0;
356 if (latDist > 0 && latDist > distToLeftLaneBorder) {
357 direction = 1;
358 } else if (latDist < 0 && -latDist > distToRightLaneBorder) {
359 direction = -1;
360 }
361 const int changerDirection = vehicle->getLaneChangeModel().isOpposite() ? -direction : direction;
362 ChangerIt to = from;
363#ifdef DEBUG_MANEUVER
364 if (DEBUG_COND) {
365 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' latDist=" << latDist << " maneuverDist=" << maneuverDist
366 << " distRight=" << distToRightLaneBorder << " distLeft=" << distToLeftLaneBorder
367 << " dir=" << direction << " cDir=" << changerDirection << " mayChange=" << mayChange(changerDirection) << "\n";
368 }
369#endif
370 if (mayChange(changerDirection)) {
371 to = from + changerDirection;
372 } else if (changerDirection == 1 && source->getOpposite() != nullptr) {
373 // change to the opposite direction lane
374 to = (source->getOpposite()->getEdge().myLaneChanger->getChanger().end() - 1);
375 } else {
376 // This may occur during maneuver continuation in non-actionsteps.
377 // TODO: Understand better why and test later if additional sublane actionstep debugging resolves this
378 // (XXX: perhaps one should try to extrapolate check for this case before to avoid maneuver initialization
379 // similar as for continuous LC in MSLaneChanger::checkChange())
380 //assert(false);
381 abortLCManeuver(vehicle);
382 return false;
383 }
384
385 // The following does:
386 // 1) update vehicles lateral position according to latDist and target lane
387 // 2) distinguish several cases
388 // a) vehicle moves completely within the same lane
389 // b) vehicle intersects another lane
390 // - vehicle must be moved to the lane where its midpoint is (either old or new)
391 // - shadow vehicle must be created/moved to the other lane if the vehicle intersects it
392 // 3) updated dens of all lanes that hold the vehicle or its shadow
393
394 vehicle->myState.myPosLat += latDist * (vehicle->getLaneChangeModel().isOpposite() ? -1 : 1);
395 for (int i = 0; i < (int)vehicle->myFurtherLanesPosLat.size(); i++) {
396 vehicle->myFurtherLanesPosLat[i] += latDist * (vehicle->getLaneChangeModel().isOpposite() ? -1 : 1);
397 }
399 vehicle->getLaneChangeModel().setSpeedLat(DIST2SPEED(latDist));
400#ifdef DEBUG_MANEUVER
401 if (DEBUG_COND) {
402 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "' with maneuverDist=" << maneuverDist
403 << " and committedSpeed=" << vehicle->getLaneChangeModel().getCommittedSpeed()
404 << " increments lateral position by latDist=" << latDist << std::endl;
405 }
406#endif
407#ifdef DEBUG_SURROUNDING
408 if (DEBUG_COND) {
409 std::cout << SIMTIME << " vehicle '" << vehicle->getID() << "'\n to->ahead=" << to->ahead.toString()
410 << "'\n to->aheadNext=" << to->aheadNext.toString()
411 << std::endl;
412 }
413#endif
414 const bool completedPriorManeuver = fabs(vehicle->getLaneChangeModel().getPreviousManeuverDist()) < NUMERICAL_EPS;
415 const bool completedManeuver = fabs(maneuverDist - latDist) < NUMERICAL_EPS;
416 vehicle->getLaneChangeModel().updateSafeLatDist(latDist);
417
418 // current maneuver is aborted when direction or reason changes
419 const int priorReason = vehicle->getLaneChangeModel().getPrevState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
420 const int reason = vehicle->getLaneChangeModel().getOwnState() & LCA_CHANGE_REASONS & ~LCA_SUBLANE;
421#ifdef DEBUG_MANEUVER
422 if (DEBUG_COND) {
423 std::cout << SIMTIME << " vehicle '" << vehicle->getID()
424 << "' completedPriorManeuver=" << completedPriorManeuver
425 << " completedManeuver=" << completedManeuver
426 << " priorReason=" << toString((LaneChangeAction)priorReason)
427 << " reason=" << toString((LaneChangeAction)reason)
428 << " priorManeuverDist=" << vehicle->getLaneChangeModel().getPreviousManeuverDist()
429 << " maneuverDist=" << maneuverDist
430 << " latDist=" << latDist
431 << std::endl;
432 }
433#endif
434 if (!completedManeuver && !completedPriorManeuver && priorReason != 0 &&
435 (vehicle->getLaneChangeModel().getPreviousManeuverDist() * latDist < 0
436 || priorReason != reason)) {
437 const int priorDirection = vehicle->getLaneChangeModel().getPreviousManeuverDist() > 0 ? 1 : -1;
438 // original from cannot be reconstructed
439#ifdef DEBUG_MANEUVER
440 if (DEBUG_COND) {
441 std::cout << SIMTIME << " startChangeSublane abort priorReason=" << toString((LaneChangeAction)priorReason)
442 << " reason=" << toString((LaneChangeAction)reason) << " veh=" << vehicle->getID() << "\n";
443 }
444#endif
445 outputLCEnded(vehicle, from, from, priorDirection);
446 }
447
448 outputLCStarted(vehicle, from, to, direction, maneuverDist);
449 vehicle->getLaneChangeModel().setManeuverDist(maneuverDist - latDist);
450 const bool changedToNewLane = checkChangeToNewLane(vehicle, direction, from, to);
451
452 MSLane* oldShadowLane = vehicle->getLaneChangeModel().getShadowLane();
454 MSLane* shadowLane = vehicle->getLaneChangeModel().getShadowLane();
455 if (shadowLane != nullptr && shadowLane != oldShadowLane
456 && &shadowLane->getEdge() == &source->getEdge()) {
457 assert(oldShadowLane == 0 || vehicle->getLaneChangeModel().isOpposite() || to != from);
458 const double latOffset = vehicle->getLane()->getRightSideOnEdge() - shadowLane->getRightSideOnEdge();
459 (myChanger.begin() + shadowLane->getIndex())->ahead.addLeader(vehicle, false, latOffset);
460 }
461 if (completedManeuver) {
462 outputLCEnded(vehicle, from, to, direction);
463 }
464
465 // Update maneuver reservations on target lanes
466 MSLane* targetLane = vehicle->getLaneChangeModel().updateTargetLane();
467 if (!changedToNewLane && targetLane != nullptr
468 && vehicle->getActionStepLength() > DELTA_T
469 && &targetLane->getEdge() == &source->getEdge()
470 ) {
471 const int dir = (vehicle->getLaneChangeModel().getManeuverDist() > 0 ? 1 : -1);
472 ChangerIt target = from + dir;
473 const double actionStepDist = dir * vehicle->getVehicleType().getMaxSpeedLat() * vehicle->getActionStepLengthSecs();
474 const double latOffset = vehicle->getLatOffset(targetLane) + actionStepDist;
475 target->ahead.addLeader(vehicle, false, latOffset);
476 //std::cout << SIMTIME << " veh=" << vehicle->getID() << " target=" << targetLane->getID()
477 // << " actionStepDist=" << actionStepDist << " latOffset=" << latOffset
478 // << " targetAhead=" << target->ahead.toString() << "\n";
479 }
480
481 // compute new angle of the vehicle from the x- and y-distances travelled within last time step
482 // (should happen last because primaryLaneChanged() also triggers angle computation)
483 // this part of the angle comes from the orientation of our current lane
484 double laneAngle = vehicle->computeAngle();
485 if (vehicle->getLaneChangeModel().isOpposite()) {
486 // reverse lane angle
487 laneAngle += M_PI;
488 }
489#ifdef DEBUG_MANEUVER
490 if (DEBUG_COND) {
491 std::cout << SIMTIME << " startChangeSublane"
492 << " oldLane=" << from->lane->getID()
493 << " newLane=" << to->lane->getID()
494 << " shadowLane=" << (shadowLane != nullptr ? shadowLane->getID() : "NULL")
495 << " targetLane=" << (targetLane != nullptr ? targetLane->getID() : "NULL")
496 << " maneuverDist=" << vehicle->getLaneChangeModel().getManeuverDist()
497 << " latDist=" << latDist
498 << " oldShadowLane=" << Named::getIDSecure(oldShadowLane)
499 << " newShadowLane=" << Named::getIDSecure(vehicle->getLaneChangeModel().getShadowLane())
500 << " laneA=" << RAD2DEG(laneAngle)
501 << " oldA=" << RAD2DEG(vehicle->getAngle())
502 << " oppposite=" << vehicle->getLaneChangeModel().isOpposite()
503 << " changedToNewLane=" << changedToNewLane
504 << "\n";
505 }
506#endif
507 vehicle->setAngle(laneAngle, completedManeuver);
508
509 // check if a traci maneuver must continue
510 // getOwnState is reset to 0 when changing lanes so we use the stored reason
511 if ((reason & LCA_TRACI) != 0) {
512#ifdef DEBUG_MANEUVER
513 if (DEBUG_COND) {
514 std::cout << SIMTIME << " continue TraCI-maneuver remainingLatDist=" << vehicle->getLaneChangeModel().getManeuverDist() << "\n";
515 }
516#endif
518 }
519 from->lane->requireCollisionCheck();
520 to->lane->requireCollisionCheck();
521 return changedToNewLane;
522}
523
524bool
526 const int oppositeSign = vehicle->getLaneChangeModel().isOpposite() ? -1 : 1;
527 const bool opposite = (&from->lane->getEdge() != &to->lane->getEdge());
528 const bool changedToNewLane = (to->lane != from->lane
529 && fabs(vehicle->getLateralPositionOnLane()) > 0.5 * vehicle->getLane()->getWidth()
530 && (mayChange(direction * oppositeSign) || opposite));
531 if (changedToNewLane) {
532 vehicle->myState.myPosLat -= direction * 0.5 * (from->lane->getWidth() + to->lane->getWidth()) * oppositeSign;
533 if (!opposite) {
534 to->lane->myTmpVehicles.insert(to->lane->myTmpVehicles.begin(), vehicle);
535 to->dens += vehicle->getVehicleType().getLengthWithGap();
536 }
538 if (!vehicle->isActive()) {
539 // update leaders beyond the current edge for all lanes
540 // @note to->aheadNext and from->aheadNext are only needed for output in non-action steps.
541 to->aheadNext = getLeaders(to, vehicle);
542 from->aheadNext = getLeaders(from, vehicle);
543 }
544 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
545 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
546 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
547 }
548 vehicle->getLaneChangeModel().startLaneChangeManeuver(from->lane, to->lane, direction);
549 if (!opposite) {
550 to->ahead.addLeader(vehicle, false, 0);
551 }
552 } else {
553 from->ahead.addLeader(vehicle, false, 0);
554 }
555 return changedToNewLane;
556}
557
558void
559MSLaneChangerSublane::outputLCStarted(MSVehicle* vehicle, ChangerIt& from, ChangerIt& to, int direction, double maneuverDist) {
561 // non-sublane change started
562 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)
563 && ((vehicle->getLaneChangeModel().getOwnState() & LCA_STAY) == 0)
564 // no changing for the same reason in previous step (either not wanted or blocked)
567 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_STAY) != 0)
568 || ((vehicle->getLaneChangeModel().getPrevState() & LCA_BLOCKED) != 0))
569 ) {
570#ifdef DEBUG_STATE
571 if (DEBUG_COND) {
572 std::cout << SIMTIME << " veh=" << vehicle->getID() << " laneChangeStarted state=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getOwnState())
573 << " prevState=" << toString((LaneChangeAction)vehicle->getLaneChangeModel().getPrevState())
576 << "\n";
577 }
578#endif
579 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
580 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
581 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
582 vehicle->getLaneChangeModel().laneChangeOutput("changeStarted", from->lane, to->lane, direction, maneuverDist);
583 }
584}
585
586void
589 // non-sublane change ended
590 && ((vehicle->getLaneChangeModel().getOwnState() & (LCA_CHANGE_REASONS & ~LCA_SUBLANE)) != 0)) {
591 vehicle->getLaneChangeModel().setLeaderGaps(to->aheadNext);
592 vehicle->getLaneChangeModel().setFollowerGaps(to->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true));
593 vehicle->getLaneChangeModel().setOrigLeaderGaps(from->aheadNext);
594 vehicle->getLaneChangeModel().laneChangeOutput("changeEnded", from->lane, to->lane, direction);
595 }
596}
597
598
600MSLaneChangerSublane::getLeaders(const ChangerIt& target, const MSVehicle* vehicle) const {
601 // get the leading vehicle on the lane to change to
602#ifdef DEBUG_SURROUNDING
603 if (DEBUG_COND) {
604 std::cout << SIMTIME << " getLeaders lane=" << target->lane->getID() << " ego=" << vehicle->getID() << " ahead=" << target->ahead.toString() << "\n";
605 }
606#endif
607 MSLeaderDistanceInfo result(target->lane->getWidth(), nullptr, 0);
608 int sublaneShift = 0;
609 if (target->lane == vehicle->getLane()) {
611 sublaneShift = int(-vehicle->getLeftSideOnLane() / MSGlobals::gLateralResolution);
612 } else if (vehicle->getRightSideOnLane() > target->lane->getWidth() + MSGlobals::gLateralResolution) {
613 sublaneShift = -int((vehicle->getRightSideOnLane() - target->lane->getWidth()) / MSGlobals::gLateralResolution);
614 }
615 result.setSublaneOffset(sublaneShift);
616 }
617 for (int i = 0; i < target->ahead.numSublanes(); ++i) {
618 const MSVehicle* veh = target->ahead[i];
619 if (veh != nullptr) {
620 const double gap = veh->getBackPositionOnLane(target->lane) - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
621#ifdef DEBUG_SURROUNDING
622 if (DEBUG_COND) {
623 std::cout << " ahead lead=" << veh->getID() << " leadBack=" << veh->getBackPositionOnLane() << " gap=" << gap << " sublaneShift=" << sublaneShift << "\n";
624 }
625#endif
626 if (i + sublaneShift >= 0 && i + sublaneShift < result.numSublanes()) {
627 result.addLeader(veh, gap, 0, i + sublaneShift);
628 }
629 }
630 }
631 if (sublaneShift != 0) {
632 for (MSVehicle* cand : target->outsideBounds) {
633 const double gap = cand->getBackPositionOnLane() - vehicle->getPositionOnLane() - vehicle->getVehicleType().getMinGap();
634 result.addLeader(cand, gap);
635 }
636 }
637#ifdef DEBUG_SURROUNDING
638 if (DEBUG_COND) {
639 std::cout << " outsideBounds=" << toString(target->outsideBounds) << " result=" << result.toString() << "\n";
640 }
641#endif
642 // @note use the exact same vehiclePos as in getLastVehicleInformation() to avoid missing vehicles
643 target->lane->addLeaders(vehicle, vehicle->getPositionOnLane(vehicle->getLane()), result);
644 return result;
645}
646
647
648int
650 int laneOffset,
651 LaneChangeAction alternatives,
652 const std::vector<MSVehicle::LaneQ>& preb,
653 double& latDist,
654 double& maneuverDist) const {
655
656 ChangerIt target = myCandi + laneOffset;
657 MSVehicle* vehicle = veh(myCandi);
658 const MSLane& neighLane = *(target->lane);
659 int blocked = 0;
660
661 MSLeaderDistanceInfo neighLeaders = target->aheadNext;
662 MSLeaderDistanceInfo neighFollowers = target->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
663 MSLeaderDistanceInfo neighBlockers(neighLane.getWidth(), vehicle, vehicle->getLane()->getRightSideOnEdge() - neighLane.getRightSideOnEdge());
664 MSLeaderDistanceInfo leaders = myCandi->aheadNext;
665 addOutsideLeaders(vehicle, leaders);
666 MSLeaderDistanceInfo followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
667 MSLeaderDistanceInfo blockers(vehicle->getLane()->getWidth(), vehicle, 0);
668
669 // consider sibling lanes of the origin and target lane
670 for (int offset : myCandi->siblings) {
671 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
672 ChangerIt ceSib = myCandi + offset;
673 MSLeaderDistanceInfo sibFollowers = ceSib->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
674 if (sibFollowers.hasVehicles()) {
675 followers.addLeaders(sibFollowers);
676 }
677 if (ceSib->aheadNext.hasVehicles()) {
678 leaders.addLeaders(ceSib->aheadNext);
679 }
680#ifdef DEBUG_SURROUNDING
681 if (DEBUG_COND) {
682 std::cout << SIMTIME << " ego=" << vehicle->getID() << " ahead=" << myCandi->aheadNext.toString() << " sib=" << ceSib->lane->getID() << " sibAhead=" << ceSib->aheadNext.toString() << " leaders=" << leaders.toString() << "\n";
683 }
684#endif
685 }
686 for (int offset : target->siblings) {
687 // treat sibling lanes (internal lanes with the same origin lane) as if they have the same geometry
688 ChangerIt ceSib = target + offset;
689 MSLeaderDistanceInfo sibFollowers = ceSib->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
690 if (sibFollowers.hasVehicles()) {
691 neighFollowers.addLeaders(sibFollowers);
692 }
693 if (ceSib->aheadNext.hasVehicles()) {
694 neighLeaders.addLeaders(ceSib->aheadNext);
695 }
696#ifdef DEBUG_SURROUNDING
697 if (DEBUG_COND) {
698 std::cout << SIMTIME << " ego=" << vehicle->getID() << " neighAhead=" << target->aheadNext.toString() << " sib=" << ceSib->lane->getID() << " sibAhead=" << ceSib->aheadNext.toString() << " neighLeaders=" << neighLeaders.toString() << "\n";
699 }
700#endif
701 }
702
703 // break leader symmetry
704 if (laneOffset == -1 && neighLeaders.hasVehicles()) {
705 neighLeaders.moveSamePosTo(vehicle, neighFollowers);
706 }
707
708#ifdef DEBUG_SURROUNDING
709 if (DEBUG_COND) std::cout << SIMTIME
710 << " checkChangeSublane: veh=" << vehicle->getID()
711 << " laneOffset=" << laneOffset
712 << "\n leaders=" << leaders.toString()
713 << "\n neighLeaders=" << neighLeaders.toString()
714 << "\n followers=" << followers.toString()
715 << "\n neighFollowers=" << neighFollowers.toString()
716 << "\n";
717#endif
718
719
720 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
721 laneOffset, alternatives,
722 leaders, followers, blockers,
723 neighLeaders, neighFollowers, neighBlockers,
724 neighLane, preb,
725 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
726
727
728 if (checkOpened && (blocked & LCA_BLOCKED) == 0 && (wish & LCA_WANTS_LANECHANGE) != 0
729 && vehicle->getLane()->isNormal()
730 && vehicle->getBestLanesContinuation().size() > 1) {
731 const MSLink* link = vehicle->getLane()->getLinkTo(vehicle->getBestLanesContinuation()[1]);
732 if (link != nullptr && link->isEntryLink()) {
733 const MSLink* link2 = link->getParallelLink(laneOffset);
734 if (link2 != nullptr) {
735 auto api = link->getApproachingPtr(vehicle);
736 if (api != nullptr) {
737 if (!link2->opened(api->arrivalTime, api->arrivalSpeed, api->leaveSpeed, vehicle->getLength(),
738 vehicle->getImpatience(), vehicle->getCarFollowModel().getMaxDecel(), vehicle->getWaitingTime(), vehicle->getLateralPositionOnLane(),
739 nullptr, false, vehicle, api->dist)) {
740 //std::cout << SIMTIME << " unsafeLC " << vehicle->getID() << "\n";
741 blocked |= LCA_BLOCKED;
742 }
743 }
744 }
745 }
746 }
747
748 int state = blocked | wish;
749
750 // XXX
751 // do are more careful (but expensive) check to ensure that a
752 // safety-critical leader is not being overlooked
753
754 // let TraCI influence the wish to change lanes and the security to take
755 const int oldstate = state;
756 state = vehicle->influenceChangeDecision(state);
757#ifdef DEBUG_STATE
758 if (DEBUG_COND && state != oldstate) {
759 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
760 }
761#endif
762 vehicle->getLaneChangeModel().getCanceledState(laneOffset) |= blocked;
763 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
764 if (laneOffset != 0) {
765 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
766 }
767 return state;
768}
769
770
771bool
773 MSVehicle* vehicle,
774 int laneOffset,
775 MSLane* targetLane,
776 const std::pair<MSVehicle* const, double>& leader,
777 const std::pair<MSVehicle* const, double>& neighLead,
778 const std::pair<MSVehicle* const, double>& neighFollow,
779 const std::vector<MSVehicle::LaneQ>& preb) {
781
782 UNUSED_PARAMETER(leader);
783 UNUSED_PARAMETER(neighLead);
784 UNUSED_PARAMETER(neighFollow);
785
786 const MSLane& neighLane = *targetLane;
787 MSLane* curLane = myCandi->lane;
788
789 MSLeaderDistanceInfo neighLeaders(targetLane->getWidth(), nullptr, 0);
790 MSLeaderDistanceInfo neighFollowers(targetLane->getWidth(), nullptr, 0);
791 MSLeaderDistanceInfo neighBlockers(targetLane->getWidth(), nullptr, 0);
792 MSLeaderDistanceInfo leaders(curLane->getWidth(), nullptr, 0);
793 MSLeaderDistanceInfo followers(curLane->getWidth(), nullptr, 0);
794 MSLeaderDistanceInfo blockers(curLane->getWidth(), nullptr, 0);
795
796 const double backPosOnTarget = vehicle->getLane()->getOppositePos(vehicle->getBackPositionOnLane());
797 if (vehicle->getLaneChangeModel().isOpposite()) {
798 leaders = curLane->getFollowersOnConsecutive(vehicle, vehicle->getPositionOnLane(), true, -1, MSLane::MinorLinkMode::FOLLOW_ONCOMING);
799 leaders.fixOppositeGaps(false);
800 curLane->addLeaders(vehicle, vehicle->getBackPositionOnLane(), followers);
801 followers.fixOppositeGaps(true);
802 neighFollowers = targetLane->getFollowersOnConsecutive(vehicle, backPosOnTarget, true);
803 neighFollowers.fixOppositeGaps(false);
804 // artificially increase the position to ensure that ego is not added as a leader
805 const double posOnTarget = backPosOnTarget + vehicle->getVehicleType().getLength() + POSITION_EPS;
806 targetLane->addLeaders(vehicle, posOnTarget, neighLeaders);
807 neighLeaders.patchGaps(2 * POSITION_EPS);
808 int sublaneIndex = 0;
809 for (int i = 0; i < targetLane->getIndex(); i++) {
810 sublaneIndex += MSLeaderInfo(targetLane->getEdge().getLanes()[i]->getWidth()).numSublanes();
811 }
812 vehicle->getLaneChangeModel().updateExpectedSublaneSpeeds(neighLeaders, sublaneIndex, targetLane->getIndex());
813 } else {
814 leaders = myCandi->aheadNext;
815 followers = myCandi->lane->getFollowersOnConsecutive(vehicle, vehicle->getBackPositionOnLane(), true);
816 const double posOnTarget = backPosOnTarget - vehicle->getVehicleType().getLength();
817 targetLane->addLeaders(vehicle, backPosOnTarget, neighFollowers, true);
818 neighFollowers.fixOppositeGaps(true);
819 neighLeaders = targetLane->getFollowersOnConsecutive(vehicle, posOnTarget, true);
820 neighLeaders.fixOppositeGaps(false);
821 }
822
823
824#ifdef DEBUG_CHANGE_OPPOSITE
825 if (DEBUG_COND) std::cout << SIMTIME
826 << " checkChangeOppositeSublane: veh=" << vehicle->getID()
827 << " isOpposite=" << vehicle->getLaneChangeModel().isOpposite()
828 << " laneOffset=" << laneOffset
829 << "\n leaders=" << leaders.toString()
830 << "\n neighLeaders=" << neighLeaders.toString()
831 << "\n followers=" << followers.toString()
832 << "\n neighFollowers=" << neighFollowers.toString()
833 << "\n";
834#endif
835
837 | (mayChange(1) ? LCA_LEFT : LCA_NONE));
838
839 int blocked = 0;
840 double latDist = 0;
841 double maneuverDist = 0;
842 const int wish = vehicle->getLaneChangeModel().wantsChangeSublane(
843 laneOffset, alternatives,
844 leaders, followers, blockers,
845 neighLeaders, neighFollowers, neighBlockers,
846 neighLane, preb,
847 &(myCandi->lastBlocked), &(myCandi->firstBlocked), latDist, maneuverDist, blocked);
848 int state = blocked | wish;
849
850 const int oldstate = state;
851 state = vehicle->influenceChangeDecision(state);
852#ifdef DEBUG_CHANGE_OPPOSITE
853 if (DEBUG_COND && state != oldstate) {
854 std::cout << SIMTIME << " veh=" << vehicle->getID() << " stateAfterTraCI=" << toString((LaneChangeAction)state) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
855 }
856#endif
857 vehicle->getLaneChangeModel().saveLCState(laneOffset, oldstate, state);
858 if (laneOffset != 0) {
859 vehicle->getLaneChangeModel().saveNeighbors(laneOffset, neighFollowers, neighLeaders);
860 }
861
862 if ((state & LCA_WANTS_LANECHANGE) != 0 && (state & LCA_BLOCKED) == 0) {
863 // change if the vehicle wants to and is allowed to change
864#ifdef DEBUG_CHANGE_OPPOSITE
865 if (DEBUG_COND) {
866 std::cout << SIMTIME << " veh '" << vehicle->getID() << "' performing sublane change latDist=" << latDist << " maneuverDist=" << maneuverDist << "\n";
867 }
868#endif
869 vehicle->getLaneChangeModel().setOwnState(state);
870 return startChangeSublane(vehicle, myCandi, latDist, maneuverDist);
871 } else {
872 vehicle->getLaneChangeModel().setSpeedLat(0);
873 return false;
874 }
875}
876
877std::pair<MSVehicle*, double>
879 const double egoWidth = vehicle->getVehicleType().getWidth() + vehicle->getVehicleType().getMinGapLat();
880 std::pair<MSVehicle*, double> leader(nullptr, std::numeric_limits<double>::max());
881 for (int i = 0; i < leaders.numSublanes(); ++i) {
882 CLeaderDist cand = leaders[i];
883 if (cand.first != nullptr) {
884 double rightSide = cand.first->getRightSideOnLane();
885 if (cand.first->getLane() != vehicle->getLane()) {
886 // the candidate may be a parial (sideways) occupier so getRightSideOnLane() cannot be used
887 rightSide += (cand.first->getCenterOnEdge(cand.first->getLane())
888 - vehicle->getCenterOnEdge(vehicle->getLane()));
889 }
890#ifdef DEBUG_CHANGE_OPPOSITE
891 if (vehicle->isSelected()) {
892 std::cout << SIMTIME << " cand=" << cand.first->getID() << " rightSide=" << rightSide << "\n";
893 }
894#endif
895 if (cand.second < leader.second
896 && rightSide < egoWidth
897 && vehicle->getLane()->getWidth() - rightSide - cand.first->getVehicleType().getWidth() < egoWidth) {
898 leader.first = const_cast<MSVehicle*>(cand.first);
899 leader.second = cand.second;
900 }
901 }
902 }
903 return leader;
904}
905
906
907void
909 if (vehicle->getLaneChangeModel().getShadowLane() == nullptr) {
910 const MSLane* lane = vehicle->getLane();
911 const double rightOL = vehicle->getRightSideOnLane(lane);
912 const double leftOL = vehicle->getLeftSideOnLane(lane);
913 const bool outsideLeft = rightOL > lane->getWidth();
914#ifdef DEBUG_SURROUNDING
915 if (DEBUG_COND) {
916 std::cout << SIMTIME << " addOutsideLeaders veh=" << vehicle->getID() << " lane=" << lane->getID() << " rightOL=" << rightOL << " leftOL=" << leftOL << "\n";
917 }
918#endif
919 if (leftOL < 0 || outsideLeft) {
920 int sublaneOffset = 0;
921 if (outsideLeft) {
922 sublaneOffset = MIN2(0, -(int)ceil((leftOL - lane->getWidth()) / MSGlobals::gLateralResolution) + 1);
923 } else {
924 sublaneOffset = MAX2(0, (int)ceil(-rightOL / MSGlobals::gLateralResolution) - 1);
925 }
926 if (sublaneOffset != 0) {
927 leaders.setSublaneOffset(sublaneOffset);
928#ifdef DEBUG_SURROUNDING
929 if (DEBUG_COND) {
930 std::cout << " sublaneOffset=" << sublaneOffset << " outsideLeft=" << outsideLeft << "\n";
931 }
932#endif
933 for (const MSVehicle* cand : lane->myTmpVehicles) {
934#ifdef DEBUG_SURROUNDING
935 if (DEBUG_COND) {
936 std::cout << " cand=" << cand->getID() << " cLOE=" << cand->getLeftSideOnEdge() << " cROE=" << cand->getRightSideOnEdge() << "\n";
937 }
938#endif
939 if (cand->getPositionOnLane() > vehicle->getPositionOnLane()
940 && ((!outsideLeft && cand->getLeftSideOnEdge() < 0)
941 || (outsideLeft && cand->getLeftSideOnEdge() > lane->getEdge().getWidth()))) {
942 const double gap = cand->getPositionOnLane() - vehicle->getPositionOnLane() - cand->getLength() - vehicle->getVehicleType().getMinGap();
943 leaders.addLeader(cand, gap);
944#ifdef DEBUG_SURROUNDING
945 if (DEBUG_COND) {
946 std::cout << " outsideLeader=" << cand->getID() << " ahead=" << leaders.toString() << "\n";
947 }
948#endif
949 }
950 }
951 }
952 }
953 }
954}
955
956/****************************************************************************/
#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.
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
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...
virtual bool isSelected() const
whether this vehicle is selected in the GUI
double getImpatience() const
Returns this vehicles impatience.
double getLength() const
Returns the vehicle's length.
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.
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:269
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:927
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:664
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:1493
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2745
void addLeaders(const MSVehicle *vehicle, double vehPos, MSLeaderDistanceInfo &result, bool oppositeDirection=false)
get leaders for ego on the given lane
Definition MSLane.cpp:4148
double getRightSideOnEdge() const
Definition MSLane.h:1202
int getIndex() const
Returns the lane's index.
Definition MSLane.h:647
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4395
bool isNormal() const
Definition MSLane.cpp:2626
@ FOLLOW_ONCOMING
Definition MSLane.h:983
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4383
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:769
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:3803
double getWidth() const
Returns the lane's width.
Definition MSLane.h:640
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
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
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.
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
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:1943
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:1921
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:969
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:735
State myState
This Vehicles driving state (pos and speed)
Definition MSVehicle.h:1873
double getCenterOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
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:323
#define UNUSED_PARAMETER(x)
#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