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