View Javadoc
1   package org.opentrafficsim.ahfe;
2   
3   import java.util.ArrayList;
4   import java.util.HashMap;
5   import java.util.List;
6   
7   import org.djunits.value.vdouble.scalar.Duration;
8   import org.djunits.value.vdouble.scalar.Time;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.base.Identifiable;
11  import org.opentrafficsim.base.TimeStampedObject;
12  import org.opentrafficsim.base.Type;
13  import org.opentrafficsim.base.parameters.ParameterException;
14  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
15  import org.opentrafficsim.base.parameters.Parameters;
16  import org.opentrafficsim.core.gtu.GTUException;
17  import org.opentrafficsim.core.gtu.perception.PerceptionException;
18  import org.opentrafficsim.core.network.LateralDirectionality;
19  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
20  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
21  import org.opentrafficsim.road.gtu.lane.perception.categories.LaneBasedAbstractPerceptionCategory;
22  import org.opentrafficsim.road.gtu.lane.perception.categories.LaneBasedPerceptionCategory;
23  
24  /**
25   * Utility superclass for perception categories with single delayed snapshots.
26   * <p>
27   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
28   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
29   * <p>
30   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 feb. 2017 <br>
31   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
32   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
33   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
34   */
35  @Deprecated
36  public abstract class AbstractDelayedPerceptionCategory extends LaneBasedAbstractPerceptionCategory
37          implements LaneBasedPerceptionCategory
38  {
39  
40      /** Margin of 1 millisecond. */
41      private static final Duration MARGIN = Duration.createSI(0.001);
42  
43      /** */
44      private static final long serialVersionUID = 20170217L;
45  
46      /**
47       * @param perception LanePerception; perception
48       */
49      public AbstractDelayedPerceptionCategory(final LanePerception perception)
50      {
51          super(perception);
52      }
53  
54      /** Map of info type and list of time stamped data of that info type. */
55      private final HashMap<DelayedInfoType<?>, HashMap<RelativeLane, List<TimeStampedObject<?>>>> map = new HashMap<>();
56  
57      /**
58       * Set info of given delayed info type, not pertaining to any lane.
59       * @param delayedInfoType DelayedInfoType&lt;T&gt;; info type
60       * @param info TimeStampedObject&lt;T&gt;; info
61       * @param <T> data type of delayed info
62       */
63      public final <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final TimeStampedObject<T> info)
64      {
65          setInfo(delayedInfoType, null, info);
66      }
67  
68      /**
69       * Set info of given delayed info type, pertaining to a lane.
70       * @param delayedInfoType DelayedInfoType&lt;T&gt;; info type
71       * @param lane RelativeLane; lane, may be {@code null}
72       * @param info TimeStampedObject&lt;T&gt;; info
73       * @param <T> data type of delayed info
74       */
75      public final <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane,
76              final TimeStampedObject<T> info)
77      {
78          Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
79          Throw.whenNull(info, "Info may not be null.");
80          if (!this.map.containsKey(delayedInfoType))
81          {
82              this.map.put(delayedInfoType, new HashMap<>());
83          }
84          if (!this.map.get(delayedInfoType).containsKey(lane))
85          {
86              this.map.get(delayedInfoType).put(lane, new ArrayList<TimeStampedObject<?>>());
87          }
88          List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
89          if (!list.isEmpty())
90          {
91              Throw.when(!list.isEmpty() && info.getTimestamp().le(list.get(list.size() - 1).getTimestamp()),
92                      RuntimeException.class,
93                      "Setting delayed info for type %s with timestamp %s while info with timestamp %s is already present.",
94                      delayedInfoType, info.getTimestamp(), list.get(list.size() - 1).getTimestamp());
95          }
96  
97          // append data at end
98          list.add(info);
99      }
100 
101     /**
102      * Returns the most recent info of the given type, that is older than the delay. If all data is more recent than the delay,
103      * the oldest data is returned. If no data is present, an exception is thrown.
104      * @param delayedInfoType DelayedInfoType&lt;T&gt;; info type
105      * @param <T> data type of the info type
106      * @return info of the given type
107      * @throws PerceptionException if info was not perceived
108      */
109     public final <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType) throws PerceptionException
110     {
111         return getInfo(delayedInfoType, null);
112     }
113 
114     /**
115      * Returns the most recent info of the given type, that is older than the delay. If all data is more recent than the delay,
116      * the oldest data is returned. If no data is present, an exception is thrown.
117      * @param delayedInfoType DelayedInfoType&lt;T&gt;; info type
118      * @param lane RelativeLane; lane the data pertains to, may be {@code null}
119      * @param <T> data type of the info type
120      * @return info of the given type
121      * @throws PerceptionException if info was not perceived
122      */
123     @SuppressWarnings("unchecked")
124     public final <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane)
125             throws PerceptionException
126     {
127         Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
128         Throw.when(!this.map.containsKey(delayedInfoType), PerceptionException.class,
129                 "Perception does not contain any data for info type %s.", delayedInfoType);
130         Throw.when(!this.map.get(delayedInfoType).containsKey(lane), PerceptionException.class,
131                 "Perception does not contain any data for info type %s for lane %s.", delayedInfoType, lane);
132         List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
133         Throw.when(list.isEmpty(), RuntimeException.class, "Perception does not contain any data for info type %s.",
134                 delayedInfoType);
135 
136         // remove old data if required
137         Parameters params;
138         Time now;
139         try
140         {
141             params = getPerception().getGtu().getParameters();
142             now = getPerception().getGtu().getSimulator().getSimulatorTime();
143         }
144         catch (GTUException exception)
145         {
146             throw new RuntimeException("GTU not yet initialized.", exception);
147         }
148         Time delayedTime;
149         try
150         {
151             delayedTime = now.minus(params.getParameter(delayedInfoType.getDelayParameter())).plus(MARGIN);
152         }
153         catch (ParameterException exception)
154         {
155             throw new RuntimeException("Delay parameter not found.", exception);
156         }
157         while (list.size() > 1 && list.get(1).getTimestamp().le(delayedTime))
158         {
159             list.remove(0);
160         }
161 
162         return (TimeStampedObject<T>) list.get(0);
163     }
164 
165     /**
166      * Move data coupled to a lane to another lane to account for a lane change. The tactical planner needs to call this exactly
167      * when it flips logic concerning the origin and target lane.
168      * @param dir LateralDirectionality; direction of lane change
169      */
170     public final void changeLane(final LateralDirectionality dir)
171     {
172         for (DelayedInfoType<?> delayedInfoType : this.map.keySet())
173         {
174             HashMap<RelativeLane, List<TimeStampedObject<?>>> newMap = new HashMap<>();
175             for (RelativeLane lane : this.map.get(delayedInfoType).keySet())
176             {
177                 if (lane != null)
178                 {
179                     newMap.put(dir.isLeft() ? lane.getRight() : lane.getLeft(), this.map.get(delayedInfoType).get(lane));
180                 }
181                 else
182                 {
183                     newMap.put(lane, this.map.get(delayedInfoType).get(lane));
184                 }
185             }
186             this.map.put(delayedInfoType, newMap);
187         }
188     }
189 
190     /**
191      * Superclass for delayed info.
192      * <p>
193      * Copyright (c) 2013-2019 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 14 feb. 2017 <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> type of information.
202      */
203     public static class DelayedInfoType<T> extends Type<DelayedInfoType<T>> implements Identifiable
204     {
205 
206         /** Id. */
207         private final String id;
208 
209         /** Parameter for delay. */
210         private final ParameterTypeDuration delayParameter;
211 
212         /**
213          * Constructor.
214          * @param id String; id
215          * @param delayParameter ParameterTypeDuration; delay parameter type
216          */
217         public DelayedInfoType(final String id, final ParameterTypeDuration delayParameter)
218         {
219             this.id = id;
220             this.delayParameter = delayParameter;
221         }
222 
223         /**
224          * Returns the id.
225          * @return id
226          */
227         @Override
228         public final String getId()
229         {
230             return this.getId();
231         }
232 
233         /**
234          * Returns the delay parameter type.
235          * @return delayParameter
236          */
237         public final ParameterTypeDuration getDelayParameter()
238         {
239             return this.delayParameter;
240         }
241 
242         /** {@inheritDoc} */
243         @Override
244         public final int hashCode()
245         {
246             final int prime = 31;
247             int result = 1;
248             result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
249             return result;
250         }
251 
252         /** {@inheritDoc} */
253         @Override
254         public final boolean equals(final Object obj)
255         {
256             if (this == obj)
257             {
258                 return true;
259             }
260             if (obj == null)
261             {
262                 return false;
263             }
264             if (getClass() != obj.getClass())
265             {
266                 return false;
267             }
268             DelayedInfoType<?> other = (DelayedInfoType<?>) obj;
269             if (this.id == null)
270             {
271                 if (other.id != null)
272                 {
273                     return false;
274                 }
275             }
276             else if (!this.id.equals(other.id))
277             {
278                 return false;
279             }
280             return true;
281         }
282 
283     }
284 
285 }