1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashMap;
5 import java.util.LinkedHashSet;
6 import java.util.LinkedList;
7 import java.util.Map;
8 import java.util.Queue;
9 import java.util.Set;
10 import java.util.SortedMap;
11 import java.util.TreeMap;
12
13 import org.djunits.value.vdouble.scalar.Length;
14 import org.djutils.exceptions.Try;
15 import org.opentrafficsim.core.gtu.GtuException;
16 import org.opentrafficsim.core.gtu.RelativePosition;
17 import org.opentrafficsim.core.network.Link;
18 import org.opentrafficsim.core.network.route.Route;
19 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
20 import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
21 import org.opentrafficsim.road.gtu.lane.perception.structure.LaneRecordInterface;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public abstract class AbstractPerceptionIterable<H extends Headway, U, C> extends AbstractPerceptionReiterable<H, U>
37 {
38
39
40 private final LaneRecordInterface<?> root;
41
42
43 private final Length initialPosition;
44
45
46 private final boolean downstream;
47
48
49 private final double maxDistance;
50
51
52 private final RelativePosition relativePosition;
53
54
55 private final Route route;
56
57
58
59
60
61
62
63
64
65
66
67 public AbstractPerceptionIterable(final LaneBasedGtu perceivingGtu, final LaneRecordInterface<?> root,
68 final Length initialPosition, final boolean downstream, final Length maxDistance,
69 final RelativePosition relativePosition, final Route route)
70 {
71 super(perceivingGtu);
72 this.root = root;
73 this.initialPosition = initialPosition;
74 this.downstream = downstream;
75 this.maxDistance = maxDistance.si;
76 this.relativePosition = relativePosition;
77 this.route = route;
78 }
79
80
81
82
83
84 public boolean isDownstream()
85 {
86 return this.downstream;
87 }
88
89
90 @Override
91 public Iterator<PrimaryIteratorEntry> primaryIterator()
92 {
93 return new PrimaryIterator();
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 protected abstract Entry getNext(LaneRecordInterface<?> record, Length position, C counter) throws GtuException;
108
109
110
111
112
113
114
115
116
117 protected abstract Length getDistance(U object, LaneRecordInterface<?> record, Length position);
118
119
120
121
122
123
124 protected Length getDx()
125 {
126 return this.relativePosition.dx();
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141 private class PrimaryIterator implements Iterator<PrimaryIteratorEntry>
142 {
143
144
145 private SortedMap<PrimaryIteratorEntry, LaneRecordInterface<?>> map;
146
147
148 private Map<LaneRecordInterface<?>, Length> positions = new LinkedHashMap<>();
149
150
151 private Set<U> returnedItems = new LinkedHashSet<>();
152
153
154 private Map<LaneRecordInterface<?>, Queue<PrimaryIteratorEntry>> queues = new LinkedHashMap<>();
155
156
157 private Map<LaneRecordInterface<?>, C> counters = new LinkedHashMap<>();
158
159
160 private LaneRecordInterface<?> postponedRecord = null;
161
162
163 private Length postponedPosition = null;
164
165
166 PrimaryIterator()
167 {
168
169 }
170
171
172 @Override
173 public boolean hasNext()
174 {
175
176 startProcess();
177
178
179 return !this.map.isEmpty();
180 }
181
182
183 @Override
184 public PrimaryIteratorEntry next()
185 {
186
187 startProcess();
188
189
190 PrimaryIteratorEntry nextEntry = this.map.firstKey();
191 U next = nextEntry.getObject();
192 LaneRecordInterface<?> record = this.map.get(nextEntry);
193 this.map.remove(nextEntry);
194
195
196 Queue<PrimaryIteratorEntry> queue = this.queues.get(next);
197 if (queue != null)
198 {
199 PrimaryIteratorEntry nextNext = queue.poll();
200 this.map.put(nextNext, record);
201 if (queue.isEmpty())
202 {
203 this.queues.remove(record);
204 }
205 preventDuplicateEntries(nextEntry.getObject());
206 return nextNext;
207 }
208
209
210 this.postponedRecord = record;
211 this.postponedPosition = this.positions.get(record);
212 preventDuplicateEntries(nextEntry.getObject());
213 return nextEntry;
214 }
215
216
217
218
219
220 private void preventDuplicateEntries(final U object)
221 {
222 this.returnedItems.add(object);
223 Iterator<PrimaryIteratorEntry> it = this.map.keySet().iterator();
224 while (it.hasNext())
225 {
226 PrimaryIteratorEntry entry = it.next();
227 if (entry.getObject().equals(object))
228 {
229 it.remove();
230 }
231 }
232 }
233
234
235
236
237 @SuppressWarnings("synthetic-access")
238 private void startProcess()
239 {
240 if (this.postponedRecord != null)
241 {
242
243 prepareNext(this.postponedRecord, this.postponedPosition);
244 this.postponedRecord = null;
245 this.postponedPosition = null;
246 }
247 else if (this.map == null)
248 {
249
250 this.map = new TreeMap<>();
251 prepareNext(AbstractPerceptionIterable.this.root, AbstractPerceptionIterable.this.initialPosition);
252 }
253 }
254
255
256
257
258
259
260 @SuppressWarnings("synthetic-access")
261 private void prepareNext(final LaneRecordInterface<?> record, final Length position)
262 {
263 Entry next = Try.assign(() -> AbstractPerceptionIterable.this.getNext(record, position, this.counters.get(record)),
264 "Exception while deriving next object.");
265 if (next == null)
266 {
267 this.counters.remove(record);
268 double distance = AbstractPerceptionIterable.this.downstream
269 ? record.getStartDistance().si + record.getLength().si : -record.getStartDistance().si;
270
271 if (distance < AbstractPerceptionIterable.this.maxDistance)
272 {
273 if (AbstractPerceptionIterable.this.downstream)
274 {
275 for (LaneRecordInterface<?> nextRecord : record.getNext())
276 {
277 if (isOnRoute(nextRecord))
278 {
279 prepareNext(nextRecord, Length.instantiateSI(-1e-9));
280 }
281 }
282 }
283 else
284 {
285 for (LaneRecordInterface<?> nextRecord : record.getPrev())
286 {
287 if (isOnRoute(nextRecord))
288 {
289 prepareNext(nextRecord, nextRecord.getLength());
290 }
291 }
292 }
293 }
294 }
295 else
296 {
297 this.counters.put(record, next.counter);
298 if (next.isSet())
299 {
300 Iterator<U> it = next.set.iterator();
301 U nextNext = it.next();
302 if (!this.returnedItems.contains(nextNext))
303 {
304 Length distance = getDistance(nextNext, record, next.position);
305 if (distance == null
306 || distance.si <= AbstractPerceptionIterable.this.maxDistance)
307 {
308
309 this.map.put(new PrimaryIteratorEntry(nextNext, distance), record);
310 this.positions.put(record, next.position);
311 if (next.set.size() > 1)
312 {
313
314 Queue<PrimaryIteratorEntry> queue = new LinkedList<>();
315 while (it.hasNext())
316 {
317 nextNext = it.next();
318 queue.add(new PrimaryIteratorEntry(nextNext, getDistance(nextNext, record, next.position)));
319 }
320 this.queues.put(record, queue);
321 }
322 }
323 }
324 }
325 else if (!this.returnedItems.contains(next.object))
326 {
327 Length distance = getDistance(next.object, record, next.position);
328 if (distance == null
329 || distance.si <= AbstractPerceptionIterable.this.maxDistance)
330 {
331
332 this.map.put(new PrimaryIteratorEntry(next.object, distance), record);
333 this.positions.put(record, next.position);
334 }
335 }
336 }
337 }
338
339 }
340
341
342
343
344
345
346 final boolean isOnRoute(final LaneRecordInterface<?> record)
347 {
348 if (this.route == null)
349 {
350 return true;
351 }
352 Link link = record.getLane().getLink();
353 int from;
354 int to;
355 from = this.route.indexOf(link.getStartNode());
356 to = this.route.indexOf(link.getEndNode());
357 return from != -1 && to != -1 && to - from == 1;
358 }
359
360
361
362
363
364
365
366
367
368
369
370
371
372 protected class Entry
373 {
374
375
376 private final Set<U> set;
377
378
379 private final U object;
380
381
382 private final C counter;
383
384
385 private final Length position;
386
387
388
389
390
391
392
393 public Entry(final U object, final C counter, final Length position)
394 {
395 this.set = null;
396 this.object = object;
397 this.counter = counter;
398 this.position = position;
399 }
400
401
402
403
404
405
406
407 public Entry(final Set<U> set, final C counter, final Length position)
408 {
409 this.set = set;
410 this.object = null;
411 this.counter = counter;
412 this.position = position;
413 }
414
415
416
417
418
419 final boolean isSet()
420 {
421 return this.set != null;
422 }
423
424
425
426
427
428 public U getObject()
429 {
430 return this.object;
431 }
432
433
434
435
436
437 public Set<U> getSet()
438 {
439 return this.set;
440 }
441
442 }
443
444 }