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