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