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