1 package org.opentrafficsim.road.network.lane;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Collections;
6 import java.util.Iterator;
7 import java.util.LinkedHashMap;
8 import java.util.LinkedHashSet;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.NavigableMap;
13 import java.util.Set;
14 import java.util.SortedMap;
15 import java.util.TreeMap;
16
17 import org.djunits.unit.LengthUnit;
18 import org.djunits.unit.TimeUnit;
19 import org.djunits.value.vdouble.scalar.Length;
20 import org.djunits.value.vdouble.scalar.Speed;
21 import org.djunits.value.vdouble.scalar.Time;
22 import org.djutils.event.TimedEventType;
23 import org.djutils.exceptions.Throw;
24 import org.djutils.immutablecollections.Immutable;
25 import org.djutils.immutablecollections.ImmutableArrayList;
26 import org.djutils.immutablecollections.ImmutableLinkedHashMap;
27 import org.djutils.immutablecollections.ImmutableList;
28 import org.djutils.immutablecollections.ImmutableMap;
29 import org.djutils.multikeymap.MultiKeyMap;
30 import org.opentrafficsim.core.geometry.OTSGeometryException;
31 import org.opentrafficsim.core.gtu.GTUDirectionality;
32 import org.opentrafficsim.core.gtu.GTUException;
33 import org.opentrafficsim.core.gtu.GTUType;
34 import org.opentrafficsim.core.gtu.RelativePosition;
35 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
36 import org.opentrafficsim.core.network.LateralDirectionality;
37 import org.opentrafficsim.core.network.Link;
38 import org.opentrafficsim.core.network.NetworkException;
39 import org.opentrafficsim.core.network.Node;
40 import org.opentrafficsim.core.perception.HistoryManager;
41 import org.opentrafficsim.core.perception.collections.HistoricalArrayList;
42 import org.opentrafficsim.core.perception.collections.HistoricalList;
43 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
44 import org.opentrafficsim.road.network.RoadNetwork;
45 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
46 import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
47 import org.opentrafficsim.road.network.lane.object.sensor.AbstractSensor;
48 import org.opentrafficsim.road.network.lane.object.sensor.DestinationSensor;
49 import org.opentrafficsim.road.network.lane.object.sensor.SingleSensor;
50 import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
51
52 import nl.tudelft.simulation.dsol.SimRuntimeException;
53 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
54 import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
55 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 public class Lane extends CrossSectionElement implements Serializable
76 {
77
78 private static final long serialVersionUID = 20150826L;
79
80
81 private final LaneType laneType;
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 private Map<GTUType, Speed> speedLimitMap;
114
115
116 private final Map<GTUType, Speed> cachedSpeedLimits = new LinkedHashMap<>();
117
118
119
120
121
122
123 private final SortedMap<Double, List<SingleSensor>> sensors = new TreeMap<>();
124
125
126
127
128
129
130 private final SortedMap<Double, List<LaneBasedObject>> laneBasedObjects = new TreeMap<>();
131
132
133 private final HistoricalList<LaneBasedGTU> gtuList;
134
135
136 private List<LaneBasedGTU> gtuListAtTime = null;
137
138
139 private Time gtuListTime = null;
140
141
142
143
144
145
146 private final MultiKeyMap<Set<Lane>> leftNeighbours =
147 new MultiKeyMap<>(GTUType.class, GTUDirectionality.class, Boolean.class);
148
149
150
151
152
153
154 private final MultiKeyMap<Set<Lane>> rightNeighbours =
155 new MultiKeyMap<>(GTUType.class, GTUDirectionality.class, Boolean.class);
156
157
158
159
160
161 private Map<GTUType, Map<Lane, GTUDirectionality>> nextLanes = null;
162
163
164
165
166
167 private Map<GTUType, Map<Lane, GTUDirectionality>> prevLanes = null;
168
169
170
171
172
173 private MultiKeyMap<ImmutableMap<Lane, GTUDirectionality>> downLanes =
174 new MultiKeyMap<>(GTUType.class, GTUDirectionality.class);
175
176
177
178
179
180 private MultiKeyMap<ImmutableMap<Lane, GTUDirectionality>> upLanes =
181 new MultiKeyMap<>(GTUType.class, GTUDirectionality.class);
182
183
184
185
186
187 public static final TimedEventType GTU_ADD_EVENT = new TimedEventType("LANE.GTU.ADD");
188
189
190
191
192
193
194
195
196
197 public static final TimedEventType GTU_REMOVE_EVENT = new TimedEventType("LANE.GTU.REMOVE");
198
199
200
201
202
203 public static final TimedEventType SENSOR_ADD_EVENT = new TimedEventType("LANE.SENSOR.ADD");
204
205
206
207
208
209 public static final TimedEventType SENSOR_REMOVE_EVENT = new TimedEventType("LANE.SENSOR.REMOVE");
210
211
212
213
214
215 public static final TimedEventType OBJECT_ADD_EVENT = new TimedEventType("LANE.OBJECT.ADD");
216
217
218
219
220
221 public static final TimedEventType OBJECT_REMOVE_EVENT = new TimedEventType("LANE.OBJECT.REMOVE");
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239 @SuppressWarnings("checkstyle:parameternumber")
240 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
241 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
242 final Map<GTUType, Speed> speedLimitMap, final boolean fixGradualLateralOffset)
243 throws OTSGeometryException, NetworkException
244 {
245 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth, fixGradualLateralOffset);
246 this.laneType = laneType;
247 checkDirectionality();
248 this.speedLimitMap = speedLimitMap;
249 this.gtuList = new HistoricalArrayList<>(getManager(parentLink));
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 @SuppressWarnings("checkstyle:parameternumber")
268 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
269 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
270 final Map<GTUType, Speed> speedLimitMap) throws OTSGeometryException, NetworkException
271 {
272 this(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth, laneType, speedLimitMap, false);
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 @SuppressWarnings("checkstyle:parameternumber")
292 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
293 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
294 final Speed speedLimit, final boolean fixGradualLateralOffset) throws OTSGeometryException, NetworkException
295 {
296 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth, fixGradualLateralOffset);
297 this.laneType = laneType;
298 checkDirectionality();
299 this.speedLimitMap = new LinkedHashMap<>();
300 this.speedLimitMap.put(parentLink.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE), speedLimit);
301 this.gtuList = new HistoricalArrayList<>(getManager(parentLink));
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319 @SuppressWarnings("checkstyle:parameternumber")
320 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
321 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
322 final Speed speedLimit) throws OTSGeometryException, NetworkException
323 {
324 this(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth, laneType, speedLimit, false);
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339 @SuppressWarnings("checkstyle:parameternumber")
340 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffset, final Length width,
341 final LaneType laneType, final Map<GTUType, Speed> speedLimitMap) throws OTSGeometryException, NetworkException
342 {
343 super(parentLink, id, lateralOffset, width);
344 this.laneType = laneType;
345 checkDirectionality();
346 this.speedLimitMap = speedLimitMap;
347 this.gtuList = new HistoricalArrayList<>(getManager(parentLink));
348 }
349
350
351
352
353
354
355
356 private static Map<GTUType, Speed> constructDefaultSpeedLimitMap(final Speed speedLimit, final RoadNetwork network)
357 {
358 Map<GTUType, Speed> result = new LinkedHashMap<>();
359 result.put(network.getGtuType(GTUType.DEFAULTS.VEHICLE), speedLimit);
360 return result;
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375 @SuppressWarnings("checkstyle:parameternumber")
376 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffset, final Length width,
377 final LaneType laneType, final Speed speedLimit) throws OTSGeometryException, NetworkException
378 {
379 this(parentLink, id, lateralOffset, width, laneType,
380 constructDefaultSpeedLimitMap(speedLimit, parentLink.getNetwork()));
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396 @SuppressWarnings("checkstyle:parameternumber")
397 public Lane(final CrossSectionLink parentLink, final String id, final List<CrossSectionSlice> crossSectionSlices,
398 final LaneType laneType, final Map<GTUType, Speed> speedLimitMap) throws OTSGeometryException, NetworkException
399 {
400 super(parentLink, id, crossSectionSlices);
401 this.laneType = laneType;
402 checkDirectionality();
403 this.speedLimitMap = speedLimitMap;
404 this.gtuList = new HistoricalArrayList<>(getManager(parentLink));
405 }
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 @SuppressWarnings("checkstyle:parameternumber")
421 public Lane(final CrossSectionLink parentLink, final String id, final List<CrossSectionSlice> crossSectionSlices,
422 final LaneType laneType, final Speed speedLimit) throws OTSGeometryException, NetworkException
423 {
424 this(parentLink, id, crossSectionSlices, laneType, constructDefaultSpeedLimitMap(speedLimit, parentLink.getNetwork()));
425 }
426
427
428
429
430
431
432
433
434 protected Lane(Laneinal CrossSectionLink newParentLink, final Lane cse) throws NetworkException
435 {
436 super(newParentLink, newParentLink.getNetwork().getSimulator(), cse);
437 this.laneType = cse.laneType;
438 this.speedLimitMap = new LinkedHashMap<>(cse.speedLimitMap);
439 this.gtuList = new HistoricalArrayList<>(getManager(newParentLink));
440 }
441
442
443
444
445
446
447 private HistoryManager getManager(final CrossSectionLink parentLink)
448 {
449 return parentLink.getSimulator().getReplication().getHistoryManager(parentLink.getSimulator());
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465 private Set<Lane> neighbors(final LateralDirectionality direction, final GTUType gtuType,
466 final GTUDirectionality drivingDirection, final boolean legal)
467 {
468 MultiKeyMap<Set<Lane>> cache = direction.isLeft() ? this.leftNeighbours : this.rightNeighbours;
469 return cache.get(() -> {
470 Set<Lane> lanes = new LinkedHashSet<>(1);
471 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
472 {
473 if (cse instanceof Lane && !cse.equals(this))
474 {
475 Laneef="../../../../../org/opentrafficsim/road/network/lane/Lane.html#Lane">Lane lane = (Lane) cse;
476 if (laterallyAdjacentAndAccessible(lane, direction, gtuType, drivingDirection, legal))
477 {
478 lanes.add(lane);
479 }
480 }
481 }
482 return lanes;
483 }, gtuType, drivingDirection, legal);
484 }
485
486
487 static final Length ADJACENT_MARGIN = new Length(0.2, LengthUnit.METER);
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502 private boolean laterallyAdjacentAndAccessible(final Lane lane, final LateralDirectionality direction,
503 final GTUType gtuType, final GTUDirectionality drivingDirection, final boolean legal)
504 {
505 if (!lane.getLaneType().isCompatible(gtuType, drivingDirection))
506 {
507
508 return false;
509 }
510
511 if (direction.equals(LateralDirectionality.LEFT))
512 {
513
514 if (lane.getDesignLineOffsetAtBegin().si + ADJACENT_MARGIN.si > getDesignLineOffsetAtBegin().si
515 && lane.getDesignLineOffsetAtEnd().si + ADJACENT_MARGIN.si > getDesignLineOffsetAtEnd().si
516 && (lane.getDesignLineOffsetAtBegin().si - lane.getBeginWidth().si / 2.0)
517 - (getDesignLineOffsetAtBegin().si + getBeginWidth().si / 2.0) < ADJACENT_MARGIN.si
518 && (lane.getDesignLineOffsetAtEnd().si - lane.getEndWidth().si / 2.0)
519 - (getDesignLineOffsetAtEnd().si + getEndWidth().si / 2.0) < ADJACENT_MARGIN.si)
520 {
521
522 if (legal)
523 {
524 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
525 {
526 if (cse instanceof Stripe)
527 {
528 Stripe../../../../../org/opentrafficsim/road/network/lane/Stripe.html#Stripe">Stripe stripe = (Stripe) cse;
529
530 if ((getDesignLineOffsetAtBegin().si < stripe.getDesignLineOffsetAtBegin().si
531 && stripe.getDesignLineOffsetAtBegin().si < lane.getDesignLineOffsetAtBegin().si)
532 || (getDesignLineOffsetAtEnd().si < stripe.getDesignLineOffsetAtEnd().si
533 && stripe.getDesignLineOffsetAtEnd().si < lane.getDesignLineOffsetAtEnd().si))
534 {
535 if (!stripe.isPermeable(gtuType, LateralDirectionality.LEFT))
536 {
537
538 return false;
539 }
540 }
541 }
542 }
543 }
544
545
546 return true;
547 }
548 }
549
550 else
551
552 {
553
554 if (lane.getDesignLineOffsetAtBegin().si < getDesignLineOffsetAtBegin().si + ADJACENT_MARGIN.si
555 && lane.getDesignLineOffsetAtEnd().si < getDesignLineOffsetAtEnd().si + ADJACENT_MARGIN.si
556 && (getDesignLineOffsetAtBegin().si - getBeginWidth().si / 2.0)
557 - (lane.getDesignLineOffsetAtBegin().si + lane.getBeginWidth().si / 2.0) < ADJACENT_MARGIN.si
558 && (getDesignLineOffsetAtEnd().si - getEndWidth().si / 2.0)
559 - (lane.getDesignLineOffsetAtEnd().si + lane.getEndWidth().si / 2.0) < ADJACENT_MARGIN.si)
560 {
561
562 if (legal)
563 {
564 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
565 {
566 if (cse instanceof Stripe)
567 {
568 Stripe../../../../../org/opentrafficsim/road/network/lane/Stripe.html#Stripe">Stripe stripe = (Stripe) cse;
569
570 if ((getDesignLineOffsetAtBegin().si > stripe.getDesignLineOffsetAtBegin().si
571 && stripe.getDesignLineOffsetAtBegin().si > lane.getDesignLineOffsetAtBegin().si)
572 || (getDesignLineOffsetAtEnd().si > stripe.getDesignLineOffsetAtEnd().si
573 && stripe.getDesignLineOffsetAtEnd().si > lane.getDesignLineOffsetAtEnd().si))
574 {
575 if (!stripe.isPermeable(gtuType, LateralDirectionality.RIGHT))
576 {
577
578 return false;
579 }
580 }
581 }
582 }
583 }
584
585
586 return true;
587 }
588 }
589
590
591 return false;
592 }
593
594
595
596
597
598
599 public final void addSensor(final SingleSensor sensor) throws NetworkException
600 {
601 double position = sensor.getLongitudinalPosition().si;
602 if (position < 0 || position > getLength().getSI())
603 {
604 throw new NetworkException("Illegal position for sensor " + position + " valid range is 0.." + getLength().getSI());
605 }
606 if (this.parentLink.getNetwork().containsObject(sensor.getFullId()))
607 {
608 throw new NetworkException("Network already contains an object with the name " + sensor.getFullId());
609 }
610 List<SingleSensor> sensorList = this.sensors.get(position);
611 if (null == sensorList)
612 {
613 sensorList = new ArrayList<>(1);
614 this.sensors.put(position, sensorList);
615 }
616 sensorList.add(sensor);
617 this.parentLink.getNetwork().addObject(sensor);
618 fireTimedEvent(Lane.SENSOR_ADD_EVENT, new Object[] { sensor.getId(), sensor },
619 sensor.getSimulator().getSimulatorTime());
620 }
621
622
623
624
625
626
627 public final void removeSensor(final SingleSensor sensor) throws NetworkException
628 {
629 fireTimedEvent(Lane.SENSOR_REMOVE_EVENT, new Object[] { sensor.getId(), sensor },
630 sensor.getSimulator().getSimulatorTime());
631 List<SingleSensor> sensorList = this.sensors.get(sensor.getLongitudinalPosition().si);
632 if (null == sensorList)
633 {
634 throw new NetworkException("No sensor at " + sensor.getLongitudinalPosition().si);
635 }
636 sensorList.remove(sensor);
637 if (sensorList.size() == 0)
638 {
639 this.sensors.remove(sensor.getLongitudinalPosition().si);
640 }
641 this.parentLink.getNetwork().removeObject(sensor);
642 }
643
644
645
646
647
648
649
650
651
652
653 public final List<SingleSensor> getSensors(final Length minimumPosition, final Length maximumPosition,
654 final GTUType gtuType, final GTUDirectionality direction)
655 {
656 List<SingleSensor> sensorList = new ArrayList<>(1);
657 for (List<SingleSensor> sl : this.sensors.values())
658 {
659 for (SingleSensor sensor : sl)
660 {
661 if (sensor.isCompatible(gtuType, direction) && sensor.getLongitudinalPosition().ge(minimumPosition)
662 && sensor.getLongitudinalPosition().le(maximumPosition))
663 {
664 sensorList.add(sensor);
665 }
666 }
667 }
668 return sensorList;
669 }
670
671
672
673
674
675
676
677
678 public final List<SingleSensor> getSensors(final GTUType gtuType, final GTUDirectionality direction)
679 {
680 List<SingleSensor> sensorList = new ArrayList<>(1);
681 for (List<SingleSensor> sl : this.sensors.values())
682 {
683 for (SingleSensor sensor : sl)
684 {
685 if (sensor.isCompatible(gtuType, direction))
686 {
687 sensorList.add(sensor);
688 }
689 }
690 }
691 return sensorList;
692 }
693
694
695
696
697
698 public final List<SingleSensor> getSensors()
699 {
700 if (this.sensors == null)
701 {
702 return new ArrayList<>();
703 }
704 List<SingleSensor> sensorList = new ArrayList<>(1);
705 for (List<SingleSensor> sl : this.sensors.values())
706 {
707 for (SingleSensor sensor : sl)
708 {
709 sensorList.add(sensor);
710 }
711 }
712 return sensorList;
713 }
714
715
716
717
718
719
720
721 public final SortedMap<Double, List<SingleSensor>> getSensorMap(final GTUType gtuType, final GTUDirectionality direction)
722 {
723 SortedMap<Double, List<SingleSensor>> sensorMap = new TreeMap<>();
724 for (double d : this.sensors.keySet())
725 {
726 List<SingleSensor> sensorList = new ArrayList<>(1);
727 for (List<SingleSensor> sl : this.sensors.values())
728 {
729 for (SingleSensor sensor : sl)
730 {
731 if (sensor.getLongitudinalPosition().si == d && sensor.isCompatible(gtuType, direction))
732 {
733 sensorList.add(sensor);
734 }
735 }
736 }
737 if (sensorList.size() > 0)
738 {
739 sensorMap.put(d, sensorList);
740 }
741 }
742
743
744
745
746
747
748
749
750
751 return sensorMap;
752 }
753
754
755
756
757
758
759
760
761
762 public final void scheduleSensorTriggers(final LaneBasedGTU gtu, final double referenceStartSI,
763 final double referenceMoveSI) throws NetworkException, SimRuntimeException
764 {
765 GTUDirectionality drivingDirection;
766 double minPos;
767 double maxPos;
768 if (referenceMoveSI >= 0)
769 {
770 drivingDirection = GTUDirectionality.DIR_PLUS;
771 minPos = referenceStartSI + gtu.getRear().getDx().si;
772 maxPos = referenceStartSI + gtu.getFront().getDx().si + referenceMoveSI;
773 }
774 else
775 {
776 drivingDirection = GTUDirectionality.DIR_MINUS;
777 minPos = referenceStartSI - gtu.getFront().getDx().si + referenceMoveSI;
778 maxPos = referenceStartSI - gtu.getRear().getDx().si;
779 }
780 Map<Double, List<SingleSensor>> map = this.sensors.subMap(minPos, maxPos);
781 for (double pos : map.keySet())
782 {
783 for (SingleSensor sensor : map.get(pos))
784 {
785 if (sensor.isCompatible(gtu.getGTUType(), drivingDirection))
786 {
787 double dx = gtu.getRelativePositions().get(sensor.getPositionType()).getDx().si;
788 if (drivingDirection.isPlus())
789 {
790 minPos = referenceStartSI + dx;
791 maxPos = minPos + referenceMoveSI;
792 }
793 else
794 {
795 maxPos = referenceStartSI - dx;
796 minPos = maxPos + referenceMoveSI;
797 }
798 if (minPos <= sensor.getLongitudinalPosition().si && maxPos > sensor.getLongitudinalPosition().si)
799 {
800 double d = drivingDirection.isPlus() ? sensor.getLongitudinalPosition().si - minPos
801 : maxPos - sensor.getLongitudinalPosition().si;
802 if (d < 0)
803 {
804 throw new NetworkException("scheduleTriggers for gtu: " + gtu + ", d<0 d=" + d);
805 }
806 OperationalPlan oPlan = gtu.getOperationalPlan();
807 Time triggerTime = oPlan.timeAtDistance(Length.instantiateSI(d));
808 if (triggerTime.gt(oPlan.getEndTime()))
809 {
810 System.err.println("Time=" + gtu.getSimulator().getSimulatorTime().getSI()
811 + " - Scheduling trigger at " + triggerTime.getSI() + "s. > " + oPlan.getEndTime().getSI()
812 + "s. (nextEvalTime) for sensor " + sensor + " , gtu " + gtu);
813 System.err.println(" v=" + gtu.getSpeed() + ", a=" + gtu.getAcceleration() + ", lane=" + toString()
814 + ", refStartSI=" + referenceStartSI + ", moveSI=" + referenceMoveSI);
815 triggerTime = new Time(oPlan.getEndTime().getSI() - Math.ulp(oPlan.getEndTime().getSI()),
816 TimeUnit.DEFAULT);
817 }
818 SimEvent<SimTimeDoubleUnit> event = new SimEvent<>(new SimTimeDoubleUnit(triggerTime), this, sensor,
819 "trigger", new Object[] { gtu });
820 gtu.getSimulator().scheduleEvent(event);
821 gtu.addTrigger(this, event);
822 }
823 else if (sensor.getLongitudinalPosition().si < minPos
824 && (sensor instanceof SinkSensor || sensor instanceof DestinationSensor))
825 {
826
827
828 SimEvent<SimTimeDoubleUnit> event =
829 new SimEvent<>(new SimTimeDoubleUnit(gtu.getSimulator().getSimulatorTime()), this, sensor,
830 "trigger", new Object[] { gtu });
831 gtu.getSimulator().scheduleEvent(event);
832 gtu.addTrigger(this, event);
833 }
834 }
835 }
836 }
837 }
838
839
840
841
842
843
844
845 public final synchronized void addLaneBasedObject(final LaneBasedObject laneBasedObject) throws NetworkException
846 {
847 double position = laneBasedObject.getLongitudinalPosition().si;
848 if (position < 0 || position > getLength().getSI())
849 {
850 throw new NetworkException(
851 "Illegal position for laneBasedObject " + position + " valid range is 0.." + getLength().getSI());
852 }
853 if (this.parentLink.getNetwork().containsObject(laneBasedObject.getFullId()))
854 {
855 throw new NetworkException("Network already contains an object with the name " + laneBasedObject.getFullId());
856 }
857 List<LaneBasedObject> laneBasedObjectList = this.laneBasedObjects.get(position);
858 if (null == laneBasedObjectList)
859 {
860 laneBasedObjectList = new ArrayList<>(1);
861 this.laneBasedObjects.put(position, laneBasedObjectList);
862 }
863 laneBasedObjectList.add(laneBasedObject);
864 this.parentLink.getNetwork().addObject(laneBasedObject);
865 fireTimedEvent(Lane.OBJECT_ADD_EVENT, new Object[] { laneBasedObject },
866 getParentLink().getSimulator().getSimulatorTime());
867 }
868
869
870
871
872
873
874 public final synchronized void removeLaneBasedObject(final LaneBasedObject laneBasedObject) throws NetworkException
875 {
876 fireTimedEvent(Lane.OBJECT_REMOVE_EVENT, new Object[] { laneBasedObject },
877 getParentLink().getSimulator().getSimulatorTime());
878 List<LaneBasedObject> laneBasedObjectList =
879 this.laneBasedObjects.get(laneBasedObject.getLongitudinalPosition().getSI());
880 if (null == laneBasedObjectList)
881 {
882 throw new NetworkException("No laneBasedObject at " + laneBasedObject.getLongitudinalPosition().si);
883 }
884 laneBasedObjectList.remove(laneBasedObject);
885 if (laneBasedObjectList.isEmpty())
886 {
887 this.laneBasedObjects.remove(laneBasedObject.getLongitudinalPosition().doubleValue());
888 }
889 this.parentLink.getNetwork().removeObject(laneBasedObject);
890 }
891
892
893
894
895
896
897
898
899 public final List<LaneBasedObject> getLaneBasedObjects(final Length minimumPosition, final Length maximumPosition)
900 {
901 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
902 for (List<LaneBasedObject> lbol : this.laneBasedObjects.values())
903 {
904 for (LaneBasedObject lbo : lbol)
905 {
906 if (lbo.getLongitudinalPosition().ge(minimumPosition) && lbo.getLongitudinalPosition().le(maximumPosition))
907 {
908 laneBasedObjectList.add(lbo);
909 }
910 }
911 }
912 return laneBasedObjectList;
913 }
914
915
916
917
918
919 public final List<LaneBasedObject> getLaneBasedObjects()
920 {
921 if (this.laneBasedObjects == null)
922 {
923 return new ArrayList<>();
924 }
925 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
926 for (List<LaneBasedObject> lbol : this.laneBasedObjects.values())
927 {
928 for (LaneBasedObject lbo : lbol)
929 {
930 laneBasedObjectList.add(lbo);
931 }
932 }
933 return laneBasedObjectList;
934 }
935
936
937
938
939
940 public final SortedMap<Double, List<LaneBasedObject>> getLaneBasedObjectMap()
941 {
942 SortedMap<Double, List<LaneBasedObject>> laneBasedObjectMap = new TreeMap<>();
943 for (double d : this.laneBasedObjects.keySet())
944 {
945 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
946 for (LaneBasedObject lbo : this.laneBasedObjects.get(d))
947 {
948 laneBasedObjectList.add(lbo);
949 }
950 laneBasedObjectMap.put(d, laneBasedObjectList);
951 }
952 return laneBasedObjectMap;
953 }
954
955
956
957
958
959
960 public final Length position(final double fraction)
961 {
962 if (this.length.getDisplayUnit().isBaseSIUnit())
963 {
964 return new Length(this.length.si * fraction, LengthUnit.SI);
965 }
966 return new Length(this.length.getInUnit() * fraction, this.length.getDisplayUnit());
967 }
968
969
970
971
972
973
974 public final double positionSI(final double fraction)
975 {
976 return this.length.si * fraction;
977 }
978
979
980
981
982
983
984 public final double fraction(final Length position)
985 {
986 return position.si / this.length.si;
987 }
988
989
990
991
992
993
994 public final double fractionSI(final double positionSI)
995 {
996 return positionSI / this.length.si;
997 }
998
999
1000
1001
1002
1003
1004
1005
1006
1007 public final int addGTU(final LaneBasedGTU gtu, final double fractionalPosition) throws GTUException
1008 {
1009
1010 int index;
1011
1012 if (this.gtuList.size() == 0)
1013 {
1014 this.gtuList.add(gtu);
1015 index = 0;
1016 }
1017 else
1018 {
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 {
1032
1033 for (index = 0; index < this.gtuList.size(); index++)
1034 {
1035 LaneBasedGTU otherGTU = this.gtuList.get(index);
1036 if (gtu == otherGTU)
1037 {
1038 throw new GTUException(gtu + " already registered on Lane " + this + " [registered lanes: "
1039 + gtu.positions(gtu.getFront()).keySet() + "] locations: "
1040 + gtu.positions(gtu.getFront()).values() + " time: " + gtu.getSimulator().getSimulatorTime());
1041 }
1042 if (otherGTU.fractionalPosition(this, otherGTU.getFront()) >= fractionalPosition)
1043 {
1044 break;
1045 }
1046 }
1047 this.gtuList.add(index, gtu);
1048
1049
1050
1051
1052
1053
1054
1055
1056 }
1057 }
1058
1059
1060 fireTimedEvent(Lane.GTU_ADD_EVENT, new Object[] { gtu.getId(), this.gtuList.size() },
1061 gtu.getSimulator().getSimulatorTime());
1062 getParentLink().addGTU(gtu);
1063 return index;
1064 }
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074 public final int addGTU(final LaneBasedGTU gtu, final Length longitudinalPosition) throws GTUException
1075 {
1076 return addGTU(gtu, longitudinalPosition.getSI() / getLength().getSI());
1077 }
1078
1079
1080
1081
1082
1083
1084
1085 public final void removeGTU(final LaneBasedGTU gtu, final boolean removeFromParentLink, final Length position)
1086 {
1087 boolean contained = this.gtuList.remove(gtu);
1088 if (contained)
1089 {
1090 fireTimedEvent(Lane.GTU_REMOVE_EVENT, new Object[] { gtu.getId(), gtu, this.gtuList.size(), position },
1091 gtu.getSimulator().getSimulatorTime());
1092 }
1093 if (removeFromParentLink)
1094 {
1095 this.parentLink.removeGTU(gtu);
1096 }
1097 }
1098
1099
1100
1101
1102
1103
1104
1105
1106 public final LaneBasedGTU getLastGtu(final GTUDirectionality direction) throws GTUException
1107 {
1108 if (this.gtuList.size() == 0)
1109 {
1110 return null;
1111 }
1112 if (direction.equals(GTUDirectionality.DIR_PLUS))
1113 {
1114 return this.gtuList.get(this.gtuList.size() - 1);
1115 }
1116 else
1117 {
1118 return this.gtuList.get(0);
1119 }
1120 }
1121
1122
1123
1124
1125
1126
1127
1128
1129 public final LaneBasedGTU getFirstGtu(final GTUDirectionality direction) throws GTUException
1130 {
1131 if (this.gtuList.size() == 0)
1132 {
1133 return null;
1134 }
1135 if (direction.equals(GTUDirectionality.DIR_PLUS))
1136 {
1137 return this.gtuList.get(0);
1138 }
1139 else
1140 {
1141 return this.gtuList.get(this.gtuList.size() - 1);
1142 }
1143 }
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157 public final LaneBasedGTU getGtuAhead(final Length position, final GTUDirectionality direction,
1158 final RelativePosition.TYPE relativePosition, final Time when) throws GTUException
1159 {
1160 List<LaneBasedGTU> list = this.gtuList.get(when);
1161 if (list.isEmpty())
1162 {
1163 return null;
1164 }
1165 int[] search = lineSearch((final int index) -> {
1166 LaneBasedGTU gtu = list.get(index);
1167 return gtu.position(this, gtu.getRelativePositions().get(relativePosition), when).si;
1168 }, list.size(), position.si);
1169 if (direction.equals(GTUDirectionality.DIR_PLUS))
1170 {
1171 if (search[1] < list.size())
1172 {
1173 return list.get(search[1]);
1174 }
1175 }
1176 else
1177 {
1178 if (search[0] >= 0)
1179 {
1180 return list.get(search[0]);
1181 }
1182 }
1183 return null;
1184 }
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196 private int[] lineSearch(final Positions positions, final int listSize, final double position) throws GTUException
1197 {
1198 int[] out = new int[2];
1199
1200 double pos0 = positions.get(0);
1201 double posEnd;
1202 if (position < pos0)
1203 {
1204 out[0] = -1;
1205 out[1] = 0;
1206 }
1207 else if (position == pos0)
1208 {
1209 out[0] = -1;
1210 out[1] = 1;
1211 }
1212 else if (position > (posEnd = positions.get(listSize - 1)))
1213 {
1214 out[0] = listSize - 1;
1215 out[1] = listSize;
1216 }
1217 else if (position == posEnd)
1218 {
1219 out[0] = listSize - 2;
1220 out[1] = listSize;
1221 }
1222 else
1223 {
1224 int low = 0;
1225 int mid = (int) ((listSize - 1) * position / this.length.si);
1226 mid = mid < 0 ? 0 : mid >= listSize ? listSize - 1 : mid;
1227 int high = listSize - 1;
1228 while (high - low > 1)
1229 {
1230 double midPos = positions.get(mid);
1231 if (midPos < position)
1232 {
1233 low = mid;
1234 }
1235 else if (midPos > position)
1236 {
1237 high = mid;
1238 }
1239 else
1240 {
1241 low = mid - 1;
1242 high = mid + 1;
1243 break;
1244 }
1245 mid = (low + high) / 2;
1246 }
1247 out[0] = low;
1248 out[1] = high;
1249 }
1250 return out;
1251 }
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263 public final List<LaneBasedObject> getObjectAhead(final Length position, final GTUDirectionality direction)
1264 {
1265 if (direction.equals(GTUDirectionality.DIR_PLUS))
1266 {
1267 for (double distance : this.laneBasedObjects.keySet())
1268 {
1269 if (distance > position.si)
1270 {
1271 return new ArrayList<>(this.laneBasedObjects.get(distance));
1272 }
1273 }
1274 }
1275 else
1276 {
1277 NavigableMap<Double, List<LaneBasedObject>> reverseLBO =
1278 (NavigableMap<Double, List<LaneBasedObject>>) this.laneBasedObjects;
1279 for (double distance : reverseLBO.descendingKeySet())
1280 {
1281 if (distance < position.si)
1282 {
1283 return new ArrayList<>(this.laneBasedObjects.get(distance));
1284 }
1285 }
1286 }
1287 return null;
1288 }
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300 public final List<LaneBasedObject> getObjectBehind(final Length position, final GTUDirectionality direction)
1301 {
1302 if (direction.equals(GTUDirectionality.DIR_PLUS))
1303 {
1304 return getObjectAhead(position, GTUDirectionality.DIR_MINUS);
1305 }
1306 return getObjectAhead(position, GTUDirectionality.DIR_PLUS);
1307 }
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321 public final LaneBasedGTU getGtuBehind(final Length position, final GTUDirectionality direction,
1322 final RelativePosition.TYPE relativePosition, final Time when) throws GTUException
1323 {
1324 if (direction.equals(GTUDirectionality.DIR_PLUS))
1325 {
1326 return getGtuAhead(position, GTUDirectionality.DIR_MINUS, relativePosition, when);
1327 }
1328 return getGtuAhead(position, GTUDirectionality.DIR_PLUS, relativePosition, when);
1329 }
1330
1331
1332
1333
1334
1335
1336
1337 public static final Length MARGIN = new Length(0.5, LengthUnit.METER);
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354 public final Map<Lane, GTUDirectionality> nextLanes(final GTUType gtuType)
1355 {
1356 if (this.nextLanes == null)
1357 {
1358 this.nextLanes = new LinkedHashMap<>(1);
1359 }
1360 if (!this.nextLanes.containsKey(gtuType))
1361 {
1362
1363 Map<Lane, GTUDirectionality> laneMap = new LinkedHashMap<>(1);
1364 this.nextLanes.put(gtuType, laneMap);
1365
1366 for (Link link : getParentLink().getEndNode().getLinks())
1367 {
1368 if (!(link.equals(this.getParentLink())) && link instanceof CrossSectionLink)
1369 {
1370 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
1371 {
1372 if (cse instanceof Lane)
1373 {
1374 Laneef="../../../../../org/opentrafficsim/road/network/lane/Lane.html#Lane">Lane lane = (Lane) cse;
1375 Length jumpToStart = this.getCenterLine().getLast().distance(lane.getCenterLine().getFirst());
1376 Length jumpToEnd = this.getCenterLine().getLast().distance(lane.getCenterLine().getLast());
1377
1378 if (jumpToStart.lt(MARGIN) && jumpToStart.lt(jumpToEnd)
1379 && link.getStartNode().equals(getParentLink().getEndNode()))
1380 {
1381
1382
1383 if (gtuType == null || lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_PLUS))
1384 {
1385 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1386 }
1387 else if (lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_MINUS))
1388 {
1389 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1390 }
1391 }
1392
1393 else if (jumpToEnd.lt(MARGIN) && jumpToEnd.lt(jumpToStart)
1394 && link.getEndNode().equals(getParentLink().getEndNode()))
1395 {
1396
1397
1398 if (lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_PLUS))
1399 {
1400 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1401 }
1402 else if (gtuType == null
1403 || lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_MINUS))
1404 {
1405 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1406 }
1407 }
1408
1409 }
1410 }
1411 }
1412 }
1413 }
1414 return this.nextLanes.get(gtuType);
1415 }
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433 public final Map<Lane, GTUDirectionality> prevLanes(final GTUType gtuType)
1434 {
1435 if (this.prevLanes == null)
1436 {
1437 this.prevLanes = new LinkedHashMap<>(1);
1438 }
1439 if (!this.prevLanes.containsKey(gtuType))
1440 {
1441 Map<Lane, GTUDirectionality> laneMap = new LinkedHashMap<>(1);
1442 this.prevLanes.put(gtuType, laneMap);
1443
1444 for (Link link : getParentLink().getStartNode().getLinks())
1445 {
1446 if (!(link.equals(this.getParentLink())) && link instanceof CrossSectionLink)
1447 {
1448 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
1449 {
1450 if (cse instanceof Lane)
1451 {
1452 Laneef="../../../../../org/opentrafficsim/road/network/lane/Lane.html#Lane">Lane lane = (Lane) cse;
1453 Length jumpToStart = this.getCenterLine().getFirst().distance(lane.getCenterLine().getFirst());
1454 Length jumpToEnd = this.getCenterLine().getFirst().distance(lane.getCenterLine().getLast());
1455
1456 if (jumpToStart.lt(MARGIN) && jumpToStart.lt(jumpToEnd)
1457 && link.getStartNode().equals(getParentLink().getStartNode()))
1458 {
1459
1460
1461 if (lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_PLUS))
1462 {
1463 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1464 }
1465 else if (gtuType == null
1466 || lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_MINUS))
1467 {
1468 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1469 }
1470 }
1471
1472 else if (jumpToEnd.lt(MARGIN) && jumpToEnd.lt(jumpToStart)
1473 && link.getEndNode().equals(getParentLink().getStartNode()))
1474 {
1475
1476
1477 if (gtuType == null || lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_PLUS))
1478 {
1479 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1480 }
1481 else if (lane.getLaneType().isCompatible(gtuType, GTUDirectionality.DIR_MINUS))
1482 {
1483 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1484 }
1485 }
1486
1487 }
1488 }
1489 }
1490 }
1491 }
1492 return this.prevLanes.get(gtuType);
1493 }
1494
1495
1496
1497
1498
1499
1500
1501 public final synchronized ImmutableMap<Lane, GTUDirectionality> downstreamLanes(final GTUDirectionality direction,
1502 final GTUType gtuType)
1503 {
1504 return this.downLanes.get(() -> {
1505 Map<Lane, GTUDirectionality> downMap =
1506 new LinkedHashMap<>(direction.isPlus() ? nextLanes(gtuType) : prevLanes(gtuType));
1507 Node downNode = direction.isPlus() ? getParentLink().getEndNode() : getParentLink().getStartNode();
1508 Iterator<Entry<Lane, GTUDirectionality>> iterator = downMap.entrySet().iterator();
1509 while (iterator.hasNext())
1510 {
1511 Entry<Lane, GTUDirectionality> entry = iterator.next();
1512 if ((entry.getValue().isPlus() && !entry.getKey().getParentLink().getStartNode().equals(downNode))
1513 || (entry.getValue().isMinus() && !entry.getKey().getParentLink().getEndNode().equals(downNode)))
1514 {
1515
1516 iterator.remove();
1517 }
1518 }
1519 return new ImmutableLinkedHashMap<>(downMap, Immutable.WRAP);
1520 }, gtuType, direction);
1521 }
1522
1523
1524
1525
1526
1527
1528
1529 public final synchronized ImmutableMap<Lane, GTUDirectionality> upstreamLanes(final GTUDirectionality direction,
1530 final GTUType gtuType)
1531 {
1532 return this.upLanes.get(() -> {
1533 Map<Lane, GTUDirectionality> upMap =
1534 new LinkedHashMap<>(direction.isPlus() ? prevLanes(gtuType) : nextLanes(gtuType));
1535 Node upNode = direction.isPlus() ? getParentLink().getStartNode() : getParentLink().getEndNode();
1536 Iterator<Entry<Lane, GTUDirectionality>> iterator = upMap.entrySet().iterator();
1537 while (iterator.hasNext())
1538 {
1539 Entry<Lane, GTUDirectionality> entry = iterator.next();
1540 if ((entry.getValue().isPlus() && !entry.getKey().getParentLink().getEndNode().equals(upNode))
1541 || (entry.getValue().isMinus() && !entry.getKey().getParentLink().getStartNode().equals(upNode)))
1542 {
1543
1544 iterator.remove();
1545 }
1546 }
1547 return new ImmutableLinkedHashMap<>(upMap, Immutable.WRAP);
1548 }, gtuType, direction);
1549 }
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563 public final Set<Lane> accessibleAdjacentLanesPhysical(final LateralDirectionality lateralDirection, final GTUType gtuType,
1564 final GTUDirectionality drivingDirection)
1565 {
1566 LateralDirectionality dir =
1567 drivingDirection.equals(GTUDirectionality.DIR_PLUS) ? lateralDirection : lateralDirection.flip();
1568 return neighbors(dir, gtuType, drivingDirection, false);
1569 }
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585 public final Set<Lane> accessibleAdjacentLanesLegal(final LateralDirectionality lateralDirection, final GTUType gtuType,
1586 final GTUDirectionality drivingDirection)
1587 {
1588 Set<Lane> candidates = new LinkedHashSet<>(1);
1589 LateralDirectionality dir =
1590 drivingDirection.equals(GTUDirectionality.DIR_PLUS) ? lateralDirection : lateralDirection.flip();
1591 for (Lane lane : neighbors(dir, gtuType, drivingDirection, true))
1592 {
1593 if (lane.getLaneType().isCompatible(gtuType, drivingDirection))
1594 {
1595 candidates.add(lane);
1596 }
1597 }
1598 return candidates;
1599 }
1600
1601
1602
1603
1604
1605
1606
1607
1608 public final Speed getSpeedLimit(final GTUType gtuType) throws NetworkException
1609 {
1610 Speed speedLimit = this.cachedSpeedLimits.get(gtuType);
1611 if (speedLimit == null)
1612 {
1613 if (this.speedLimitMap.containsKey(gtuType))
1614 {
1615 speedLimit = this.speedLimitMap.get(gtuType);
1616 }
1617 else if (gtuType.getParent() != null)
1618 {
1619 speedLimit = getSpeedLimit(gtuType.getParent());
1620 }
1621 else
1622 {
1623 throw new NetworkException("No speed limit set for GTUType " + gtuType + " on lane " + toString());
1624 }
1625 this.cachedSpeedLimits.put(gtuType, speedLimit);
1626 }
1627 return speedLimit;
1628 }
1629
1630
1631
1632
1633
1634
1635 public final Speed getLowestSpeedLimit() throws NetworkException
1636 {
1637 Throw.when(this.speedLimitMap.isEmpty(), NetworkException.class, "Lane %s has no speed limits set.", toString());
1638 Speed out = Speed.POSITIVE_INFINITY;
1639 for (GTUType gtuType : this.speedLimitMap.keySet())
1640 {
1641 out = Speed.min(out, this.speedLimitMap.get(gtuType));
1642 }
1643 return out;
1644 }
1645
1646
1647
1648
1649
1650
1651 public final Speed getHighestSpeedLimit() throws NetworkException
1652 {
1653 Throw.when(this.speedLimitMap.isEmpty(), NetworkException.class, "Lane %s has no speed limits set.", toString());
1654 Speed out = Speed.ZERO;
1655 for (GTUType gtuType : this.speedLimitMap.keySet())
1656 {
1657 out = Speed.max(out, this.speedLimitMap.get(gtuType));
1658 }
1659 return out;
1660 }
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676 public final void setSpeedLimit(final GTUType gtuType, final Speed speedLimit)
1677 {
1678 this.speedLimitMap.put(gtuType, speedLimit);
1679 this.cachedSpeedLimits.clear();
1680 }
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690 public final void removeSpeedLimit(final GTUType gtuType)
1691 {
1692 this.speedLimitMap.remove(gtuType);
1693 this.cachedSpeedLimits.clear();
1694 }
1695
1696
1697
1698
1699 public final LaneType getLaneType()
1700 {
1701 return this.laneType;
1702 }
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747 private void checkDirectionality() throws NetworkException
1748 {
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759 }
1760
1761
1762
1763
1764 public final ImmutableList<LaneBasedGTU> getGtuList()
1765 {
1766
1767 return this.gtuList == null ? new ImmutableArrayList<>(new ArrayList<>())
1768 : new ImmutableArrayList<>(this.gtuList, Immutable.COPY);
1769 }
1770
1771
1772
1773
1774
1775
1776 public final List<LaneBasedGTU> getGtuList(final Time time)
1777 {
1778 if (time.equals(this.gtuListTime))
1779 {
1780 return this.gtuListAtTime;
1781 }
1782 this.gtuListTime = time;
1783 this.gtuListAtTime = this.gtuList == null ? new ArrayList<>() : this.gtuList.get(time);
1784 return this.gtuListAtTime;
1785 }
1786
1787
1788
1789
1790
1791 public final int numberOfGtus()
1792 {
1793 return this.gtuList.size();
1794 }
1795
1796
1797
1798
1799
1800
1801 public final int numberOfGtus(final Time time)
1802 {
1803 return getGtuList(time).size();
1804 }
1805
1806
1807
1808
1809
1810
1811 public final int indexOfGtu(final LaneBasedGTU gtu)
1812 {
1813 return Collections.binarySearch(this.gtuList, gtu, (gtu1, gtu2) -> {
1814 try
1815 {
1816 return gtu1.position(this, gtu1.getReference()).compareTo(gtu2.position(this, gtu2.getReference()));
1817 }
1818 catch (GTUException exception)
1819 {
1820 throw new RuntimeException(exception);
1821 }
1822 });
1823 }
1824
1825
1826
1827
1828
1829
1830
1831 public final int indexOfGtu(final LaneBasedGTU gtu, final Time time)
1832 {
1833 return Collections.binarySearch(getGtuList(time), gtu, (gtu1, gtu2) -> {
1834 try
1835 {
1836 return Double.compare(gtu1.fractionalPosition(this, gtu1.getReference(), time),
1837 gtu2.fractionalPosition(this, gtu2.getReference(), time));
1838 }
1839 catch (GTUException exception)
1840 {
1841 throw new RuntimeException(exception);
1842 }
1843 });
1844 }
1845
1846
1847
1848
1849
1850
1851 public final LaneBasedGTU getGtu(final int index)
1852 {
1853 return this.gtuList.get(index);
1854 }
1855
1856
1857
1858
1859
1860
1861
1862 public final LaneBasedGTU getGtu(final int index, final Time time)
1863 {
1864 return getGtuList(time).get(index);
1865 }
1866
1867
1868 @Override
1869 @SuppressWarnings("checkstyle:designforextension")
1870 public double getZ()
1871 {
1872 return 0.0;
1873 }
1874
1875
1876 @Override
1877 public final String toString()
1878 {
1879 CrossSectionLink link = getParentLink();
1880 return String.format("Lane %s of %s", getId(), link.getId());
1881 }
1882
1883
1884 private Integer cachedHashCode = null;
1885
1886
1887 @SuppressWarnings("checkstyle:designforextension")
1888 @Override
1889 public int hashCode()
1890 {
1891 if (this.cachedHashCode == null)
1892 {
1893 final int prime = 31;
1894 int result = super.hashCode();
1895 result = prime * result + ((this.laneType == null) ? 0 : this.laneType.hashCode());
1896 this.cachedHashCode = result;
1897 }
1898 return this.cachedHashCode;
1899 }
1900
1901
1902 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
1903 @Override
1904 public boolean equals(final Object obj)
1905 {
1906 if (this == obj)
1907 return true;
1908 if (!super.equals(obj))
1909 return false;
1910 if (getClass() != obj.getClass())
1911 return false;
1912 Lanef="../../../../../org/opentrafficsim/road/network/lane/Lane.html#Lane">Lane other = (Lane) obj;
1913 if (this.laneType == null)
1914 {
1915 if (other.laneType != null)
1916 return false;
1917 }
1918 else if (!this.laneType.equals(other.laneType))
1919 return false;
1920 return true;
1921 }
1922
1923
1924 @Override
1925 @SuppressWarnings("checkstyle:designforextension")
1926 public Lane clone(final CrossSectionLink newParentLink, final SimulatorInterface.TimeDoubleUnit newSimulator)
1927 throws NetworkException
1928 {
1929 Lanenetwork/lane/Lane.html#Lane">Lane newLane = new Lane(newParentLink, this);
1930
1931
1932 SortedMap<Double, List<SingleSensor>> newSensorMap = new TreeMap<>();
1933 for (double distance : this.sensors.keySet())
1934 {
1935 List<SingleSensor> newSensorList = new ArrayList<>();
1936 for (SingleSensor sensor : this.sensors.get(distance))
1937 {
1938 SingleSensor newSensor = ((AbstractSensor) sensor).clone(newLane, newSimulator);
1939 newSensorList.add(newSensor);
1940 }
1941 newSensorMap.put(distance, newSensorList);
1942 }
1943 newLane.sensors.clear();
1944 newLane.sensors.putAll(newSensorMap);
1945
1946 SortedMap<Double, List<LaneBasedObject>> newLaneBasedObjectMap = new TreeMap<>();
1947 for (double distance : this.laneBasedObjects.keySet())
1948 {
1949 List<LaneBasedObject> newLaneBasedObjectList = new ArrayList<>();
1950 for (LaneBasedObject lbo : this.laneBasedObjects.get(distance))
1951 {
1952 AbstractLaneBasedObjectfficsim/road/network/lane/object/AbstractLaneBasedObject.html#AbstractLaneBasedObject">AbstractLaneBasedObject laneBasedObject = (AbstractLaneBasedObject) lbo;
1953 LaneBasedObject newLbo = laneBasedObject.clone(newLane, newSimulator);
1954 newLaneBasedObjectList.add(newLbo);
1955 }
1956 newLaneBasedObjectMap.put(distance, newLaneBasedObjectList);
1957 }
1958 newLane.laneBasedObjects.clear();
1959 newLane.laneBasedObjects.putAll(newLaneBasedObjectMap);
1960
1961 return newLane;
1962 }
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976 private interface Positions
1977 {
1978
1979
1980
1981
1982
1983
1984 double get(int index) throws GTUException;
1985 }
1986
1987 }