1 package org.opentrafficsim.road.gtu.lane.perception;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import org.djunits.unit.LengthUnit;
13 import org.djunits.unit.SpeedUnit;
14 import org.djunits.value.vdouble.scalar.Length;
15 import org.djunits.value.vdouble.scalar.Speed;
16 import org.djunits.value.vdouble.scalar.Time;
17 import org.opentrafficsim.core.gtu.GTUDirectionality;
18 import org.opentrafficsim.core.gtu.GTUException;
19 import org.opentrafficsim.core.gtu.RelativePosition;
20 import org.opentrafficsim.core.network.LateralDirectionality;
21 import org.opentrafficsim.core.network.NetworkException;
22 import org.opentrafficsim.core.perception.PerceivedObject;
23 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
24 import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
25 import org.opentrafficsim.road.gtu.lane.tactical.LanePathInfo;
26 import org.opentrafficsim.road.gtu.lane.tactical.following.HeadwayGTU;
27 import org.opentrafficsim.road.network.lane.Lane;
28 import org.opentrafficsim.road.network.lane.LaneDirection;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public abstract class AbstractLanePerception implements LanePerception
49 {
50
51 private static final long serialVersionUID = 20151128L;
52
53
54 private LaneBasedGTU gtu;
55
56
57 private TimeStampedObject<HeadwayGTU> forwardHeadwayGTU;
58
59
60 private TimeStampedObject<HeadwayGTU> backwardHeadwayGTU;
61
62
63 private TimeStampedObject<Speed> speedLimit;
64
65
66 private TimeStampedObject<Map<Lane, Set<Lane>>> accessibleAdjacentLanesLeft;
67
68
69 private TimeStampedObject<Map<Lane, Set<Lane>>> accessibleAdjacentLanesRight;
70
71
72 private TimeStampedObject<Set<LaneBasedGTU>> parallelGTUsLeft;
73
74
75 private TimeStampedObject<Set<LaneBasedGTU>> parallelGTUsRight;
76
77
78 private TimeStampedObject<Collection<HeadwayGTU>> neighboringGTUsLeft;
79
80
81 private TimeStampedObject<Collection<HeadwayGTU>> neighboringGTUsRight;
82
83
84 private TimeStampedObject<LanePathInfo> lanePathInfo;
85
86
87
88
89
90
91
92
93
94 public AbstractLanePerception()
95 {
96 super();
97 }
98
99
100 @Override
101 public final void setGTU(final LaneBasedGTU laneBasedGtu)
102 {
103 this.gtu = laneBasedGtu;
104 }
105
106
107
108
109
110
111 private Time.Abs getTimestamp() throws GTUException
112 {
113 if (this.gtu == null)
114 {
115 throw new GTUException("gtu value has not been initialized for LanePerception when perceiving.");
116 }
117 return this.gtu.getSimulator().getSimulatorTime().getTime();
118 }
119
120
121
122
123
124 public final void updateLanePathInfo() throws GTUException, NetworkException
125 {
126 Time.Abs timestamp = getTimestamp();
127 this.lanePathInfo =
128 new TimeStampedObject<LanePathInfo>(AbstractLaneBasedTacticalPlanner.buildLanePathInfo(this.gtu, this.gtu
129 .getBehavioralCharacteristics().getForwardHeadwayDistance()), timestamp);
130 }
131
132
133 @Override
134 public final void updateSpeedLimit() throws GTUException, NetworkException
135 {
136 Time.Abs timestamp = getTimestamp();
137
138 this.speedLimit = new TimeStampedObject<>(new Speed(Double.MAX_VALUE, SpeedUnit.SI), timestamp);
139 for (Lane lane : this.gtu.getLanes().keySet())
140 {
141 if (lane.getSpeedLimit(this.gtu.getGTUType()).lt(this.speedLimit.getObject()))
142 {
143 this.speedLimit = new TimeStampedObject<>(lane.getSpeedLimit(this.gtu.getGTUType()), timestamp);
144 }
145 }
146 }
147
148
149 @Override
150 public final void updateForwardHeadwayGTU() throws GTUException, NetworkException
151 {
152 Time.Abs timestamp = getTimestamp();
153 if (this.lanePathInfo == null || this.lanePathInfo.getTimestamp().ne(timestamp))
154 {
155 updateLanePathInfo();
156 }
157 Length.Rel maximumForwardHeadway = this.gtu.getBehavioralCharacteristics().getForwardHeadwayDistance();
158 this.forwardHeadwayGTU = new TimeStampedObject<>(forwardHeadway(maximumForwardHeadway), timestamp);
159 }
160
161
162 @Override
163 public final void updateBackwardHeadwayGTU() throws GTUException, NetworkException
164 {
165 Time.Abs timestamp = getTimestamp();
166 Length.Rel maximumReverseHeadway = this.gtu.getBehavioralCharacteristics().getBackwardHeadwayDistance();
167 this.backwardHeadwayGTU = new TimeStampedObject<>(backwardHeadway(maximumReverseHeadway), timestamp);
168 }
169
170
171 @Override
172 public final void updateAccessibleAdjacentLanesLeft() throws GTUException
173 {
174 Time.Abs timestamp = getTimestamp();
175 Map<Lane, Set<Lane>> accessibleAdjacentLanesMap = new HashMap<>();
176 for (Lane lane : this.gtu.getLanes().keySet())
177 {
178 Set<Lane> adjacentLanes = new HashSet<Lane>(1);
179 adjacentLanes.addAll(lane.accessibleAdjacentLanes(LateralDirectionality.LEFT, this.gtu.getGTUType()));
180 accessibleAdjacentLanesMap.put(lane, adjacentLanes);
181 }
182 this.accessibleAdjacentLanesLeft = new TimeStampedObject<>(accessibleAdjacentLanesMap, timestamp);
183 }
184
185
186 @Override
187 public final void updateAccessibleAdjacentLanesRight() throws GTUException
188 {
189 Time.Abs timestamp = getTimestamp();
190 Map<Lane, Set<Lane>> accessibleAdjacentLanesMap = new HashMap<>();
191 for (Lane lane : this.gtu.getLanes().keySet())
192 {
193 Set<Lane> adjacentLanes = new HashSet<Lane>(1);
194 adjacentLanes.addAll(lane.accessibleAdjacentLanes(LateralDirectionality.RIGHT, this.gtu.getGTUType()));
195 accessibleAdjacentLanesMap.put(lane, adjacentLanes);
196 }
197 this.accessibleAdjacentLanesRight = new TimeStampedObject<>(accessibleAdjacentLanesMap, timestamp);
198 }
199
200
201 @Override
202 public final void updateParallelGTUsLeft() throws GTUException
203 {
204 Time.Abs timestamp = getTimestamp();
205 if (this.accessibleAdjacentLanesLeft == null || !timestamp.equals(this.accessibleAdjacentLanesLeft.getTimestamp()))
206 {
207 updateAccessibleAdjacentLanesLeft();
208 }
209 Set<LaneBasedGTU> parallelGTUSet = new HashSet<>();
210 for (Lane lane : this.accessibleAdjacentLanesLeft.getObject().keySet())
211 {
212 for (Lane adjacentLane : this.accessibleAdjacentLanesLeft.getObject().get(lane))
213 {
214 parallelGTUSet.addAll(parallel(adjacentLane, timestamp));
215 }
216 }
217 this.parallelGTUsLeft = new TimeStampedObject<>(parallelGTUSet, timestamp);
218 }
219
220
221 @Override
222 public final void updateParallelGTUsRight() throws GTUException
223 {
224 Time.Abs timestamp = getTimestamp();
225 if (this.accessibleAdjacentLanesRight == null || !timestamp.equals(this.accessibleAdjacentLanesRight.getTimestamp()))
226 {
227 updateAccessibleAdjacentLanesRight();
228 }
229 Set<LaneBasedGTU> parallelGTUSet = new HashSet<>();
230 for (Lane lane : this.accessibleAdjacentLanesRight.getObject().keySet())
231 {
232 for (Lane adjacentLane : this.accessibleAdjacentLanesRight.getObject().get(lane))
233 {
234 parallelGTUSet.addAll(parallel(adjacentLane, timestamp));
235 }
236 }
237 this.parallelGTUsRight = new TimeStampedObject<>(parallelGTUSet, timestamp);
238 }
239
240
241 @Override
242 public final void updateLaneTrafficLeft() throws GTUException, NetworkException
243 {
244 Time.Abs timestamp = getTimestamp();
245 if (this.accessibleAdjacentLanesLeft == null || !timestamp.equals(this.accessibleAdjacentLanesLeft.getTimestamp()))
246 {
247 updateAccessibleAdjacentLanesLeft();
248 }
249
250 if (this.parallelGTUsLeft == null || !timestamp.equals(this.parallelGTUsLeft.getTimestamp()))
251 {
252 updateParallelGTUsLeft();
253 }
254
255
256 Length.Rel maximumForwardHeadway = this.gtu.getBehavioralCharacteristics().getForwardHeadwayDistance();
257 Length.Rel maximumReverseHeadway = this.gtu.getBehavioralCharacteristics().getBackwardHeadwayDistance();
258 this.neighboringGTUsLeft =
259 new TimeStampedObject<>(collectNeighborLaneTraffic(LateralDirectionality.LEFT, timestamp,
260 maximumForwardHeadway, maximumReverseHeadway), timestamp);
261 }
262
263
264 @Override
265 public final void updateLaneTrafficRight() throws GTUException, NetworkException
266 {
267 Time.Abs timestamp = getTimestamp();
268 if (this.accessibleAdjacentLanesRight == null || !timestamp.equals(this.accessibleAdjacentLanesRight.getTimestamp()))
269 {
270 updateAccessibleAdjacentLanesRight();
271 }
272
273 if (this.parallelGTUsRight == null || !timestamp.equals(this.parallelGTUsRight.getTimestamp()))
274 {
275 updateParallelGTUsRight();
276 }
277
278
279 Length.Rel maximumForwardHeadway = this.gtu.getBehavioralCharacteristics().getForwardHeadwayDistance();
280 Length.Rel maximumReverseHeadway = this.gtu.getBehavioralCharacteristics().getBackwardHeadwayDistance();
281 this.neighboringGTUsRight =
282 new TimeStampedObject<>(collectNeighborLaneTraffic(LateralDirectionality.RIGHT, timestamp,
283 maximumForwardHeadway, maximumReverseHeadway), timestamp);
284 }
285
286
287 @Override
288 public final Map<Lane, Set<Lane>> accessibleAdjacentLaneMap(final LateralDirectionality lateralDirection)
289 {
290 return lateralDirection.equals(LateralDirectionality.LEFT) ? this.accessibleAdjacentLanesLeft.getObject()
291 : this.accessibleAdjacentLanesRight.getObject();
292 }
293
294
295 @Override
296 public final Set<LaneBasedGTU> parallelGTUs(final LateralDirectionality lateralDirection)
297 {
298 return lateralDirection.equals(LateralDirectionality.LEFT) ? this.parallelGTUsLeft.getObject() : this.parallelGTUsRight
299 .getObject();
300 }
301
302
303 @Override
304 public final Collection<HeadwayGTU> neighboringGTUCollection(final LateralDirectionality lateralDirection)
305 {
306 return lateralDirection.equals(LateralDirectionality.LEFT) ? this.neighboringGTUsLeft.getObject()
307 : this.neighboringGTUsRight.getObject();
308 }
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330 private HeadwayGTU forwardHeadway(final Length.Rel maxDistance) throws GTUException, NetworkException
331 {
332 LanePathInfo lpi = getLanePathInfo();
333 return forwardHeadway(lpi, maxDistance);
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354 private HeadwayGTU forwardHeadway(final LanePathInfo lpi, final Length.Rel maxDistance) throws GTUException,
355 NetworkException
356 {
357 GTUException.failIf(maxDistance.le(Length.Rel.ZERO), "forwardHeadway: maxDistance should be positive");
358
359 int ldIndex = 0;
360 LaneDirection ld = lpi.getReferenceLaneDirection();
361 double gtuPosFrontSI = lpi.getReferencePosition().si;
362 if (lpi.getReferenceLaneDirection().getDirection().isPlus())
363 {
364 gtuPosFrontSI += this.gtu.getFront().getDx().si;
365 }
366 else
367 {
368 gtuPosFrontSI -= this.gtu.getFront().getDx().si;
369 }
370
371
372
373 while ((gtuPosFrontSI > ld.getLane().getLength().si || gtuPosFrontSI < 0.0) && ldIndex < lpi.getLaneDirectionList().size() - 1)
374 {
375 ldIndex++;
376 if (ld.getDirection().isPlus())
377 {
378 if (lpi.getLaneDirectionList().get(ldIndex).getDirection().isPlus())
379 gtuPosFrontSI -= ld.getLane().getLength().si;
380 else
381 gtuPosFrontSI = lpi.getLaneDirectionList().get(ldIndex).getLane().getLength().si - gtuPosFrontSI;
382 ld = lpi.getLaneDirectionList().get(ldIndex);
383 }
384 else
385 {
386 if (lpi.getLaneDirectionList().get(ldIndex).getDirection().isPlus())
387 gtuPosFrontSI += ld.getLane().getLength().si;
388 else
389 gtuPosFrontSI += lpi.getLaneDirectionList().get(ldIndex).getLane().getLength().si;
390 ld = lpi.getLaneDirectionList().get(ldIndex);
391 }
392 }
393
394 double maxDistanceSI = maxDistance.si;
395 Time.Abs time = this.gtu.getSimulator().getSimulatorTime().getTime();
396
397
398 HeadwayGTU closest = headwayGTULane(ld, gtuPosFrontSI, 0.0, time);
399 if (closest != null)
400 {
401 if (closest.getDistance().si > maxDistanceSI)
402 {
403 return new HeadwayGTU(null, null, maxDistanceSI, null);
404 }
405 return closest;
406 }
407 double cumDistSI = ld.getDirection().isPlus() ? ld.getLane().getLength().si - gtuPosFrontSI : gtuPosFrontSI;
408 for (int i = ldIndex + 1; i < lpi.getLaneDirectionList().size(); i++)
409 {
410 ld = lpi.getLaneDirectionList().get(i);
411 closest = headwayGTULane(ld, ld.getDirection().isPlus() ? 0.0 : ld.getLane().getLength().si, cumDistSI, time);
412 if (closest != null)
413 {
414 if (closest.getDistance().si > maxDistanceSI)
415 {
416 return new HeadwayGTU(null, null, maxDistanceSI, null);
417 }
418 return closest;
419 }
420 cumDistSI += ld.getLane().getLength().si;
421 }
422 return new HeadwayGTU(null, null, maxDistanceSI, null);
423 }
424
425
426
427
428
429
430
431
432
433
434
435 private HeadwayGTU headwayGTULane(final LaneDirection laneDirection, final double startPosSI, final double cumDistSI,
436 final Time.Abs now) throws GTUException
437 {
438 Lane lane = laneDirection.getLane();
439 LaneBasedGTU laneBasedGTU =
440 lane.getGtuAhead(new Length.Rel(startPosSI, LengthUnit.SI), laneDirection.getDirection(),
441 RelativePosition.REAR, now);
442 if (laneBasedGTU == null)
443 {
444 return null;
445 }
446 double distanceSI = Math.abs(laneBasedGTU.position(lane, laneBasedGTU.getRear()).si - startPosSI);
447 return new HeadwayGTU(laneBasedGTU.getId(), laneBasedGTU.getVelocity(), cumDistSI + distanceSI,
448 laneBasedGTU.getGTUType());
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 private HeadwayGTU backwardHeadway(final Length.Rel maxDistance) throws GTUException, NetworkException
466 {
467 GTUException.failIf(maxDistance.ge(Length.Rel.ZERO), "backwardHeadway: maxDistance should be negative");
468 Time.Abs time = this.gtu.getSimulator().getSimulatorTime().getTime();
469 double maxDistanceSI = maxDistance.si;
470 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, null, -maxDistanceSI, null);
471 for (Lane lane : this.gtu.positions(this.gtu.getRear()).keySet())
472 {
473 HeadwayGTU closest =
474 headwayRecursiveBackwardSI(lane, this.gtu.getLanes().get(lane),
475 this.gtu.position(lane, this.gtu.getRear(), time).getSI(), 0.0, -maxDistanceSI, time);
476 if (closest.getDistance().si < -maxDistanceSI && closest.getDistance().si < -foundMaxGTUDistanceSI.getDistance().si)
477 {
478 foundMaxGTUDistanceSI = closest;
479 }
480 }
481 return new HeadwayGTU(foundMaxGTUDistanceSI.getGtuId(), foundMaxGTUDistanceSI.getGtuSpeed(), foundMaxGTUDistanceSI
482 .getDistance().multiplyBy(-1.0), foundMaxGTUDistanceSI.getGtuType());
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 private HeadwayGTU headwayRecursiveBackwardSI(final Lane lane, final GTUDirectionality direction,
502 final double lanePositionSI, final double cumDistanceSI, final double maxDistanceSI, final Time.Abs when)
503 throws GTUException
504 {
505 LaneBasedGTU otherGTU =
506 lane.getGtuBehind(new Length.Rel(lanePositionSI, LengthUnit.SI), direction, RelativePosition.FRONT, when);
507 if (otherGTU != null)
508 {
509 double distanceM = cumDistanceSI + lanePositionSI - otherGTU.position(lane, otherGTU.getFront(), when).getSI();
510 if (distanceM > 0 && distanceM <= maxDistanceSI)
511 {
512 return new HeadwayGTU(otherGTU.getId(), otherGTU.getVelocity(), distanceM, otherGTU.getGTUType());
513 }
514 return new HeadwayGTU(null, null, Double.MAX_VALUE, null);
515 }
516
517
518 if (cumDistanceSI + lanePositionSI < maxDistanceSI)
519 {
520
521 if (lane.prevLanes(this.gtu.getGTUType()).size() > 0)
522 {
523 HeadwayGTU foundMaxGTUDistanceSI = new HeadwayGTU(null, null, Double.MAX_VALUE, null);
524 for (Lane prevLane : lane.prevLanes(this.gtu.getGTUType()).keySet())
525 {
526
527 double traveledDistanceSI = cumDistanceSI + lanePositionSI;
528
529 HeadwayGTU closest =
530 headwayRecursiveBackwardSI(prevLane, direction, prevLane.getLength().getSI(), traveledDistanceSI,
531 maxDistanceSI, when);
532 if (closest.getDistance().si < maxDistanceSI
533 && closest.getDistance().si < foundMaxGTUDistanceSI.getDistance().si)
534 {
535 foundMaxGTUDistanceSI = closest;
536 }
537 }
538 return foundMaxGTUDistanceSI;
539 }
540 }
541
542
543 return new HeadwayGTU(null, null, Double.MAX_VALUE, null);
544 }
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 private Set<LaneBasedGTU> parallel(final Lane lane, final Time.Abs when) throws GTUException
561 {
562 Set<LaneBasedGTU> gtuSet = new LinkedHashSet<LaneBasedGTU>();
563 for (Lane l : this.gtu.getLanes().keySet())
564 {
565
566 if (l.getParentLink().equals(lane.getParentLink()))
567 {
568
569 double posFractionRef = this.gtu.fractionalPosition(l, this.gtu.getReference(), when);
570 double posFractionFront = Math.max(0.0, posFractionRef + this.gtu.getFront().getDx().si / lane.getLength().si);
571 double posFractionRear = Math.min(1.0, posFractionRef + this.gtu.getRear().getDx().si / lane.getLength().si);
572
573
574 double posMin = Math.min(posFractionFront, posFractionRear);
575 double posMax = Math.max(posFractionFront, posFractionRear);
576 for (LaneBasedGTU otherGTU : lane.getGtuList())
577 {
578 if (!otherGTU.equals(this))
579 {
580
581
582
583
584 double gtuFractionRef = otherGTU.fractionalPosition(lane, otherGTU.getReference(), when);
585 double gtuFractionFront = Math.max(0.0, gtuFractionRef + otherGTU.getFront().getDx().si / lane.getLength().si);
586 double gtuFractionRear = Math.min(1.0, gtuFractionRef + otherGTU.getRear().getDx().si / lane.getLength().si);
587
588
589 double gtuMin = Math.min(gtuFractionFront, gtuFractionRear);
590 double gtuMax = Math.max(gtuFractionFront, gtuFractionRear);
591 if ((gtuMin >= posMin && gtuMin <= posMax) || (gtuMax >= posMin && gtuMax <= posMax)
592 || (posMin >= gtuMin && posMin <= gtuMax) || (posMax >= gtuMin && posMax <= gtuMax))
593 {
594 gtuSet.add(otherGTU);
595 }
596 }
597 }
598 }
599 }
600 return gtuSet;
601 }
602
603
604
605
606
607
608
609
610
611
612
613
614 private Set<LaneBasedGTU> parallel(final LateralDirectionality lateralDirection, final Time.Abs when) throws GTUException
615 {
616 Set<LaneBasedGTU> gtuSet = new LinkedHashSet<LaneBasedGTU>();
617 for (Lane lane : this.gtu.getLanes().keySet())
618 {
619 for (Lane adjacentLane : accessibleAdjacentLaneMap(lateralDirection).get(lane))
620 {
621 gtuSet.addAll(parallel(adjacentLane, when));
622 }
623 }
624 return gtuSet;
625 }
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648 public final Lane bestAccessibleAdjacentLane(final Lane currentLane, final LateralDirectionality lateralDirection,
649 final Length.Rel longitudinalPosition)
650 {
651 Set<Lane> candidates = accessibleAdjacentLaneMap(lateralDirection).get(currentLane);
652 if (candidates.isEmpty())
653 {
654 return null;
655 }
656 if (candidates.size() == 1)
657 {
658 return candidates.iterator().next();
659 }
660
661 Lane bestLane = null;
662 double widestSeen = Double.NEGATIVE_INFINITY;
663 for (Lane lane : candidates)
664 {
665 if (lane.getWidth(longitudinalPosition).getSI() > widestSeen)
666 {
667 widestSeen = lane.getWidth(longitudinalPosition).getSI();
668 bestLane = lane;
669 }
670 }
671 return bestLane;
672 }
673
674
675
676
677
678
679
680
681
682
683
684
685 private Collection<HeadwayGTU> collectNeighborLaneTraffic(final LateralDirectionality directionality, final Time.Abs when,
686 final Length.Rel maximumForwardHeadway, final Length.Rel maximumReverseHeadway) throws NetworkException,
687 GTUException
688 {
689 Collection<HeadwayGTU> result = new HashSet<HeadwayGTU>();
690 for (LaneBasedGTU p : parallel(directionality, when))
691 {
692 result.add(new HeadwayGTU(p.getId(), p.getVelocity(), Double.NaN, p.getGTUType()));
693 }
694
695
696 for (Lane adjacentLane : accessibleAdjacentLaneMap(directionality).get(getLanePathInfo().getReferenceLane()))
697 {
698 LanePathInfo lpiAdjacent = buildLanePathInfoAdjacent(adjacentLane, directionality, when);
699 HeadwayGTU leader = forwardHeadway(lpiAdjacent, maximumForwardHeadway);
700 if (null != leader.getGtuId() && !result.contains(leader))
701 {
702 result.add(leader);
703 }
704 }
705
706
707 for (Lane lane : this.gtu.getLanes().keySet())
708 {
709 for (Lane adjacentLane : accessibleAdjacentLaneMap(directionality).get(lane))
710 {
711 HeadwayGTU follower =
712 headwayRecursiveBackwardSI(adjacentLane, this.gtu.getLanes().get(lane),
713 this.gtu.projectedPosition(adjacentLane, this.gtu.getRear(), when).getSI(), 0.0,
714 -maximumReverseHeadway.getSI(), when);
715 if (null != follower.getGtuId())
716 {
717 boolean found = false;
718 for (HeadwayGTU hg : result)
719 {
720 if (hg.getGtuId().equals(follower.getGtuId()))
721 {
722 found = true;
723 }
724 }
725 if (!found)
726 {
727 result.add(new HeadwayGTU(follower.getGtuId(), follower.getGtuSpeed(), -follower.getDistance().si,
728 follower.getGtuType()));
729 }
730 }
731 }
732 }
733 return result;
734 }
735
736
737
738
739
740
741
742
743
744
745
746 private LanePathInfo buildLanePathInfoAdjacent(final Lane adjacentLane, final LateralDirectionality direction,
747 final Time.Abs when) throws GTUException, NetworkException
748 {
749 if (this.lanePathInfo == null || this.lanePathInfo.getTimestamp().ne(when))
750 {
751 updateLanePathInfo();
752 }
753 LanePathInfo lpi = getLanePathInfo();
754 List<LaneDirection> laneDirectionList = new ArrayList<>();
755 laneDirectionList.add(new LaneDirection(adjacentLane, lpi.getReferenceLaneDirection().getDirection()));
756 Length.Rel referencePosition = this.gtu.projectedPosition(adjacentLane, this.gtu.getReference(), when);
757 for (int i = 1; i < lpi.getLaneDirectionList().size(); i++)
758 {
759 LaneDirection ld = lpi.getLaneDirectionList().get(i);
760 Set<Lane> accessibleLanes = ld.getLane().accessibleAdjacentLanes(direction, this.gtu.getGTUType());
761 Lane adjLane = null;
762 for (Lane lane : accessibleLanes)
763 {
764 if (lane.getParentLink().equals(ld.getLane().getParentLink()))
765 {
766 adjLane = lane;
767 }
768 }
769 if (adjLane == null)
770 {
771 break;
772 }
773 laneDirectionList.add(new LaneDirection(adjLane, ld.getDirection()));
774 }
775 return new LanePathInfo(null, laneDirectionList, referencePosition);
776 }
777
778
779
780
781
782
783 @Override
784 public final LaneBasedGTU getGTU()
785 {
786 return this.gtu;
787 }
788
789
790
791
792
793 public final LanePathInfo getLanePathInfo()
794 {
795 return this.lanePathInfo.getObject();
796 }
797
798
799 @Override
800 public final HeadwayGTU getForwardHeadwayGTU()
801 {
802 return this.forwardHeadwayGTU.getObject();
803 }
804
805
806 @Override
807 public final HeadwayGTU getBackwardHeadwayGTU()
808 {
809 return this.backwardHeadwayGTU.getObject();
810 }
811
812
813 @Override
814 public final Map<Lane, Set<Lane>> getAccessibleAdjacentLanesLeft()
815 {
816 return this.accessibleAdjacentLanesLeft.getObject();
817 }
818
819
820 @Override
821 public final Map<Lane, Set<Lane>> getAccessibleAdjacentLanesRight()
822 {
823 return this.accessibleAdjacentLanesRight.getObject();
824 }
825
826
827 @Override
828 public final Collection<HeadwayGTU> getNeighboringGTUsLeft()
829 {
830 return this.neighboringGTUsLeft.getObject();
831 }
832
833
834 @Override
835 public final Collection<HeadwayGTU> getNeighboringGTUsRight()
836 {
837 return this.neighboringGTUsRight.getObject();
838 }
839
840
841 @Override
842 public final Set<LaneBasedGTU> getParallelGTUsLeft()
843 {
844 return this.parallelGTUsLeft.getObject();
845 }
846
847
848 @Override
849 public final Set<LaneBasedGTU> getParallelGTUsRight()
850 {
851 return this.parallelGTUsRight.getObject();
852 }
853
854
855 @Override
856 public final Speed getSpeedLimit()
857 {
858 return this.speedLimit.getObject();
859 }
860
861
862 @Override
863 public final Set<PerceivedObject> getPerceivedObjects()
864 {
865
866 return new HashSet<PerceivedObject>();
867 }
868
869
870 @Override
871 public final TimeStampedObject<HeadwayGTU> getTimeStampedForwardHeadwayGTU()
872 {
873 return this.forwardHeadwayGTU;
874 }
875
876
877 @Override
878 public final TimeStampedObject<HeadwayGTU> getTimeStampedBackwardHeadwayGTU()
879 {
880 return this.backwardHeadwayGTU;
881 }
882
883
884 @Override
885 public final TimeStampedObject<Map<Lane, Set<Lane>>> getTimeStampedAccessibleAdjacentLanesLeft()
886 {
887 return this.accessibleAdjacentLanesLeft;
888 }
889
890
891 @Override
892 public final TimeStampedObject<Map<Lane, Set<Lane>>> getTimeStampedAccessibleAdjacentLanesRight()
893 {
894 return this.accessibleAdjacentLanesRight;
895 }
896
897
898 @Override
899 public final TimeStampedObject<Collection<HeadwayGTU>> getTimeStampedNeighboringGTUsLeft()
900 {
901 return this.neighboringGTUsLeft;
902 }
903
904
905 @Override
906 public final TimeStampedObject<Collection<HeadwayGTU>> getTimeStampedNeighboringGTUsRight()
907 {
908 return this.neighboringGTUsRight;
909 }
910
911
912 @Override
913 public final TimeStampedObject<Set<LaneBasedGTU>> getTimeStampedParallelGTUsLeft()
914 {
915 return this.parallelGTUsLeft;
916 }
917
918
919 @Override
920 public final TimeStampedObject<Set<LaneBasedGTU>> getTimeStampedParallelGTUsRight()
921 {
922 return this.parallelGTUsRight;
923 }
924
925
926 @Override
927 public final TimeStampedObject<Speed> getTimeStampedSpeedLimit()
928 {
929 return this.speedLimit;
930 }
931
932
933 @Override
934 public TimeStampedObject<Set<PerceivedObject>> getTimeStampedPerceivedObjects() throws GTUException
935 {
936
937 return new TimeStampedObject<Set<PerceivedObject>>(new HashSet<PerceivedObject>(), getTimestamp());
938 }
939
940 }