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