1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Set;
7 import java.util.TreeMap;
8
9 import org.djunits.unit.LengthUnit;
10 import org.djunits.value.vdouble.scalar.Length;
11 import org.djunits.value.vdouble.scalar.Time;
12 import org.opentrafficsim.core.gtu.GTUDirectionality;
13 import org.opentrafficsim.core.gtu.GTUException;
14 import org.opentrafficsim.core.gtu.GTUType;
15 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
16 import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
17 import org.opentrafficsim.core.gtu.perception.AbstractPerception;
18 import org.opentrafficsim.core.network.LateralDirectionality;
19 import org.opentrafficsim.core.network.Link;
20 import org.opentrafficsim.core.network.NetworkException;
21 import org.opentrafficsim.core.network.Node;
22 import org.opentrafficsim.core.network.route.Route;
23 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
24 import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
25 import org.opentrafficsim.road.network.lane.DirectedLanePosition;
26 import org.opentrafficsim.road.network.lane.Lane;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public abstract class AbstractLanePerception extends AbstractPerception implements LanePerception
48 {
49
50
51 private static final long serialVersionUID = 20151128L;
52
53
54 private LaneStructure laneStructure = null;
55
56
57 private Time updateTime = null;
58
59
60
61
62
63
64
65 public AbstractLanePerception(final LaneBasedGTU gtu)
66 {
67 super(gtu);
68 }
69
70
71 @Override
72 public final LaneBasedGTU getGtu()
73 {
74 return (LaneBasedGTU) super.getGtu();
75 }
76
77
78 @Override
79 public final LaneStructure getLaneStructure() throws ParameterException
80 {
81 if (this.laneStructure == null || this.updateTime.lt(getGtu().getSimulator().getSimulatorTime().getTime()))
82 {
83
84 Length down = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.PERCEPTION);
85
86 Length up = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKBACK);
87
88 Length downSplit = getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD);
89
90 Length upMerge = Length.max(up, downSplit);
91
92 up = up.multiplyBy(-1.0);
93 upMerge = upMerge.multiplyBy(-1.0);
94
95 DirectedLanePosition dlp;
96 try
97 {
98 dlp = getGtu().getReferencePosition();
99 }
100 catch (GTUException exception)
101 {
102
103 throw new RuntimeException("Could not get fraction on root lane.", exception);
104 }
105 Lane rootLane = dlp.getLane();
106 GTUDirectionality direction = dlp.getGtuDirection();
107 double fraction = dlp.getPosition().si / rootLane.getLength().si;
108 LaneStructureRecord rootLSR =
109 new LaneStructureRecord(rootLane, direction, rootLane.getLength().multiplyBy(-fraction));
110 this.laneStructure = new LaneStructure(rootLSR, downSplit);
111 this.laneStructure.addLaneStructureRecord(rootLSR, RelativeLane.CURRENT);
112 this.relativeLaneMap.clear();
113 this.relativeLaneMap.put(rootLSR, RelativeLane.CURRENT);
114 startBuild(rootLSR, fraction, getGtu().getGTUType(), down, downSplit, up, upMerge);
115
116
117
118 this.updateTime = getGtu().getSimulator().getSimulatorTime().getTime();
119 }
120 return this.laneStructure;
121 }
122
123
124
125
126 private final Map<LaneStructureRecord, RelativeLane> relativeLaneMap = new HashMap<>();
127
128
129 private final Set<Lane> ignoreSet = new HashSet<>();
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 private void startBuild(final LaneStructureRecord rootLSR, final double fraction, final GTUType gtuType, final Length down,
158 final Length downSplit, final Length up, final Length upMerge)
159 {
160
161 Set<LaneStructureRecord> recordSet = new HashSet<>();
162 Set<Lane> laneSet = new HashSet<>();
163 recordSet.add(rootLSR);
164 laneSet.add(rootLSR.getLane());
165 for (LateralDirectionality latDirection : new LateralDirectionality[] { LateralDirectionality.LEFT,
166 LateralDirectionality.RIGHT })
167 {
168 LaneStructureRecord current = rootLSR;
169 RelativeLane relativeLane = RelativeLane.CURRENT;
170 while (!current.getLane().accessibleAdjacentLanes(latDirection, gtuType).isEmpty())
171 {
172 relativeLane = latDirection.isLeft() ? relativeLane.getLeft() : relativeLane.getRight();
173 Lane lane = current.getLane().accessibleAdjacentLanes(latDirection, gtuType).iterator().next();
174 LaneStructureRecord adjacentRecord =
175 constructRecord(lane, current.getDirection(), lane.getLength().multiplyBy(-fraction), relativeLane);
176 if (latDirection.isLeft())
177 {
178 if (lane.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).contains(current.getLane()))
179 {
180 adjacentRecord.setRight(current);
181 }
182 current.setLeft(adjacentRecord);
183 }
184 else
185 {
186 if (lane.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).contains(current.getLane()))
187 {
188 adjacentRecord.setLeft(current);
189 }
190 current.setRight(adjacentRecord);
191 }
192 recordSet.add(adjacentRecord);
193 laneSet.add(lane);
194 current = adjacentRecord;
195 }
196 }
197 try
198 {
199
200 this.ignoreSet.clear();
201 buildDownstreamRecursive(recordSet, gtuType, down, up, downSplit, upMerge);
202
203 this.ignoreSet.clear();
204 buildUpstreamRecursive(recordSet, gtuType, down, up, upMerge);
205 }
206 catch (GTUException | NetworkException exception)
207 {
208 throw new RuntimeException("Exception while building lane map.", exception);
209 }
210 }
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 private void buildDownstreamRecursive(final Set<LaneStructureRecord> recordSet, final GTUType gtuType, final Length down,
239 final Length up, final Length downSplit, final Length upMerge) throws GTUException, NetworkException
240 {
241
242 Map<Link, Set<Lane>> laneSets = new HashMap<>();
243 Map<Link, TreeMap<RelativeLane, LaneStructureRecord>> recordSets = new HashMap<>();
244 Map<Link, Length> maxStart = new HashMap<>();
245 for (LaneStructureRecord laneRecord : recordSet)
246 {
247 if (!laneRecord.isCutOffEnd())
248 {
249 for (Lane nextLane : laneRecord.getLane().nextLanes(gtuType).keySet())
250 {
251 Link nextLink = nextLane.getParentLink();
252 if (!laneSets.containsKey(nextLink))
253 {
254 laneSets.put(nextLink, new HashSet<>());
255 recordSets.put(nextLink, new TreeMap<>());
256 maxStart.put(nextLink, new Length(Double.MIN_VALUE, LengthUnit.SI));
257 }
258 laneSets.get(nextLink).add(nextLane);
259 RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
260 Length start = laneRecord.getStartDistance().plus(laneRecord.getLane().getLength());
261 maxStart.put(nextLink, Length.max(maxStart.get(nextLink), start));
262 LaneStructureRecord nextRecord = constructRecord(nextLane,
263 laneRecord.getLane().nextLanes(gtuType).get(nextLane), start, relativeLane);
264 if (start.plus(nextLane.getLength()).ge(down))
265 {
266 nextRecord.setCutOffEnd(down.minus(start));
267
268 }
269 recordSets.get(nextLink).put(relativeLane, nextRecord);
270 laneRecord.addNext(nextRecord);
271 nextRecord.addPrev(laneRecord);
272 }
273 }
274 else
275 {
276 for (Lane nextLane : laneRecord.getLane().nextLanes(gtuType).keySet())
277 {
278 this.ignoreSet.add(nextLane);
279 }
280 }
281 }
282
283 Link currentLink = recordSet.iterator().next().getLane().getParentLink();
284 GTUDirectionality direction = recordSet.iterator().next().getDirection();
285 for (Link link : laneSets.keySet())
286 {
287 connectLaterally(recordSets.get(link), gtuType);
288 Set<LaneStructureRecord> set = new HashSet<>(recordSets.get(link).values());
289
290 set = extendLateral(set, gtuType, down, up, upMerge, true);
291
292 Node nextNode = direction.isPlus() ? currentLink.getEndNode() : currentLink.getStartNode();
293 Length downLimit = down;
294 Route route = getGtu().getStrategicalPlanner().getRoute();
295 if (route != null && (!route.contains(nextNode)
296 || !((LaneBasedStrategicalRoutePlanner) getGtu().getStrategicalPlanner())
297 .nextLinkDirection(nextNode, currentLink, gtuType).equals(link)))
298 {
299
300 downLimit = Length.min(downLimit, maxStart.get(link).plus(downSplit));
301 }
302
303 buildDownstreamRecursive(set, gtuType, downLimit, up, downSplit, upMerge);
304 }
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 private Set<LaneStructureRecord> extendLateral(final Set<LaneStructureRecord> recordSet, final GTUType gtuType,
336 final Length down, final Length up, final Length upMerge, final boolean downstreamBuild)
337 throws GTUException, NetworkException
338 {
339 Set<Lane> laneSet = new HashSet<>();
340 for (LaneStructureRecord laneStructureRecord : recordSet)
341 {
342 laneSet.add(laneStructureRecord.getLane());
343 }
344 for (LateralDirectionality latDirection : new LateralDirectionality[] { LateralDirectionality.LEFT,
345 LateralDirectionality.RIGHT })
346 {
347 Set<LaneStructureRecord> expandSet = new HashSet<>();
348 Length startDistance = null;
349 Length endDistance = null;
350 for (LaneStructureRecord laneRecord : recordSet)
351 {
352 LaneStructureRecord current = laneRecord;
353 startDistance = current.getStartDistance();
354 endDistance = current.getStartDistance().plus(current.getLane().getLength());
355 RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
356 while (!current.getLane().accessibleAdjacentLanes(latDirection, gtuType).isEmpty())
357 {
358 Lane laneAdjacent = current.getLane().accessibleAdjacentLanes(latDirection, gtuType).iterator().next();
359 Length adjacentStart = downstreamBuild ? startDistance : endDistance.minus(laneAdjacent.getLength());
360
361 if (!laneSet.contains(laneAdjacent) && !adjacentStart.plus(laneAdjacent.getLength()).le(up)
362 && !adjacentStart.ge(down) && !this.ignoreSet.contains(laneAdjacent))
363 {
364 laneSet.add(laneAdjacent);
365 relativeLane = latDirection.isLeft() ? relativeLane.getLeft() : relativeLane.getRight();
366 LaneStructureRecord recordAdjacent =
367 constructRecord(laneAdjacent, laneRecord.getDirection(), adjacentStart, relativeLane);
368 expandSet.add(recordAdjacent);
369 recordSet.add(recordAdjacent);
370 if (latDirection.isLeft())
371 {
372 if (laneAdjacent.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType)
373 .contains(current.getLane()))
374 {
375 recordAdjacent.setRight(current);
376 }
377 current.setLeft(recordAdjacent);
378 }
379 else
380 {
381 if (laneAdjacent.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType)
382 .contains(current.getLane()))
383 {
384 recordAdjacent.setLeft(current);
385 }
386 current.setRight(recordAdjacent);
387 }
388 if (adjacentStart.plus(laneAdjacent.getLength()).ge(down))
389 {
390 recordAdjacent.setCutOffEnd(down.minus(adjacentStart));
391
392 }
393 if (adjacentStart.le(up))
394 {
395 recordAdjacent.setCutOffStart(up.minus(adjacentStart));
396
397 }
398 current = recordAdjacent;
399 }
400 else
401 {
402 break;
403 }
404 }
405 }
406 if (downstreamBuild & !expandSet.isEmpty())
407 {
408
409
410 buildUpstreamRecursive(expandSet, gtuType, down, startDistance.plus(upMerge), upMerge);
411
412 }
413 }
414 return recordSet;
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428 private void buildUpstreamRecursive(final Set<LaneStructureRecord> recordSet, final GTUType gtuType, final Length down,
429 final Length up, final Length upMerge) throws GTUException, NetworkException
430 {
431
432 Map<Link, Set<Lane>> laneSets = new HashMap<>();
433 Map<Link, TreeMap<RelativeLane, LaneStructureRecord>> recordSets = new HashMap<>();
434 Map<Link, Length> minStart = new HashMap<>();
435 for (LaneStructureRecord laneRecord : recordSet)
436 {
437 if (!laneRecord.isCutOffStart())
438 {
439 for (Lane prevLane : laneRecord.getLane().prevLanes(gtuType).keySet())
440 {
441 Link prevLink = prevLane.getParentLink();
442 if (!laneSets.containsKey(prevLink))
443 {
444 laneSets.put(prevLink, new HashSet<>());
445 recordSets.put(prevLink, new TreeMap<>());
446 minStart.put(prevLink, new Length(Double.MAX_VALUE, LengthUnit.SI));
447 }
448 laneSets.get(prevLink).add(prevLane);
449 RelativeLane relativeLane = this.relativeLaneMap.get(laneRecord);
450 Length start = laneRecord.getStartDistance().minus(laneRecord.getLane().getLength());
451 minStart.put(prevLink, Length.min(minStart.get(prevLink), start));
452 LaneStructureRecord prevRecord = constructRecord(prevLane,
453 laneRecord.getLane().prevLanes(gtuType).get(prevLane), start, relativeLane);
454 if (start.le(up))
455 {
456 prevRecord.setCutOffStart(up.minus(start));
457
458 }
459 recordSets.get(prevLink).put(relativeLane, prevRecord);
460 laneRecord.addPrev(prevRecord);
461 prevRecord.addNext(laneRecord);
462 }
463 }
464 else
465 {
466 for (Lane prevLane : laneRecord.getLane().prevLanes(gtuType).keySet())
467 {
468 this.ignoreSet.add(prevLane);
469 }
470 }
471 }
472
473 for (Link link : laneSets.keySet())
474 {
475 connectLaterally(recordSets.get(link), gtuType);
476 Set<LaneStructureRecord> set = new HashSet<>(recordSets.get(link).values());
477
478 set = extendLateral(set, gtuType, down, up, upMerge, false);
479
480 buildUpstreamRecursive(set, gtuType, down, up, upMerge);
481 }
482 }
483
484
485
486
487
488
489
490
491
492 private LaneStructureRecord constructRecord(final Lane lane, final GTUDirectionality direction, final Length startDistance,
493 final RelativeLane relativeLane)
494 {
495
496 LaneStructureRecord record = new LaneStructureRecord(lane, direction, startDistance);
497 this.laneStructure.addLaneStructureRecord(record, relativeLane);
498 this.relativeLaneMap.put(record, relativeLane);
499 return record;
500 }
501
502
503
504
505
506
507 private void connectLaterally(final Map<RelativeLane, LaneStructureRecord> map, final GTUType gtuType)
508 {
509 for (RelativeLane relativeLane : map.keySet())
510 {
511 if (map.containsKey(relativeLane.getRight()))
512 {
513 Lane thisLane = map.get(relativeLane).getLane();
514 Lane rightLane = map.get(relativeLane.getRight()).getLane();
515 if (thisLane.accessibleAdjacentLanes(LateralDirectionality.RIGHT, gtuType).contains(rightLane))
516 {
517 map.get(relativeLane).setRight(map.get(relativeLane.getRight()));
518 }
519 if (rightLane.accessibleAdjacentLanes(LateralDirectionality.LEFT, gtuType).contains(thisLane))
520 {
521 map.get(relativeLane.getRight()).setLeft(map.get(relativeLane));
522 }
523 }
524 }
525 }
526
527
528 public final EnvironmentState getEnvironmentState()
529 {
530 return this.laneStructure;
531 }
532
533 }