1 package org.opentrafficsim.road.network.lane;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.LinkedHashMap;
6 import java.util.LinkedHashSet;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10 import java.util.SortedMap;
11 import java.util.TreeMap;
12
13 import nl.tudelft.simulation.dsol.SimRuntimeException;
14
15 import org.djunits.unit.TimeUnit;
16 import org.opentrafficsim.core.OTS_SCALAR;
17 import org.opentrafficsim.core.geometry.OTSGeometryException;
18 import org.opentrafficsim.core.gtu.GTUType;
19 import org.opentrafficsim.core.gtu.RelativePosition;
20 import org.opentrafficsim.core.network.LateralDirectionality;
21 import org.opentrafficsim.core.network.Link;
22 import org.opentrafficsim.core.network.LongitudinalDirectionality;
23 import org.opentrafficsim.core.network.NetworkException;
24 import org.opentrafficsim.graphs.LaneBasedGTUSampler;
25 import org.opentrafficsim.road.gtu.lane.AbstractLaneBasedGTU;
26 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
27 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class Lane extends CrossSectionElement implements Serializable, OTS_SCALAR
49 {
50
51 private static final long serialVersionUID = 20150826L;
52
53
54 private final LaneType laneType;
55
56
57
58
59
60 private final Map<GTUType, LongitudinalDirectionality> directionalityMap;
61
62
63
64
65
66 private Map<GTUType, Speed.Abs> speedLimitMap;
67
68
69
70
71
72 private final SortedMap<Double, List<GTUTypeSensor>> sensors = new TreeMap<>();
73
74
75 private final List<LaneBasedGTU> gtuList = new ArrayList<LaneBasedGTU>();
76
77
78
79
80
81 private Map<GTUType, Set<Lane>> leftNeighbors = null;
82
83
84
85
86
87 private Map<GTUType, Set<Lane>> rightNeighbors = null;
88
89
90
91
92
93 private Map<GTUType, Set<Lane>> nextLanes = null;
94
95
96
97
98
99 private Map<GTUType, Set<Lane>> prevLanes = null;
100
101
102 private ArrayList<LaneBasedGTUSampler> samplers = new ArrayList<LaneBasedGTUSampler>();
103
104
105 private final OvertakingConditions overtakingConditions;
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 @SuppressWarnings("checkstyle:parameternumber")
124 public Lane(final CrossSectionLink parentLink, final String id, final Length.Rel lateralOffsetAtStart,
125 final Length.Rel lateralOffsetAtEnd, final Length.Rel beginWidth, final Length.Rel endWidth,
126 final LaneType laneType, final Map<GTUType, LongitudinalDirectionality> directionalityMap,
127 final Map<GTUType, Speed.Abs> speedLimitMap, final OvertakingConditions overtakingConditions)
128 throws OTSGeometryException, NetworkException
129 {
130 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth);
131 this.laneType = laneType;
132 this.directionalityMap = directionalityMap;
133 this.speedLimitMap = speedLimitMap;
134 this.overtakingConditions = overtakingConditions;
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 @SuppressWarnings("checkstyle:parameternumber")
154 public Lane(final CrossSectionLink parentLink, final String id, final Length.Rel lateralOffsetAtStart,
155 final Length.Rel lateralOffsetAtEnd, final Length.Rel beginWidth, final Length.Rel endWidth,
156 final LaneType laneType, final LongitudinalDirectionality directionality, final Speed.Abs speedLimit,
157 final OvertakingConditions overtakingConditions) throws OTSGeometryException, NetworkException
158 {
159 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth);
160 this.laneType = laneType;
161 this.directionalityMap = new LinkedHashMap<>(1);
162 this.directionalityMap.put(GTUType.ALL, directionality);
163 this.speedLimitMap = new LinkedHashMap<>();
164 this.speedLimitMap.put(GTUType.ALL, speedLimit);
165 this.overtakingConditions = overtakingConditions;
166 }
167
168
169
170
171
172
173
174
175 private Set<Lane> neighbors(final LateralDirectionality direction, final GTUType gtuType)
176 {
177 if (this.leftNeighbors == null || this.rightNeighbors == null)
178 {
179 this.leftNeighbors = new LinkedHashMap<>(1);
180 this.rightNeighbors = new LinkedHashMap<>(1);
181 }
182
183 if (!this.leftNeighbors.containsKey(gtuType) || !this.rightNeighbors.containsKey(gtuType))
184 {
185 Set<Lane> leftSet = new LinkedHashSet<>(1);
186 Set<Lane> rightSet = new LinkedHashSet<>(1);
187 this.leftNeighbors.put(gtuType, leftSet);
188 this.rightNeighbors.put(gtuType, rightSet);
189 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
190 {
191 if (cse instanceof Lane && !cse.equals(this))
192 {
193 Lane lane = (Lane) cse;
194 if (laterallyAdjacentAndAccessible(lane, LateralDirectionality.LEFT, gtuType))
195 {
196 leftSet.add(lane);
197 }
198 if (laterallyAdjacentAndAccessible(lane, LateralDirectionality.RIGHT, gtuType))
199 {
200 rightSet.add(lane);
201 }
202 }
203 }
204 }
205
206 Set<Lane> lanes = new LinkedHashSet<>();
207 if (direction == LateralDirectionality.LEFT)
208 {
209 lanes.addAll(this.leftNeighbors.get(gtuType));
210 }
211 else
212 {
213 lanes.addAll(this.rightNeighbors.get(gtuType));
214 }
215 return lanes;
216 }
217
218
219 static final Length.Rel ADJACENT_MARGIN = new Length.Rel(0.2, METER);
220
221
222
223
224
225
226
227
228
229
230
231
232 private boolean laterallyAdjacentAndAccessible(final Lane lane, final LateralDirectionality direction,
233 final GTUType gtuType)
234 {
235 if (!lane.getLaneType().isCompatible(gtuType) || gtuType.equals(GTUType.ALL) || gtuType.equals(GTUType.NONE))
236 {
237
238 return false;
239 }
240
241 if (direction.equals(LateralDirectionality.LEFT))
242 {
243 if (Math.abs((this.designLineOffsetAtBegin.getSI() + this.beginWidth.getSI() / 2.0)
244 - (lane.designLineOffsetAtBegin.getSI() - lane.beginWidth.getSI() / 2.0)) < ADJACENT_MARGIN.getSI()
245 && Math.abs((this.designLineOffsetAtEnd.getSI() + this.endWidth.getSI() / 2.0)
246 - (lane.designLineOffsetAtEnd.getSI() - lane.endWidth.getSI() / 2.0)) < ADJACENT_MARGIN.getSI())
247 {
248
249 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
250 {
251 if (cse instanceof Stripe)
252 {
253 Stripe stripe = (Stripe) cse;
254 if (Math.abs((this.designLineOffsetAtBegin.getSI() + this.beginWidth.getSI() / 2.0)
255 - stripe.designLineOffsetAtBegin.getSI()) < ADJACENT_MARGIN.getSI()
256 && Math.abs((this.designLineOffsetAtEnd.getSI() + this.endWidth.getSI() / 2.0)
257 - stripe.designLineOffsetAtEnd.getSI()) < ADJACENT_MARGIN.getSI())
258 {
259 if (!stripe.isPermeable(gtuType, LateralDirectionality.LEFT))
260 {
261
262 return false;
263 }
264 }
265 }
266 }
267
268
269 return true;
270 }
271 }
272
273 else
274
275 {
276 if (Math.abs((this.designLineOffsetAtBegin.getSI() - this.beginWidth.getSI() / 2.0)
277 - (lane.designLineOffsetAtBegin.getSI() + lane.beginWidth.getSI() / 2.0)) < ADJACENT_MARGIN.getSI()
278 && Math.abs((this.designLineOffsetAtEnd.getSI() - this.endWidth.getSI() / 2.0)
279 - (lane.designLineOffsetAtEnd.getSI() + lane.endWidth.getSI() / 2.0)) < ADJACENT_MARGIN.getSI())
280 {
281
282 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
283 {
284 if (cse instanceof Stripe)
285 {
286 Stripe stripe = (Stripe) cse;
287 if (Math.abs((this.designLineOffsetAtBegin.getSI() - this.beginWidth.getSI() / 2.0)
288 - stripe.designLineOffsetAtBegin.getSI()) < ADJACENT_MARGIN.getSI()
289 && Math.abs((this.designLineOffsetAtEnd.getSI() - this.endWidth.getSI() / 2.0)
290 - stripe.designLineOffsetAtEnd.getSI()) < ADJACENT_MARGIN.getSI())
291 {
292 if (!stripe.isPermeable(gtuType, LateralDirectionality.RIGHT))
293 {
294
295 return false;
296 }
297 }
298 }
299 }
300
301
302 return true;
303 }
304 }
305
306
307 return false;
308 }
309
310
311
312
313
314
315
316 public final void addSensor(final Sensor sensor, final GTUType gtuType) throws NetworkException
317 {
318 double position = sensor.getLongitudinalPositionSI();
319 if (position < 0 || position > getLength().getSI())
320 {
321 throw new NetworkException("Illegal position for sensor " + position + " valid range is 0.."
322 + getLength().getSI());
323 }
324 List<GTUTypeSensor> sensorList = this.sensors.get(position);
325 if (null == sensorList)
326 {
327 sensorList = new ArrayList<GTUTypeSensor>(1);
328 this.sensors.put(position, sensorList);
329 }
330 sensorList.add(new GTUTypeSensor(gtuType, sensor));
331 }
332
333
334
335
336
337
338 public final void removeSensor(final Sensor sensor) throws NetworkException
339 {
340 List<GTUTypeSensor> sensorList = this.sensors.get(sensor.getLongitudinalPosition().getSI());
341 if (null == sensorList)
342 {
343 throw new NetworkException("No sensor at " + sensor.getLongitudinalPositionSI());
344 }
345 List<GTUTypeSensor> sensorList2 = new ArrayList<GTUTypeSensor>(1);
346 for (GTUTypeSensor gs : sensorList)
347 {
348 if (!gs.getSensor().equals(sensor))
349 {
350 sensorList2.add(gs);
351 }
352 }
353 if (sensorList2.size() == 0)
354 {
355 this.sensors.remove(sensor.getLongitudinalPosition().doubleValue());
356 }
357 else
358 {
359 this.sensors.put(sensor.getLongitudinalPosition().doubleValue(), sensorList2);
360 }
361 }
362
363
364
365
366
367
368
369
370
371 public final List<Sensor> getSensors(final Length.Rel minimumPosition, final Length.Rel maximumPosition,
372 final GTUType gtuType)
373 {
374 List<Sensor> sensorList = new ArrayList<>(1);
375 for (List<GTUTypeSensor> gtsl : this.sensors.values())
376 {
377 for (GTUTypeSensor gs : gtsl)
378 {
379 if ((gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL))
380 && gs.getSensor().getLongitudinalPosition().gt(minimumPosition)
381 && gs.getSensor().getLongitudinalPosition().le(maximumPosition))
382 {
383 sensorList.add(gs.getSensor());
384 }
385 }
386 }
387 return sensorList;
388 }
389
390
391
392
393
394
395
396 public final List<Sensor> getSensors(final GTUType gtuType)
397 {
398 List<Sensor> sensorList = new ArrayList<>(1);
399 for (List<GTUTypeSensor> gtsl : this.sensors.values())
400 {
401 for (GTUTypeSensor gs : gtsl)
402 {
403 if ((gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL)))
404 {
405 sensorList.add(gs.getSensor());
406 }
407 }
408 }
409 return sensorList;
410 }
411
412
413
414
415
416 public final List<Sensor> getSensors()
417 {
418 List<Sensor> sensorList = new ArrayList<>(1);
419 for (List<GTUTypeSensor> gtsl : this.sensors.values())
420 {
421 for (GTUTypeSensor gs : gtsl)
422 {
423 sensorList.add(gs.getSensor());
424 }
425 }
426 return sensorList;
427 }
428
429
430
431
432
433
434
435 public final SortedMap<Double, List<Sensor>> getSensorMap(final GTUType gtuType)
436 {
437 SortedMap<Double, List<Sensor>> sensorMap = new TreeMap<>();
438 for (double d : this.sensors.keySet())
439 {
440 List<Sensor> sensorList = new ArrayList<>(1);
441 for (GTUTypeSensor gs : this.sensors.get(d))
442 {
443 if (gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL))
444 {
445 sensorList.add(gs.getSensor());
446 }
447 }
448 if (sensorList.size() > 0)
449 {
450 sensorMap.put(d, sensorList);
451 }
452 }
453 return sensorMap;
454 }
455
456
457
458
459
460
461
462
463
464 public final void scheduleTriggers(final LaneBasedGTU gtu, final double referenceStartSI,
465 final double referenceMoveSI) throws NetworkException, SimRuntimeException
466 {
467 for (List<Sensor> sensorList : getSensorMap(gtu.getGTUType()).values())
468 {
469 for (Sensor sensor : sensorList)
470 {
471 for (RelativePosition relativePosition : gtu.getRelativePositions().values())
472 {
473 if (sensor.getPositionType().equals(relativePosition.getType())
474 && referenceStartSI + relativePosition.getDx().getSI() <= sensor.getLongitudinalPositionSI()
475 && referenceStartSI + referenceMoveSI + relativePosition.getDx().getSI() > sensor
476 .getLongitudinalPositionSI())
477 {
478
479
480 double d =
481 sensor.getLongitudinalPositionSI() - referenceStartSI - relativePosition.getDx().getSI();
482 if (d < 0)
483 {
484 throw new NetworkException("scheduleTriggers for gtu: " + gtu + ", d<0 d=" + d);
485 }
486
487 Time.Abs triggerTime = gtu.timeAtDistance(new Length.Rel(d, METER));
488 if (triggerTime.gt(gtu.getNextEvaluationTime()))
489 {
490 System.err.println("Time=" + gtu.getSimulator().getSimulatorTime().getTime().getSI()
491 + " - Scheduling trigger at " + triggerTime.getSI() + "s. > "
492 + gtu.getNextEvaluationTime().getSI() + "s. (nextEvalTime) for sensor " + sensor
493 + " , gtu " + gtu);
494 System.err.println(" v=" + gtu.getVelocity() + ", a=" + gtu.getAcceleration() + ", lane="
495 + toString() + ", refStartSI=" + referenceStartSI + ", moveSI=" + referenceMoveSI);
496 triggerTime =
497 new Time.Abs(gtu.getNextEvaluationTime().getSI()
498 - Math.ulp(gtu.getNextEvaluationTime().getSI()), TimeUnit.SI);
499
500
501 }
502
503
504 gtu.getSimulator().scheduleEventAbs(triggerTime, this, sensor, "trigger", new Object[]{gtu});
505 }
506 }
507 }
508 }
509 }
510
511
512
513
514
515
516 public final Length.Rel position(final double fraction)
517 {
518 return new Length.Rel(this.getLength().getInUnit() * fraction, this.getLength().getUnit());
519 }
520
521
522
523
524
525
526 public final double positionSI(final double fraction)
527 {
528 return this.getLength().getSI() * fraction;
529 }
530
531
532
533
534
535
536 public final double fraction(final Length.Rel position)
537 {
538 return position.getSI() / this.getLength().getSI();
539 }
540
541
542
543
544
545
546 public final double fractionSI(final double positionSI)
547 {
548 return positionSI / this.getLength().getSI();
549 }
550
551
552
553
554
555
556
557
558
559
560 public final int addGTU(final LaneBasedGTU gtu, final double fractionalPosition) throws NetworkException
561 {
562
563 int index;
564 for (index = 0; index < this.gtuList.size(); index++)
565 {
566 LaneBasedGTU otherGTU = this.gtuList.get(index);
567 if (gtu == otherGTU)
568 {
569 throw new NetworkException("GTU " + gtu + " already registered on Lane " + this
570 + " [registered lanes: " + gtu.positions(gtu.getFront()).keySet() + "] locations: "
571 + gtu.positions(gtu.getFront()).values() + " time: "
572 + gtu.getSimulator().getSimulatorTime().getTime());
573 }
574 if (otherGTU.fractionalPosition(this, otherGTU.getFront()) >= fractionalPosition)
575 {
576 break;
577 }
578 }
579 this.gtuList.add(index, gtu);
580 return index;
581 }
582
583
584
585
586
587
588
589
590
591
592 public final int addGTU(final LaneBasedGTU gtu, final Length.Rel longitudinalPosition) throws NetworkException
593 {
594 return addGTU(gtu, longitudinalPosition.getSI() / getLength().getSI());
595 }
596
597
598
599
600
601 public final void removeGTU(final LaneBasedGTU gtu)
602 {
603 this.gtuList.remove(gtu);
604 }
605
606
607
608
609
610
611
612
613 public final LaneBasedGTU getGtuAfter(final Length.Rel position, final RelativePosition.TYPE relativePosition,
614 final Time.Abs when) throws NetworkException
615 {
616 for (LaneBasedGTU gtu : this.gtuList)
617 {
618 if (relativePosition.equals(RelativePosition.FRONT))
619 {
620 if (gtu.position(this, gtu.getFront(), when).gt(position))
621 {
622 return gtu;
623 }
624 }
625 else if (relativePosition.equals(RelativePosition.REAR))
626 {
627 if (gtu.position(this, gtu.getRear(), when).ge(position))
628 {
629 return gtu;
630 }
631 }
632 else
633 {
634 throw new NetworkException("Can only use Lane.getGtuAfter(...) method with FRONT and REAR positions");
635 }
636 }
637 return null;
638 }
639
640
641
642
643
644
645
646
647 public final LaneBasedGTU getGtuBefore(final Length.Rel position, final RelativePosition.TYPE relativePosition,
648 final Time.Abs when) throws NetworkException
649 {
650 for (int i = this.gtuList.size() - 1; i >= 0; i--)
651 {
652 LaneBasedGTU gtu = this.gtuList.get(i);
653 if (relativePosition.equals(RelativePosition.FRONT))
654 {
655 if (gtu.position(this, gtu.getFront(), when).getSI() < position.getSI())
656 {
657 return gtu;
658 }
659 }
660 else if (relativePosition.equals(RelativePosition.REAR))
661 {
662 if (gtu.position(this, gtu.getRear(), when).getSI() < position.getSI())
663 {
664 return gtu;
665 }
666 }
667 else
668 {
669 throw new NetworkException("Can only use Lane.getGtuBefore(...) method with FRONT and REAR positions");
670 }
671 }
672 return null;
673 }
674
675
676
677
678
679
680
681
682 private boolean laterallyCloseEnough(final CrossSectionElement incomingCSE, final CrossSectionElement outgoingCSE,
683 final Length.Rel margin)
684 {
685 return Math.abs(incomingCSE.getDesignLineOffsetAtEnd().getSI()
686 - outgoingCSE.getDesignLineOffsetAtBegin().getSI()) <= margin.getSI();
687 }
688
689
690
691
692
693
694
695 static final Length.Rel LATERAL_MARGIN = new Length.Rel(0.5, METER);
696
697
698
699
700
701
702
703
704
705
706
707
708
709 public final Set<Lane> nextLanes(final GTUType gtuType)
710 {
711 if (this.nextLanes == null)
712 {
713 this.nextLanes = new LinkedHashMap<>(1);
714 }
715 if (!this.nextLanes.containsKey(gtuType))
716 {
717 Set<Lane> laneSet = new LinkedHashSet<>(1);
718 this.nextLanes.put(gtuType, laneSet);
719
720 for (Link link : getParentLink().getEndNode().getLinksOut())
721 {
722 if (link instanceof CrossSectionLink)
723 {
724 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
725 {
726 if (cse instanceof Lane && laterallyCloseEnough(this, cse, LATERAL_MARGIN))
727 {
728 laneSet.add((Lane) cse);
729 }
730 }
731 }
732 }
733 }
734 return this.nextLanes.get(gtuType);
735 }
736
737
738
739
740
741
742
743
744
745
746
747
748
749 public final Set<Lane> prevLanes(final GTUType gtuType)
750 {
751 if (this.prevLanes == null)
752 {
753 this.prevLanes = new LinkedHashMap<>(1);
754 }
755 if (!this.prevLanes.containsKey(gtuType))
756 {
757 Set<Lane> laneSet = new LinkedHashSet<>(1);
758 this.prevLanes.put(gtuType, laneSet);
759
760 for (Link link : getParentLink().getStartNode().getLinksIn())
761 {
762 if (link instanceof CrossSectionLink)
763 {
764 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
765 {
766 if (cse instanceof Lane && laterallyCloseEnough(cse, this, LATERAL_MARGIN))
767 {
768 laneSet.add((Lane) cse);
769 }
770 }
771 }
772 }
773 }
774 return this.prevLanes.get(gtuType);
775 }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790 public final Set<Lane> accessibleAdjacentLanes(final LateralDirectionality lateralDirection, final GTUType gtuType)
791 {
792 Set<Lane> candidates = new LinkedHashSet<>(1);
793 for (Lane lane : neighbors(lateralDirection, gtuType))
794 {
795 if (lane.getDirectionality(gtuType).equals(LongitudinalDirectionality.BOTH)
796 || lane.getDirectionality(gtuType).equals(this.getDirectionality(gtuType)))
797 {
798 candidates.add(lane);
799 }
800 }
801 return candidates;
802 }
803
804
805
806
807
808 public final void addSampler(final LaneBasedGTUSampler sampler)
809 {
810 this.samplers.add(sampler);
811 }
812
813
814
815
816
817 public final void removeSampler(final LaneBasedGTUSampler sampler)
818 {
819 this.samplers.remove(sampler);
820 }
821
822
823
824
825
826
827 public final void sample(final AbstractLaneBasedGTU gtu) throws NetworkException
828 {
829
830 if (gtu.getNextEvaluationTime().getSI() == Double.MAX_VALUE)
831 {
832 return;
833 }
834 for (LaneBasedGTUSampler sampler : this.samplers)
835 {
836 sampler.addData(gtu, this);
837 }
838 }
839
840
841
842
843
844 public final Speed.Abs getSpeedLimit(final GTUType gtuType)
845 {
846 if (this.speedLimitMap.containsKey(gtuType))
847 {
848 return this.speedLimitMap.get(gtuType);
849 }
850 if (this.speedLimitMap.containsKey(GTUType.ALL))
851 {
852 return this.speedLimitMap.get(GTUType.ALL);
853 }
854 return new Speed.Abs(0.0, METER_PER_SECOND);
855 }
856
857
858
859
860
861 public final void setSpeedLimit(final GTUType gtuType, final Speed.Abs speedLimit)
862 {
863 this.speedLimitMap.put(gtuType, speedLimit);
864 }
865
866
867
868
869 public final LaneType getLaneType()
870 {
871 return this.laneType;
872 }
873
874
875
876
877
878 public final LongitudinalDirectionality getDirectionality(final GTUType gtuType)
879 {
880 if (this.directionalityMap.containsKey(gtuType))
881 {
882 return this.directionalityMap.get(gtuType);
883 }
884 if (this.directionalityMap.containsKey(GTUType.ALL))
885 {
886 return this.directionalityMap.get(GTUType.ALL);
887 }
888 return LongitudinalDirectionality.NONE;
889 }
890
891
892
893
894 public final List<LaneBasedGTU> getGtuList()
895 {
896 return this.gtuList;
897 }
898
899
900 @Override
901 @SuppressWarnings("checkstyle:designforextension")
902 protected double getZ()
903 {
904 return 0.0;
905 }
906
907
908
909
910 public final OvertakingConditions getOvertakingConditions()
911 {
912 return this.overtakingConditions;
913 }
914
915
916 public final String toString()
917 {
918 CrossSectionLink link = getParentLink();
919 return String.format("Lane %s of %s", getId(), link.toString());
920 }
921
922
923 @SuppressWarnings("checkstyle:designforextension")
924 @Override
925 public int hashCode()
926 {
927 final int prime = 31;
928 int result = super.hashCode();
929 result = prime * result + ((this.laneType == null) ? 0 : this.laneType.hashCode());
930 return result;
931 }
932
933
934 @SuppressWarnings({"checkstyle:designforextension", "checkstyle:needbraces"})
935 @Override
936 public boolean equals(final Object obj)
937 {
938 if (this == obj)
939 return true;
940 if (!super.equals(obj))
941 return false;
942 if (getClass() != obj.getClass())
943 return false;
944 Lane other = (Lane) obj;
945 if (this.laneType == null)
946 {
947 if (other.laneType != null)
948 return false;
949 }
950 else if (!this.laneType.equals(other.laneType))
951 return false;
952 return true;
953 }
954
955
956
957
958
959
960
961
962
963
964
965
966 private class GTUTypeSensor implements Serializable
967 {
968
969 private static final long serialVersionUID = 20150828L;
970
971
972 private final GTUType gtuType;
973
974
975 private final Sensor sensor;
976
977
978
979
980
981 public GTUTypeSensor(final GTUType gtuType, final Sensor sensor)
982 {
983 this.gtuType = gtuType;
984 this.sensor = sensor;
985 }
986
987
988
989
990 public final GTUType getGtuType()
991 {
992 return this.gtuType;
993 }
994
995
996
997
998 public final Sensor getSensor()
999 {
1000 return this.sensor;
1001 }
1002 }
1003 }