1 package org.opentrafficsim.road.gtu.lane.tactical.pt;
2
3 import java.util.LinkedHashMap;
4 import java.util.List;
5 import java.util.Map;
6 import java.util.Set;
7
8 import org.djunits.value.vdouble.scalar.Duration;
9 import org.djunits.value.vdouble.scalar.Time;
10 import org.djutils.exceptions.Throw;
11 import org.opentrafficsim.core.gtu.GtuType;
12 import org.opentrafficsim.core.network.NetworkException;
13 import org.opentrafficsim.core.network.Node;
14 import org.opentrafficsim.core.network.route.Route;
15
16 /**
17 * <p>
18 * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
19 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
20 * </p>
21 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
22 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
23 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
24 */
25 public class BusSchedule extends Route
26 {
27
28 /** */
29 private static final long serialVersionUID = 20170124L;
30
31 /** Line of the bus schedule. */
32 private final String line;
33
34 /** List of bus stops. */
35 private final Map<String, BusStopInfo> schedule = new LinkedHashMap<>();
36
37 /** Map of actual departures stored per bus stop. */
38 private final Map<String, Time> actualDeparturesBusStop = new LinkedHashMap<>();
39
40 /** Map of actual departures stored per conflict. */
41 private final Map<String, Time> actualDeparturesConflict = new LinkedHashMap<>();
42
43 /**
44 * @param id String; id
45 * @param gtuType GtuType; the GtuType for which this is a route
46 * @param nodes List<Node>; nodes
47 * @param line String; line of the bus schedule
48 * @throws NetworkException if intermediate nodes are missing in the route.
49 */
50 public BusSchedule(final String id, final GtuType gtuType, final List<Node> nodes, final String line)
51 throws NetworkException
52 {
53 super(id, gtuType, nodes);
54 this.line = line;
55 }
56
57 /**
58 * @param id String; id
59 * @param gtuType GtuType; the GtuType for which this is a route
60 * @param line String; line of the bus schedule
61 */
62 public BusSchedule(final String id, final GtuType gtuType, final String line)
63 {
64 super(id, gtuType);
65 this.line = line;
66 }
67
68 /**
69 * Adds a stop to the schedule.
70 * @param busStopId String; bus stop id
71 * @param departureTime Time; departure time
72 * @param dwellTime Duration; dwell time
73 * @param forceSchedule boolean; whether to wait until departure time
74 */
75 public final void addBusStop(final String busStopId, final Time departureTime, final Duration dwellTime,
76 final boolean forceSchedule)
77 {
78 Throw.whenNull(busStopId, "Bus stop id may not be null.");
79 Throw.whenNull(departureTime, "Departure time may not be null.");
80 Throw.whenNull(dwellTime, "Dwell time may not be null.");
81 this.schedule.put(busStopId, new BusStopInfo(departureTime, dwellTime, forceSchedule));
82 }
83
84 /**
85 * Whether the bus of this line should stop for this bus stop. False if not the correct line, or already stopped.
86 * @param busStopId String; id of bus stop
87 * @param time Time; time to check
88 * @return whether the bus of this line should stop for this bus stop
89 */
90 public final boolean isLineStop(final String busStopId, final Time time)
91 {
92 return this.schedule.containsKey(busStopId) && (!this.actualDeparturesConflict.containsKey(busStopId)
93 || time.lt(this.actualDeparturesConflict.get(busStopId)));
94 }
95
96 /**
97 * Returns departure time for the given bus stop.
98 * @param busStopId String; id of bus stop
99 * @return departure time for the given bus stop
100 */
101 public final Time getDepartureTime(final String busStopId)
102 {
103 checkStop(busStopId);
104 return this.schedule.get(busStopId).getDepartureTime();
105 }
106
107 /**
108 * Returns dwell time for the given bus stop.
109 * @param busStopId String; id of bus stop
110 * @return dwell time for the given bus stop
111 */
112 public final Duration getDwellTime(final String busStopId)
113 {
114 checkStop(busStopId);
115 return this.schedule.get(busStopId).getDwellTime();
116 }
117
118 /**
119 * Returns whether the departure time is enforced.
120 * @param busStopId String; id of bus stop
121 * @return whether the departure time is enforced
122 */
123 public final boolean isForceSchedule(final String busStopId)
124 {
125 checkStop(busStopId);
126 return this.schedule.get(busStopId).isForceSchedule();
127 }
128
129 /**
130 * Throws exception when the bus stop is not part of this schedule.
131 * @param busStopId String; id of bus stop
132 * @throws IllegalArgumentException if the bus stop is not part of this schedule
133 */
134 private void checkStop(final String busStopId)
135 {
136 Throw.when(!this.schedule.containsKey(busStopId), IllegalArgumentException.class, "Bus stop %s is not for schedule %s.",
137 busStopId, this);
138 }
139
140 /**
141 * Set actual departure time.
142 * @param busStopId String; bus stop id
143 * @param conflictIds Set<String>; conflicts downstream of the bus stop
144 * @param time Time; actual departure time
145 */
146 public final void setActualDeparture(final String busStopId, final Set<String> conflictIds, final Time time)
147 {
148 this.actualDeparturesBusStop.put(busStopId, time);
149 for (String conflictId : conflictIds)
150 {
151 this.actualDeparturesConflict.put(conflictId, time);
152 }
153 }
154
155 /**
156 * Return the actual departure time.
157 * @param busStopId String; bus stop id
158 * @return actual departure time, {@code null} if not given
159 */
160 public final Time getActualDepartureBusStop(final String busStopId)
161 {
162 return this.actualDeparturesBusStop.get(busStopId);
163 }
164
165 /**
166 * Return the actual departure time.
167 * @param conflictId String; conflict id
168 * @return actual departure time, {@code null} if not given
169 */
170 public final Time getActualDepartureConflict(final String conflictId)
171 {
172 return this.actualDeparturesConflict.get(conflictId);
173 }
174
175 /**
176 * @return line.
177 */
178 public final String getLine()
179 {
180 return this.line;
181 }
182
183 /** {@inheritDoc} */
184 @Override
185 public final String toString()
186 {
187 return "BusSchedule [id=" + getId() + ", line=" + this.line + "]";
188 }
189
190 /**
191 * Class to contain info regarding a stop in the schedule.
192 * <p>
193 * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
194 * <br>
195 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
196 * </p>
197 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
198 * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
199 * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
200 */
201 private class BusStopInfo
202 {
203
204 /** Departure time. */
205 private final Time departureTime;
206
207 /** Dwell time. */
208 private final Duration dwellTime;
209
210 /** Whether to wait until departure time. */
211 private final boolean forceSchedule;
212
213 /**
214 * @param departureTime Time; departure time
215 * @param dwellTime Duration; dwell time
216 * @param forceSchedule boolean; whether to wait until departure time
217 */
218 BusStopInfo(final Time departureTime, final Duration dwellTime, final boolean forceSchedule)
219 {
220 this.departureTime = departureTime;
221 this.dwellTime = dwellTime;
222 this.forceSchedule = forceSchedule;
223 }
224
225 /**
226 * @return departureTime.
227 */
228 public final Time getDepartureTime()
229 {
230 return this.departureTime;
231 }
232
233 /**
234 * @return dwellTime.
235 */
236 public final Duration getDwellTime()
237 {
238 return this.dwellTime;
239 }
240
241 /**
242 * @return forceSchedule.
243 */
244 public final boolean isForceSchedule()
245 {
246 return this.forceSchedule;
247 }
248
249 /** {@inheritDoc} */
250 @Override
251 public String toString()
252 {
253 return "BusStopInfo [departureTime=" + this.departureTime + ", dwellTime=" + this.dwellTime + ", forceSchedule="
254 + this.forceSchedule + "]";
255 }
256
257 }
258
259 }