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, conflictPlans);
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
518 public static boolean stopForPriorityConflict(final HeadwayConflict conflict,
519 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Length vehicleLength,
520 final Parameters parameters, final ConflictPlans yieldPlans) throws ParameterException
521 {
522
523 if (leaders.isEmpty() || conflict.getUpstreamConflictingGTUs().isEmpty())
524 {
525
526 return false;
527 }
528
529
530
531 Length typeCorrection = conflict.isCrossing() ? conflict.getLength() : Length.ZERO;
532
533 Length distance = conflict.getDistance().minus(leaders.first().getDistance())
534 .plus(passableDistance(vehicleLength, parameters)).plus(typeCorrection);
535 if (distance.gt0())
536 {
537
538 Length required = conflict.getDistance().plus(typeCorrection).plus(passableDistance(vehicleLength, parameters));
539 for (HeadwayGTU leader : leaders)
540 {
541 if (leader.getSpeed().eq0())
542 {
543
544
545 return leader.getDistance().ge(conflict.getDistance()) && required.ge(leader.getDistance());
546 }
547 required = required
548 .plus(passableDistance(leader.getLength(), leader.getParameters()));
549 }
550 }
551 return false;
552
553 }
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569 @SuppressWarnings("checkstyle:parameternumber")
570 public static boolean stopForGiveWayConflict(final HeadwayConflict conflict,
571 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Acceleration acceleration,
572 final Length vehicleLength, final Parameters parameters, final SpeedLimitInfo speedLimitInfo,
573 final CarFollowingModel carFollowingModel, final ParameterTypeAcceleration bType) throws ParameterException
574 {
575
576
577
578 if (conflict.getConflictType().equals(ConflictType.CROSSING) && !conflict.getDownstreamConflictingGTUs().isEmpty()
579 && conflict.getDownstreamConflictingGTUs().first().isParallel())
580 {
581
582 return true;
583 }
584
585
586
587 Acceleration b = parameters.getParameter(bType).neg();
588 double f = parameters.getParameter(TIME_FACTOR);
589 Duration gap = parameters.getParameter(MIN_GAP);
590
591 Length distance = conflict.getDistance().plus(vehicleLength);
592 if (conflict.isCrossing())
593 {
594
595 distance = distance.plus(conflict.getLength());
596 }
597
598 AnticipationInfo ttcOa = AnticipationInfo.anticipateMovementFreeAcceleration(distance, speed, parameters,
599 carFollowingModel, speedLimitInfo, TIME_STEP);
600
601 AnticipationInfo ttpDz = null;
602 AnticipationInfo ttpDs = null;
603 if (conflict.isCrossing())
604 {
605 if (!leaders.isEmpty())
606 {
607 distance = conflict.getDistance().minus(leaders.first().getDistance()).plus(conflict.getLength())
608 .plus(passableDistance(vehicleLength, parameters));
609 ttpDz = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), Acceleration.ZERO);
610 ttpDs = AnticipationInfo.anticipateMovement(distance, leaders.first().getSpeed(), b);
611 }
612 else
613 {
614
615 ttpDz = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
616 ttpDs = new AnticipationInfo(Duration.ZERO, Speed.ZERO);
617 }
618 }
619
620 PerceptionCollectable<HeadwayGTU, LaneBasedGTU> conflictingVehiclesCollectable = conflict.getUpstreamConflictingGTUs();
621 Iterable<HeadwayGTU> conflictingVehicles;
622 if (conflictingVehiclesCollectable.isEmpty())
623 {
624 if (conflict.getConflictingTrafficLightDistance() == null)
625 {
626
627 try
628 {
629 HeadwayGTUSimple conflictGtu = new HeadwayGTUSimple("virtual " + UUID.randomUUID().toString(), GTUType.CAR,
630 conflict.getConflictingVisibility(), new Length(4.0, LengthUnit.SI), new Length(2.0, LengthUnit.SI),
631 conflict.getConflictingSpeedLimit(), Acceleration.ZERO, Speed.ZERO);
632 List<HeadwayGTU> conflictingVehiclesList = new ArrayList<>();
633 conflictingVehiclesList.add(conflictGtu);
634 conflictingVehicles = conflictingVehiclesList;
635 }
636 catch (GTUException exception)
637 {
638 throw new RuntimeException("Could not create a virtual conflicting vehicle at visibility range.",
639 exception);
640 }
641 }
642 else
643 {
644
645 return false;
646 }
647 }
648 else
649 {
650 conflictingVehicles = conflictingVehiclesCollectable;
651 }
652
653
654 boolean first = true;
655 for (HeadwayGTU conflictingVehicle : conflictingVehicles)
656 {
657
658
659 if (first && conflictingVehicle.getSpeed().eq0() && conflictingVehicle.isAhead())
660 {
661 return false;
662 }
663 first = false;
664
665
666 if (!isOnRoute(conflict.getConflictingLink(), conflictingVehicle))
667 {
668 continue;
669 }
670
671
672 AnticipationInfo tteCa;
673 if (conflictingVehicle instanceof HeadwayGTUSimple)
674 {
675 tteCa = AnticipationInfo.anticipateMovement(conflictingVehicle.getDistance(), conflictingVehicle.getSpeed(),
676 conflictingVehicle.getAcceleration());
677 }
678 else
679 {
680 Parameters params = conflictingVehicle.getParameters();
681 SpeedLimitInfo sli = conflictingVehicle.getSpeedLimitInfo();
682 CarFollowingModel cfm = conflictingVehicle.getCarFollowingModel();
683
684 tteCa = AnticipationInfo.anticipateMovementFreeAcceleration(conflictingVehicle.getDistance(),
685 conflictingVehicle.getSpeed(), params, cfm, sli, TIME_STEP);
686 }
687 AnticipationInfo tteCs =
688 AnticipationInfo.anticipateMovement(conflictingVehicle.getDistance(), conflictingVehicle.getSpeed(), b);
689
690
691 if (conflict.isMerge())
692 {
693
694
695 double vSelf = ttcOa.getEndSpeed().si;
696 double speedDiff = conflictingVehicle.getSpeed().si - vSelf;
697 speedDiff = speedDiff > 0 ? speedDiff : 0;
698 Duration additionalTime = new Duration(speedDiff / -b.si, DurationUnit.SI);
699
700 double followerFront = conflictingVehicle.getSpeed().si * ttcOa.getDuration().si
701 - conflictingVehicle.getDistance().si + (conflictingVehicle.getSpeed().si * additionalTime.si
702 + 0.5 * b.si * additionalTime.si * additionalTime.si);
703 double ownRear = vSelf * additionalTime.si;
704 Duration tMax = parameters.getParameter(ParameterTypes.TMAX);
705 Length s0 = parameters.getParameter(S0);
706
707
708
709 if (ttcOa.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
710 || ttcOa.getDuration().plus(additionalTime).multiplyBy(f).plus(gap).gt(tteCs.getDuration())
711 || ownRear < (followerFront + (tMax.si + gap.si) * vSelf + s0.si) * f)
712 {
713 return true;
714 }
715
716 }
717 else if (conflict.isCrossing())
718 {
719
720
721
722
723
724
725 if (ttpDz.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
726 || ttcOa.getDuration().multiplyBy(f).plus(gap).gt(tteCa.getDuration())
727 || ttpDs.getDuration().multiplyBy(f).plus(gap).gt(tteCs.getDuration()))
728 {
729 return true;
730 }
731
732 }
733 else
734 {
735 throw new RuntimeException(
736 "Conflict is of unknown type " + conflict.getConflictType() + ", which is not merge nor a crossing.");
737 }
738 }
739
740
741 return false;
742
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759 @SuppressWarnings("checkstyle:parameternumber")
760 public static boolean stopForStopConflict(final HeadwayConflict conflict,
761 final PerceptionCollectable<HeadwayGTU, LaneBasedGTU> leaders, final Speed speed, final Acceleration acceleration,
762 final Length vehicleLength, final Parameters parameters, final SpeedLimitInfo speedLimitInfo,
763 final CarFollowingModel carFollowingModel, final ParameterTypeAcceleration bType) throws ParameterException
764 {
765
766 return stopForGiveWayConflict(conflict, leaders, speed, acceleration, vehicleLength, parameters, speedLimitInfo,
767 carFollowingModel, bType);
768 }
769
770
771
772
773
774
775
776 public static boolean stopForAllStopConflict(final HeadwayConflict conflict, final ConflictPlans conflictPlans)
777 {
778
779
780 if (conflictPlans.isStopPhaseRun(conflict.getStopLine()))
781 {
782 return false;
783 }
784
785 return false;
786 }
787
788
789
790
791
792
793
794 private static boolean isOnRoute(final CrossSectionLink conflictingLink, final HeadwayGTU gtu)
795 {
796 try
797 {
798 Route route = gtu.getRoute();
799 if (route == null)
800 {
801
802 return true;
803 }
804 Node startNode = conflictingLink.getStartNode();
805 Node endNode = conflictingLink.getEndNode();
806 return route.contains(startNode) && route.contains(endNode)
807 && Math.abs(route.indexOf(endNode) - route.indexOf(startNode)) == 1;
808 }
809 catch (UnsupportedOperationException uoe)
810 {
811
812 return true;
813 }
814 }
815
816
817
818
819
820
821
822
823 private static Length passableDistance(final Length vehicleLength, final Parameters parameters) throws ParameterException
824 {
825 return parameters.getParameter(S0).plus(vehicleLength);
826 }
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844 public static final class ConflictPlans implements Blockable, Serializable
845 {
846
847
848 private static final long serialVersionUID = 20160811L;
849
850
851 private final HashMap<String, StopPhase> stopPhases = new HashMap<>();
852
853
854 private final HashMap<String, Time> arrivalTimes = new HashMap<>();
855
856
857 private TurnIndicatorIntent indicatorIntent = TurnIndicatorIntent.NONE;
858
859
860 private Length indicatorObjectDistance = null;
861
862
863 private boolean blocking;
864
865
866
867
868 void cleanPlans()
869 {
870 this.indicatorIntent = TurnIndicatorIntent.NONE;
871 this.indicatorObjectDistance = null;
872 }
873
874
875
876
877
878
879 void setArrivalTime(final AbstractHeadwayGTU gtu, final Time time)
880 {
881 this.arrivalTimes.put(gtu.getId(), time);
882 }
883
884
885
886
887
888
889 Time getArrivalTime(final AbstractHeadwayGTU gtu)
890 {
891 return this.arrivalTimes.get(gtu.getId());
892 }
893
894
895
896
897
898 void setStopPhaseApproach(final HeadwayStopLine stopLine)
899 {
900 this.stopPhases.put(stopLine.getId(), StopPhase.APPROACH);
901 }
902
903
904
905
906
907
908 void setStopPhaseYield(final HeadwayStopLine stopLine)
909 {
910 Throw.when(
911 !this.stopPhases.containsKey(stopLine.getId())
912 || !this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH),
913 RuntimeException.class, "Yield stop phase is set for stop line that was not approached.");
914 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
915 }
916
917
918
919
920
921
922 void setStopPhaseRun(final HeadwayStopLine stopLine)
923 {
924 Throw.when(!this.stopPhases.containsKey(stopLine.getId()), RuntimeException.class,
925 "Run stop phase is set for stop line that was not approached.");
926 this.stopPhases.put(stopLine.getId(), StopPhase.YIELD);
927 }
928
929
930
931
932
933 boolean isStopPhaseApproach(final HeadwayStopLine stopLine)
934 {
935 return this.stopPhases.containsKey(stopLine.getId())
936 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.APPROACH);
937 }
938
939
940
941
942
943 boolean isStopPhaseYield(final HeadwayStopLine stopLine)
944 {
945 return this.stopPhases.containsKey(stopLine.getId())
946 && this.stopPhases.get(stopLine.getId()).equals(StopPhase.YIELD);
947 }
948
949
950
951
952
953 boolean isStopPhaseRun(final HeadwayStopLine stopLine)
954 {
955 return this.stopPhases.containsKey(stopLine.getId()) && this.stopPhases.get(stopLine.getId()).equals(StopPhase.RUN);
956 }
957
958
959 @Override
960 public String toString()
961 {
962 return "ConflictPlans";
963 }
964
965
966
967
968 public TurnIndicatorIntent getIndicatorIntent()
969 {
970 return this.indicatorIntent;
971 }
972
973
974
975
976 public Length getIndicatorObjectDistance()
977 {
978 return this.indicatorObjectDistance;
979 }
980
981
982
983
984
985 public void setIndicatorIntent(final TurnIndicatorIntent intent, final Length distance)
986 {
987 if (this.indicatorObjectDistance == null || this.indicatorObjectDistance.gt(distance))
988 {
989 this.indicatorIntent = intent;
990 this.indicatorObjectDistance = distance;
991 }
992 }
993
994
995 @Override
996 public boolean isBlocking()
997 {
998 return this.blocking;
999 }
1000
1001
1002
1003
1004
1005 public void setBlocking(final boolean blocking)
1006 {
1007 this.blocking = blocking;
1008 }
1009
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024 private enum StopPhase
1025 {
1026
1027 APPROACH,
1028
1029
1030 YIELD,
1031
1032
1033 RUN;
1034 }
1035
1036 }