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