1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.util.Iterator;
4 import java.util.NoSuchElementException;
5 import java.util.function.Function;
6 import java.util.function.Supplier;
7
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.opentrafficsim.base.parameters.ParameterException;
10 import org.opentrafficsim.core.gtu.GtuException;
11 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
12 import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 public abstract class AbstractPerceptionReiterable<P extends LaneBasedObject, H extends Headway, U>
31 implements PerceptionCollectable<H, U>
32 {
33
34
35 private SecondaryIteratorEntry first;
36
37
38 private SecondaryIteratorEntry last;
39
40
41 private Iterator<PrimaryIteratorEntry> primaryIterator;
42
43
44 private final P perceivingObject;
45
46
47
48
49
50 protected AbstractPerceptionReiterable(final P perceivingObject)
51 {
52 this.perceivingObject = perceivingObject;
53 }
54
55
56
57
58
59 protected P getObject()
60 {
61 return this.perceivingObject;
62 }
63
64
65
66
67
68 final Iterator<PrimaryIteratorEntry> getPrimaryIterator()
69 {
70 if (this.primaryIterator == null)
71 {
72 this.primaryIterator = primaryIterator();
73 }
74 return this.primaryIterator;
75 }
76
77
78
79
80
81 protected abstract Iterator<PrimaryIteratorEntry> primaryIterator();
82
83
84
85
86
87
88
89
90
91 protected abstract H perceive(U object, Length distance) throws GtuException, ParameterException;
92
93 @Override
94 public final synchronized H first()
95 {
96 assureFirst();
97 if (this.first == null)
98 {
99 return null;
100 }
101 return this.first.getValue();
102 }
103
104
105
106
107 private synchronized void assureFirst()
108 {
109 if (this.first == null && getPrimaryIterator().hasNext())
110 {
111 addNext(getPrimaryIterator().next());
112 }
113 }
114
115
116
117
118
119 final void addNext(final PrimaryIteratorEntry next)
120 {
121 SecondaryIteratorEntry entry = new SecondaryIteratorEntry(next.object, next.distance);
122 if (AbstractPerceptionReiterable.this.last == null)
123 {
124 AbstractPerceptionReiterable.this.first = entry;
125 AbstractPerceptionReiterable.this.last = entry;
126 }
127 else
128 {
129 AbstractPerceptionReiterable.this.last.next = entry;
130 AbstractPerceptionReiterable.this.last = entry;
131 }
132 }
133
134 @Override
135 public final boolean isEmpty()
136 {
137 return first() == null;
138 }
139
140 @Override
141 public final Iterator<H> iterator()
142 {
143 return new PerceptionIterator();
144 }
145
146 @Override
147 public final <C, I> C collect(final Supplier<I> identity, final PerceptionAccumulator<? super U, I> accumulator,
148 final Function<I, C> finalizer)
149 {
150 Intermediate<I> intermediate = new Intermediate<>(identity.get());
151 assureFirst();
152 if (this.first != null)
153 {
154 SecondaryIteratorEntry lastReturned = null;
155 SecondaryIteratorEntry next = this.first;
156 next = assureNext(next, lastReturned);
157 while (next != null && !intermediate.isStop())
158 {
159 intermediate = accumulator.accumulate(intermediate, next.object, next.distance);
160 intermediate.step();
161 lastReturned = next;
162 next = lastReturned.next;
163 next = assureNext(next, lastReturned);
164 }
165 }
166 return finalizer.apply(intermediate.getObject());
167 }
168
169 @Override
170 public Iterator<U> underlying()
171 {
172 assureFirst();
173 SecondaryIteratorEntry firstInContext = this.first;
174 return new Iterator<U>()
175 {
176
177 private SecondaryIteratorEntry lastReturned = null;
178
179
180 private SecondaryIteratorEntry next = firstInContext;
181
182 @Override
183 public boolean hasNext()
184 {
185 this.next = assureNext(this.next, this.lastReturned);
186 return this.next != null;
187 }
188
189 @Override
190 public U next()
191 {
192
193
194
195
196
197
198
199
200
201 this.lastReturned = this.next;
202 this.next = this.lastReturned.next;
203 this.next = assureNext(this.next, this.lastReturned);
204 return this.lastReturned.object;
205 }
206 };
207 }
208
209 @Override
210 public Iterator<UnderlyingDistance<U>> underlyingWithDistance()
211 {
212 assureFirst();
213 SecondaryIteratorEntry firstInContext = this.first;
214 return new Iterator<UnderlyingDistance<U>>()
215 {
216
217 private SecondaryIteratorEntry lastReturned = null;
218
219
220 private SecondaryIteratorEntry next = firstInContext;
221
222 @Override
223 public boolean hasNext()
224 {
225 this.next = assureNext(this.next, this.lastReturned);
226 return this.next != null;
227 }
228
229 @Override
230 public UnderlyingDistance<U> next()
231 {
232 this.lastReturned = this.next;
233 this.next = this.lastReturned.next;
234 this.next = assureNext(this.next, this.lastReturned);
235 return new UnderlyingDistance<>(this.lastReturned.object, this.lastReturned.distance);
236 }
237 };
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public class PerceptionIterator implements Iterator<H>
254 {
255
256
257 private SecondaryIteratorEntry lastReturned;
258
259
260 private SecondaryIteratorEntry next;
261
262
263 PerceptionIterator()
264 {
265 this.next = AbstractPerceptionReiterable.this.first;
266 }
267
268 @Override
269 public boolean hasNext()
270 {
271 this.next = assureNext(this.next, this.lastReturned);
272 return this.next != null;
273 }
274
275 @Override
276 public H next()
277 {
278 this.next = assureNext(this.next, this.lastReturned);
279 if (this.next == null)
280 {
281 throw new NoSuchElementException();
282 }
283 this.lastReturned = this.next;
284 this.next = this.lastReturned.next;
285 return this.lastReturned.getValue();
286 }
287
288 }
289
290
291
292
293
294
295
296
297 synchronized SecondaryIteratorEntry assureNext(final SecondaryIteratorEntry next, final SecondaryIteratorEntry lastReturned)
298 {
299 if (next != null)
300 {
301 return next;
302 }
303 if (lastReturned != null)
304 {
305 if (lastReturned.next == null)
306 {
307 if (getPrimaryIterator().hasNext())
308 {
309 addNext(getPrimaryIterator().next());
310 }
311 }
312 return lastReturned.next;
313 }
314 if (getPrimaryIterator().hasNext())
315 {
316 addNext(getPrimaryIterator().next());
317 }
318 return AbstractPerceptionReiterable.this.first;
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332 protected class PrimaryIteratorEntry implements Comparable<PrimaryIteratorEntry>
333 {
334
335 private final U object;
336
337
338 private final Length distance;
339
340
341
342
343
344
345 public PrimaryIteratorEntry(final U object, final Length distance)
346 {
347 this.object = object;
348 this.distance = distance;
349 }
350
351 @Override
352 public int compareTo(final PrimaryIteratorEntry o)
353 {
354 return this.distance.compareTo(o.distance);
355 }
356
357
358
359
360
361 protected U getObject()
362 {
363 return this.object;
364 }
365 }
366
367
368
369
370
371
372
373
374
375
376
377
378 private class SecondaryIteratorEntry
379 {
380
381 private final U object;
382
383
384 private final Length distance;
385
386
387 private H value;
388
389
390 private SecondaryIteratorEntry next;
391
392
393
394
395
396
397 SecondaryIteratorEntry(final U object, final Length distance)
398 {
399 this.object = object;
400 this.distance = distance;
401 }
402
403
404
405
406
407 H getValue()
408 {
409 if (this.value == null)
410 {
411
412
413
414
415 try
416 {
417 this.value = perceive(this.object, this.distance);
418 }
419 catch (Exception e)
420 {
421 e.printStackTrace();
422 }
423
424 }
425 return this.value;
426 }
427 }
428
429 }