1 package org.opentrafficsim.road.network.lane;
2
3 import java.awt.Color;
4 import java.io.Serializable;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.LinkedHashMap;
9 import java.util.LinkedHashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.NavigableMap;
13 import java.util.Set;
14 import java.util.SortedMap;
15 import java.util.TreeMap;
16
17 import javax.naming.NamingException;
18
19 import org.djunits.unit.LengthUnit;
20 import org.djunits.unit.TimeUnit;
21 import org.djunits.value.vdouble.scalar.Length;
22 import org.djunits.value.vdouble.scalar.Speed;
23 import org.djunits.value.vdouble.scalar.Time;
24 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
25 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
26 import org.opentrafficsim.core.geometry.OTSGeometryException;
27 import org.opentrafficsim.core.gtu.GTUDirectionality;
28 import org.opentrafficsim.core.gtu.GTUException;
29 import org.opentrafficsim.core.gtu.GTUType;
30 import org.opentrafficsim.core.gtu.RelativePosition;
31 import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
32 import org.opentrafficsim.core.network.LateralDirectionality;
33 import org.opentrafficsim.core.network.Link;
34 import org.opentrafficsim.core.network.LongitudinalDirectionality;
35 import org.opentrafficsim.core.network.NetworkException;
36 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
37 import org.opentrafficsim.road.network.animation.LaneAnimation;
38 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
39 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
40 import org.opentrafficsim.road.network.lane.object.LaneBasedObject;
41 import org.opentrafficsim.road.network.lane.object.sensor.AbstractSensor;
42 import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
43
44 import nl.tudelft.simulation.dsol.SimRuntimeException;
45 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEvent;
46 import nl.tudelft.simulation.event.EventType;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class Lane extends CrossSectionElement implements Serializable
67 {
68
69 private static final long serialVersionUID = 20150826L;
70
71
72 private final LaneType laneType;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 private final Map<GTUType, LongitudinalDirectionality> directionalityMap;
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104 private Map<GTUType, Speed> speedLimitMap;
105
106
107
108
109
110
111 private final SortedMap<Double, List<GTUTypeSensor>> sensors = new TreeMap<>();
112
113
114
115
116
117
118 private final SortedMap<Double, List<LaneBasedObject>> laneBasedObjects = new TreeMap<>();
119
120
121 private final List<LaneBasedGTU> gtuList = new ArrayList<LaneBasedGTU>();
122
123
124
125
126
127
128 private Map<GTUType, Set<Lane>> leftNeighbors = null;
129
130
131
132
133
134
135 private Map<GTUType, Set<Lane>> rightNeighbors = null;
136
137
138
139
140
141 private Map<GTUType, Map<Lane, GTUDirectionality>> nextLanes = null;
142
143
144
145
146
147 private Map<GTUType, Map<Lane, GTUDirectionality>> prevLanes = null;
148
149
150
151 private final OvertakingConditions overtakingConditions;
152
153
154
155
156
157 public static final EventType GTU_ADD_EVENT = new EventType("GTU.ADD");
158
159
160
161
162
163 public static final EventType GTU_REMOVE_EVENT = new EventType("GTU.REMOVE");
164
165
166
167
168
169 public static final EventType SENSOR_ADD_EVENT = new EventType("SENSOR.ADD");
170
171
172
173
174
175 public static final EventType SENSOR_REMOVE_EVENT = new EventType("SENSOR.REMOVE");
176
177
178
179
180
181 public static final EventType OBJECT_ADD_EVENT = new EventType("OBJECT.ADD");
182
183
184
185
186
187 public static final EventType OBJECT_REMOVE_EVENT = new EventType("OBJECT.REMOVE");
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 @SuppressWarnings("checkstyle:parameternumber")
208 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
209 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
210 final Map<GTUType, LongitudinalDirectionality> directionalityMap, final Map<GTUType, Speed> speedLimitMap,
211 final OvertakingConditions overtakingConditions) throws OTSGeometryException, NetworkException
212 {
213 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth);
214 this.laneType = laneType;
215 this.directionalityMap = directionalityMap;
216 checkDirectionality();
217 this.speedLimitMap = speedLimitMap;
218 this.overtakingConditions = overtakingConditions;
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 @SuppressWarnings("checkstyle:parameternumber")
239 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffsetAtStart,
240 final Length lateralOffsetAtEnd, final Length beginWidth, final Length endWidth, final LaneType laneType,
241 final LongitudinalDirectionality directionality, final Speed speedLimit,
242 final OvertakingConditions overtakingConditions) throws OTSGeometryException, NetworkException
243 {
244 super(parentLink, id, lateralOffsetAtStart, lateralOffsetAtEnd, beginWidth, endWidth);
245 this.laneType = laneType;
246 this.directionalityMap = new LinkedHashMap<>(1);
247 this.directionalityMap.put(GTUType.ALL, directionality);
248 checkDirectionality();
249 this.speedLimitMap = new LinkedHashMap<>();
250 this.speedLimitMap.put(GTUType.ALL, speedLimit);
251 this.overtakingConditions = overtakingConditions;
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 @SuppressWarnings("checkstyle:parameternumber")
270 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffset, final Length width,
271 final LaneType laneType, final Map<GTUType, LongitudinalDirectionality> directionalityMap,
272 final Map<GTUType, Speed> speedLimitMap, final OvertakingConditions overtakingConditions)
273 throws OTSGeometryException, NetworkException
274 {
275 super(parentLink, id, lateralOffset, width);
276 this.laneType = laneType;
277 this.directionalityMap = directionalityMap;
278 checkDirectionality();
279 this.speedLimitMap = speedLimitMap;
280 this.overtakingConditions = overtakingConditions;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 @SuppressWarnings("checkstyle:parameternumber")
298 public Lane(final CrossSectionLink parentLink, final String id, final Length lateralOffset, final Length width,
299 final LaneType laneType, final LongitudinalDirectionality directionality, final Speed speedLimit,
300 final OvertakingConditions overtakingConditions) throws OTSGeometryException, NetworkException
301 {
302 super(parentLink, id, lateralOffset, width);
303 this.laneType = laneType;
304 this.directionalityMap = new LinkedHashMap<>(1);
305 this.directionalityMap.put(GTUType.ALL, directionality);
306 checkDirectionality();
307 this.speedLimitMap = new LinkedHashMap<>();
308 this.speedLimitMap.put(GTUType.ALL, speedLimit);
309 this.overtakingConditions = overtakingConditions;
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 @SuppressWarnings("checkstyle:parameternumber")
329 public Lane(final CrossSectionLink parentLink, final String id, final List<CrossSectionSlice> crossSectionSlices,
330 final LaneType laneType, final Map<GTUType, LongitudinalDirectionality> directionalityMap,
331 final Map<GTUType, Speed> speedLimitMap, final OvertakingConditions overtakingConditions)
332 throws OTSGeometryException, NetworkException
333 {
334 super(parentLink, id, crossSectionSlices);
335 this.laneType = laneType;
336 this.directionalityMap = directionalityMap;
337 checkDirectionality();
338 this.speedLimitMap = speedLimitMap;
339 this.overtakingConditions = overtakingConditions;
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357 @SuppressWarnings("checkstyle:parameternumber")
358 public Lane(final CrossSectionLink parentLink, final String id, final List<CrossSectionSlice> crossSectionSlices,
359 final LaneType laneType, final LongitudinalDirectionality directionality, final Speed speedLimit,
360 final OvertakingConditions overtakingConditions) throws OTSGeometryException, NetworkException
361 {
362 super(parentLink, id, crossSectionSlices);
363 this.laneType = laneType;
364 this.directionalityMap = new LinkedHashMap<>(1);
365 this.directionalityMap.put(GTUType.ALL, directionality);
366 checkDirectionality();
367 this.speedLimitMap = new LinkedHashMap<>();
368 this.speedLimitMap.put(GTUType.ALL, speedLimit);
369 this.overtakingConditions = overtakingConditions;
370 }
371
372
373
374
375
376
377
378
379
380
381 protected Lane(final CrossSectionLink newParentLink, final OTSSimulatorInterface newSimulator, final boolean animation,
382 final Lane cse) throws NetworkException
383 {
384 super(newParentLink, newSimulator, animation, cse);
385 this.laneType = cse.laneType;
386 this.directionalityMap = new HashMap<GTUType, LongitudinalDirectionality>(cse.directionalityMap);
387 this.speedLimitMap = new HashMap<GTUType, Speed>(cse.speedLimitMap);
388 this.overtakingConditions = cse.overtakingConditions;
389
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403 private Set<Lane> neighbors(final LateralDirectionality direction, final GTUType gtuType)
404 {
405 if (this.leftNeighbors == null || this.rightNeighbors == null)
406 {
407 this.leftNeighbors = new LinkedHashMap<>(1);
408 this.rightNeighbors = new LinkedHashMap<>(1);
409 }
410
411 if (!this.leftNeighbors.containsKey(gtuType) || !this.rightNeighbors.containsKey(gtuType))
412 {
413 Set<Lane> leftSet = new LinkedHashSet<>(1);
414 Set<Lane> rightSet = new LinkedHashSet<>(1);
415 this.leftNeighbors.put(gtuType, leftSet);
416 this.rightNeighbors.put(gtuType, rightSet);
417 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
418 {
419 if (cse instanceof Lane && !cse.equals(this))
420 {
421 Lane lane = (Lane) cse;
422 if (laterallyAdjacentAndAccessible(lane, LateralDirectionality.LEFT, gtuType))
423 {
424 leftSet.add(lane);
425 }
426 if (laterallyAdjacentAndAccessible(lane, LateralDirectionality.RIGHT, gtuType))
427 {
428 rightSet.add(lane);
429 }
430 }
431 }
432 }
433
434 Set<Lane> lanes = new LinkedHashSet<>();
435 if (direction == LateralDirectionality.LEFT)
436 {
437 lanes.addAll(this.leftNeighbors.get(gtuType));
438 }
439 else
440 {
441 lanes.addAll(this.rightNeighbors.get(gtuType));
442 }
443 return lanes;
444 }
445
446
447 static final Length ADJACENT_MARGIN = new Length(0.2, LengthUnit.METER);
448
449
450
451
452
453
454
455
456
457
458
459
460 private boolean laterallyAdjacentAndAccessible(final Lane lane, final LateralDirectionality direction,
461 final GTUType gtuType)
462 {
463 if (!lane.getLaneType().isCompatible(gtuType) || gtuType.equals(GTUType.ALL) || gtuType.equals(GTUType.NONE))
464 {
465
466 return false;
467 }
468
469 if (direction.equals(LateralDirectionality.LEFT))
470 {
471
472 if (Math.abs((getDesignLineOffsetAtBegin().getSI() + getBeginWidth().getSI() / 2.0)
473 - (lane.getDesignLineOffsetAtBegin().getSI() - lane.getBeginWidth().getSI() / 2.0)) < ADJACENT_MARGIN
474 .getSI()
475 && Math.abs((getDesignLineOffsetAtEnd().getSI() + getEndWidth().getSI() / 2.0)
476 - (lane.getDesignLineOffsetAtEnd().getSI() - lane.getEndWidth().getSI() / 2.0)) < ADJACENT_MARGIN
477 .getSI())
478 {
479
480 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
481 {
482 if (cse instanceof Stripe)
483 {
484 Stripe stripe = (Stripe) cse;
485
486 if (Math.abs((getDesignLineOffsetAtBegin().getSI() + getBeginWidth().getSI() / 2.0)
487 - stripe.getDesignLineOffsetAtBegin().getSI()) < ADJACENT_MARGIN.getSI()
488 && Math.abs((getDesignLineOffsetAtEnd().getSI() + getEndWidth().getSI() / 2.0)
489 - stripe.getDesignLineOffsetAtEnd().getSI()) < ADJACENT_MARGIN.getSI())
490 {
491 if (!stripe.isPermeable(gtuType, LateralDirectionality.LEFT))
492 {
493
494 return false;
495 }
496 }
497 }
498 }
499
500
501 return true;
502 }
503 }
504
505 else
506
507 {
508
509 if (Math.abs((getDesignLineOffsetAtBegin().getSI() - getBeginWidth().getSI() / 2.0)
510 - (lane.getDesignLineOffsetAtBegin().getSI() + lane.getBeginWidth().getSI() / 2.0)) < ADJACENT_MARGIN
511 .getSI()
512 && Math.abs((getDesignLineOffsetAtEnd().getSI() - getEndWidth().getSI() / 2.0)
513 - (lane.getDesignLineOffsetAtEnd().getSI() + lane.getEndWidth().getSI() / 2.0)) < ADJACENT_MARGIN
514 .getSI())
515 {
516
517 for (CrossSectionElement cse : this.parentLink.getCrossSectionElementList())
518 {
519 if (cse instanceof Stripe)
520 {
521 Stripe stripe = (Stripe) cse;
522
523 if (Math.abs((getDesignLineOffsetAtBegin().getSI() - getBeginWidth().getSI() / 2.0)
524 - stripe.getDesignLineOffsetAtBegin().getSI()) < ADJACENT_MARGIN.getSI()
525 && Math.abs((getDesignLineOffsetAtEnd().getSI() - getEndWidth().getSI() / 2.0)
526 - stripe.getDesignLineOffsetAtEnd().getSI()) < ADJACENT_MARGIN.getSI())
527 {
528 if (!stripe.isPermeable(gtuType, LateralDirectionality.RIGHT))
529 {
530
531 return false;
532 }
533 }
534 }
535 }
536
537
538 return true;
539 }
540 }
541
542
543 return false;
544 }
545
546
547
548
549
550
551
552 public final void addSensor(final Sensor sensor, final GTUType gtuType) throws NetworkException
553 {
554 double position = sensor.getLongitudinalPosition().si;
555 if (position < 0 || position > getLength().getSI())
556 {
557 throw new NetworkException("Illegal position for sensor " + position + " valid range is 0.." + getLength().getSI());
558 }
559 List<GTUTypeSensor> sensorList = this.sensors.get(position);
560 if (null == sensorList)
561 {
562 sensorList = new ArrayList<GTUTypeSensor>(1);
563 this.sensors.put(position, sensorList);
564 }
565 sensorList.add(new GTUTypeSensor(gtuType, sensor));
566 fireTimedEvent(Lane.SENSOR_ADD_EVENT, new Object[] { sensor.getId(), sensor },
567 sensor.getSimulator().getSimulatorTime());
568 }
569
570
571
572
573
574
575 public final void removeSensor(final Sensor sensor) throws NetworkException
576 {
577 fireTimedEvent(Lane.SENSOR_REMOVE_EVENT, new Object[] { sensor.getId(), sensor },
578 sensor.getSimulator().getSimulatorTime());
579 List<GTUTypeSensor> sensorList = this.sensors.get(sensor.getLongitudinalPosition().getSI());
580 if (null == sensorList)
581 {
582 throw new NetworkException("No sensor at " + sensor.getLongitudinalPosition().si);
583 }
584 List<GTUTypeSensor> sensorList2 = new ArrayList<GTUTypeSensor>(1);
585 for (GTUTypeSensor gs : sensorList)
586 {
587 if (!gs.getSensor().equals(sensor))
588 {
589 sensorList2.add(gs);
590 }
591 }
592 if (sensorList2.size() == 0)
593 {
594 this.sensors.remove(sensor.getLongitudinalPosition().doubleValue());
595 }
596 else
597 {
598 this.sensors.put(sensor.getLongitudinalPosition().doubleValue(), sensorList2);
599 }
600 }
601
602
603
604
605
606
607
608
609
610 public final List<Sensor> getSensors(final Length minimumPosition, final Length maximumPosition, final GTUType gtuType)
611 {
612 List<Sensor> sensorList = new ArrayList<>(1);
613 for (List<GTUTypeSensor> gtsl : this.sensors.values())
614 {
615 for (GTUTypeSensor gs : gtsl)
616 {
617 if ((gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL))
618 && gs.getSensor().getLongitudinalPosition().gt(minimumPosition)
619 && gs.getSensor().getLongitudinalPosition().le(maximumPosition))
620 {
621 sensorList.add(gs.getSensor());
622 }
623 }
624 }
625 return sensorList;
626 }
627
628
629
630
631
632
633
634 public final List<Sensor> getSensors(final GTUType gtuType)
635 {
636 List<Sensor> sensorList = new ArrayList<>(1);
637 for (List<GTUTypeSensor> gtsl : this.sensors.values())
638 {
639 for (GTUTypeSensor gs : gtsl)
640 {
641 if ((gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL)))
642 {
643 sensorList.add(gs.getSensor());
644 }
645 }
646 }
647 return sensorList;
648 }
649
650
651
652
653
654 public final List<Sensor> getSensors()
655 {
656 if (this.sensors == null)
657 {
658 return new ArrayList<>();
659 }
660 List<Sensor> sensorList = new ArrayList<>(1);
661 for (List<GTUTypeSensor> gtsl : this.sensors.values())
662 {
663 for (GTUTypeSensor gs : gtsl)
664 {
665 sensorList.add(gs.getSensor());
666 }
667 }
668 return sensorList;
669 }
670
671
672
673
674
675
676
677 public final SortedMap<Double, List<Sensor>> getSensorMap(final GTUType gtuType)
678 {
679 SortedMap<Double, List<Sensor>> sensorMap = new TreeMap<>();
680 for (double d : this.sensors.keySet())
681 {
682 List<Sensor> sensorList = new ArrayList<>(1);
683 for (GTUTypeSensor gs : this.sensors.get(d))
684 {
685 if (gs.getGtuType().equals(gtuType) || gs.getGtuType().equals(GTUType.ALL))
686 {
687 sensorList.add(gs.getSensor());
688 }
689 }
690 if (sensorList.size() > 0)
691 {
692 sensorMap.put(d, sensorList);
693 }
694 }
695 return sensorMap;
696 }
697
698
699
700
701
702
703
704
705
706 public final void scheduleSensorTriggers(final LaneBasedGTU gtu, final double referenceStartSI,
707 final double referenceMoveSI) throws NetworkException, SimRuntimeException
708 {
709 for (List<Sensor> sensorList : getSensorMap(gtu.getGTUType()).values())
710 {
711 for (Sensor sensor : sensorList)
712 {
713 for (RelativePosition relativePosition : gtu.getRelativePositions().values())
714 {
715
716
717 if (sensor.getPositionType().equals(relativePosition.getType())
718 && referenceStartSI + relativePosition.getDx().getSI() <= sensor.getLongitudinalPosition().si
719 && referenceStartSI + referenceMoveSI
720 + relativePosition.getDx().getSI() > sensor.getLongitudinalPosition().si)
721 {
722
723
724
725 double d = sensor.getLongitudinalPosition().si - referenceStartSI - relativePosition.getDx().getSI();
726 if (d < 0)
727 {
728 throw new NetworkException("scheduleTriggers for gtu: " + gtu + ", d<0 d=" + d);
729 }
730
731 OperationalPlan oPlan = gtu.getOperationalPlan();
732 Time triggerTime = oPlan.timeAtDistance(new Length(d, LengthUnit.METER));
733 if (triggerTime.gt(oPlan.getEndTime()))
734 {
735 System.err.println("Time=" + gtu.getSimulator().getSimulatorTime().getTime().getSI()
736 + " - Scheduling trigger at " + triggerTime.getSI() + "s. > " + oPlan.getEndTime().getSI()
737 + "s. (nextEvalTime) for sensor " + sensor + " , gtu " + gtu);
738 System.err.println(" v=" + gtu.getSpeed() + ", a=" + gtu.getAcceleration() + ", lane=" + toString()
739 + ", refStartSI=" + referenceStartSI + ", moveSI=" + referenceMoveSI);
740 triggerTime =
741 new Time(oPlan.getEndTime().getSI() - Math.ulp(oPlan.getEndTime().getSI()), TimeUnit.SI);
742
743
744 }
745
746
747
748 SimEvent<OTSSimTimeDouble> event = new SimEvent<OTSSimTimeDouble>(new OTSSimTimeDouble(triggerTime),
749 this, sensor, "trigger", new Object[] { gtu });
750 gtu.getSimulator().scheduleEvent(event);
751 gtu.addTrigger(this, event);
752 }
753 }
754 }
755 }
756 }
757
758
759
760
761
762
763 public final void addLaneBasedObject(final LaneBasedObject laneBasedObject) throws NetworkException
764 {
765 double position = laneBasedObject.getLongitudinalPosition().si;
766 if (position < 0 || position > getLength().getSI())
767 {
768 throw new NetworkException(
769 "Illegal position for laneBasedObject " + position + " valid range is 0.." + getLength().getSI());
770 }
771 List<LaneBasedObject> laneBasedObjectList = this.laneBasedObjects.get(position);
772 if (null == laneBasedObjectList)
773 {
774 laneBasedObjectList = new ArrayList<LaneBasedObject>(1);
775 this.laneBasedObjects.put(position, laneBasedObjectList);
776 }
777 laneBasedObjectList.add(laneBasedObject);
778 fireEvent(Lane.OBJECT_ADD_EVENT, new Object[] { laneBasedObject });
779 }
780
781
782
783
784
785
786 public final void removeLaneBasedObject(final LaneBasedObject laneBasedObject) throws NetworkException
787 {
788 fireEvent(Lane.OBJECT_REMOVE_EVENT, new Object[] { laneBasedObject });
789 List<LaneBasedObject> laneBasedObjectList =
790 this.laneBasedObjects.get(laneBasedObject.getLongitudinalPosition().getSI());
791 if (null == laneBasedObjectList)
792 {
793 throw new NetworkException("No laneBasedObject at " + laneBasedObject.getLongitudinalPosition().si);
794 }
795 laneBasedObjectList.remove(laneBasedObject);
796 if (laneBasedObjectList.isEmpty())
797 {
798 this.laneBasedObjects.remove(laneBasedObject.getLongitudinalPosition().doubleValue());
799 }
800 }
801
802
803
804
805
806
807
808
809 public final List<LaneBasedObject> getLaneBasedObjects(final Length minimumPosition, final Length maximumPosition)
810 {
811 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
812 for (List<LaneBasedObject> lbol : this.laneBasedObjects.values())
813 {
814 for (LaneBasedObject lbo : lbol)
815 {
816 if (lbo.getLongitudinalPosition().gt(minimumPosition) && lbo.getLongitudinalPosition().le(maximumPosition))
817 {
818 laneBasedObjectList.add(lbo);
819 }
820 }
821 }
822 return laneBasedObjectList;
823 }
824
825
826
827
828
829 public final List<LaneBasedObject> getLaneBasedObjects()
830 {
831 if (this.laneBasedObjects == null)
832 {
833 return new ArrayList<>();
834 }
835 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
836 for (List<LaneBasedObject> lbol : this.laneBasedObjects.values())
837 {
838 for (LaneBasedObject lbo : lbol)
839 {
840 laneBasedObjectList.add(lbo);
841 }
842 }
843 return laneBasedObjectList;
844 }
845
846
847
848
849
850 public final SortedMap<Double, List<LaneBasedObject>> getLaneBasedObjectMap()
851 {
852 SortedMap<Double, List<LaneBasedObject>> laneBasedObjectMap = new TreeMap<>();
853 for (double d : this.laneBasedObjects.keySet())
854 {
855 List<LaneBasedObject> laneBasedObjectList = new ArrayList<>(1);
856 for (LaneBasedObject lbo : this.laneBasedObjects.get(d))
857 {
858 laneBasedObjectList.add(lbo);
859 }
860 laneBasedObjectMap.put(d, laneBasedObjectList);
861 }
862 return laneBasedObjectMap;
863 }
864
865
866
867
868
869
870 public final Length position(final double fraction)
871 {
872 if (this.length.getUnit().isBaseSIUnit())
873 {
874 return new Length(this.length.si * fraction, LengthUnit.SI);
875 }
876 return new Length(this.length.getInUnit() * fraction, this.length.getUnit());
877 }
878
879
880
881
882
883
884 public final double positionSI(final double fraction)
885 {
886 return this.length.si * fraction;
887 }
888
889
890
891
892
893
894 public final double fraction(final Length position)
895 {
896 return position.si / this.length.si;
897 }
898
899
900
901
902
903
904 public final double fractionSI(final double positionSI)
905 {
906 return positionSI / this.length.si;
907 }
908
909
910
911
912
913
914
915
916
917 public final int addGTU(final LaneBasedGTU gtu, final double fractionalPosition) throws GTUException
918 {
919
920 int index;
921 for (index = 0; index < this.gtuList.size(); index++)
922 {
923 LaneBasedGTU otherGTU = this.gtuList.get(index);
924 if (gtu == otherGTU)
925 {
926 throw new GTUException(gtu + " already registered on Lane " + this + " [registered lanes: "
927 + gtu.positions(gtu.getFront()).keySet() + "] locations: " + gtu.positions(gtu.getFront()).values()
928 + " time: " + gtu.getSimulator().getSimulatorTime().getTime());
929 }
930 if (otherGTU.fractionalPosition(this, otherGTU.getFront()) >= fractionalPosition)
931 {
932 break;
933 }
934 }
935 this.gtuList.add(index, gtu);
936 fireTimedEvent(Lane.GTU_ADD_EVENT, new Object[] { gtu.getId(), gtu, this.gtuList.size() },
937 gtu.getSimulator().getSimulatorTime());
938 getParentLink().addGTU(gtu);
939 return index;
940 }
941
942
943
944
945
946
947
948
949
950 public final int addGTU(final LaneBasedGTU gtu, final Length longitudinalPosition) throws GTUException
951 {
952 return addGTU(gtu, longitudinalPosition.getSI() / getLength().getSI());
953 }
954
955
956
957
958
959
960 public final void removeGTU(final LaneBasedGTU gtu, final boolean removeFromParentLink)
961 {
962 this.gtuList.remove(gtu);
963 fireTimedEvent(Lane.GTU_REMOVE_EVENT, new Object[] { gtu.getId(), gtu, this.gtuList.size() },
964 gtu.getSimulator().getSimulatorTime());
965 if (removeFromParentLink)
966 {
967 this.parentLink.removeGTU(gtu);
968 }
969 }
970
971
972
973
974
975
976
977
978
979
980
981
982
983 public final LaneBasedGTU getGtuAhead(final Length position, final GTUDirectionality direction,
984 final RelativePosition.TYPE relativePosition, final Time when) throws GTUException
985 {
986 if (direction.equals(GTUDirectionality.DIR_PLUS))
987 {
988 for (LaneBasedGTU gtu : this.gtuList)
989 {
990 if (gtu.position(this, gtu.getRelativePositions().get(relativePosition), when).gt(position))
991 {
992 return gtu;
993 }
994 }
995 }
996 else
997 {
998 for (int i = this.gtuList.size() - 1; i >= 0; i--)
999 {
1000 LaneBasedGTU gtu = this.gtuList.get(i);
1001 if (gtu.position(this, gtu.getRelativePositions().get(relativePosition), when).lt(position))
1002 {
1003 return gtu;
1004 }
1005 }
1006 }
1007 return null;
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 public final List<LaneBasedObject> getObjectAhead(final Length position, final GTUDirectionality direction)
1021 {
1022 if (direction.equals(GTUDirectionality.DIR_PLUS))
1023 {
1024 for (double distance : this.laneBasedObjects.keySet())
1025 {
1026 if (distance > position.si)
1027 {
1028 return new ArrayList<>(this.laneBasedObjects.get(distance));
1029 }
1030 }
1031 }
1032 else
1033 {
1034 NavigableMap<Double, List<LaneBasedObject>> reverseLBO =
1035 (NavigableMap<Double, List<LaneBasedObject>>) this.laneBasedObjects;
1036 for (double distance : reverseLBO.descendingKeySet())
1037 {
1038 if (distance < position.si)
1039 {
1040 return new ArrayList<>(this.laneBasedObjects.get(distance));
1041 }
1042 }
1043 }
1044 return null;
1045 }
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 public final LaneBasedGTU getGtuBehind(final Length position, final GTUDirectionality direction,
1060 final RelativePosition.TYPE relativePosition, final Time when) throws GTUException
1061 {
1062 if (direction.equals(GTUDirectionality.DIR_PLUS))
1063 {
1064 return getGtuAhead(position, GTUDirectionality.DIR_MINUS, relativePosition, when);
1065 }
1066 return getGtuAhead(position, direction, relativePosition, when);
1067 }
1068
1069
1070
1071
1072
1073
1074
1075 public static final Length MARGIN = new Length(0.5, LengthUnit.METER);
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090 public final Map<Lane, GTUDirectionality> nextLanes(final GTUType gtuType)
1091 {
1092 if (this.nextLanes == null)
1093 {
1094 this.nextLanes = new LinkedHashMap<>(1);
1095 }
1096 if (!this.nextLanes.containsKey(gtuType))
1097 {
1098 Map<Lane, GTUDirectionality> laneMap = new LinkedHashMap<>(1);
1099 this.nextLanes.put(gtuType, laneMap);
1100
1101 for (Link link : getParentLink().getEndNode().getLinks())
1102 {
1103 if (!(link.equals(this.getParentLink())) && link instanceof CrossSectionLink)
1104 {
1105 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
1106 {
1107 if (cse instanceof Lane)
1108 {
1109 Lane lane = (Lane) cse;
1110 Length df = this.getCenterLine().getLast().distance(lane.getCenterLine().getFirst());
1111 Length dl = this.getCenterLine().getLast().distance(lane.getCenterLine().getLast());
1112
1113 if (df.lt(MARGIN) && df.lt(dl) && link.getStartNode().equals(getParentLink().getEndNode()))
1114 {
1115
1116
1117 if (lane.getDirectionality(gtuType).isForwardOrBoth())
1118 {
1119 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1120 }
1121 else if (lane.getDirectionality(gtuType).isBackwardOrBoth())
1122 {
1123 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1124 }
1125 }
1126
1127 else if (dl.lt(MARGIN) && dl.lt(df) && link.getEndNode().equals(getParentLink().getEndNode()))
1128 {
1129
1130
1131 if (lane.getDirectionality(gtuType).isForwardOrBoth())
1132 {
1133 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1134 }
1135 else if (lane.getDirectionality(gtuType).isBackwardOrBoth())
1136 {
1137 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1138 }
1139 }
1140 }
1141 }
1142 }
1143 }
1144 }
1145 return this.nextLanes.get(gtuType);
1146 }
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162 public final Map<Lane, GTUDirectionality> prevLanes(final GTUType gtuType)
1163 {
1164 if (this.prevLanes == null)
1165 {
1166 this.prevLanes = new LinkedHashMap<>(1);
1167 }
1168 if (!this.prevLanes.containsKey(gtuType))
1169 {
1170 Map<Lane, GTUDirectionality> laneMap = new LinkedHashMap<>(1);
1171 this.prevLanes.put(gtuType, laneMap);
1172
1173 for (Link link : getParentLink().getStartNode().getLinks())
1174 {
1175 if (!(link.equals(this.getParentLink())) && link instanceof CrossSectionLink)
1176 {
1177 for (CrossSectionElement cse : ((CrossSectionLink) link).getCrossSectionElementList())
1178 {
1179 if (cse instanceof Lane)
1180 {
1181 Lane lane = (Lane) cse;
1182 Length df = this.getCenterLine().getFirst().distance(lane.getCenterLine().getFirst());
1183 Length dl = this.getCenterLine().getFirst().distance(lane.getCenterLine().getLast());
1184
1185 if (df.lt(MARGIN) && df.lt(dl) && link.getStartNode().equals(getParentLink().getStartNode()))
1186 {
1187
1188
1189 if (lane.getDirectionality(gtuType).isForwardOrBoth())
1190 {
1191 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1192 }
1193 else if (lane.getDirectionality(gtuType).isBackwardOrBoth())
1194 {
1195 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1196 }
1197 }
1198
1199 else if (dl.lt(MARGIN) && dl.lt(df) && link.getEndNode().equals(getParentLink().getStartNode()))
1200 {
1201
1202
1203 if (lane.getDirectionality(gtuType).isForwardOrBoth())
1204 {
1205 laneMap.put(lane, GTUDirectionality.DIR_PLUS);
1206 }
1207 else if (lane.getDirectionality(gtuType).isBackwardOrBoth())
1208 {
1209 laneMap.put(lane, GTUDirectionality.DIR_MINUS);
1210 }
1211 }
1212 }
1213 }
1214 }
1215 }
1216 }
1217 return this.prevLanes.get(gtuType);
1218 }
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233 public final Set<Lane> accessibleAdjacentLanes(final LateralDirectionality lateralDirection, final GTUType gtuType)
1234 {
1235 Set<Lane> candidates = new LinkedHashSet<>(1);
1236 LateralDirectionality dir = this.getDirectionality(gtuType).isForwardOrBoth() ? lateralDirection
1237 : lateralDirection.isLeft() ? LateralDirectionality.RIGHT : LateralDirectionality.LEFT;
1238 for (Lane lane : neighbors(dir, gtuType))
1239 {
1240 if (lane.getDirectionality(gtuType).equals(LongitudinalDirectionality.DIR_BOTH)
1241 || lane.getDirectionality(gtuType).equals(this.getDirectionality(gtuType)))
1242 {
1243 candidates.add(lane);
1244 }
1245 }
1246 return candidates;
1247 }
1248
1249
1250
1251
1252
1253
1254
1255
1256 public final Speed getSpeedLimit(final GTUType gtuType) throws NetworkException
1257 {
1258 if (this.speedLimitMap.containsKey(gtuType))
1259 {
1260 return this.speedLimitMap.get(gtuType);
1261 }
1262 if (this.speedLimitMap.containsKey(GTUType.ALL))
1263 {
1264 return this.speedLimitMap.get(GTUType.ALL);
1265 }
1266 throw new NetworkException("No speed limit set for GTUType " + gtuType + " on lane " + toString());
1267 }
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 public final void setSpeedLimit(final GTUType gtuType, final Speed speedLimit)
1284 {
1285 this.speedLimitMap.put(gtuType, speedLimit);
1286 }
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296 public final void removeSpeedLimit(final GTUType gtuType)
1297 {
1298 this.speedLimitMap.remove(gtuType);
1299 }
1300
1301
1302
1303
1304 public final LaneType getLaneType()
1305 {
1306 return this.laneType;
1307 }
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326 public final LongitudinalDirectionality getDirectionality(final GTUType gtuType)
1327 {
1328 if (this.directionalityMap.containsKey(gtuType))
1329 {
1330 return this.directionalityMap.get(gtuType);
1331 }
1332 if (this.directionalityMap.containsKey(GTUType.ALL))
1333 {
1334 return this.directionalityMap.get(GTUType.ALL);
1335 }
1336 return LongitudinalDirectionality.DIR_NONE;
1337 }
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358 public void addDirectionality(final GTUType gtuType, final LongitudinalDirectionality directionality)
1359 throws NetworkException
1360 {
1361 this.directionalityMap.put(gtuType, directionality);
1362 checkDirectionality();
1363 }
1364
1365
1366
1367
1368
1369
1370
1371 public void removeDirectionality(final GTUType gtuType)
1372 {
1373 this.directionalityMap.remove(gtuType);
1374 }
1375
1376
1377
1378
1379
1380
1381
1382 private void checkDirectionality() throws NetworkException
1383 {
1384 for (GTUType gtuType : this.directionalityMap.keySet())
1385 {
1386 LongitudinalDirectionality directionality = this.directionalityMap.get(gtuType);
1387 if (!getParentLink().getDirectionality(gtuType).contains(directionality))
1388 {
1389 throw new NetworkException("Lane " + toString() + " allows " + gtuType + " a directionality of "
1390 + directionality + " which is not present in the overarching link " + getParentLink().toString());
1391 }
1392 }
1393 }
1394
1395
1396
1397
1398 public final List<LaneBasedGTU> getGtuList()
1399 {
1400 return this.gtuList == null ? new ArrayList<>() : this.gtuList;
1401 }
1402
1403
1404 @Override
1405 @SuppressWarnings("checkstyle:designforextension")
1406 protected double getZ()
1407 {
1408 return 0.0;
1409 }
1410
1411
1412
1413
1414 public final OvertakingConditions getOvertakingConditions()
1415 {
1416 return this.overtakingConditions;
1417 }
1418
1419
1420 public final String toString()
1421 {
1422 CrossSectionLink link = getParentLink();
1423 return String.format("Lane %s of %s", getId(), link.getId());
1424 }
1425
1426
1427 private Integer cachedHashCode = null;
1428
1429
1430 @SuppressWarnings("checkstyle:designforextension")
1431 @Override
1432 public int hashCode()
1433 {
1434 if (this.cachedHashCode == null)
1435 {
1436 final int prime = 31;
1437 int result = super.hashCode();
1438 result = prime * result + ((this.laneType == null) ? 0 : this.laneType.hashCode());
1439 this.cachedHashCode = result;
1440 }
1441 return this.cachedHashCode;
1442 }
1443
1444
1445 @SuppressWarnings({ "checkstyle:designforextension", "checkstyle:needbraces" })
1446 @Override
1447 public boolean equals(final Object obj)
1448 {
1449 if (this == obj)
1450 return true;
1451 if (!super.equals(obj))
1452 return false;
1453 if (getClass() != obj.getClass())
1454 return false;
1455 Lane other = (Lane) obj;
1456 if (this.laneType == null)
1457 {
1458 if (other.laneType != null)
1459 return false;
1460 }
1461 else if (!this.laneType.equals(other.laneType))
1462 return false;
1463 return true;
1464 }
1465
1466
1467 @Override
1468 @SuppressWarnings("checkstyle:designforextension")
1469 public Lane clone(final CrossSectionLink newParentLink, final OTSSimulatorInterface newSimulator, final boolean animation)
1470 throws NetworkException
1471 {
1472 try
1473 {
1474 Lane newLane = new Lane(newParentLink, newSimulator, animation, this);
1475
1476
1477 SortedMap<Double, List<GTUTypeSensor>> newSensorMap = new TreeMap<>();
1478 for (double distance : this.sensors.keySet())
1479 {
1480 List<GTUTypeSensor> newSensorList = new ArrayList<>();
1481 for (GTUTypeSensor gtuTypeSensor : this.sensors.get(distance))
1482 {
1483 AbstractSensor sensor = (AbstractSensor) gtuTypeSensor.getSensor();
1484 GTUTypeSensor newSensor =
1485 new GTUTypeSensor(gtuTypeSensor.getGtuType(), sensor.clone(newLane, newSimulator, animation));
1486 newSensorList.add(newSensor);
1487 }
1488 newSensorMap.put(distance, newSensorList);
1489 }
1490 newLane.sensors.clear();
1491 newLane.sensors.putAll(newSensorMap);
1492
1493 SortedMap<Double, List<LaneBasedObject>> newLaneBasedObjectMap = new TreeMap<>();
1494 for (double distance : this.laneBasedObjects.keySet())
1495 {
1496 List<LaneBasedObject> newLaneBasedObjectList = new ArrayList<>();
1497 for (LaneBasedObject lbo : this.laneBasedObjects.get(distance))
1498 {
1499 AbstractLaneBasedObject laneBasedObject = (AbstractLaneBasedObject) lbo;
1500 LaneBasedObject newLbo = laneBasedObject.clone(newLane, newSimulator, animation);
1501 newLaneBasedObjectList.add(newLbo);
1502 }
1503 newLaneBasedObjectMap.put(distance, newLaneBasedObjectList);
1504 }
1505 newLane.laneBasedObjects.clear();
1506 newLane.laneBasedObjects.putAll(newLaneBasedObjectMap);
1507
1508 if (animation)
1509 {
1510 new LaneAnimation(newLane, newSimulator, Color.DARK_GRAY, false);
1511 }
1512 return newLane;
1513 }
1514 catch (NamingException | RemoteException exception)
1515 {
1516 throw new NetworkException(exception);
1517 }
1518 }
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532 private class GTUTypeSensor implements Serializable
1533 {
1534
1535 private static final long serialVersionUID = 20150828L;
1536
1537
1538 private final GTUType gtuType;
1539
1540
1541 private final Sensor sensor;
1542
1543
1544
1545
1546
1547 public GTUTypeSensor(final GTUType gtuType, final Sensor sensor)
1548 {
1549 this.gtuType = gtuType;
1550 this.sensor = sensor;
1551 }
1552
1553
1554
1555
1556 public final GTUType getGtuType()
1557 {
1558 return this.gtuType;
1559 }
1560
1561
1562
1563
1564 public final Sensor getSensor()
1565 {
1566 return this.sensor;
1567 }
1568
1569
1570 @Override
1571 public final String toString()
1572 {
1573 return "GTUTypeSensor [gtuType=" + this.gtuType + ", sensor=" + this.sensor + "]";
1574 }
1575
1576 }
1577
1578 }