1 package org.opentrafficsim.road.network.lane.conflict;
2
3 import java.rmi.RemoteException;
4 import java.util.Iterator;
5 import java.util.LinkedHashMap;
6 import java.util.LinkedHashSet;
7 import java.util.Map;
8 import java.util.NoSuchElementException;
9 import java.util.Set;
10 import java.util.UUID;
11
12 import org.djunits.value.vdouble.scalar.Length;
13 import org.djunits.value.vdouble.scalar.Time;
14 import org.djutils.event.EventInterface;
15 import org.djutils.event.EventListenerInterface;
16 import org.djutils.exceptions.Throw;
17 import org.djutils.exceptions.Try;
18 import org.opentrafficsim.base.parameters.ParameterException;
19 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
20 import org.opentrafficsim.core.geometry.OTSGeometryException;
21 import org.opentrafficsim.core.geometry.OTSLine3D;
22 import org.opentrafficsim.core.geometry.OTSPoint3D;
23 import org.opentrafficsim.core.gtu.GTUDirectionality;
24 import org.opentrafficsim.core.gtu.GTUException;
25 import org.opentrafficsim.core.gtu.GTUType;
26 import org.opentrafficsim.core.gtu.RelativePosition;
27 import org.opentrafficsim.core.network.LongitudinalDirectionality;
28 import org.opentrafficsim.core.network.NetworkException;
29 import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
30 import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionIterable;
31 import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionReiterable;
32 import org.opentrafficsim.road.gtu.lane.perception.DownstreamNeighborsIterable;
33 import org.opentrafficsim.road.gtu.lane.perception.LaneBasedObjectIterable;
34 import org.opentrafficsim.road.gtu.lane.perception.LaneDirectionRecord;
35 import org.opentrafficsim.road.gtu.lane.perception.LaneRecord;
36 import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
37 import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
38 import org.opentrafficsim.road.gtu.lane.perception.UpstreamNeighborsIterable;
39 import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
40 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
41 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUReal;
42 import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayTrafficLight;
43 import org.opentrafficsim.road.network.lane.CrossSectionElement;
44 import org.opentrafficsim.road.network.lane.Lane;
45 import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
46 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public final class Conflict extends AbstractLaneBasedObject implements EventListenerInterface
67 {
68
69
70 private static final long serialVersionUID = 20160915L;
71
72
73 private final ConflictType conflictType;
74
75
76 private final ConflictRule conflictRule;
77
78
79 private Conflict otherConflict;
80
81
82 private final Length length;
83
84
85 private final GTUDirectionality direction;
86
87
88 private final OTSSimulatorInterface simulator;
89
90
91 private final GTUType gtuType;
92
93
94 private final boolean permitted;
95
96
97 private Length trafficLightDistance;
98
99
100 private Length maxMaxTrafficLightDistance;
101
102
103 private final Object cloneLock;
104
105
106
107
108
109
110 private final LaneDirectionRecord root;
111
112
113 private final Length rootPosition;
114
115
116 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> upstreamGtus;
117
118
119 private Time upstreamTime;
120
121
122 private Map<LaneBasedGTU, Lane> upstreamLanes;
123
124
125 private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> downstreamGtus;
126
127
128 private Time downstreamTime;
129
130
131 private Map<LaneBasedGTU, Lane> downstreamLanes;
132
133
134 private final HeadwayGtuType conflictGtuType = new ConflictGtuType();
135
136
137 private Length maxUpstreamVisibility = Length.ZERO;
138
139
140 private Length maxDownstreamVisibility = Length.ZERO;
141
142
143 private Set<LaneBasedGTU> upstreamListening = new LinkedHashSet<>();
144
145
146 private Set<LaneBasedGTU> downstreamListening = new LinkedHashSet<>();
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 @SuppressWarnings("checkstyle:parameternumber")
166 private Conflict(final Lane lane, final Length longitudinalPosition, final Length length, final GTUDirectionality direction,
167 final OTSLine3D geometry, final ConflictType conflictType, final ConflictRule conflictRule,
168 final OTSSimulatorInterface simulator, final GTUType gtuType, final boolean permitted, final Object cloneLock)
169 throws NetworkException
170 {
171 super(UUID.randomUUID().toString(), lane, Throw.whenNull(direction, "Direction may not be null.").isPlus()
172 ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS, longitudinalPosition, geometry);
173 this.length = length;
174 this.direction = direction;
175 this.conflictType = conflictType;
176 this.conflictRule = conflictRule;
177 this.simulator = simulator;
178 this.gtuType = gtuType;
179 this.permitted = permitted;
180 this.cloneLock = cloneLock;
181
182
183 if (conflictType.equals(ConflictType.SPLIT) || conflictType.equals(ConflictType.MERGE))
184 {
185 Length position =
186 conflictType.equals(ConflictType.SPLIT) ? (direction.isPlus() ? length : lane.getLength().minus(length))
187 : (direction.isPlus() ? lane.getLength() : Length.ZERO);
188 try
189 {
190 new ConflictEnd(this, lane,
191 direction.isPlus() ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS,
192 position);
193 }
194 catch (OTSGeometryException exception)
195 {
196
197 throw new RuntimeException("Could not create dummy geometry for ConflictEnd.", exception);
198 }
199 }
200
201
202 this.rootPosition = direction.isPlus() ? longitudinalPosition : lane.getLength().minus(longitudinalPosition);
203 this.root = new LaneDirectionRecord(lane, direction, this.rootPosition.neg(), gtuType);
204 }
205
206
207
208
209
210 private void provideUpstreamVisibility(final Length visibility)
211 {
212 if (visibility.gt(this.maxUpstreamVisibility))
213 {
214 this.maxUpstreamVisibility = visibility;
215 this.upstreamTime = null;
216 this.downstreamTime = null;
217 }
218 }
219
220
221
222
223
224 private void provideDownstreamVisibility(final Length visibility)
225 {
226 if (visibility.gt(this.maxDownstreamVisibility))
227 {
228 this.maxDownstreamVisibility = visibility;
229 this.upstreamTime = null;
230 this.downstreamTime = null;
231 }
232 }
233
234
235
236
237
238
239
240
241 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getUpstreamGtus(final LaneBasedGTU perceivingGtu,
242 final HeadwayGtuType headwayGtuType, final Length visibility)
243 {
244 provideUpstreamVisibility(visibility);
245 Time time = this.getLane().getParentLink().getSimulator().getSimulatorAbsTime();
246 if (this.upstreamTime == null || !time.eq(this.upstreamTime))
247 {
248 for (LaneBasedGTU gtu : this.upstreamListening)
249 {
250 Try.execute(() -> gtu.removeListener(this, LaneBasedGTU.LANE_CHANGE_EVENT), "Unable to unlisten to GTU %s.",
251 gtu);
252 }
253 this.upstreamListening.clear();
254
255 this.upstreamGtus = new UpstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition,
256 this.maxUpstreamVisibility, RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT)
257 {
258
259 @SuppressWarnings("synthetic-access")
260 @Override
261 protected AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer>.Entry getNext(
262 final LaneRecord<?> record, final Length position, final Integer counter) throws GTUException
263 {
264 AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer>.Entry entry =
265 super.getNext(record, position, counter);
266 if (entry != null)
267 {
268 Conflict.this.upstreamListening.add(entry.getObject());
269 Try.execute(() -> entry.getObject().addListener(Conflict.this, LaneBasedGTU.LANE_CHANGE_EVENT),
270 "Unable to listen to GTU %s.", entry.getObject());
271 Conflict.this.upstreamLanes.put(entry.getObject(), record.getLane());
272 }
273 return entry;
274 }
275 };
276 this.upstreamTime = time;
277 this.upstreamLanes = new LinkedHashMap<>();
278 }
279
280 return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
281
282 }
283
284
285
286
287
288
289
290
291 public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getDownstreamGtus(final LaneBasedGTU perceivingGtu,
292 final HeadwayGtuType headwayGtuType, final Length visibility)
293 {
294 provideDownstreamVisibility(visibility);
295 Time time = this.getLane().getParentLink().getSimulator().getSimulatorAbsTime();
296 if (this.downstreamTime == null || !time.eq(this.downstreamTime))
297 {
298 for (LaneBasedGTU gtu : this.downstreamListening)
299 {
300 Try.execute(() -> gtu.removeListener(this, LaneBasedGTU.LANE_CHANGE_EVENT), "Unable to unlisten to GTU %s.",
301 gtu);
302 }
303 this.downstreamListening.clear();
304
305 boolean ignoreIfUpstream = false;
306 this.downstreamGtus =
307 new DownstreamNeighborsIterable(null, this.root, this.rootPosition, this.maxDownstreamVisibility,
308 RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT, ignoreIfUpstream)
309 {
310
311 @SuppressWarnings("synthetic-access")
312 @Override
313 protected AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer>.Entry getNext(
314 final LaneRecord<?> record, final Length position, final Integer counter) throws GTUException
315 {
316 AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer>.Entry entry =
317 super.getNext(record, position, counter);
318 if (entry != null)
319 {
320 Conflict.this.downstreamListening.add(entry.getObject());
321 Try.execute(() -> entry.getObject().addListener(Conflict.this, LaneBasedGTU.LANE_CHANGE_EVENT),
322 "Unable to listen to GTU %s.", entry.getObject());
323 Conflict.this.downstreamLanes.put(entry.getObject(), record.getLane());
324 }
325 return entry;
326 }
327 };
328 this.downstreamTime = time;
329 this.downstreamLanes = new LinkedHashMap<>();
330 }
331
332 return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
333 this.downstreamGtus);
334
335 }
336
337
338 @Override
339 public void notify(final EventInterface event) throws RemoteException
340 {
341 LaneBasedGTU gtu = (LaneBasedGTU) event.getSourceId();
342 if (this.upstreamListening.contains(gtu))
343 {
344 this.upstreamTime = null;
345 }
346 if (this.downstreamListening.contains(gtu))
347 {
348 this.downstreamTime = null;
349 }
350 }
351
352
353
354
355 public ConflictType getConflictType()
356 {
357 return this.conflictType;
358 }
359
360
361
362
363 public ConflictRule getConflictRule()
364 {
365 return this.conflictRule;
366 }
367
368
369
370
371 public ConflictPriority conflictPriority()
372 {
373 return this.conflictRule.determinePriority(this);
374 }
375
376
377
378
379 public Length getLength()
380 {
381 return this.length;
382 }
383
384
385
386
387 public Conflict getOtherConflict()
388 {
389 return this.otherConflict;
390 }
391
392
393
394
395 public GTUType getGtuType()
396 {
397 return this.gtuType;
398 }
399
400
401
402
403
404 public boolean isPermitted()
405 {
406 return this.permitted;
407 }
408
409
410
411
412
413
414 public Length getTrafficLightDistance(final Length maxDistance)
415 {
416 if (this.trafficLightDistance == null)
417 {
418 if (this.maxMaxTrafficLightDistance == null || this.maxMaxTrafficLightDistance.lt(maxDistance))
419 {
420 this.maxMaxTrafficLightDistance = maxDistance;
421 boolean downstream = false;
422 LaneBasedObjectIterable<HeadwayTrafficLight,
423 TrafficLight> it = new LaneBasedObjectIterable<HeadwayTrafficLight, TrafficLight>(null,
424 TrafficLight.class, this.root, getLongitudinalPosition(), downstream, maxDistance,
425 RelativePosition.REFERENCE_POSITION, null)
426 {
427
428 @Override
429 protected HeadwayTrafficLight perceive(final LaneBasedGTU perceivingGtu, final TrafficLight object,
430 final Length distance) throws GTUException, ParameterException
431 {
432 return new HeadwayTrafficLight(object, distance);
433 }
434 };
435 if (!it.isEmpty())
436 {
437 this.trafficLightDistance = it.first().getDistance();
438 }
439 }
440 }
441 if (this.trafficLightDistance != null && maxDistance.ge(this.trafficLightDistance))
442 {
443 return this.trafficLightDistance;
444 }
445 return Length.POSITIVE_INFINITY;
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468 @SuppressWarnings("checkstyle:parameternumber")
469 public static void generateConflictPair(final ConflictType conflictType, final ConflictRule conflictRule,
470 final boolean permitted, final Lane lane1, final Length longitudinalPosition1, final Length length1,
471 final GTUDirectionality direction1, final OTSLine3D geometry1, final GTUType gtuType1, final Lane lane2,
472 final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
473 final OTSLine3D geometry2, final GTUType gtuType2, final OTSSimulatorInterface simulator) throws NetworkException
474 {
475
476 Throw.whenNull(conflictType, "Conflict type may not be null.");
477
478 Object cloneLock = new Object();
479 Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule,
480 simulator, gtuType1, permitted, cloneLock);
481 conf1.init();
482 Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
483 simulator, gtuType2, permitted, cloneLock);
484 conf2.init();
485 conf1.otherConflict = conf2;
486 conf2.otherConflict = conf1;
487 }
488
489
490 @Override
491 public String toString()
492 {
493 return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
494 }
495
496
497
498
499 private Conflict otherClone;
500
501
502 @Override
503 public Conflict clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator) throws NetworkException
504 {
505 Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
506 Throw.when(!(newSimulator instanceof OTSSimulatorInterface), NetworkException.class,
507 "simulator should be a DEVSSimulator");
508 Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
509 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
510 this.cloneLock);
511 out.init();
512 synchronized (this.cloneLock)
513 {
514
515 if (this.otherClone == null || this.otherClone.simulator != newSimulator)
516 {
517
518 this.otherConflict.otherClone = out;
519 }
520 else
521 {
522 out.otherConflict = this.otherClone;
523 this.otherClone.otherConflict = out;
524 }
525
526 this.otherClone = null;
527 }
528 return out;
529 }
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 public class ConflictEnd extends AbstractLaneBasedObject
545 {
546
547 private static final long serialVersionUID = 20161214L;
548
549
550 private final Conflict conflict;
551
552
553
554
555
556
557
558
559
560
561 ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
562 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
563 {
564
565 super(conflict.getId() + "End", lane, direction, longitudinalPosition,
566 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
567 this.conflict = conflict;
568 }
569
570
571
572
573 public final Conflict getConflict()
574 {
575 return this.conflict;
576 }
577
578
579 @Override
580 public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator)
581 throws NetworkException
582 {
583
584 return null;
585 }
586
587
588 @Override
589 public final String toString()
590 {
591 return "ConflictEnd [conflict=" + this.conflict + "]";
592 }
593 }
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613 private class ConflictGtu extends HeadwayGTUReal
614 {
615
616 private static final long serialVersionUID = 20180221L;
617
618
619 private final LaneBasedGTU gtu;
620
621
622
623
624
625
626
627
628
629 ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
630 throws GTUException
631 {
632 super(gtu, overlapFront, overlap, overlapRear, true);
633 this.gtu = gtu;
634 }
635
636
637
638
639
640
641
642 ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
643 {
644 super(gtu, distance, true);
645 this.gtu = gtu;
646 }
647 }
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662 private class ConflictGtuType implements HeadwayGtuType
663 {
664
665 ConflictGtuType()
666 {
667
668 }
669
670
671 @Override
672 public ConflictGtu createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
673 final Length distance, final boolean downstream) throws GTUException
674 {
675 return new ConflictGtu(perceivedGtu, distance);
676 }
677
678
679 @Override
680 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
681 final Length distance) throws GTUException, ParameterException
682 {
683 return new ConflictGtu(perceivedGtu, distance);
684 }
685
686
687 @Override
688 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
689 final Length distance) throws GTUException, ParameterException
690 {
691 return new ConflictGtu(perceivedGtu, distance);
692 }
693
694
695 @Override
696 public ConflictGtu createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
697 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
698 {
699 throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
700 }
701 }
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717 private class OverlapHeadway implements HeadwayGtuType
718 {
719
720 private HeadwayGtuType wrappedType;
721
722
723
724
725
726 OverlapHeadway(final HeadwayGtuType wrappedType)
727 {
728 this.wrappedType = wrappedType;
729 }
730
731
732 @Override
733 public HeadwayGTU createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
734 final boolean downstream) throws GTUException, ParameterException
735 {
736 if (dist.ge(getLength()))
737 {
738
739 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
740 }
741 else
742 {
743 Length overlapRear = dist;
744 Length overlap = getLength();
745 @SuppressWarnings("synthetic-access")
746 Lane lane = downstream ? Conflict.this.downstreamLanes.get(perceivedGtu)
747 : Conflict.this.upstreamLanes.get(perceivedGtu);
748 Length overlapFront = dist.plus(perceivedGtu.getProjectedLength(lane)).minus(getLength());
749 if (overlapFront.lt0())
750 {
751 overlap = overlap.plus(overlapFront);
752 }
753 if (overlapRear.gt0())
754 {
755 overlap = overlap.minus(overlapRear);
756 }
757 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
758 }
759 }
760
761
762 @Override
763 public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
764 final Length distance) throws GTUException, ParameterException
765 {
766 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
767 }
768
769
770 @Override
771 public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
772 final Length distance) throws GTUException, ParameterException
773 {
774 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
775 }
776
777
778 @Override
779 public HeadwayGTU createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
780 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
781 {
782 return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
783 }
784 }
785
786
787
788
789
790
791
792
793
794
795
796
797
798 private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
799 {
800
801 private final HeadwayGtuType headwayGtuType;
802
803
804 private final Length visibility;
805
806
807 private final boolean downstream;
808
809
810 private final Iterator<HeadwayGTU> baseIterator;
811
812
813
814
815
816
817
818
819 ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
820 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
821 {
822 super(perceivingGtu);
823 this.headwayGtuType = headwayGtuType;
824 this.visibility = visibility;
825 this.downstream = downstream;
826 this.baseIterator = base.iterator();
827 }
828
829
830 @Override
831 protected Iterator<PrimaryIteratorEntry> primaryIterator()
832 {
833
834
835
836 class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
837 {
838
839 private PrimaryIteratorEntry next;
840
841
842 @SuppressWarnings("synthetic-access")
843 @Override
844 public boolean hasNext()
845 {
846 if (this.next == null)
847 {
848 if (ConflictGtuIterable.this.baseIterator.hasNext())
849 {
850
851 ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
852 if (gtu.gtu.getId().equals(getGtu().getId()))
853 {
854 if (ConflictGtuIterable.this.baseIterator.hasNext())
855 {
856 gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
857 }
858 else
859 {
860 return false;
861 }
862 }
863 if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
864 {
865 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
866 }
867 }
868 }
869 return this.next != null;
870 }
871
872
873 @Override
874 public PrimaryIteratorEntry next()
875 {
876 if (hasNext())
877 {
878 PrimaryIteratorEntry out = this.next;
879 this.next = null;
880 return out;
881 }
882 throw new NoSuchElementException();
883 }
884 }
885 return new ConflictGtuIterator();
886 }
887
888
889 @Override
890 protected HeadwayGTU perceive(final LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
891 throws GTUException, ParameterException
892 {
893 return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
894 }
895 }
896
897 }