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