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 }