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