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