Eclipse SUMO - Simulation of Urban MObility
MSAbstractLaneChangeModel.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
20 // Interface for lane-change models
21 /****************************************************************************/
22 
23 // ===========================================================================
24 // DEBUG
25 // ===========================================================================
26 //#define DEBUG_TARGET_LANE
27 //#define DEBUG_SHADOWLANE
28 #define DEBUG_MANEUVER
29 #define DEBUG_COND (myVehicle.isSelected())
30 
31 
32 // ===========================================================================
33 // included modules
34 // ===========================================================================
35 #include <config.h>
36 
39 #include <microsim/MSNet.h>
40 #include <microsim/MSEdge.h>
41 #include <microsim/MSLane.h>
42 #include <microsim/MSGlobals.h>
43 #include "MSLCM_DK2008.h"
44 #include "MSLCM_LC2013.h"
45 #include "MSLCM_SL2015.h"
46 
47 /* -------------------------------------------------------------------------
48  * static members
49  * ----------------------------------------------------------------------- */
54 const double MSAbstractLaneChangeModel::NO_NEIGHBOR(std::numeric_limits<double>::max());
55 
56 /* -------------------------------------------------------------------------
57  * MSAbstractLaneChangeModel-methods
58  * ----------------------------------------------------------------------- */
59 
60 void
62  myAllowOvertakingRight = oc.getBool("lanechange.overtake-right");
63  myLCOutput = oc.isSet("lanechange-output");
64  myLCStartedOutput = oc.getBool("lanechange-output.started");
65  myLCEndedOutput = oc.getBool("lanechange-output.ended");
66 }
67 
68 
71  if (MSGlobals::gLateralResolution > 0 && lcm != LCM_SL2015 && lcm != LCM_DEFAULT) {
72  throw ProcessError("Lane change model '" + toString(lcm) + "' is not compatible with sublane simulation");
73  }
74  switch (lcm) {
75  case LCM_DK2008:
76  return new MSLCM_DK2008(v);
77  case LCM_LC2013:
78  return new MSLCM_LC2013(v);
79  case LCM_SL2015:
80  return new MSLCM_SL2015(v);
81  case LCM_DEFAULT:
83  return new MSLCM_LC2013(v);
84  } else {
85  return new MSLCM_SL2015(v);
86  }
87  default:
88  throw ProcessError("Lane change model '" + toString(lcm) + "' not implemented");
89  }
90 }
91 
92 
94  myVehicle(v),
95  myOwnState(0),
96  myPreviousState(0),
101  mySpeedLat(0),
102  myCommittedSpeed(0),
105  myManeuverDist(0.),
107  myAlreadyChanged(false),
108  myShadowLane(nullptr),
109  myTargetLane(nullptr),
110  myCarFollowModel(v.getCarFollowModel()),
111  myModel(model),
114  myLastLeaderGap(0.),
115  myLastFollowerGap(0.),
123  myDontResetLCGaps(false),
124  myMaxSpeedLatStanding(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING, v.getVehicleType().getMaxSpeedLat())),
125  myMaxSpeedLatFactor(v.getVehicleType().getParameter().getLCParam(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR, 1)),
127  myAmOpposite(false) {
131 }
132 
133 
135 }
136 
137 void
140  myOwnState = state;
141  myPreviousState = state; // myOwnState is modified in prepareStep so we make a backup
142 }
143 
144 void
145 MSAbstractLaneChangeModel::updateSafeLatDist(const double travelledLatDist) {
146  UNUSED_PARAMETER(travelledLatDist);
147 }
148 
149 
150 void
152 #ifdef DEBUG_MANEUVER
153  if (DEBUG_COND) {
154  std::cout << SIMTIME
155  << " veh=" << myVehicle.getID()
156  << " setManeuverDist() old=" << myManeuverDist << " new=" << dist
157  << std::endl;
158  }
159 #endif
160  myManeuverDist = fabs(dist) < NUMERICAL_EPS ? 0. : dist;
161  // store value which may be modified by the model during the next step
163 }
164 
165 
166 double
168  return myManeuverDist;
169 }
170 
171 double
173  return myPreviousManeuverDist;
174 }
175 
176 void
178  if (dir == -1) {
179  myLeftFollowers = std::make_shared<MSLeaderDistanceInfo>(followers);
180  myLeftLeaders = std::make_shared<MSLeaderDistanceInfo>(leaders);
181  } else if (dir == 1) {
182  myRightFollowers = std::make_shared<MSLeaderDistanceInfo>(followers);
183  myRightLeaders = std::make_shared<MSLeaderDistanceInfo>(leaders);
184  } else {
185  // dir \in {-1,1} !
186  assert(false);
187  }
188 }
189 
190 
191 void
192 MSAbstractLaneChangeModel::saveNeighbors(const int dir, const std::pair<MSVehicle* const, double>& follower, const std::pair<MSVehicle* const, double>& leader) {
193  if (dir == -1) {
194  myLeftFollowers = std::make_shared<MSLeaderDistanceInfo>(follower, myVehicle.getLane());
195  myLeftLeaders = std::make_shared<MSLeaderDistanceInfo>(leader, myVehicle.getLane());
196  } else if (dir == 1) {
197  myRightFollowers = std::make_shared<MSLeaderDistanceInfo>(follower, myVehicle.getLane());
198  myRightLeaders = std::make_shared<MSLeaderDistanceInfo>(leader, myVehicle.getLane());
199  } else {
200  // dir \in {-1,1} !
201  assert(false);
202  }
203 }
204 
205 
206 void
208  myLeftFollowers = nullptr;
209  myLeftLeaders = nullptr;
210  myRightFollowers = nullptr;
211  myRightLeaders = nullptr;
212 }
213 
214 
215 const std::shared_ptr<MSLeaderDistanceInfo>
217  if (dir == -1) {
218  return myLeftFollowers;
219  } else if (dir == 1) {
220  return myRightFollowers;
221  } else {
222  // dir \in {-1,1} !
223  assert(false);
224  }
225  return nullptr;
226 }
227 
228 const std::shared_ptr<MSLeaderDistanceInfo>
230  if (dir == -1) {
231  return myLeftLeaders;
232  } else if (dir == 1) {
233  return myRightLeaders;
234  } else {
235  // dir \in {-1,1} !
236  assert(false);
237  }
238  return nullptr;
239 }
240 
241 
242 bool
244  if (neighLeader == nullptr) {
245  return false;
246  }
247  // Congested situation are relevant only on highways (maxSpeed > 70km/h)
248  // and congested on German Highways means that the vehicles have speeds
249  // below 60km/h. Overtaking on the right is allowed then.
250  if ((myVehicle.getLane()->getSpeedLimit() <= 70.0 / 3.6) || (neighLeader->getLane()->getSpeedLimit() <= 70.0 / 3.6)) {
251 
252  return false;
253  }
254  if (myVehicle.congested() && neighLeader->congested()) {
255  return true;
256  }
257  return false;
258 }
259 
260 
261 
262 bool
263 MSAbstractLaneChangeModel::predInteraction(const std::pair<MSVehicle*, double>& leader) {
264  if (leader.first == 0) {
265  return false;
266  }
267  // let's check it on highways only
268  if (leader.first->getSpeed() < (80.0 / 3.6)) {
269  return false;
270  }
271  return leader.second < myCarFollowModel.interactionGap(&myVehicle, leader.first->getSpeed());
272 }
273 
274 
275 bool
279  myLaneChangeDirection = direction;
280  setManeuverDist((target->getWidth() + source->getWidth()) * 0.5 * direction);
283  if (myLCOutput) {
285  }
286  return true;
287  } else {
288  primaryLaneChanged(source, target, direction);
289  return false;
290  }
291 }
292 
293 void
295  myDontResetLCGaps = true;
296 }
297 
298 void
300  myDontResetLCGaps = false;
301 }
302 
303 void
305  initLastLaneChangeOffset(direction);
307  source->leftByLaneChange(&myVehicle);
308  laneChangeOutput("change", source, target, direction); // record position on the source edge in case of opposite change
309  if (&source->getEdge() != &target->getEdge()) {
313  } else {
315  }
316  target->enteredByLaneChange(&myVehicle);
317  // Assure that the drive items are up to date (even if the following step is no actionstep for the vehicle).
318  // This is necessary because the lane advance uses the target lane from the corresponding drive item.
320  changed();
321 }
322 
323 void
324 MSAbstractLaneChangeModel::laneChangeOutput(const std::string& tag, MSLane* source, MSLane* target, int direction, double maneuverDist) {
325  if (myLCOutput) {
326  OutputDevice& of = OutputDevice::getDeviceByOption("lanechange-output");
327  of.openTag(tag);
330  of.writeAttr(SUMO_ATTR_TIME, time2string(MSNet::getInstance()->getCurrentTimeStep()));
331  of.writeAttr(SUMO_ATTR_FROM, source->getID());
332  of.writeAttr(SUMO_ATTR_TO, target->getID());
333  of.writeAttr(SUMO_ATTR_DIR, direction);
336  of.writeAttr("reason", toString((LaneChangeAction)(myOwnState & ~(
341  of.writeAttr("leaderGap", myLastLeaderGap == NO_NEIGHBOR ? "None" : toString(myLastLeaderGap));
342  of.writeAttr("leaderSecureGap", myLastLeaderSecureGap == NO_NEIGHBOR ? "None" : toString(myLastLeaderSecureGap));
343  of.writeAttr("leaderSpeed", myLastLeaderSpeed == NO_NEIGHBOR ? "None" : toString(myLastLeaderSpeed));
344  of.writeAttr("followerGap", myLastFollowerGap == NO_NEIGHBOR ? "None" : toString(myLastFollowerGap));
345  of.writeAttr("followerSecureGap", myLastFollowerSecureGap == NO_NEIGHBOR ? "None" : toString(myLastFollowerSecureGap));
346  of.writeAttr("followerSpeed", myLastFollowerSpeed == NO_NEIGHBOR ? "None" : toString(myLastFollowerSpeed));
347  of.writeAttr("origLeaderGap", myLastOrigLeaderGap == NO_NEIGHBOR ? "None" : toString(myLastOrigLeaderGap));
348  of.writeAttr("origLeaderSecureGap", myLastOrigLeaderSecureGap == NO_NEIGHBOR ? "None" : toString(myLastOrigLeaderSecureGap));
349  of.writeAttr("origLeaderSpeed", myLastOrigLeaderSpeed == NO_NEIGHBOR ? "None" : toString(myLastOrigLeaderSpeed));
351  const double latGap = direction < 0 ? myLastLateralGapRight : myLastLateralGapLeft;
352  of.writeAttr("latGap", latGap == NO_NEIGHBOR ? "None" : toString(latGap));
353  if (maneuverDist != 0) {
354  of.writeAttr("maneuverDistance", toString(maneuverDist));
355  }
356  }
357  of.closeTag();
360  }
361  }
362 }
363 
364 
365 double
366 MSAbstractLaneChangeModel::computeSpeedLat(double /*latDist*/, double& maneuverDist) {
368  int stepsToChange = (int)ceil(maneuverDist / SPEED2DIST(myVehicle.getVehicleType().getMaxSpeedLat()));
369  return DIST2SPEED(maneuverDist / stepsToChange);
370  } else {
371  return maneuverDist / STEPS2TIME(MSGlobals::gLaneChangeDuration);
372  }
373 }
374 
375 
376 double
378  throw ProcessError("Method getAssumedDecelForLaneChangeDuration() not implemented by model " + toString(myModel));
379 }
380 
381 
382 bool
384  const bool pastBefore = pastMidpoint();
385  // maneuverDist is not updated in the context of continuous lane changing but represents the full LC distance
386  double maneuverDist = getManeuverDist();
387  mySpeedLat = computeSpeedLat(0, maneuverDist);
389  return !pastBefore && pastMidpoint();
390 }
391 
392 
393 void
395  UNUSED_PARAMETER(reason);
403  // aborted maneuver
405  }
406 }
407 
408 
409 MSLane*
410 MSAbstractLaneChangeModel::getShadowLane(const MSLane* lane, double posLat) const {
412  // initialize shadow lane
413  const double overlap = myVehicle.getLateralOverlap(posLat);
414 #ifdef DEBUG_SHADOWLANE
415  if (debugVehicle()) {
416  std::cout << SIMTIME << " veh=" << myVehicle.getID() << " posLat=" << posLat << " overlap=" << overlap << "\n";
417  }
418 #endif
419  if (myAmOpposite) {
420  // return the neigh-lane in forward direction
421  return lane->getParallelLane(1);
422  } else if (overlap > NUMERICAL_EPS) {
423  const int shadowDirection = posLat < 0 ? -1 : 1;
424  return lane->getParallelLane(shadowDirection);
425  } else if (isChangingLanes() && myLaneChangeCompletion < 0.5) {
426  // "reserve" target lane even when there is no overlap yet
428  } else {
429  return nullptr;
430  }
431  } else {
432  return nullptr;
433  }
434 }
435 
436 
437 MSLane*
440 }
441 
442 
443 void
445  if (myShadowLane != nullptr) {
446  if (debugVehicle()) {
447  std::cout << SIMTIME << " cleanupShadowLane\n";
448  }
450  myShadowLane = nullptr;
451  }
452  for (std::vector<MSLane*>::const_iterator it = myShadowFurtherLanes.begin(); it != myShadowFurtherLanes.end(); ++it) {
453  if (debugVehicle()) {
454  std::cout << SIMTIME << " cleanupShadowLane2\n";
455  }
456  (*it)->resetPartialOccupation(&myVehicle);
457  }
458  myShadowFurtherLanes.clear();
460 }
461 
462 void
464  if (myTargetLane != nullptr) {
465  if (debugVehicle()) {
466  std::cout << SIMTIME << " cleanupTargetLane\n";
467  }
469  myTargetLane = nullptr;
470  }
471  for (std::vector<MSLane*>::const_iterator it = myFurtherTargetLanes.begin(); it != myFurtherTargetLanes.end(); ++it) {
472  if (debugVehicle()) {
473  std::cout << SIMTIME << " cleanupTargetLane\n";
474  }
475  if (*it != nullptr) {
476  (*it)->resetManeuverReservation(&myVehicle);
477  }
478  }
479  myFurtherTargetLanes.clear();
480 // myNoPartiallyOccupatedByShadow.clear();
481 }
482 
483 
484 bool
485 MSAbstractLaneChangeModel::cancelRequest(int state, int laneOffset) {
486  // store request before canceling
487  getCanceledState(laneOffset) |= state;
488  int ret = myVehicle.influenceChangeDecision(state);
489  return ret != state;
490 }
491 
492 
493 void
495  if (dir > 0) {
497  } else if (dir < 0) {
499  }
500 }
501 
502 void
504  if (!haveLateralDynamics()) {
505  // assume each vehicle drives at the center of its lane and act as if it fits
506  return;
507  }
508  if (myShadowLane != nullptr) {
509 #ifdef DEBUG_SHADOWLANE
510  if (debugVehicle()) {
511  std::cout << SIMTIME << " updateShadowLane()\n";
512  }
513 #endif
515  }
517  std::vector<MSLane*> passed;
518  if (myShadowLane != nullptr) {
520  const std::vector<MSLane*>& further = myVehicle.getFurtherLanes();
521  const std::vector<double>& furtherPosLat = myVehicle.getFurtherLanesPosLat();
522  assert(further.size() == furtherPosLat.size());
523  passed.push_back(myShadowLane);
524  for (int i = 0; i < (int)further.size(); ++i) {
525  MSLane* shadowFurther = getShadowLane(further[i], furtherPosLat[i]);
526 #ifdef DEBUG_SHADOWLANE
527  if (debugVehicle()) {
528  std::cout << SIMTIME << " further=" << further[i]->getID() << " (posLat=" << furtherPosLat[i] << ") shadowFurther=" << Named::getIDSecure(shadowFurther) << "\n";
529  }
530 #endif
531  if (shadowFurther != nullptr && MSLinkContHelper::getConnectingLink(*shadowFurther, *passed.back()) != nullptr) {
532  passed.push_back(shadowFurther);
533  }
534  }
535  std::reverse(passed.begin(), passed.end());
536  } else {
538  WRITE_WARNING("Vehicle '" + myVehicle.getID() + "' could not finish continuous lane change (lane disappeared) time=" +
539  time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
541  }
542  }
543 #ifdef DEBUG_SHADOWLANE
544  if (debugVehicle()) {
545  std::cout << SIMTIME << " updateShadowLane() veh=" << myVehicle.getID()
546  << " newShadowLane=" << Named::getIDSecure(myShadowLane)
547  << "\n before:" << " myShadowFurtherLanes=" << toString(myShadowFurtherLanes) << " further=" << toString(myVehicle.getFurtherLanes()) << " passed=" << toString(passed);
548  std::cout << std::endl;
549  }
550 #endif
552 #ifdef DEBUG_SHADOWLANE
553  if (debugVehicle()) std::cout
554  << "\n after:" << " myShadowFurtherLanes=" << toString(myShadowFurtherLanes) << "\n";
555 #endif
556 }
557 
558 
559 int
561  if (isChangingLanes()) {
562  if (pastMidpoint()) {
563  return -myLaneChangeDirection;
564  } else {
565  return myLaneChangeDirection;
566  }
567  } else if (myShadowLane == nullptr) {
568  return 0;
569  } else if (myAmOpposite) {
570  // return neigh-lane in forward direction
571  return 1;
572  } else {
573  assert(&myShadowLane->getEdge() == &myVehicle.getLane()->getEdge());
575  }
576 }
577 
578 
579 MSLane*
581 #ifdef DEBUG_TARGET_LANE
582  MSLane* oldTarget = myTargetLane;
583  std::vector<MSLane*> oldFurtherTargets = myFurtherTargetLanes;
584  if (debugVehicle()) {
585  std::cout << SIMTIME << " veh '" << myVehicle.getID() << "' (lane=" << myVehicle.getLane()->getID() << ") updateTargetLane()"
586  << "\n oldTarget: " << (oldTarget == nullptr ? "NULL" : oldTarget->getID())
587  << " oldFurtherTargets: " << toString(oldFurtherTargets);
588  }
589 #endif
590  if (myTargetLane != nullptr) {
592  }
593  // Clear old further target lanes
594  for (MSLane* oldTargetLane : myFurtherTargetLanes) {
595  if (oldTargetLane != nullptr) {
596  oldTargetLane->resetManeuverReservation(&myVehicle);
597  }
598  }
599  myFurtherTargetLanes.clear();
600 
601  // Get new target lanes and issue a maneuver reservation.
602  int targetDir;
603  myTargetLane = determineTargetLane(targetDir);
604  if (myTargetLane != nullptr) {
606  // further targets are just the target lanes corresponding to the vehicle's further lanes
607  // @note In a neglectable amount of situations we might add a reservation for a shadow further lane.
608  for (MSLane* furtherLane : myVehicle.getFurtherLanes()) {
609  MSLane* furtherTargetLane = furtherLane->getParallelLane(targetDir);
610  myFurtherTargetLanes.push_back(furtherTargetLane);
611  if (furtherTargetLane != nullptr) {
612  furtherTargetLane->setManeuverReservation(&myVehicle);
613  }
614  }
615  }
616 #ifdef DEBUG_TARGET_LANE
617  if (debugVehicle()) {
618  std::cout << "\n newTarget (offset=" << targetDir << "): " << (myTargetLane == nullptr ? "NULL" : myTargetLane->getID())
619  << " newFurtherTargets: " << toString(myFurtherTargetLanes)
620  << std::endl;
621  }
622 #endif
623  return myTargetLane;
624 }
625 
626 
627 MSLane*
629  targetDir = 0;
630  if (myManeuverDist == 0) {
631  return nullptr;
632  }
633  // Current lateral boundaries of the vehicle
634  const double vehRight = myVehicle.getLateralPositionOnLane() - 0.5 * myVehicle.getWidth();
635  const double vehLeft = myVehicle.getLateralPositionOnLane() + 0.5 * myVehicle.getWidth();
636  const double halfLaneWidth = 0.5 * myVehicle.getLane()->getWidth();
637 
638  if (vehRight + myManeuverDist < -halfLaneWidth) {
639  // Vehicle intends to traverse the right lane boundary
640  targetDir = -1;
641  } else if (vehLeft + myManeuverDist > halfLaneWidth) {
642  // Vehicle intends to traverse the left lane boundary
643  targetDir = 1;
644  }
645  if (targetDir == 0) {
646  // Presently, no maneuvering into another lane is begun.
647  return nullptr;
648  }
649  MSLane* target = myVehicle.getLane()->getParallelLane(targetDir);
650  if (target == nullptr || target == myShadowLane) {
651  return nullptr;
652  } else {
653  return target;
654  }
655 }
656 
657 
658 
659 double
662  return myLaneChangeDirection * angleOffset;
663 }
664 
665 
666 double
667 MSAbstractLaneChangeModel::estimateLCDuration(const double speed, const double remainingManeuverDist, const double decel) const {
668 
670  if (lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING) == lcParams.end() && lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR) == lcParams.end()) {
672  // no dependency of lateral speed on longitudinal speed. (Only called prior to LC initialization to determine whether it could be completed)
674  } else {
675  return remainingManeuverDist / myVehicle.getVehicleType().getMaxSpeedLat();
676  }
677  }
678 
679  if (remainingManeuverDist == 0) {
680  return 0;
681  }
682 
683  // Check argument assumptions
684  assert(speed >= 0);
685  assert(remainingManeuverDist >= 0);
686  assert(decel > 0);
687  assert(myVehicle.getVehicleType().getMaxSpeedLat() > 0);
689  assert(myMaxSpeedLatStanding >= 0);
690 
691  // for brevity
692  const double v0 = speed;
693  const double D = remainingManeuverDist;
694  const double b = decel;
695  const double wmin = myMaxSpeedLatStanding;
696  const double f = myMaxSpeedLatFactor;
697  const double wmax = myVehicle.getVehicleType().getMaxSpeedLat();
698 
699  /* Here's the approach for the calculation of the required time for the LC:
700  * To obtain the maximal LC-duration, for v(t) we assume that v(t)=max(0, v0-b*t),
701  * Where v(t)=0 <=> t >= ts:=v0/b
702  * For the lateral speed w(t) this gives:
703  * w(t) = min(wmax, wmin + f*v(t))
704  * The lateral distance covered until t is
705  * d(t) = int_0^t w(s) ds
706  * We distinguish three possibilities for the solution d(T)=D, where T is the time of the LC completion.
707  * 1) w(T) = wmax, i.e. v(T)>(wmax-wmin)/f
708  * 2) wmin < w(T) < wmax, i.e. (wmax-wmin)/f > v(T) > 0
709  * 3) w(T) = wmin, i.e., v(T)=0
710  */
711  const double vm = (wmax - wmin) / f;
712  double distSoFar = 0.;
713  double timeSoFar = 0.;
714  double v = v0;
715  if (v > vm) {
716  const double wmaxTime = (v0 - vm) / b;
717  const double d1 = wmax * wmaxTime;
718  if (d1 >= D) {
719  return D / wmax;
720  } else {
721  distSoFar += d1;
722  timeSoFar += wmaxTime;
723  v = vm;
724  }
725  }
726  if (v > 0) {
727  /* Here, w(t1+t) = wmin + f*v(t1+t) = wmin + f*(v - b*t)
728  * Thus, the additional lateral distance covered after time t is:
729  * d2 = (wmin + f*v)*t - 0.5*f*b*t^2
730  * and the additional lateral distance covered until v=0 at t=v/b is:
731  * d2 = (wmin + 0.5*f*v)*t
732  */
733  const double t = v / b; // stop time
734  const double d2 = (wmin + 0.5 * f * v) * t; // lateral distance covered until stop
735  assert(d2 > 0);
736  if (distSoFar + d2 >= D) {
737  // LC is completed during this phase
738  const double x = 0.5 * f * b;
739  const double y = wmin + f * v;
740  /* Solve D - distSoFar = y*t - x*t^2.
741  * 0 = x*t^2 - y*t/x + (D - distSoFar)/x
742  */
743  const double p = 0.5 * y / x;
744  const double q = (D - distSoFar) / x;
745  assert(p * p - q > 0);
746  const double t2 = p + sqrt(p * p - q);
747  return timeSoFar + t2;
748  } else {
749  distSoFar += d2;
750  timeSoFar += t;
751  //v = 0;
752  }
753  }
754  // If we didn't return yet this means the LC was not completed until the vehicle stops (if braking with rate b)
755  if (wmin == 0) {
756  // LC won't be completed if vehicle stands
757  return -1;
758  } else {
759  // complete LC with lateral speed wmin
760  return timeSoFar + (D - distSoFar) / wmin;
761  }
762 }
763 
764 SUMOTime
766  assert(isChangingLanes()); // Only to be called during ongoing lane change
768  if (lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATSTANDING) == lcParams.end() && lcParams.find(SUMO_ATTR_LCA_MAXSPEEDLATFACTOR) == lcParams.end()) {
771  } else {
773  }
774  }
775  // Using maxSpeedLat(Factor/Standing)
777 }
778 
779 
780 void
782  //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " @=" << &myVehicle << " set shadow approaching=" << link->getViaLaneOrLane()->getID() << "\n";
783  myApproachedByShadow.push_back(link);
784 }
785 
786 void
788  for (std::vector<MSLink*>::iterator it = myApproachedByShadow.begin(); it != myApproachedByShadow.end(); ++it) {
789  //std::cout << SIMTIME << " veh=" << myVehicle.getID() << " @=" << &myVehicle << " remove shadow approaching=" << (*it)->getViaLaneOrLane()->getID() << "\n";
790  (*it)->removeApproaching(&myVehicle);
791  }
792  myApproachedByShadow.clear();
793 }
794 
795 
796 
797 void
800  int oldstate = myVehicle.getLaneChangeModel().getOwnState();
801  if (myOwnState != newstate) {
803  // Calculate and set the lateral maneuver distance corresponding to the change request
804  // to induce a corresponding sublane change.
805  const int dir = (newstate & LCA_RIGHT) != 0 ? -1 : ((newstate & LCA_LEFT) != 0 ? 1 : 0);
806  // minimum distance to move the vehicle fully onto the lane at offset dir
807  const double latLaneDist = myVehicle.lateralDistanceToLane(dir);
808  if ((newstate & LCA_TRACI) != 0) {
809  if ((newstate & LCA_STAY) != 0) {
810  setManeuverDist(0.);
811  } else if (((newstate & LCA_RIGHT) != 0 && dir < 0)
812  || ((newstate & LCA_LEFT) != 0 && dir > 0)) {
813  setManeuverDist(latLaneDist);
814  }
815  }
816  if (myVehicle.hasInfluencer()) {
817  // lane change requests override sublane change requests
819  }
820 
821  }
822  setOwnState(newstate);
823  } else {
824  // Check for sublane change requests
826  const double maneuverDist = myVehicle.getInfluencer().getLatDist();
829  newstate |= LCA_TRACI;
830  if (myOwnState != newstate) {
831  setOwnState(newstate);
832  }
833  if (gDebugFlag2) {
834  std::cout << " traci influenced maneuverDist=" << maneuverDist << "\n";
835  }
836  }
837  }
838  if (gDebugFlag2) {
839  std::cout << SIMTIME << " veh=" << myVehicle.getID() << " stateAfterTraCI=" << toString((LaneChangeAction)newstate) << " original=" << toString((LaneChangeAction)oldstate) << "\n";
840  }
841 }
842 
843 void
846  myAlreadyChanged = true;
847 }
848 
849 void
851  if (follower.first != 0) {
852  myLastFollowerGap = follower.second + follower.first->getVehicleType().getMinGap();
853  myLastFollowerSecureGap = secGap;
854  myLastFollowerSpeed = follower.first->getSpeed();
855  }
856 }
857 
858 void
860  if (leader.first != 0) {
861  myLastLeaderGap = leader.second + myVehicle.getVehicleType().getMinGap();
862  myLastLeaderSecureGap = secGap;
863  myLastLeaderSpeed = leader.first->getSpeed();
864  }
865 }
866 
867 void
869  if (leader.first != 0) {
871  myLastOrigLeaderSecureGap = secGap;
872  myLastOrigLeaderSpeed = leader.first->getSpeed();
873  }
874 }
875 
876 void
878  int rightmost;
879  int leftmost;
880  vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
881  for (int i = rightmost; i <= leftmost; ++i) {
882  CLeaderDist vehDist = vehicles[i];
883  if (vehDist.first != 0) {
884  const MSVehicle* leader = &myVehicle;
885  const MSVehicle* follower = vehDist.first;
886  const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
887  if (netGap < myLastFollowerGap && netGap >= 0) {
888  myLastFollowerGap = netGap;
889  myLastFollowerSecureGap = follower->getCarFollowModel().getSecureGap(follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
890  myLastFollowerSpeed = follower->getSpeed();
891  }
892  }
893  }
894 }
895 
896 void
898  int rightmost;
899  int leftmost;
900  vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
901  for (int i = rightmost; i <= leftmost; ++i) {
902  CLeaderDist vehDist = vehicles[i];
903  if (vehDist.first != 0) {
904  const MSVehicle* leader = vehDist.first;
905  const MSVehicle* follower = &myVehicle;
906  const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
907  if (netGap < myLastLeaderGap && netGap >= 0) {
908  myLastLeaderGap = netGap;
909  myLastLeaderSecureGap = follower->getCarFollowModel().getSecureGap(follower->getSpeed(), leader->getSpeed(), leader->getCarFollowModel().getMaxDecel());
910  myLastLeaderSpeed = leader->getSpeed();
911  }
912  }
913  }
914 }
915 
916 void
918  int rightmost;
919  int leftmost;
920  vehicles.getSubLanes(&myVehicle, 0, rightmost, leftmost);
921  for (int i = rightmost; i <= leftmost; ++i) {
922  CLeaderDist vehDist = vehicles[i];
923  if (vehDist.first != 0) {
924  const MSVehicle* leader = vehDist.first;
925  const MSVehicle* follower = &myVehicle;
926  const double netGap = vehDist.second + follower->getVehicleType().getMinGap();
927  if (netGap < myLastOrigLeaderGap && netGap >= 0) {
928  myLastOrigLeaderGap = netGap;
930  myLastOrigLeaderSpeed = leader->getSpeed();
931  }
932  }
933  }
934 }
935 
936 
937 bool
939  const int stateRight = mySavedStateRight.second;
940  if (
941  (stateRight & LCA_STRATEGIC) != 0
942  && (stateRight & LCA_RIGHT) != 0
943  && (stateRight & LCA_BLOCKED) != 0) {
944  return true;
945  }
946  const int stateLeft = mySavedStateLeft.second;
947  if (
948  (stateLeft & LCA_STRATEGIC) != 0
949  && (stateLeft & LCA_LEFT) != 0
950  && (stateLeft & LCA_BLOCKED) != 0) {
951  return true;
952  }
953  return false;
954 }
bool myDontResetLCGaps
Flag to prevent resetting the memorized values for LC relevant gaps until the LC output is triggered ...
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
static double gLateralResolution
Definition: MSGlobals.h:85
A lane change model developed by J. Erdmann.
Definition: MSLCM_SL2015.h:38
#define DIST2SPEED(x)
Definition: SUMOTime.h:49
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
const SubParams & getLCParams() const
Returns the LC parameter.
saves leader/follower vehicles and their distances relative to an ego vehicle
Definition: MSLeaderInfo.h:133
std::shared_ptr< MSLeaderDistanceInfo > myRightLeaders
double myLastLeaderSpeed
speeds of surrounding vehicles at the time of lane change
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:670
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:80
long long int SUMOTime
Definition: SUMOTime.h:35
std::pair< int, int > mySavedStateRight
#define SPEED2DIST(x)
Definition: SUMOTime.h:47
std::map< SumoXMLAttr, std::string > SubParams
sub-model parameters
std::shared_ptr< MSLeaderDistanceInfo > myLeftLeaders
int myPreviousState
lane changing state from the previous simulation step
virtual double getAssumedDecelForLaneChangeDuration() const
Returns a deceleration value which is used for the estimation of the duration of a lane change...
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:561
void setLeaderGaps(CLeaderDist, double secGap)
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)
void clearNeighbors()
Clear info on neighboring vehicle from previous step.
double myLastLeaderGap
the actual minimum longitudinal distances to vehicles on the target lane
int getShadowDirection() const
return the direction in which the current shadow lane lies
double getManeuverDist() const
Returns the remaining unblocked distance for the current maneuver. (only used by sublane model) ...
double myLaneChangeCompletion
progress of the lane change maneuver 0:started, 1:complete
static bool haveLateralDynamics()
whether any kind of lateral dynamics is active
double getPositionOnLane() const
Get the vehicle&#39;s position along the lane.
Definition: MSVehicle.h:397
double myPreviousManeuverDist
Maneuver distance from the previous simulation step.
Notification
Definition of a vehicle state.
virtual void resetManeuverReservation(MSVehicle *v)
Unregisters a vehicle, which previously registered for maneuvering into this lane.
Definition: MSLane.cpp:312
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
Wants go to the right.
static bool myLCOutput
whether to record lane-changing
double lateralDistanceToLane(const int offset) const
Get the minimal lateral distance required to move fully onto the lane at given offset.
Definition: MSVehicle.cpp:5366
std::shared_ptr< MSLeaderDistanceInfo > myRightFollowers
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
double myLastOrigLeaderGap
acutal and secure distance to closest leader vehicle on the original when performing lane change ...
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
double getAngleOffset() const
return the angle offset during a continuous change maneuver
#define DEBUG_COND
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:70
virtual std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this laneChangeModel. Throw exception for unsupported key ...
void leftByLaneChange(MSVehicle *v)
Definition: MSLane.cpp:2641
MSLane * myShadowLane
A lane that is partially occupied by the front of the vehicle but that is not the primary lane...
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const std::string & getID() const
Returns the id.
Definition: Named.h:77
virtual bool predInteraction(const std::pair< MSVehicle *, double > &leader)
#define TIME2STEPS(x)
Definition: SUMOTime.h:59
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition: MSLane.cpp:268
const int VTYPEPARS_MAXSPEED_LAT_SET
Wants go to the left.
MSLane * myTargetLane
The target lane for the vehicle&#39;s current maneuver.
MSLane * getParallelLane(int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to this one or 0 if it does not exist.
Definition: MSLane.cpp:2187
virtual void setManeuverReservation(MSVehicle *v)
Registers the lane change intentions (towards this lane) for the given vehicle.
Definition: MSLane.cpp:301
double getWidth() const
Returns the lane&#39;s width.
Definition: MSLane.h:557
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:32
SUMOTime remainingTime() const
Compute the remaining time until LC completion.
void enterLaneAtLaneChange(MSLane *enteredLane)
Update when the vehicle enters a new lane in the laneChange step.
Definition: MSVehicle.cpp:4448
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:239
void memorizeGapsAtLCInit()
Control for resetting the memorized values for LC relevant gaps until the LC output is triggered in t...
void checkTraCICommands()
Check for commands issued for the vehicle via TraCI and apply the appropriate state changes For the s...
MSAbstractLaneChangeModel & getLaneChangeModel()
Definition: MSVehicle.cpp:4609
#define SIMTIME
Definition: SUMOTime.h:64
Right blinker lights are switched on.
Definition: MSVehicle.h:1180
bool wasSet(int what) const
Returns whether the given parameter was set.
Definition: MSVehicleType.h:83
std::vector< double > myShadowFurtherLanesPosLat
void setFollowerGaps(CLeaderDist follower, double secGap)
Needs to stay on the current lane.
const LaneChangeModel myModel
the type of this model
static bool myAllowOvertakingRight
whether overtaking on the right is permitted
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
LaneChangeModel
void leaveLane(const MSMoveReminder::Notification reason, const MSLane *approachedLane=0)
Update of members if vehicle leaves a new lane in the lane change step or at arrival.
Definition: MSVehicle.cpp:4559
The vehicle changes lanes (micro only)
virtual double estimateLCDuration(const double speed, const double remainingManeuverDist, const double decel) const
Calculates the maximal time needed to complete a lane change maneuver if lcMaxSpeedLatFactor and lcMa...
const MSCFModel & getCarFollowModel() const
Returns the vehicle&#39;s car following model definition.
Definition: MSVehicle.h:894
The action has not been determined.
A lane change model developed by D. Krajzewicz, J. Erdmann et al. between 2004 and 2013...
Definition: MSLCM_LC2013.h:48
int getIndex() const
Returns the lane&#39;s index.
Definition: MSLane.h:564
Left blinker lights are switched on.
Definition: MSVehicle.h:1182
std::vector< MSLane * > myNoPartiallyOccupatedByShadow
double myManeuverDist
The complete lateral distance the vehicle wants to travel to finish its maneuver Only used by sublane...
blocked in all directions
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:48
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition: MSLane.cpp:282
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it&#39;s primary lane ...
Definition: MSVehicle.cpp:5416
double updateFurtherLanes(std::vector< MSLane *> &furtherLanes, std::vector< double > &furtherLanesPosLat, const std::vector< MSLane *> &passedLanes)
update a vector of further lanes and return the new backPos
Definition: MSVehicle.cpp:3922
virtual double getSecureGap(const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
Definition: MSCFModel.h:328
void enteredByLaneChange(MSVehicle *v)
Definition: MSLane.cpp:2648
std::vector< MSLane * > myShadowFurtherLanes
const std::vector< MSLane * > & getFurtherLanes() const
Definition: MSVehicle.h:792
double getSpeedLimit() const
Returns the lane&#39;s maximum allowed speed.
Definition: MSLane.h:533
#define STEPS2TIME(x)
Definition: SUMOTime.h:57
void getSubLanes(const MSVehicle *veh, double latOffset, int &rightmost, int &leftmost) const
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition: MSLane.cpp:1013
virtual double interactionGap(const MSVehicle *const veh, double vL) const
Returns the maximum gap at which an interaction between both vehicles occurs.
Definition: MSCFModel.cpp:224
The action is needed to follow the route (navigational lc)
int myLaneChangeDirection
direction of the lane change maneuver -1 means right, 1 means left
bool hasInfluencer() const
Definition: MSVehicle.h:1680
bool pastMidpoint() const
return whether the vehicle passed the midpoint of a continuous lane change maneuver ...
double getMinGap() const
Get the free space in front of vehicles of this class.
virtual void changed()=0
static void initGlobalOptions(const OptionsCont &oc)
init global model parameters
double getMaxDecel() const
Get the vehicle type&#39;s maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:218
void fixPosition()
repair errors in vehicle position after changing between internal edges
Definition: MSVehicle.cpp:5034
void setShadowApproachingInformation(MSLink *link) const
set approach information for the shadow vehicle
double myLastLeaderSecureGap
the minimum longitudinal distances to vehicles on the target lane that would be necessary for stringe...
int myOwnState
The current state of the vehicle.
MSLane * determineTargetLane(int &targetDir) const
virtual bool debugVehicle() const
whether the current vehicles shall be debugged
bool cancelRequest(int state, int laneOffset)
whether the influencer cancels the given request
const SUMOVTypeParameter & getParameter() const
double getLateralPositionOnLane() const
Get the vehicle&#39;s lateral position on the lane.
Definition: MSVehicle.h:434
void setOrigLeaderGaps(CLeaderDist, double secGap)
bool startLaneChangeManeuver(MSLane *source, MSLane *target, int direction)
start the lane change maneuver and return whether it continues
const std::vector< double > & getFurtherLanesPosLat() const
Definition: MSVehicle.h:796
double getMaxSpeedLat() const
Get vehicle&#39;s maximum lateral speed [m/s].
void primaryLaneChanged(MSLane *source, MSLane *target, int direction)
called once when the vehicles primary lane changes
MSVehicle & myVehicle
The vehicle this lane-changer belongs to.
std::pair< const MSVehicle *, double > CLeaderDist
Definition: MSLeaderInfo.h:35
trigger: the time of the step
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:5817
std::shared_ptr< MSLeaderDistanceInfo > myLeftFollowers
Cached info on lc-relevant neighboring vehicles.
LaneChangeAction
The state of a vehicle&#39;s lane-change behavior.
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 void setOwnState(const int state)
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition: MSLane.cpp:3508
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type definition.
void setTentativeLaneAndPosition(MSLane *lane, double pos, double posLat=0)
set tentative lane and position during insertion to ensure that all cfmodels work (some of them requi...
Definition: MSVehicle.cpp:5240
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
A storage for options typed value containers)
Definition: OptionsCont.h:90
std::vector< MSLane * > myFurtherTargetLanes
double mySpeedLat
the current lateral speed
const std::string & getID() const
Returns the name of the vehicle type.
Definition: MSVehicleType.h:94
The abstract direction of a link.
A lane change model developed by D. Krajzewicz between 2004 and 2010.
Definition: MSLCM_DK2008.h:40
virtual double computeSpeedLat(double latDist, double &maneuverDist)
decides the next lateral speed depending on the remaining lane change distance to be covered and upda...
const std::shared_ptr< MSLeaderDistanceInfo > getFollowers(const int dir)
Returns the neighboring, lc-relevant followers for the last step in the requested direction...
The action is due to a TraCI request.
bool gDebugFlag2
Definition: StdDefs.cpp:34
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
void changedToOpposite()
called when a vehicle changes between lanes in opposite directions
void switchOffSignal(int signal)
Switches the given signal off.
Definition: MSVehicle.h:1241
void switchOnSignal(int signal)
Switches the given signal on.
Definition: MSVehicle.h:1233
double myCommittedSpeed
the speed when committing to a change maneuver
#define NUMERICAL_EPS
Definition: config.h:145
std::vector< MSLink * > myApproachedByShadow
links which are approached by the shadow vehicle
const std::shared_ptr< MSLeaderDistanceInfo > getLeaders(const int dir)
Returns the neighboring, lc-relevant leaders for the last step in the requested direction.
MSLane * getShadowLane() const
Returns the lane the vehicle&#39;s shadow is on during continuous/sublane lane change.
void setManeuverDist(const double dist)
Updates the remaining distance for the current maneuver while it is continued within non-action steps...
virtual void updateSafeLatDist(const double travelledLatDist)
Updates the value of safe lateral distances (in SL2015) during maneuver continuation in non-action st...
int myPreviousState2
lane changing state from step before the previous simulation step
double getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:477
int influenceChangeDecision(int state)
allow TraCI to influence a lane change decision
Definition: MSVehicle.cpp:5841
double myLastLateralGapLeft
the minimum lateral gaps to other vehicles that were found when last changing to the left and right ...
double getLatDist() const
Definition: MSVehicle.h:1589
static SUMOTime gLaneChangeDuration
Definition: MSGlobals.h:82
static MSAbstractLaneChangeModel * build(LaneChangeModel lcm, MSVehicle &vehicle)
Factory method for instantiating new lane changing models.
const std::string & getID() const
Returns the name of the vehicle.
Representation of a lane in the micro simulation.
Definition: MSLane.h:83
bool myAlreadyChanged
whether the vehicle has already moved this step
const MSCFModel & myCarFollowModel
The vehicle&#39;s car following model.
std::pair< int, int > mySavedStateLeft
bool myAmOpposite
whether the vehicle is driving in the opposite direction
MSAbstractLaneChangeModel(MSVehicle &v, const LaneChangeModel model)
Constructor.
void saveLCState(const int dir, const int stateWithoutTraCI, const int state)
Interface for lane-change models.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
double getWidth() const
Returns the vehicle&#39;s width.
virtual bool congested(const MSVehicle *const neighLeader)
void endLaneChangeManeuver(const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_LANE_CHANGE)
void updateDriveItems()
Check whether the drive items (myLFLinkLanes) are up to date, and update them if required.
Definition: MSVehicle.cpp:3281
bool congested() const
Definition: MSVehicle.h:718
virtual ~MSAbstractLaneChangeModel()
Destructor.