1 package org.opentrafficsim.road.gtu.tactical.lmrs;
2
3 import java.util.Optional;
4
5 import org.djunits.unit.LengthUnit;
6 import org.djunits.value.vdouble.scalar.Acceleration;
7 import org.djunits.value.vdouble.scalar.Duration;
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.opentrafficsim.base.parameters.ParameterException;
10 import org.opentrafficsim.core.gtu.GtuException;
11 import org.opentrafficsim.core.gtu.Stateless;
12 import org.opentrafficsim.road.gtu.perception.FilteredIterable;
13 import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
14 import org.opentrafficsim.road.gtu.perception.RelativeLane;
15 import org.opentrafficsim.road.gtu.perception.categories.BusStopPerception;
16 import org.opentrafficsim.road.gtu.perception.object.PerceivedBusStop;
17 import org.opentrafficsim.road.gtu.tactical.TacticalContextEgo;
18 import org.opentrafficsim.road.gtu.tactical.pt.BusSchedule;
19 import org.opentrafficsim.road.gtu.tactical.util.CarFollowingUtil;
20 import org.opentrafficsim.road.network.object.BusStop;
21
22
23
24
25
26
27
28
29
30
31
32 public final class AccelerationBusStop implements AccelerationIncentive, Stateless<AccelerationIncentive>
33 {
34
35
36
37 private static final Length STOP_DISTANCE = new Length(15.0, LengthUnit.SI);
38
39
40 public static final AccelerationBusStop SINGLETON = new AccelerationBusStop();
41
42 @Override
43 public AccelerationBusStop get()
44 {
45 return SINGLETON;
46 }
47
48
49
50
51 private AccelerationBusStop()
52 {
53
54 }
55
56 @Override
57 @SuppressWarnings("checkstyle:parameternumber")
58 public Acceleration accelerate(final TacticalContextEgo context, final RelativeLane lane, final Length mergeDistance)
59 throws ParameterException, GtuException
60 {
61 PerceptionCollectable<PerceivedBusStop, BusStop> stops =
62 context.getPerception().getPerceptionCategory(BusStopPerception.class).getBusStops();
63 if (stops.isEmpty())
64 {
65 return NO_REASON;
66 }
67 BusSchedule busSchedule = (BusSchedule) context.getRoute().orElseThrow(
68 () -> new GtuException("Unable to determine acceleration for bus stops for bus without bus schedule."));
69 Duration now = context.getTime();
70 Iterable<PerceivedBusStop> it = lane.isCurrent() ? stops : new FilteredIterable<>(stops, (busStop) ->
71 {
72 return busStop.getDistance().gt(mergeDistance);
73 });
74 for (PerceivedBusStop stop : it)
75 {
76 String busStopId = stop.getId();
77 if (busSchedule.isLineStop(busStopId, now))
78 {
79
80
81 boolean stoppedAtStop =
82 stop.getRelativeLane().isCurrent() && stop.getDistance().le(STOP_DISTANCE) && context.getSpeed().eq0();
83 if (busSchedule.getActualDepartureBusStop(busStopId).isEmpty())
84 {
85 if (stoppedAtStop)
86 {
87
88 Duration departureTime = now.plus(busSchedule.getDwellTime(busStopId));
89 if (busSchedule.isForceSchedule(busStopId))
90 {
91 departureTime = Duration.max(departureTime, busSchedule.getDepartureTime(busStopId));
92 }
93 busSchedule.setActualDeparture(busStopId, stop.getConflictIds(), departureTime);
94 }
95 }
96
97
98 Optional<Duration> actualDeparture = busSchedule.getActualDepartureBusStop(busStopId);
99 if (actualDeparture.isEmpty() || now.lt(actualDeparture.get()))
100 {
101 if (stoppedAtStop)
102 {
103
104 return Acceleration.ZERO;
105 }
106 else
107 {
108
109 return CarFollowingUtil.stop(context, stop.getDistance());
110 }
111 }
112 }
113 }
114 return NO_REASON;
115 }
116
117 @Override
118 public String toString()
119 {
120 return "AccelerationBusStop";
121 }
122
123 }