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