1 package org.opentrafficsim.road.gtu.lane.tactical.util.lmrs;
2
3 import java.util.SortedSet;
4
5 import org.djunits.unit.AccelerationUnit;
6 import org.djunits.value.vdouble.scalar.Acceleration;
7 import org.djunits.value.vdouble.scalar.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djunits.value.vdouble.scalar.Speed;
10 import org.djutils.exceptions.Try;
11 import org.opentrafficsim.base.parameters.ParameterException;
12 import org.opentrafficsim.base.parameters.ParameterTypes;
13 import org.opentrafficsim.base.parameters.Parameters;
14 import org.opentrafficsim.core.gtu.perception.EgoPerception;
15 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
16 import org.opentrafficsim.core.network.LateralDirectionality;
17 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
18 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
19 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
20 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
21 import org.opentrafficsim.road.gtu.lane.perception.categories.InfrastructurePerception;
22 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.NeighborsPerception;
23 import org.opentrafficsim.road.gtu.lane.perception.object.PerceivedGtu;
24 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
25 import org.opentrafficsim.road.gtu.lane.tactical.util.CarFollowingUtil;
26 import org.opentrafficsim.road.network.LaneChangeInfo;
27 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
28
29
30
31
32
33
34
35
36
37
38
39 public interface Synchronization extends LmrsParameters
40 {
41
42
43 Synchronization DEADEND = new Synchronization()
44 {
45 @Override
46 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
47 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
48 final LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException
49 {
50 Acceleration a = Acceleration.POSITIVE_INFINITY;
51
52 Length remainingDist = Length.POSITIVE_INFINITY;
53 Speed speed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
54 Acceleration bCrit = params.getParameter(ParameterTypes.BCRIT);
55 remainingDist = remainingDist.minus(params.getParameter(ParameterTypes.S0));
56 if (remainingDist.le0())
57 {
58 if (speed.gt0())
59 {
60 a = Acceleration.min(a, bCrit.neg());
61 }
62 else
63 {
64 a = Acceleration.ONE;
65 }
66 }
67 else
68 {
69 Acceleration bMin = new Acceleration(.5 * speed.si * speed.si / remainingDist.si, AccelerationUnit.SI);
70 if (bMin.ge(bCrit))
71 {
72 a = Acceleration.min(a, bMin.neg());
73 }
74 }
75 return a;
76 }
77
78 @Override
79 public String toString()
80 {
81 return "DEADEND";
82 }
83 };
84
85
86 Synchronization PASSIVE = new Synchronization()
87 {
88 @Override
89 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
90 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
91 final LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException
92 {
93 Acceleration a = DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, initiatedLaneChange);
94 if (a.lt(params.getParameter(ParameterTypes.BCRIT).neg()))
95 {
96 return a;
97 }
98 double dCoop = params.getParameter(DCOOP);
99 RelativeLane relativeLane = new RelativeLane(lat, 1);
100
101 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> set =
102 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(relativeLane);
103 PerceivedGtu leader = null;
104 if (set != null)
105 {
106 if (desire >= dCoop && !set.isEmpty())
107 {
108 leader = set.first();
109 }
110 else
111 {
112 for (PerceivedGtu gtu : set)
113 {
114 if (gtu.getSpeed().gt0())
115 {
116 leader = gtu;
117 break;
118 }
119 }
120 }
121 }
122 Speed ownSpeed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
123 if (leader != null)
124 {
125 Length headway = leader.getDistance();
126 Acceleration aSingle =
127 LmrsUtil.singleAcceleration(headway, ownSpeed, leader.getSpeed(), desire, params, sli, cfm);
128 a = Acceleration.min(a, aSingle);
129 a = gentleUrgency(a, desire, params);
130 }
131 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders =
132 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(RelativeLane.CURRENT);
133 if (!leaders.isEmpty() && leaders.first().getSpeed().lt(params.getParameter(ParameterTypes.VCONG)))
134 {
135 Length headway = leaders.first().getDistance();
136 Acceleration aSingle =
137 LmrsUtil.singleAcceleration(headway, ownSpeed, leaders.first().getSpeed(), desire, params, sli, cfm);
138 aSingle = gentleUrgency(aSingle, desire, params);
139 a = Acceleration.min(a, aSingle);
140 }
141
142
143 Length xMerge =
144 getMergeDistance(perception, lat).minus(perception.getPerceptionCategory(EgoPerception.class).getLength());
145 if (xMerge.gt0())
146 {
147 Acceleration aMerge = LmrsUtil.singleAcceleration(xMerge, ownSpeed, Speed.ZERO, desire, params, sli, cfm);
148 a = Acceleration.max(a, aMerge);
149 }
150 return a;
151 }
152
153 @Override
154 public String toString()
155 {
156 return "PASSIVE";
157 }
158 };
159
160
161
162
163
164
165
166 Synchronization ALIGN_GAP = new Synchronization()
167 {
168 @Override
169 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
170 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
171 final LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException
172 {
173 Acceleration a = Acceleration.POSITIVE_INFINITY;
174 EgoPerception<?, ?> ego = perception.getPerceptionCategory(EgoPerception.class);
175 Speed ownSpeed = ego.getSpeed();
176 RelativeLane relativeLane = new RelativeLane(lat, 1);
177 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders =
178 perception.getPerceptionCategory(NeighborsPerception.class).getLeaders(relativeLane);
179 if (!leaders.isEmpty())
180 {
181 PerceivedGtu leader = leaders.first();
182 Length gap = leader.getDistance();
183 LmrsUtil.setDesiredHeadway(params, desire, true);
184 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> followers =
185 perception.getPerceptionCategory(NeighborsPerception.class).getFollowers(relativeLane);
186 if (!followers.isEmpty())
187 {
188 PerceivedGtu follower = followers.first();
189 Length netGap = leader.getDistance().plus(follower.getDistance()).times(0.5);
190 gap = Length.max(gap, leader.getDistance().minus(netGap).plus(cfm.desiredHeadway(params, ownSpeed)));
191 }
192 a = CarFollowingUtil.followSingleLeader(cfm, params, ownSpeed, sli, gap, leader.getSpeed());
193 LmrsUtil.resetDesiredHeadway(params);
194
195 a = gentleUrgency(a, desire, params);
196 }
197 a = Acceleration.min(a,
198 DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, initiatedLaneChange));
199
200 Length xMerge = getMergeDistance(perception, lat);
201 if (xMerge.gt0())
202 {
203 Acceleration aMerge = LmrsUtil.singleAcceleration(xMerge, ownSpeed, Speed.ZERO, desire, params, sli, cfm);
204 a = Acceleration.max(a, aMerge);
205 }
206 return a;
207 }
208
209 @Override
210 public String toString()
211 {
212 return "ALIGN_GAP";
213 }
214 };
215
216
217 Synchronization PASSIVE_MOVING = new Synchronization()
218 {
219 @Override
220 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
221 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
222 final LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException
223 {
224 double dCoop = params.getParameter(DCOOP);
225 Speed ownSpeed = perception.getPerceptionCategory(EgoPerception.class).getSpeed();
226 if (desire < dCoop && ownSpeed.si < params.getParameter(ParameterTypes.LOOKAHEAD).si
227 / params.getParameter(ParameterTypes.T0).si)
228 {
229 return DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, initiatedLaneChange);
230 }
231 return PASSIVE.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, initiatedLaneChange);
232 }
233
234 @Override
235 public String toString()
236 {
237 return "PASSIVE_MOVING";
238 }
239 };
240
241
242 Synchronization ACTIVE = new Synchronization()
243 {
244 @Override
245 public Acceleration synchronize(final LanePerception perception, final Parameters params, final SpeedLimitInfo sli,
246 final CarFollowingModel cfm, final double desire, final LateralDirectionality lat, final LmrsData lmrsData,
247 final LateralDirectionality initiatedLaneChange) throws ParameterException, OperationalPlanException
248 {
249
250 Acceleration b = params.getParameter(ParameterTypes.B);
251 Duration tMin = params.getParameter(ParameterTypes.TMIN);
252 Duration tMax = params.getParameter(ParameterTypes.TMAX);
253 Speed vCong = params.getParameter(ParameterTypes.VCONG);
254 Length x0 = params.getParameter(ParameterTypes.LOOKAHEAD);
255 Duration t0 = params.getParameter(ParameterTypes.T0);
256 Duration lc = params.getParameter(ParameterTypes.LCDUR);
257 Speed tagSpeed = x0.divide(t0);
258 double dCoop = params.getParameter(DCOOP);
259 EgoPerception<?, ?> ego = perception.getPerceptionCategory(EgoPerception.class);
260 Speed ownSpeed = ego.getSpeed();
261 Length ownLength = ego.getLength();
262 Length dx = perception.getGtu().getFront().dx();
263
264
265 InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
266 SortedSet<LaneChangeInfo> info = infra.getLegalLaneChangeInfo(RelativeLane.CURRENT);
267
268
269 Length xMerge = getMergeDistance(perception, lat);
270 int nCur = 0;
271 Length xCur = Length.POSITIVE_INFINITY;
272 for (LaneChangeInfo lcInfo : info)
273 {
274 int nCurTmp = lcInfo.numberOfLaneChanges();
275
276 Length xCurTmp = lcInfo.remainingDistance().minus(ownLength.times(2.0 * nCurTmp)).minus(dx);
277 if (xCurTmp.lt(xCur))
278 {
279 nCur = nCurTmp;
280 xCur = xCurTmp;
281 }
282 }
283
284
285
286 Length xMergeSync = xCur.minus(Length.ofSI(.5 * ownSpeed.si * ownSpeed.si / b.si));
287 xMergeSync = Length.min(xMerge, xMergeSync);
288
289
290 NeighborsPerception neighbors = perception.getPerceptionCategory(NeighborsPerception.class);
291 RelativeLane lane = new RelativeLane(lat, 1);
292 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders = neighbors.getLeaders(lane);
293 PerceivedGtu syncVehicle = lmrsData.getSyncVehicle(leaders);
294 if (syncVehicle != null && ((syncVehicle.getSpeed().lt(vCong) && syncVehicle.getDistance().lt(xMergeSync))
295 || syncVehicle.getDistance().gt(xCur)))
296 {
297 syncVehicle = null;
298 }
299
300
301 if (leaders != null && syncVehicle == null)
302 {
303 Length maxDistance = Length.min(x0, xCur);
304 for (PerceivedGtu leader : leaders)
305 {
306 if (leader.getDistance().lt(maxDistance))
307 {
308 if ((leader.getDistance().gt(xMergeSync) || leader.getSpeed().gt(vCong))
309 && tagAlongAcceleration(leader, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm)
310 .gt(b.neg()))
311 {
312 syncVehicle = leader;
313 break;
314 }
315 }
316 else
317 {
318 break;
319 }
320 }
321 }
322
323
324 PerceivedGtu up;
325 PerceptionCollectable<PerceivedGtu, LaneBasedGtu> followers = neighbors.getFollowers(lane);
326 PerceivedGtu follower = followers == null || followers.isEmpty() ? null
327 : followers.first().moved(
328 followers.first().getDistance().plus(ownLength).plus(followers.first().getLength()).neg(),
329 followers.first().getSpeed(), followers.first().getAcceleration());
330 boolean upOk;
331 if (syncVehicle == null)
332 {
333 up = null;
334 upOk = false;
335 }
336 else
337 {
338 up = getFollower(syncVehicle, leaders, follower, ownLength);
339 upOk = up == null ? false
340 : tagAlongAcceleration(up, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm).gt(b.neg());
341 }
342 while (syncVehicle != null
343 && up != null && (upOk || (!canBeAhead(up, xCur, nCur, ownSpeed, ownLength, tagSpeed, dCoop, b, tMin, tMax,
344 x0, t0, lc, desire) && desire > dCoop))
345 && (up.getDistance().gt(xMergeSync) || up.getSpeed().gt(vCong)))
346 {
347 if (up.equals(follower))
348 {
349
350 syncVehicle = null;
351 up = null;
352 break;
353 }
354 syncVehicle = up;
355 up = getFollower(syncVehicle, leaders, follower, ownLength);
356 upOk = up == null ? false
357 : tagAlongAcceleration(up, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm).gt(b.neg());
358 }
359 lmrsData.setSyncVehicle(syncVehicle);
360
361
362 Acceleration a = DEADEND.synchronize(perception, params, sli, cfm, desire, lat, lmrsData, initiatedLaneChange);
363 if (syncVehicle != null)
364 {
365 a = gentleUrgency(tagAlongAcceleration(syncVehicle, ownSpeed, ownLength, tagSpeed, desire, params, sli, cfm),
366 desire, params);
367 }
368 else if (nCur > 0 && (follower != null || (leaders != null && !leaders.isEmpty())))
369 {
370
371 if (follower != null && !canBeAhead(follower, xCur, nCur, ownSpeed, ownLength, tagSpeed, dCoop, b, tMin, tMax,
372 x0, t0, lc, desire))
373 {
374
375 double c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop).si;
376 double t = (xCur.si - follower.getDistance().si - c) / follower.getSpeed().si;
377 double xGap = ownSpeed.si * (tMin.si + desire * (tMax.si - tMin.si));
378 Acceleration acc = Acceleration.ofSI(2 * (xCur.si - c - ownSpeed.si * t - xGap) / (t * t));
379 if (follower.getSpeed().eq0() || acc.si < -ownSpeed.si / t || t < 0)
380 {
381
382
383 a = stopForEnd(xCur, xMerge, params, ownSpeed, cfm, sli);
384 }
385 else
386 {
387 a = gentleUrgency(acc, desire, params);
388 }
389 }
390 else if (!LmrsUtil.acceptLaneChange(perception, params, sli, cfm, desire, ownSpeed, Acceleration.ZERO, lat,
391 lmrsData.getGapAcceptance()))
392 {
393 a = stopForEnd(xCur, xMerge, params, ownSpeed, cfm, sli);
394
395 if (leaders != null && !leaders.isEmpty())
396 {
397 double c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop).si;
398 double t = (xCur.si - leaders.first().getDistance().si - c) / leaders.first().getSpeed().si;
399 double xGap = ownSpeed.si * (tMin.si + desire * (tMax.si - tMin.si));
400 Acceleration acc = Acceleration.ofSI(2 * (xCur.si - c - ownSpeed.si * t - xGap) / (t * t));
401 if (!(leaders.first().getSpeed().eq0() || acc.si < -ownSpeed.si / t || t < 0))
402 {
403 a = Acceleration.max(a, acc);
404 }
405 }
406 }
407 }
408
409
410 if (nCur > 1)
411 {
412 if (xMerge.gt0())
413 {
414
415 Speed vMerge = xCur.lt(xMerge) ? Speed.ZERO
416 : xCur.minus(xMerge).divide(t0.times((1 - dCoop) * (nCur - 1)).plus(lc));
417 vMerge = Speed.max(vMerge, x0.divide(t0));
418 a = Acceleration.min(a, CarFollowingUtil.approachTargetSpeed(cfm, params, ownSpeed, sli, xMerge, vMerge));
419 }
420 else
421 {
422
423 Length c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop);
424 if (xCur.lt(c))
425 {
426 a = Acceleration.min(a, b.neg());
427 }
428 }
429 }
430 return a;
431 }
432
433 @Override
434 public String toString()
435 {
436 return "ACTIVE";
437 }
438 };
439
440
441
442
443
444
445
446
447 static Length getMergeDistance(final LanePerception perception, final LateralDirectionality lat)
448 throws OperationalPlanException
449 {
450 InfrastructurePerception infra = perception.getPerceptionCategory(InfrastructurePerception.class);
451 Length dx = Try.assign(() -> perception.getGtu().getFront().dx(), "Could not obtain GTU.");
452 Length xMergeRef = infra.getLegalLaneChangePossibility(RelativeLane.CURRENT, lat);
453 if (xMergeRef.gt0() && xMergeRef.lt(dx))
454 {
455 return Length.ZERO;
456 }
457 Length xMerge = xMergeRef.minus(dx);
458 return xMerge.lt0() ? xMerge.neg() : Length.ZERO;
459 }
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475 Acceleration synchronize(LanePerception perception, Parameters params, SpeedLimitInfo sli, CarFollowingModel cfm,
476 double desire, LateralDirectionality lat, LmrsData lmrsData, LateralDirectionality initiatedLaneChange)
477 throws ParameterException, OperationalPlanException;
478
479
480
481
482
483
484
485
486
487
488 static Acceleration gentleUrgency(final Acceleration a, final double desire, final Parameters params)
489 throws ParameterException
490 {
491 Acceleration b = params.getParameter(ParameterTypes.B);
492 if (a.si > -b.si)
493 {
494 return a;
495 }
496 double dCoop = params.getParameter(DCOOP);
497 if (desire < dCoop)
498 {
499 return b.neg();
500 }
501 Acceleration bCrit = params.getParameter(ParameterTypes.BCRIT);
502 double f = (desire - dCoop) / (1.0 - dCoop);
503 Acceleration lim = Acceleration.interpolate(b.neg(), bCrit.neg(), f);
504 return Acceleration.max(a, lim);
505 }
506
507
508
509
510
511
512
513
514
515 static PerceivedGtu getFollower(final PerceivedGtu gtu, final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> leaders,
516 final PerceivedGtu follower, final Length ownLength)
517 {
518 PerceivedGtu last = null;
519 for (PerceivedGtu leader : leaders)
520 {
521 if (leader.equals(gtu))
522 {
523 return last == null ? follower : last;
524 }
525 last = leader;
526 }
527 return null;
528 }
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 @SuppressWarnings("checkstyle:parameternumber")
544 static Acceleration tagAlongAcceleration(final PerceivedGtu leader, final Speed followerSpeed, final Length followerLength,
545 final Speed tagSpeed, final double desire, final Parameters params, final SpeedLimitInfo sli,
546 final CarFollowingModel cfm) throws ParameterException
547 {
548 double dCoop = params.getParameter(DCOOP);
549 double tagV = followerSpeed.lt(tagSpeed) ? 1.0 - followerSpeed.si / tagSpeed.si : 0.0;
550 double tagD = desire <= dCoop ? 1.0 : 1.0 - (desire - dCoop) / (1.0 - dCoop);
551 double tagExtent = tagV < tagD ? tagV : tagD;
552
553
554
555
556
557
558
559
560
561
562
563 Length headwayAdjustment = params.getParameter(ParameterTypes.S0)
564 .plus(Length.min(followerLength, leader.getLength()).times(0.5)).times(tagExtent);
565 Acceleration a = LmrsUtil.singleAcceleration(leader.getDistance().plus(headwayAdjustment), followerSpeed,
566 leader.getSpeed(), desire, params, sli, cfm);
567 return a;
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589 static boolean canBeAhead(final PerceivedGtu adjacentVehicle, final Length xCur, final int nCur, final Speed ownSpeed,
590 final Length ownLength, final Speed tagSpeed, final double dCoop, final Acceleration b, final Duration tMin,
591 final Duration tMax, final Length x0, final Duration t0, final Duration lc, final double desire)
592 throws ParameterException
593 {
594
595
596 boolean tmp = LmrsUtil
597 .singleAcceleration(adjacentVehicle.getDistance().neg().minus(adjacentVehicle.getLength()).minus(ownLength),
598 adjacentVehicle.getSpeed(), ownSpeed, desire, adjacentVehicle.getBehavior().getParameters(),
599 adjacentVehicle.getBehavior().getSpeedLimitInfo(), adjacentVehicle.getBehavior().getCarFollowingModel())
600 .gt(b.neg());
601 if (adjacentVehicle.getDistance().lt(ownLength.neg())
602 && ((desire > dCoop && tmp) || (ownSpeed.lt(tagSpeed) && adjacentVehicle.getSpeed().lt(tagSpeed))))
603 {
604 return true;
605 }
606
607
608
609
610
611
612
613
614
615
616
617
618
619 Length c = requiredBufferSpace(ownSpeed, nCur, x0, t0, lc, dCoop);
620 double t = (xCur.si - c.si) / ownSpeed.si;
621 double xGap = adjacentVehicle.getSpeed().si * (tMin.si + desire * (tMax.si - tMin.si));
622 return 0.0 < t && t < (xCur.si - adjacentVehicle.getDistance().si - ownLength.si - adjacentVehicle.getLength().si - c.si
623 - xGap) / adjacentVehicle.getSpeed().si;
624 }
625
626
627
628
629
630
631
632
633
634
635
636 static Length requiredBufferSpace(final Speed speed, final int nCur, final Length x0, final Duration t0, final Duration lc,
637 final double dCoop)
638 {
639 Length xCrit = speed.times(t0);
640 xCrit = Length.max(xCrit, x0);
641 return speed.times(lc).plus(xCrit.times((nCur - 1.0) * (1.0 - dCoop)));
642 }
643
644
645
646
647
648
649
650
651
652
653
654
655 static Acceleration stopForEnd(final Length xCur, final Length xMerge, final Parameters params, final Speed ownSpeed,
656 final CarFollowingModel cfm, final SpeedLimitInfo sli) throws ParameterException
657 {
658 if (xCur.lt0())
659 {
660
661 return Acceleration.max(params.getParameter(ParameterTypes.BCRIT).neg(),
662 CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xMerge));
663 }
664 LmrsUtil.setDesiredHeadway(params, 1.0, true);
665 Acceleration a = CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xCur);
666 if (a.lt0())
667 {
668
669 a = Acceleration.min(a, params.getParameter(ParameterTypes.B).neg());
670
671 if (xMerge.gt0())
672 {
673 a = Acceleration.max(a, CarFollowingUtil.stop(cfm, params, ownSpeed, sli, xMerge));
674 }
675 }
676 else
677 {
678 a = Acceleration.POSITIVE_INFINITY;
679 }
680 LmrsUtil.resetDesiredHeadway(params);
681 return a;
682 }
683
684
685
686
687
688
689
690 static PerceivedGtu getTargetLeader(final PerceivedGtu gtu, final SortedSet<PerceivedGtu> leaders)
691 {
692 for (PerceivedGtu leader : leaders)
693 {
694 if (leader.getDistance().gt(gtu.getDistance()))
695 {
696 return leader;
697 }
698 }
699 return null;
700 }
701
702 }