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 @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.getSourceId();
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 conf1.init();
481 Conflict/network/lane/conflict/Conflict.html#Conflict">Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
482 simulator, gtuType2, permitted, cloneLock);
483 conf2.init();
484 conf1.otherConflict = conf2;
485 conf2.otherConflict = conf1;
486 }
487
488
489 @Override
490 public String toString()
491 {
492 return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
493 }
494
495
496
497
498 private Conflict otherClone;
499
500
501 @Override
502 public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
503 throws NetworkException
504 {
505 Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
506 Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
507 "simulator should be a DEVSSimulator");
508 Conflictad/network/lane/conflict/Conflict.html#Conflict">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 ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
561 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
562 {
563 super(conflict.getId() + "End", lane, direction, longitudinalPosition,
564 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
565 this.conflict = conflict;
566 }
567
568
569
570
571 public final Conflict getConflict()
572 {
573 return this.conflict;
574 }
575
576
577 @Override
578 public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
579 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
580 {
581
582 return null;
583 }
584
585
586 @Override
587 public final String toString()
588 {
589 return "ConflictEnd [conflict=" + this.conflict + "]";
590 }
591 }
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611 private class ConflictGtu extends HeadwayGTUReal
612 {
613
614 private static final long serialVersionUID = 20180221L;
615
616
617 private final LaneBasedGTU gtu;
618
619
620
621
622
623
624
625
626
627 ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
628 throws GTUException
629 {
630 super(gtu, overlapFront, overlap, overlapRear, true);
631 this.gtu = gtu;
632 }
633
634
635
636
637
638
639
640 ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
641 {
642 super(gtu, distance, true);
643 this.gtu = gtu;
644 }
645 }
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660 private class ConflictGtuType implements HeadwayGtuType
661 {
662
663 ConflictGtuType()
664 {
665
666 }
667
668
669 @Override
670 public ConflictGtu createHeadwayGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
671 final Length distance, final boolean downstream) throws GTUException
672 {
673 return new ConflictGtu(perceivedGtu, distance);
674 }
675
676
677 @Override
678 public HeadwayGTU createDownstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
679 final Length distance) throws GTUException, ParameterException
680 {
681 return new ConflictGtu(perceivedGtu, distance);
682 }
683
684
685 @Override
686 public HeadwayGTU createUpstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
687 final Length distance) throws GTUException, ParameterException
688 {
689 return new ConflictGtu(perceivedGtu, distance);
690 }
691
692
693 @Override
694 public ConflictGtu createParallelGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
695 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
696 {
697 throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
698 }
699 }
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715 private class OverlapHeadway implements HeadwayGtuType
716 {
717
718 private HeadwayGtuType wrappedType;
719
720
721
722
723
724 OverlapHeadway(final HeadwayGtuType wrappedType)
725 {
726 this.wrappedType = wrappedType;
727 }
728
729
730 @Override
731 public HeadwayGTU createHeadwayGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
732 final boolean downstream) throws GTUException, ParameterException
733 {
734 if (dist.ge(getLength()))
735 {
736
737 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
738 }
739 else
740 {
741 Length overlapRear = dist;
742 Length overlap = getLength();
743 @SuppressWarnings("synthetic-access")
744 Lane lane = downstream ? Conflict.this.downstreamLanes.get(perceivedGtu)
745 : Conflict.this.upstreamLanes.get(perceivedGtu);
746 Length overlapFront = dist.plus(perceivedGtu.getProjectedLength(lane)).minus(getLength());
747 if (overlapFront.lt0())
748 {
749 overlap = overlap.plus(overlapFront);
750 }
751 if (overlapRear.gt0())
752 {
753 overlap = overlap.minus(overlapRear);
754 }
755 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
756 }
757 }
758
759
760 @Override
761 public HeadwayGTU createDownstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
762 final Length distance) throws GTUException, ParameterException
763 {
764 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
765 }
766
767
768 @Override
769 public HeadwayGTU createUpstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
770 final Length distance) throws GTUException, ParameterException
771 {
772 throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
773 }
774
775
776 @Override
777 public HeadwayGTU createParallelGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
778 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
779 {
780 return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
781 }
782 }
783
784
785
786
787
788
789
790
791
792
793
794
795
796 private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
797 {
798
799 private final HeadwayGtuType headwayGtuType;
800
801
802 private final Length visibility;
803
804
805 private final boolean downstream;
806
807
808 private final Iterator<HeadwayGTU> baseIterator;
809
810
811
812
813
814
815
816
817 ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
818 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
819 {
820 super(perceivingGtu);
821 this.headwayGtuType = headwayGtuType;
822 this.visibility = visibility;
823 this.downstream = downstream;
824 this.baseIterator = base.iterator();
825 }
826
827
828 @Override
829 protected Iterator<PrimaryIteratorEntry> primaryIterator()
830 {
831
832
833
834 class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
835 {
836
837 private PrimaryIteratorEntry next;
838
839
840 @SuppressWarnings("synthetic-access")
841 @Override
842 public boolean hasNext()
843 {
844 if (this.next == null)
845 {
846 if (ConflictGtuIterable.this.baseIterator.hasNext())
847 {
848
849 ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
850 if (gtu.gtu.getId().equals(getGtu().getId()))
851 {
852 if (ConflictGtuIterable.this.baseIterator.hasNext())
853 {
854 gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
855 }
856 else
857 {
858 return false;
859 }
860 }
861 if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
862 {
863 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
864 }
865 }
866 }
867 return this.next != null;
868 }
869
870
871 @Override
872 public PrimaryIteratorEntry next()
873 {
874 if (hasNext())
875 {
876 PrimaryIteratorEntry out = this.next;
877 this.next = null;
878 return out;
879 }
880 throw new NoSuchElementException();
881 }
882 }
883 return new ConflictGtuIterator();
884 }
885
886
887 @Override
888 protected HeadwayGTU perceive(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
889 throws GTUException, ParameterException
890 {
891 return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
892 }
893 }
894
895 }