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