1 package org.opentrafficsim.road.gtu.lane.tactical.util;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.SortedMap;
8 import java.util.TreeMap;
9 import java.util.UUID;
10
11 import org.djunits.unit.AccelerationUnit;
12 import org.djunits.unit.DurationUnit;
13 import org.djunits.unit.LengthUnit;
14 import org.djunits.value.vdouble.scalar.Acceleration;
15 import org.djunits.value.vdouble.scalar.Duration;
16 import org.djunits.value.vdouble.scalar.Length;
17 import org.djunits.value.vdouble.scalar.Speed;
18 import org.djunits.value.vdouble.scalar.Time;
19 import org.opentrafficsim.base.parameters.ParameterException;
20 import org.opentrafficsim.base.parameters.ParameterTypeAcceleration;
21 import org.opentrafficsim.base.parameters.ParameterTypeDouble;
22 import org.opentrafficsim.base.parameters.ParameterTypeDuration;
23 import org.opentrafficsim.base.parameters.ParameterTypeLength;
24 import org.opentrafficsim.base.parameters.ParameterTypes;
25 import org.opentrafficsim.base.parameters.Parameters;
26 import org.opentrafficsim.base.parameters.constraint.ConstraintInterface;
27 import org.opentrafficsim.core.gtu.GTUException;
28 import org.opentrafficsim.core.gtu.GTUType;
29 import org.opentrafficsim.core.gtu.TurnIndicatorIntent;
30 import org.opentrafficsim.core.network.Node;
31 import org.opentrafficsim.core.network.route.Route;
32 import org.opentrafficsim.road.gtu.animation.Blockable;
33 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
34 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
35 import org.opentrafficsim.road.gtu.lane.perception.PerceptionIterable;
36 import org.opentrafficsim.road.gtu.lane.perception.headway.AbstractHeadwayGTU;
37 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayConflict;
38 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
39 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUSimple;
40 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayStopLine;
41 import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
42 import org.opentrafficsim.road.gtu.lane.tactical.pt.BusSchedule;
43 import org.opentrafficsim.road.network.lane.CrossSectionLink;
44 import org.opentrafficsim.road.network.lane.conflict.BusStopConflictRule;
45 import org.opentrafficsim.road.network.lane.conflict.Conflict;
46 import org.opentrafficsim.road.network.lane.conflict.ConflictRule;
47 import org.opentrafficsim.road.network.lane.conflict.ConflictType;
48 import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
49
50 import nl.tudelft.simulation.language.Throw;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public final class ConflictUtil
70 {
71
72
73 public static final ParameterTypeDuration MIN_GAP = new ParameterTypeDuration("minGap", "Minimum gap for conflicts.",
74 new Duration(0.000001, DurationUnit.SECOND), ConstraintInterface.POSITIVE);
75
76
77 public static final ParameterTypeAcceleration B = ParameterTypes.B;
78
79
80 public static final ParameterTypeAcceleration BCRIT = ParameterTypes.BCRIT;
81
82
83 public static final ParameterTypeLength S0 = ParameterTypes.S0;
84
85
86 public static final ParameterTypeLength S0_CONF = new ParameterTypeLength("s0 conf", "Stopping distance at conflicts.",
87 new Length(1.5, LengthUnit.METER), ConstraintInterface.POSITIVE);
88
89
90 public static final ParameterTypeDouble TIME_FACTOR =
91 new ParameterTypeDouble("timeFactor", "Safety factor on estimated time.", 1.25, ConstraintInterface.ATLEASTONE);
92
93
94 public static final ParameterTypeLength STOP_AREA =
95 new ParameterTypeLength("stopArea", "Area before stop line where one is considered arrived at the intersection.",
96 new Length(4, LengthUnit.METER), ConstraintInterface.POSITIVE);
97
98
99 public static final ParameterTypeDuration TI = new ParameterTypeDuration("ti", "Indicator time before departure.",
100 Duration.createSI(3.0), ConstraintInterface.POSITIVE);
101
102
103 private static final Duration TIME_STEP = new Duration(0.5, DurationUnit.SI);
104
105
106 private static boolean CROSSSTANDING = true;
107
108
109
110
111 private ConflictUtil()
112 {
113
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 @SuppressWarnings("checkstyle:parameternumber")
137 public static Acceleration approachConflicts(final Parameters parameters,
138 final PerceptionCollectable<HeadwayConflict, Conflict> conflicts,
139 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final CarFollowingModel carFollowingModel,
140 final Length vehicleLength, final Length vehicleWidth, final Speed speed, final Acceleration acceleration,
141 final SpeedLimitInfo speedLimitInfo, final ConflictPlans conflictPlans, final LaneBasedGTU gtu)
142 throws GTUException, ParameterException
143 {
144
145 conflictPlans.cleanPlans();
146
147 Acceleration a = Acceleration.POS_MAXVALUE;
148 Length stoppingDistance = Length.createSI(
149 parameters.getParameter(S0).si + vehicleLength.si + .5 * speed.si * speed.si / parameters.getParameter(B).si);
150 if (!conflicts.isEmpty() && conflicts.first().getDistance().gt(stoppingDistance))
151 {
152 conflictPlans.setBlocking(false);
153 return a;
154 }
155
156 List<Length> prevStarts = new ArrayList<>();
157 List<Length> prevEnds = new ArrayList<>();
158 List<Class<? extends ConflictRule>> conflictRuleTypes = new ArrayList<>();
159 boolean blocking = false;
160
161 for (HeadwayConflict conflict : conflicts)
162 {
163
164
165 if (conflict.isCrossing())
166 {
167
168 a = Acceleration.min(a, avoidCrossingCollision(parameters, conflict, carFollowingModel, speed, speedLimitInfo));
169 }
170 else
171 {
172
173 a = Acceleration.min(a, followConflictingLeaderOnMergeOrSplit(conflict, parameters, carFollowingModel, speed,
174 speedLimitInfo, vehicleWidth));
175 }
176 if (conflict.getDistance().lt0())
177 {
178 if (conflict.getConflictType().isCrossing() && !conflict.getConflictPriority().isPriority())
179 {
180
181 blocking = true;
182 }
183
184 continue;
185 }
186
187
188 if (gtu.getStrategicalPlanner().getRoute() instanceof BusSchedule && gtu.getGTUType().isOfType(GTUType.BUS)
189 && conflict.getConflictRuleType().equals(BusStopConflictRule.class))
190 {
191 BusSchedule busSchedule = (BusSchedule) gtu.getStrategicalPlanner().getRoute();
192 Time actualDeparture = busSchedule.getActualDepartureConflict(conflict.getId());
193 if (actualDeparture != null && actualDeparture.si < gtu.getSimulator().getSimulatorTime().si
194 + parameters.getParameter(TI).si)
195 {
196
197 conflictPlans.setIndicatorIntent(TurnIndicatorIntent.LEFT, conflict.getDistance());
198 }
199 }
200
201
202 boolean stop;
203 switch (conflict.getConflictPriority())
204 {
205 case PRIORITY:
206 {
207 stop = stopForPriorityConflict(conflict, leaders, speed, vehicleLength, parameters, conflictPlans);
208 break;
209 }
210 case YIELD:
211 case TURN_ON_RED:
212 {
213 stop = stopForGiveWayConflict(conflict, leaders, speed, acceleration, vehicleLength, parameters,
214 speedLimitInfo, carFollowingModel, blocking ? BCRIT : B);
215 break;
216 }
217 case STOP:
218 {
219 stop = stopForStopConflict(conflict, leaders, speed, acceleration, vehicleLength, parameters,
220 speedLimitInfo, carFollowingModel, blocking ? BCRIT : B);
221 break;
222 }
223 case ALL_STOP:
224 {
225 stop = stopForAllStopConflict(conflict, conflictPlans);
226 break;
227 }
228 case SPLIT:
229 {
230 stop = false;
231 break;
232 }
233 default:
234 {
235 throw new GTUException("Unsupported conflict rule encountered while approaching conflicts.");
236 }
237 }
238
239
240 if (!conflict.getConflictType().equals(ConflictType.SPLIT))
241 {
242
243 if (stop)
244 {
245 prevStarts.add(conflict.getDistance());
246 conflictRuleTypes.add(conflict.getConflictRuleType());
247
248 int j = 0;
249 for (int i = prevEnds.size() - 1; i >= 0; i--)
250 {
251
252 if (prevStarts.get(i + 1).minus(prevEnds.get(i)).gt(passableDistance(vehicleLength, parameters)))
253 {
254 j = i + 1;
255 break;
256 }
257 }
258 if (blocking && j == 0)
259 {
260
261 j = prevStarts.size() - 1;
262 }
263
264
265
266
267
268 parameters.setParameterResettable(S0, parameters.getParameter(S0_CONF));
269 Acceleration aCF = new Acceleration(-Double.MAX_VALUE, AccelerationUnit.SI);
270 while (aCF.si < -6.0 && j < prevStarts.size())
271 {
272 if (prevStarts.get(j).lt(parameters.getParameter(S0_CONF)))
273 {
274
275
276 aCF = Acceleration.max(aCF, new Acceleration(-6.0, AccelerationUnit.SI));
277 }
278 else
279 {
280 Acceleration aStop = CarFollowingUtil.stop(carFollowingModel, parameters, speed, speedLimitInfo,
281 prevStarts.get(j));
282 if (conflictRuleTypes.get(j).equals(BusStopConflictRule.class)
283 && aStop.lt(parameters.getParameter(ParameterTypes.BCRIT).neg()))
284 {
285
286 aStop = Acceleration.POS_MAXVALUE;
287 }
288 aCF = Acceleration.max(aCF, aStop);
289 }
290 j++;
291 }
292 parameters.resetParameter(S0);
293 a = Acceleration.min(a, aCF);
294 break;
295 }
296
297
298 if (!conflict.getUpstreamConflictingGTUs().isEmpty())
299 {
300 prevStarts.add(conflict.getDistance());
301 conflictRuleTypes.add(conflict.getConflictRuleType());
302 prevEnds.add(conflict.getDistance().plus(conflict.getLength()));
303 }
304 }
305
306 }
307 conflictPlans.setBlocking(blocking);
308
309 if (a.si < -6.0 && speed.si > 5 / 3.6)
310 {
311 System.err.println("Deceleration from conflict util stronger than 6m/s^2.");
312
313 }
314 return a;
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328 private static Acceleration followConflictingLeaderOnMergeOrSplit(final HeadwayConflict conflict,
329 final Parameters parameters, final CarFollowingModel carFollowingModel, final Speed speed,
330 final SpeedLimitInfo speedLimitInfo, final Length vehicleWidth) throws ParameterException
331 {
332
333 PerceptionIterable<HeadwayGTU> downstreamGTUs = conflict.getDownstreamConflictingGTUs();
334 if (downstreamGTUs.isEmpty() || downstreamGTUs.first().isAhead())
335 {
336 return Acceleration.POS_MAXVALUE;
337 }
338
339 HeadwayGTU c = null;
340 Length virtualHeadway = null;
341 if (conflict.getDistance().gt0())
342 {
343 c = downstreamGTUs.first();
344 virtualHeadway = conflict.getDistance().plus(c.getOverlapRear());
345 }
346 else
347 {
348 for (HeadwayGTU con : downstreamGTUs)
349 {
350 if (con.isAhead())
351 {
352
353 return Acceleration.POS_MAXVALUE;
354 }
355
356
357
358
359
360
361
362
363
364 virtualHeadway = conflict.getDistance().plus(con.getOverlapRear());
365 if (virtualHeadway.gt0())
366 {
367 if (conflict.isSplit())
368 {
369 double conflictWidth = conflict.getWidthAtFraction(
370 (-conflict.getDistance().si + virtualHeadway.si) / conflict.getConflictingLength().si).si;
371 double gtuWidth = con.getWidth().si + vehicleWidth.si;
372 if (conflictWidth > gtuWidth)
373 {
374 continue;
375 }
376 }
377
378 c = con;
379 break;
380 }
381 }
382 }
383 if (c == null)
384 {
385
386 return Acceleration.POS_MAXVALUE;
387 }
388
389 SortedMap<Length, Speed> leaders = new TreeMap<>();
390 leaders.put(virtualHeadway, c.getSpeed());
391 Acceleration a = CarFollowingUtil.followSingleLeader(carFollowingModel, parameters, speed, speedLimitInfo,
392 virtualHeadway, c.getSpeed());
393
394
395 if (conflict.isMerge() && virtualHeadway.lt(conflict.getDistance()))
396 {
397
398
399
400
401
402
403
404
405
406
407 parameters.setParameterResettable(S0, parameters.getParameter(S0_CONF));
408 Acceleration aStop =
409 CarFollowingUtil.stop(carFollowingModel, parameters, speed, speedLimitInfo, conflict.getDistance());
410 parameters.resetParameter(S0);
411 a = Acceleration.max(a, aStop);
412 }
413 return a;
414 }
415
416
417
418
419
420
421
422
423
424
425
426 private static Acceleration avoidCrossingCollision(final Parameters parameters, final HeadwayConflict conflict,
427 final CarFollowingModel carFollowingModel, final Speed speed, final SpeedLimitInfo speedLimitInfo)
428 throws ParameterException
429 {
430
431
432 List<HeadwayGTU> conflictingGTUs = new ArrayList<>();
433 for (HeadwayGTU gtu : conflict.getUpstreamConflictingGTUs())
434 {
435 if (isOnRoute(conflict.getConflictingLink(), gtu))
436 {
437
438 conflictingGTUs.add(gtu);
439 break;
440 }
441 }
442 for (HeadwayGTU gtu : conflict.getDownstreamConflictingGTUs())
443 {
444 if (gtu.isParallel())
445 {
446 conflictingGTUs.add(gtu);
447 }
448 else
449 {
450
451 break;
452 }
453 }
454
455 if (conflictingGTUs.isEmpty())
456 {
457 return Acceleration.POS_MAXVALUE;
458 }
459
460 Acceleration a = Acceleration.POS_MAXVALUE;
461 for (HeadwayGTU conflictingGTU : conflictingGTUs)
462 {
463 AnticipationInfo tteC;
464 Length distance;
465 if (conflictingGTU.isParallel())
466 {
467 tteC = new AnticipationInfo(Duration.ZERO, conflictingGTU.getSpeed());
468 distance = conflictingGTU.getOverlapRear().abs().plus(conflictingGTU.getOverlap())
469 .plus(conflictingGTU.getOverlapFront().abs());
470 }
471 else
472 {
473 tteC = AnticipationInfo.anticipateMovement(conflictingGTU.getDistance(), conflictingGTU.getSpeed(),
474 Acceleration.ZERO);
475 distance = conflictingGTU.getDistance().plus(conflict.getLength()).plus(conflictingGTU.getLength());
476 }
477 AnticipationInfo ttcC = AnticipationInfo.anticipateMovement(distance, conflictingGTU.getSpeed(), Acceleration.ZERO);
478 AnticipationInfo tteO = AnticipationInfo.anticipateMovementFreeAcceleration(conflict.getDistance(), speed,
479 parameters, carFollowingModel, speedLimitInfo, TIME_STEP);
480
481
482 if (tteC.getDuration().lt(tteO.getDuration()) && tteO.getDuration().lt(ttcC.getDuration()))
483 {
484 if (!conflictingGTU.getSpeed().eq0() || !CROSSSTANDING)
485 {
486
487 double acc = 2 * (conflict.getDistance().si - speed.si * ttcC.getDuration().si)
488 / (ttcC.getDuration().si * ttcC.getDuration().si);
489
490 if (speed.si / -acc > ttcC.getDuration().si)
491 {
492 a = Acceleration.min(a, new Acceleration(acc, AccelerationUnit.SI));
493 }
494 else
495 {
496
497 a = Acceleration.min(a, CarFollowingUtil.stop(carFollowingModel, parameters, speed, speedLimitInfo,
498 conflict.getDistance()));
499 }
500 }
501
502 }
503 }
504 return a;
505 }
506
507
508
509
510
511
512
513
514
515
516
517
518
519 public static boolean stopForPriorityConflict(final HeadwayConflict conflict,
520 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Length vehicleLength,
521 final Parameters parameters, final ConflictPlans yieldPlans) throws ParameterException
522 {
523
524 if (leaders.isEmpty() || conflict.getUpstreamConflictingGTUs().isEmpty())
525 {
526
527 return false;
528 }
529
530
531
532 Length typeCorrection = conflict.isCrossing() ? conflict.getLength() : Length.ZERO;
533
534 Length distance = conflict.getDistance().minus(leaders.first().getDistance())
535 .plus(passableDistance(vehicleLength, parameters)).plus(typeCorrection);
536 if (distance.gt0())
537 {
538
539 Length required = conflict.getDistance().plus(typeCorrection).plus(passableDistance(vehicleLength, parameters));
540 for (HeadwayGTU leader : leaders)
541 {
542 if (leader.getSpeed().eq0())
543 {
544
545
546 return leader.getDistance().ge(conflict.getDistance()) && required.ge(leader.getDistance());
547 }
548 required = required
549 .plus(passableDistance(leader.getLength(), leader.getParameters()));
550 }
551 }
552 return false;
553
554 }
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570 @SuppressWarnings("checkstyle:parameternumber")
571 public static boolean stopForGiveWayConflict(final HeadwayConflict conflict,
572 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Acceleration acceleration,
573 final Length vehicleLength, final Parameters parameters, final SpeedLimitInfo speedLimitInfo,
574 final CarFollowingModel carFollowingModel, final ParameterTypeAcceleration bType) throws ParameterException
575 {
576
577
578
579 if (conflict.getConflictType().equals(ConflictType.CROSSING) && !conflict.getDownstreamConflictingGTUs().isEmpty()
580 && conflict.getDownstreamConflictingGTUs().first().isParallel())
581 {
582
583 return true;
584 }
585
586
587
588 Acceleration b = parameters.getParameter(bType).neg();
589 double f = parameters.getParameter(TIME_FACTOR);
590 Duration gap = parameters.getParameter(MIN_GAP);
591
592 Length distance = conflict.getDistance().plus(vehicleLength);
593 if (conflict.isCrossing())
594 {
595
596 distance = distance.plus(conflict.getLength());
597 }
598
599 AnticipationInfo ttcOa = AnticipationInfo.anticipateMovementFreeAcceleration(distance, speed, parameters,
600 carFollowingModel, speedLimitInfo, TIME_STEP);
601
602 AnticipationInfo ttpDz = null;
603 AnticipationInfo ttpDs = null;
604 if (conflict.isCrossing())
605 {
606 if (!leaders.isEmpty())
607 {
608 distance = conflict.getDistance().minus(leaders.first().getDistance()).plus(conflict.getLength())
609 .plus(passableDistance(vehicleLength, parameters));
610 ttpDz = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
611 ttpDs = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), b);
612 }
613 else
614 {
615
616 ttpDz = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
617 ttpDs = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
618 }
619 }
620
621 PerceptionCollectable<HeadwayGTU, LaneBasedGTU> conflictingVehiclesCollectable = conflict.getUpstreamConflictingGTUs();
622 Iterable<HeadwayGTU> conflictingVehicles;
623 if (conflictingVehiclesCollectable.isEmpty())
624 {
625 if (conflict.getConflictingTrafficLightDistance() == null)
626 {
627
628 try
629 {
630 HeadwayGTUSimple conflictGtu = new HeadwayGTUSimple("virtual " + UUID.randomUUID().toString(), GTUType.CAR,
631 conflict.getConflictingVisibility(), new Length(4.0, LengthUnit.SI), new Length(2.0, LengthUnit.SI),
632 conflict.getConflictingSpeedLimit(), Acceleration.ZERO, Speed.ZERO);
633 List<HeadwayGTU> conflictingVehiclesList = new ArrayList<>();
634 conflictingVehiclesList.add(conflictGtu);
635 conflictingVehicles = conflictingVehiclesList;
636 }
637 catch (GTUException exception)
638 {
639 throw new RuntimeException("Could not create a virtual conflicting vehicle at visibility range.",
640 exception);
641 }
642 }
643 else
644 {
645
646 return false;
647 }
648 }
649 else
650 {
651 conflictingVehicles = conflictingVehiclesCollectable;
652 }
653
654
655 boolean first = true;
656 for (HeadwayGTU conflictingVehicle : conflictingVehicles)
657 {
658
659
660 if (first && conflictingVehicle.getSpeed().eq0() && conflictingVehicle.isAhead())
661 {
662 return false;
663 }
664 first = false;
665
666
667 if (!isOnRoute(conflict.getConflictingLink(), conflictingVehicle))
668 {
669 continue;
670 }
671
672
673 AnticipationInfo tteCa;
674 if (conflictingVehicle instanceof HeadwayGTUSimple)
675 {
676 tteCa = AnticipationInfo.anticipateMovement(conflictingVehicle.getDistance(), conflictingVehicle.getSpeed(),
677 conflictingVehicle.getAcceleration());
678 }
679 else
680 {
681 Parameters params = conflictingVehicle.getParameters();
682 SpeedLimitInfo sli = conflictingVehicle.getSpeedLimitInfo();
683 CarFollowingModel cfm = conflictingVehicle.getCarFollowingModel();
684
685 tteCa = AnticipationInfo.anticipateMovementFreeAcceleration(conflictingVehicle.getDistance(),
686 conflictingVehicle.getSpeed(), params, cfm, sli, TIME_STEP);
687 }
688 AnticipationInfo tteCs =
689 AnticipationInfo.anticipateMovement(conflictingVehicle.getDistance(), conflictingVehicle.getSpeed(), b);
690
691
692 if (conflict.isMerge())
693 {
694
695
696 double vSelf = ttcOa.getEndSpeed().si;
697 double speedDiff = conflictingVehicle.getSpeed().si - vSelf;
698 speedDiff = speedDiff > 0 ? speedDiff : 0;
699 Duration additionalTime = new Duration(speedDiff / -b.si, DurationUnit.SI);
700
701 double followerFront = conflictingVehicle.getSpeed().si * ttcOa.getDuration().si
702 - conflictingVehicle.getDistance().si + (conflictingVehicle.getSpeed().si * additionalTime.si
703 + 0.5 * b.si * additionalTime.si * additionalTime.si);
704 double ownRear = vSelf * additionalTime.si;
705 Duration tMax = parameters.getParameter(ParameterTypes.TMAX);
706 Length s0 = parameters.getParameter(S0);
707
708
709
710 if (ttcOa.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
711 || ttcOa.getDuration().plus(additionalTime).multiplyBy(f).plus(gap).gt(tteCs.getDuration())
712 || ownRear < (followerFront + (tMax.si + gap.si) * vSelf + s0.si) * f)
713 {
714 return true;
715 }
716
717 }
718 else if (conflict.isCrossing())
719 {
720
721
722
723
724
725
726 if (ttpDz.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
727 || ttcOa.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
728 || ttpDs.getDuration().multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
729 {
730 return true;
731 }
732
733 }
734 else
735 {
736 throw new RuntimeException(
737 "Conflict is of unknown type " + conflict.getConflictType() + ", which is not merge nor a crossing.");
738 }
739 }
740
741
742 return false;
743
744 }
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760 @SuppressWarnings("checkstyle:parameternumber")
761 public static boolean stopForStopConflict(final HeadwayConflict conflict,
762 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Acceleration acceleration,
763 final Length vehicleLength, final Parameters parameters, final SpeedLimitInfo speedLimitInfo,
764 final CarFollowingModel carFollowingModel, final ParameterTypeAcceleration bType) throws ParameterException
765 {
766
767 return stopForGiveWayConflict(conflict, leaders, speed, acceleration, vehicleLength, parameters, speedLimitInfo,
768 carFollowingModel, bType);
769 }
770
771
772
773
774
775
776
777 public static boolean stopForAllStopConflict(final HeadwayConflict conflict, final ConflictPlans conflictPlans)
778 {
779
780
781 if (conflictPlans.isStopPhaseRun(conflict.getStopLine()))
782 {
783 return false;
784 }
785
786 return false;
787 }
788
789
790
791
792
793
794
795 private static boolean isOnRoute(final CrossSectionLink conflictingLink, final HeadwayGTU gtu)
796 {
797 try
798 {
799 Route route = gtu.getRoute();
800 if (route == null)
801 {
802
803 return true;
804 }
805 Node startNode = conflictingLink.getStartNode();
806 Node endNode = conflictingLink.getEndNode();
807 return route.contains(startNode) && route.contains(endNode)
808 && Math.abs(route.indexOf(endNode) - route.indexOf(startNode)) == 1;
809 }
810 catch (@SuppressWarnings("unused") UnsupportedOperationException uoe)
811 {
812
813 return true;
814 }
815 }
816
817
818
819
820
821
822
823
824 private static Length passableDistance(final Length vehicleLength, final Parameters parameters) throws ParameterException
825 {
826 return parameters.getParameter(S0).plus(vehicleLength);
827 }
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845 public static final class ConflictPlans implements Blockable, Serializable
846 {
847
848
849 private static final long serialVersionUID = 20160811L;
850
851
852 private final HashMap<String, StopPhase> stopPhases = new HashMap<>();
853
854
855 private final HashMap<String, Time> arrivalTimes = new HashMap<>();
856
857
858 private TurnIndicatorIntent indicatorIntent = TurnIndicatorIntent.NONE;
859
860
861 private Length indicatorObjectDistance = null;
862
863
864 private boolean blocking;
865
866
867
868
869 void cleanPlans()
870 {
871 this.indicatorIntent = TurnIndicatorIntent.NONE;
872 this.indicatorObjectDistance = null;
873 }
874
875
876
877
878
879
880 void setArrivalTime(final AbstractHeadwayGTU gtu, final Time time)
881 {
882 this.arrivalTimes.put(gtu.getId(), time);
883 }
884
885
886
887
888
889
890 Time getArrivalTime(final AbstractHeadwayGTU gtu)
891 {
892 return this.arrivalTimes.get(gtu.getId());
893 }
894
895
896
897
898
899 void setStopPhaseApproach(final HeadwayStopLine stopLine)
900 {
901 this.stopPhases.put(stopLine.getId(), StopPhase.APPROACH);
902 }
903
904
905
906
907
908
909 void setStopPhaseYield(final HeadwayStopLine stopLine)
910 {
911 Throw.when(
912 !this.stopPhases.containsKey(stopLine.getId())
913 || !this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH),
914 RuntimeException.class, "Yield stop phase is set for stop line that was not approached.");
915 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
916 }
917
918
919
920
921
922
923 void setStopPhaseRun(final HeadwayStopLine stopLine)
924 {
925 Throw.when(!this.stopPhases.containsKey(stopLine.getId()), RuntimeException.class,
926 "Run stop phase is set for stop line that was not approached.");
927 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
928 }
929
930
931
932
933
934 boolean isStopPhaseApproach(final HeadwayStopLine stopLine)
935 {
936 return this.stopPhases.containsKey(stopLine.getId())
937 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH);
938 }
939
940
941
942
943
944 boolean isStopPhaseYield(final HeadwayStopLine stopLine)
945 {
946 return this.stopPhases.containsKey(stopLine.getId())
947 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.YIELD);
948 }
949
950
951
952
953
954 boolean isStopPhaseRun(final HeadwayStopLine stopLine)
955 {
956 return this.stopPhases.containsKey(stopLine.getId()) && this.stopPhases.get(stopLine.getId()).equals(StopPhase.RUN);
957 }
958
959
960 @Override
961 public String toString()
962 {
963 return "ConflictPlans";
964 }
965
966
967
968
969 public TurnIndicatorIntent getIndicatorIntent()
970 {
971 return this.indicatorIntent;
972 }
973
974
975
976
977 public Length getIndicatorObjectDistance()
978 {
979 return this.indicatorObjectDistance;
980 }
981
982
983
984
985
986 public void setIndicatorIntent(final TurnIndicatorIntent intent, final Length distance)
987 {
988 if (this.indicatorObjectDistance == null || this.indicatorObjectDistance.gt(distance))
989 {
990 this.indicatorIntent = intent;
991 this.indicatorObjectDistance = distance;
992 }
993 }
994
995
996 @Override
997 public boolean isBlocking()
998 {
999 return this.blocking;
1000 }
1001
1002
1003
1004
1005
1006 public void setBlocking(final boolean blocking)
1007 {
1008 this.blocking = blocking;
1009 }
1010
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 private enum StopPhase
1026 {
1027
1028 APPROACH,
1029
1030
1031 YIELD,
1032
1033
1034 RUN;
1035 }
1036
1037 }