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