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