1 package org.opentrafficsim.road.gtu.lane.perception.categories;
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.opentrafficsim.base.TimeStampedObject;
10 import org.opentrafficsim.base.Type;
11 import org.opentrafficsim.core.gtu.GTUException;
12 import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
13 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
14 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypeDuration;
15 import org.opentrafficsim.core.gtu.perception.PerceptionCategory;
16 import org.opentrafficsim.core.gtu.perception.PerceptionException;
17 import org.opentrafficsim.core.network.LateralDirectionality;
18 import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
19 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
20
21 import nl.tudelft.simulation.language.Throw;
22
23
24
25
26
27
28
29
30
31
32
33
34 public abstract class AbstractDelayedPerceptionCategory extends LaneBasedAbstractPerceptionCategory
35 implements PerceptionCategory
36 {
37
38
39 private static final Duration MARGIN = Duration.createSI(0.001);
40
41
42 private static final long serialVersionUID = 20170217L;
43
44
45
46
47 public AbstractDelayedPerceptionCategory(final LanePerception perception)
48 {
49 super(perception);
50 }
51
52
53 private final HashMap<DelayedInfoType<?>, HashMap<RelativeLane, List<TimeStampedObject<?>>>> map = new HashMap<>();
54
55
56
57
58
59
60
61 public <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final TimeStampedObject<T> info)
62 {
63 setInfo(delayedInfoType, null, info);
64 }
65
66
67
68
69
70
71
72
73 public <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane, final TimeStampedObject<T> info)
74 {
75 Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
76 Throw.whenNull(info, "Info may not be null.");
77 if (!this.map.containsKey(delayedInfoType))
78 {
79 this.map.put(delayedInfoType, new HashMap<>());
80 }
81 if (!this.map.get(delayedInfoType).containsKey(lane))
82 {
83 this.map.get(delayedInfoType).put(lane, new ArrayList<TimeStampedObject<?>>());
84 }
85 List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
86 if (!list.isEmpty())
87 {
88 Throw.when(!list.isEmpty() && info.getTimestamp().le(list.get(list.size() - 1).getTimestamp()),
89 RuntimeException.class,
90 "Setting delayed info for type %s with timestamp %s while info with timestamp %s is already present.",
91 delayedInfoType, info.getTimestamp(), list.get(list.size() - 1).getTimestamp());
92 }
93
94
95 list.add(info);
96 }
97
98
99
100
101
102
103
104
105
106 public <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType) throws PerceptionException
107 {
108 return getInfo(delayedInfoType, null);
109 }
110
111
112
113
114
115
116
117
118
119
120 @SuppressWarnings("unchecked")
121 public <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane)
122 throws PerceptionException
123 {
124 Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
125 Throw.when(!this.map.containsKey(delayedInfoType), PerceptionException.class,
126 "Perception does not contain any data for info type %s.", delayedInfoType);
127 Throw.when(!this.map.get(delayedInfoType).containsKey(lane), PerceptionException.class,
128 "Perception does not contain any data for info type %s for lane %s.", delayedInfoType, lane);
129 List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
130 Throw.when(list.isEmpty(), RuntimeException.class, "Perception does not contain any data for info type %s.",
131 delayedInfoType);
132
133
134 BehavioralCharacteristics bc;
135 Time now;
136 try
137 {
138 bc = getPerception().getGtu().getBehavioralCharacteristics();
139 now = getPerception().getGtu().getSimulator().getSimulatorTime().getTime();
140 }
141 catch (GTUException exception)
142 {
143 throw new RuntimeException("GTU not yet initialized.", exception);
144 }
145 Time delayedTime;
146 try
147 {
148 delayedTime = now.minus(bc.getParameter(delayedInfoType.getDelayParameter())).plus(MARGIN);
149 }
150 catch (ParameterException exception)
151 {
152 throw new RuntimeException("Delay parameter not found.", exception);
153 }
154 while (list.size() > 1 && list.get(1).getTimestamp().le(delayedTime))
155 {
156 list.remove(0);
157 }
158
159 return (TimeStampedObject<T>) list.get(0);
160 }
161
162
163
164
165
166
167 public void changeLane(final LateralDirectionality dir)
168 {
169 for (DelayedInfoType<?> delayedInfoType : this.map.keySet())
170 {
171 HashMap<RelativeLane, List<TimeStampedObject<?>>> newMap = new HashMap<>();
172 for (RelativeLane lane : this.map.get(delayedInfoType).keySet())
173 {
174 if (lane != null)
175 {
176 newMap.put(dir.isLeft() ? lane.getRight() : lane.getLeft(), this.map.get(delayedInfoType).get(lane));
177 }
178 else
179 {
180 newMap.put(lane, this.map.get(delayedInfoType).get(lane));
181 }
182 }
183 this.map.put(delayedInfoType, newMap);
184 }
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200 public static class DelayedInfoType<T> extends Type<DelayedInfoType<T>>
201 {
202
203
204 private final String id;
205
206
207 private final ParameterTypeDuration delayParameter;
208
209
210
211
212
213
214 public DelayedInfoType(final String id, final ParameterTypeDuration delayParameter)
215 {
216 this.id = id;
217 this.delayParameter = delayParameter;
218 }
219
220
221
222
223
224 public final String getId()
225 {
226 return this.getId();
227 }
228
229
230
231
232
233 public ParameterTypeDuration getDelayParameter()
234 {
235 return this.delayParameter;
236 }
237
238
239 @Override
240 public final int hashCode()
241 {
242 final int prime = 31;
243 int result = 1;
244 result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
245 return result;
246 }
247
248
249 @Override
250 public final boolean equals(final Object obj)
251 {
252 if (this == obj)
253 {
254 return true;
255 }
256 if (obj == null)
257 {
258 return false;
259 }
260 if (getClass() != obj.getClass())
261 {
262 return false;
263 }
264 DelayedInfoType<?> other = (DelayedInfoType<?>) obj;
265 if (this.id == null)
266 {
267 if (other.id != null)
268 {
269 return false;
270 }
271 }
272 else if (!this.id.equals(other.id))
273 {
274 return false;
275 }
276 return true;
277 }
278
279
280 @Override
281 public String toString()
282 {
283 return "DelayedInfoType [id=" + this.id + ", delayParameter=" + this.delayParameter + "]";
284 }
285
286 }
287
288 }