View Javadoc
1   package org.opentrafficsim.core.perception;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.djunits.value.vdouble.scalar.Duration;
7   import org.djunits.value.vdouble.scalar.Time;
8   import org.opentrafficsim.core.perception.AbstractHistorical.Event;
9   import org.opentrafficsim.core.perception.HistoryManager.HistoricalElement;
10  
11  import nl.tudelft.simulation.language.Throw;
12  
13  /**
14   * Base class for objects or properties that can be perceived from their actual state in the past. The principle by which a past
15   * state is determined is by storing an internal event for each change to the object. Each event can be reversed, and by working
16   * from a current state backwards, any previous state within the available history can be restored.<br>
17   * <br>
18   * This class couples the historical to a {@code HistoryManager} and in response to a request from the {@code HistoryManager}
19   * will clear old events. Subclasses need to define their own events as extensions to {@code AbstractHistorical.Event}. This
20   * class provides the following methods to subclasses to work with the events.
21   * <ul>
22   * <li>{@code now()}, returns the current time from the {@code HistoryManager}, which needs to be stored with each event.</li>
23   * <li>{@code getEvents(Time)}, returns all events between now and the given time, ordered from recent to old.</li>
24   * <li>{@code getEvent(Time)}, returns the most recent event from before the given time.</li>
25   * <li>{@code getLastEvent()}, returns the most recent event.</li>
26   * <li>{@code removeEvent(Event)}, removes (oldest occurrence off) the event.</li>
27   * <li>{@code addEvent(Event)}, add the event.</li>
28   * </ul>
29   * Typically, any change results in a new event which is added with {@code addEvent(Event)}, where the event stores information
30   * such that the event can be restored. When an old state is requested, one or more events can be obtained with either of the
31   * get methods, after which they are applied to restore a previous state in a manner depending on the nature of the
32   * subclass.<br>
33   * <br>
34   * This class is defined with a single event type parameter {@code E}. Subclasses can use different event classes, so long as
35   * all of them derive from a common ancestor. For instance an 'add' and a 'remove' event that inherit from an abstract super.
36   * <p>
37   * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
38   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
39   * <p>
40   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 1 jan. 2018 <br>
41   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
42   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
43   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
44   * @param <T> value type
45   * @param <E> event type
46   */
47  public abstract class AbstractHistorical<T, E extends Event> implements HistoricalElement
48  {
49  
50      /** History manager. */
51      private final HistoryManager historyManager;
52  
53      /** List of events to determine the value at a previous time. */
54      private final List<E> events = new ArrayList<>();
55  
56      /**
57       * Constructor.
58       * @param historyManager HistoryManager; history manager
59       */
60      protected AbstractHistorical(final HistoryManager historyManager)
61      {
62          Throw.whenNull(historyManager, "History manager may not be null.");
63          this.historyManager = historyManager;
64          historyManager.registerHistorical(this);
65      }
66  
67      /**
68       * Returns the current time.
69       * @return Time; current time
70       */
71      protected final Time now()
72      {
73          return this.historyManager.now();
74      }
75  
76      /**
77       * Returns a list of events, ordered last to first, that includes all events <i>after</i> {@code time}.
78       * @param time Time; past time up to which to include events
79       * @return List; list of events, ordered last to first, that includes all events <i>after</i> {@code time}
80       */
81      protected final List<E> getEvents(final Time time)
82      {
83          List<E> list = new ArrayList<>();
84          int i = this.events.size() - 1;
85          while (i >= 0 && this.events.get(i).getTime() > time.si)
86          {
87              list.add(this.events.get(i));
88              i--;
89          }
90          return list;
91      }
92  
93      /**
94       * Returns the most recent event from <i>before</i> or on {@code time}, or the oldest if no such event.
95       * @param time Time; past time at which to obtain event
96       * @return E; most recent event from <i>before</i> {@code time}
97       */
98      protected final E getEvent(final Time time)
99      {
100         E prev = null;
101         for (int i = this.events.size() - 1; i >= 0; i--)
102         {
103             E event = this.events.get(i);
104             if (event.getTime() <= time.si)
105             {
106                 prev = event;
107                 break;
108             }
109         }
110 
111         if (prev == null && !this.events.isEmpty())
112         {
113             return this.events.get(0);
114         }
115 
116         return prev;
117     }
118 
119     /**
120      * Returns the last event.
121      * @return E; last event
122      */
123     protected final E getLastEvent()
124     {
125         return this.events.isEmpty() ? null : this.events.get(this.events.size() - 1);
126     }
127 
128     /**
129      * Returns whether the state at the given time is equal to the state at the current time.
130      * @param time Time; time
131      * @return boolean; whether the state at the given time is equal to the state at the current time
132      */
133     protected final boolean isLastState(final Time time)
134     {
135         return this.events.isEmpty() ? true : this.events.get(this.events.size() - 1).getTime() <= time.si;
136     }
137 
138     /**
139      * Removes the given event.
140      * @param event E; event to remove
141      */
142     protected final void removeEvent(final E event)
143     {
144         this.events.remove(event);
145     }
146 
147     /**
148      * Adds the event to the list of events.
149      * @param event E; event to add
150      */
151     protected final void addEvent(final E event)
152     {
153         this.events.add(event);
154     }
155 
156     /** {@inheritDoc} */
157     @Override
158     public final void cleanUpHistory(final Duration history)
159     {
160         double past = now().si - history.si;
161         while (this.events.size() > 1 && this.events.get(0).getTime() < past)
162         {
163             this.events.remove(0);
164         }
165     }
166 
167     /**
168      * Interface for event types.
169      * <p>
170      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
171      * <br>
172      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
173      * <p>
174      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 1 jan. 2018 <br>
175      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
176      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
177      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
178      */
179     interface Event
180     {
181 
182         /**
183          * Returns the time of this event.
184          * @return double; time of this event
185          */
186         double getTime();
187 
188     }
189 
190     /**
191      * Standard event which stores a time and value.
192      * <p>
193      * Copyright (c) 2013-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
194      * <br>
195      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
196      * <p>
197      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 1 jan. 2018 <br>
198      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
199      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
200      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
201      * @param <T> value type
202      */
203     public static class EventValue<T> implements Event
204     {
205 
206         /** Time of event. */
207         private final double time;
208 
209         /** Value of event. */
210         private final T value;
211 
212         /**
213          * Constructor.
214          * @param time double; time of event
215          * @param value T; value of event
216          */
217         public EventValue(final double time, final T value)
218         {
219             this.time = time;
220             this.value = value;
221         }
222 
223         /** {@inheritDoc} */
224         @Override
225         public double getTime()
226         {
227             return this.time;
228         }
229 
230         /**
231          * Returns the value of this event.
232          * @return T; value of this event
233          */
234         public T getValue()
235         {
236             return this.value;
237         }
238 
239         /** {@inheritDoc} */
240         @Override
241         public String toString()
242         {
243             return "EventValue [time=" + this.time + ", value=" + this.value + "]";
244         }
245 
246     }
247 
248 }