View Javadoc
1   package org.opentrafficsim.road.network.lane.conflict;
2   
3   import java.util.Iterator;
4   import java.util.NoSuchElementException;
5   import java.util.UUID;
6   
7   import org.djunits.value.vdouble.scalar.Length;
8   import org.djunits.value.vdouble.scalar.Time;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.base.parameters.ParameterException;
11  import org.opentrafficsim.core.geometry.OTSGeometryException;
12  import org.opentrafficsim.core.geometry.OTSLine3D;
13  import org.opentrafficsim.core.geometry.OTSPoint3D;
14  import org.opentrafficsim.core.gtu.GTUDirectionality;
15  import org.opentrafficsim.core.gtu.GTUException;
16  import org.opentrafficsim.core.gtu.GTUType;
17  import org.opentrafficsim.core.gtu.RelativePosition;
18  import org.opentrafficsim.core.network.LongitudinalDirectionality;
19  import org.opentrafficsim.core.network.NetworkException;
20  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
21  import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionIterable;
22  import org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionReiterable;
23  import org.opentrafficsim.road.gtu.lane.perception.DownstreamNeighborsIterable;
24  import org.opentrafficsim.road.gtu.lane.perception.LaneDirectionRecord;
25  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
26  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
27  import org.opentrafficsim.road.gtu.lane.perception.UpstreamNeighborsIterable;
28  import org.opentrafficsim.road.gtu.lane.perception.categories.neighbors.HeadwayGtuType;
29  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTU;
30  import org.opentrafficsim.road.gtu.lane.perception.headway.HeadwayGTUReal;
31  import org.opentrafficsim.road.network.lane.CrossSectionElement;
32  import org.opentrafficsim.road.network.lane.Lane;
33  import org.opentrafficsim.road.network.lane.object.AbstractLaneBasedObject;
34  
35  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
36  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
37  
38  /**
39   * Conflicts deal with traffic on different links/roads that need to consider each other as their paths may be in conflict
40   * spatially. A single {@code Conflict} represents the one-sided consideration of a conflicting situation. I.e., what is
41   * considered <i>a single conflict in traffic theory, is represented by two {@code Conflict}s</i>, one on each of the
42   * conflicting {@code Lane}s.<br>
43   * <br>
44   * This class provides easy access to upstream and downstream GTUs through {@code PerceptionIterable}s using methods
45   * {@code getUpstreamGtus} and {@code getDownstreamGtus}. These methods are efficient in that they reuse underlying data
46   * structures if the GTUs are requested at the same time by another GTU.
47   * <p>
48   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
49   * BSD-style license. See <a href="http://opentrafficsim.org/docs/current/license.html">OpenTrafficSim License</a>.
50   * <p>
51   * @version $Revision$, $LastChangedDate$, by $Author$, initial version Sep 7, 2016 <br>
52   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
53   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
54   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
55   */
56  public final class Conflict extends AbstractLaneBasedObject
57  {
58  
59      /** */
60      private static final long serialVersionUID = 20160915L;
61  
62      /** Conflict type, i.e. crossing, merge or split. */
63      private final ConflictType conflictType;
64  
65      /** Conflict rule, i.e. priority, give way, stop or all-stop. */
66      private final ConflictRule conflictRule;
67  
68      /** Accompanying other conflict. */
69      private Conflict otherConflict;
70  
71      /** The length of the conflict along the lane centerline. */
72      private final Length length;
73  
74      /** GTU direction. */
75      private final GTUDirectionality direction;
76  
77      /** Simulator for animation and timed events. */
78      private final SimulatorInterface.TimeDoubleUnit simulator;
79  
80      /** GTU type. */
81      private final GTUType gtuType;
82  
83      /** Whether the conflict is a permitted conflict in traffic light control. */
84      private final boolean permitted;
85  
86      /** Lock object for cloning a pair of conflicts. */
87      private final Object cloneLock;
88  
89      /////////////////////////////////////////////////////////////////
90      // Properties regarding upstream and downstream GTUs provision //
91      /////////////////////////////////////////////////////////////////
92  
93      /** Root for GTU search. */
94      private final LaneDirectionRecord root;
95  
96      /** Position on the root. */
97      private final Length rootPosition;
98  
99      /** Current upstream GTUs provider. */
100     private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> upstreamGtus;
101 
102     /** Upstream GTUs update time. */
103     private Time upstreamTime;
104 
105     /** Current downstream GTUs provider. */
106     private AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> downstreamGtus;
107 
108     /** Downstream GTUs update time. */
109     private Time downstreamTime;
110 
111     /** Headway type for the provided GTUs. */
112     private final HeadwayGtuType conflictGtuType = new ConflictGtuType();
113 
114     /** Distance within which upstreamGTUs are provided (is automatically enlarged). */
115     private Length maxUpstreamVisibility = Length.ZERO;
116 
117     /** Distance within which downstreamGTUs are provided (is automatically enlarged). */
118     private Length maxDownstreamVisibility = Length.ZERO;
119 
120     /////////////////////////////////////////////////////////////////
121 
122     /**
123      * @param lane Lane; lane where this conflict starts
124      * @param longitudinalPosition Length; position of start of conflict on lane
125      * @param length Length; length of the conflict along the lane centerline
126      * @param direction GTUDirectionality; GTU direction
127      * @param geometry OTSLine3D; geometry of conflict
128      * @param conflictRule ConflictRule; conflict rule, i.e. determines priority, give way, stop or all-stop
129      * @param conflictType ConflictType; conflict type, i.e. crossing, merge or split
130      * @param simulator SimulatorInterface.TimeDoubleUnit; the simulator for animation and timed events
131      * @param permitted boolean; whether the conflict is permitted in traffic light control
132      * @param gtuType GTUType; gtu type
133      * @param cloneLock Object; lock object for cloning a pair of conflicts
134      * @throws NetworkException when the position on the lane is out of bounds
135      */
136     @SuppressWarnings("checkstyle:parameternumber")
137     private Conflict(final Lane lane, final Length longitudinalPosition, final Length length, final GTUDirectionality direction,
138             final OTSLine3D geometry, final ConflictType conflictType, final ConflictRule conflictRule,
139             final SimulatorInterface.TimeDoubleUnit simulator, final GTUType gtuType, final boolean permitted,
140             final Object cloneLock) throws NetworkException
141     {
142         super(UUID.randomUUID().toString(), lane, Throw.whenNull(direction, "Direction may not be null.").isPlus()
143                 ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS, longitudinalPosition, geometry);
144         this.length = length;
145         this.direction = direction;
146         this.conflictType = conflictType;
147         this.conflictRule = conflictRule;
148         this.simulator = simulator;
149         this.gtuType = gtuType;
150         this.permitted = permitted;
151         this.cloneLock = cloneLock;
152 
153         // Create conflict end
154         if (conflictType.equals(ConflictType.SPLIT) || conflictType.equals(ConflictType.MERGE))
155         {
156             Length position =
157                     conflictType.equals(ConflictType.SPLIT) ? (direction.isPlus() ? length : lane.getLength().minus(length))
158                             : (direction.isPlus() ? lane.getLength() : Length.ZERO);
159             try
160             {
161                 new ConflictEnd(this, lane,
162                         direction.isPlus() ? LongitudinalDirectionality.DIR_PLUS : LongitudinalDirectionality.DIR_MINUS,
163                         position);
164             }
165             catch (OTSGeometryException exception)
166             {
167                 // does not happen
168                 throw new RuntimeException("Could not create dummy geometry for ConflictEnd.", exception);
169             }
170         }
171 
172         // Lane record for GTU provision
173         this.rootPosition = direction.isPlus() ? longitudinalPosition : lane.getLength().minus(longitudinalPosition);
174         this.root = new LaneDirectionRecord(lane, direction, this.rootPosition.neg(),
175                 lane.getNetwork().getGtuType(GTUType.DEFAULTS.VEHICLE));
176     }
177 
178     /**
179      * Make sure the conflict can provide the given upstream visibility.
180      * @param visibility Length; visibility to guarantee
181      */
182     private void provideUpstreamVisibility(final Length visibility)
183     {
184         if (visibility.gt(this.maxUpstreamVisibility))
185         {
186             this.maxUpstreamVisibility = visibility;
187             this.upstreamTime = null;
188             this.downstreamTime = null;
189         }
190     }
191 
192     /**
193      * Make sure the conflict can provide the given downstream visibility.
194      * @param visibility Length; visibility to guarantee
195      */
196     private void provideDownstreamVisibility(final Length visibility)
197     {
198         if (visibility.gt(this.maxDownstreamVisibility))
199         {
200             this.maxDownstreamVisibility = visibility;
201             this.upstreamTime = null;
202             this.downstreamTime = null;
203         }
204     }
205 
206     /**
207      * Provides the upstream GTUs.
208      * @param perceivingGtu LaneBasedGTU; perceiving GTU
209      * @param headwayGtuType HeadwayGtuType; headway GTU type to use
210      * @param visibility Length; distance over which GTU's are provided
211      * @return PerceptionIterable&lt;HeadwayGtU&gt;; iterable over the upstream GTUs
212      */
213     public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getUpstreamGtus(final LaneBasedGTU perceivingGtu,
214             final HeadwayGtuType headwayGtuType, final Length visibility)
215     {
216         provideUpstreamVisibility(visibility);
217         Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
218         if (this.upstreamTime == null || !time.eq(this.upstreamTime))
219         {
220             // setup a base iterable to provide the GTUs
221             this.upstreamGtus =
222                     new UpstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition, this.maxUpstreamVisibility,
223                             RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT);
224             this.upstreamTime = time;
225         }
226         // return iterable that uses the base iterable
227         return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
228     }
229 
230     /**
231      * Provides the downstream GTUs.
232      * @param perceivingGtu LaneBasedGTU; perceiving GTU
233      * @param headwayGtuType HeadwayGtuType; headway GTU type to use
234      * @param visibility Length; distance over which GTU's are provided
235      * @return PerceptionIterable&lt;HeadwayGtU&gt;; iterable over the downstream GTUs
236      */
237     public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getDownstreamGtus(final LaneBasedGTU perceivingGtu,
238             final HeadwayGtuType headwayGtuType, final Length visibility)
239     {
240         provideDownstreamVisibility(visibility);
241         Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
242         if (this.downstreamTime == null || !time.eq(this.downstreamTime))
243         {
244             // setup a base iterable to provide the GTUs
245             boolean ignoreIfUpstream = false;
246             this.downstreamGtus = new DownstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition,
247                     this.maxDownstreamVisibility, RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT,
248                     ignoreIfUpstream);
249             this.downstreamTime = time;
250         }
251         // return iterable that uses the base iterable
252         return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
253                 this.downstreamGtus);
254     }
255 
256     /**
257      * @return conflictType.
258      */
259     public ConflictType getConflictType()
260     {
261         return this.conflictType;
262     }
263 
264     /**
265      * @return conflictRule.
266      */
267     public ConflictRule getConflictRule()
268     {
269         return this.conflictRule;
270     }
271 
272     /**
273      * @return conflictPriority.
274      */
275     public ConflictPriority conflictPriority()
276     {
277         return this.conflictRule.determinePriority(this);
278     }
279 
280     /**
281      * @return length.
282      */
283     public Length getLength()
284     {
285         return this.length;
286     }
287 
288     /**
289      * @return otherConflict.
290      */
291     public Conflict getOtherConflict()
292     {
293         return this.otherConflict;
294     }
295 
296     /**
297      * @return gtuType.
298      */
299     public GTUType getGtuType()
300     {
301         return this.gtuType;
302     }
303 
304     /**
305      * If permitted, traffic upstream of traffic lights may not be ignored, as these can have green light.
306      * @return permitted.
307      */
308     public boolean isPermitted()
309     {
310         return this.permitted;
311     }
312 
313     /**
314      * Creates a pair of conflicts.
315      * @param conflictType ConflictType; conflict type, i.e. crossing, merge or split
316      * @param conflictRule ConflictRule; conflict rule
317      * @param permitted boolean; whether the conflict is permitted in traffic light control
318      * @param lane1 Lane; lane of conflict 1
319      * @param longitudinalPosition1 Length; longitudinal position of conflict 1
320      * @param length1 Length; {@code Length} of conflict 1
321      * @param direction1 GTUDirectionality; GTU direction of conflict 1
322      * @param geometry1 OTSLine3D; geometry of conflict 1
323      * @param gtuType1 GTUType; gtu type of conflict 1
324      * @param lane2 Lane; lane of conflict 2
325      * @param longitudinalPosition2 Length; longitudinal position of conflict 2
326      * @param length2 Length; {@code Length} of conflict 2
327      * @param direction2 GTUDirectionality; GTU direction of conflict 2
328      * @param geometry2 OTSLine3D; geometry of conflict 2
329      * @param gtuType2 GTUType; gtu type of conflict 2
330      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator for animation and timed events
331      * @throws NetworkException if the combination of conflict type and both conflict rules is not correct
332      */
333     @SuppressWarnings("checkstyle:parameternumber")
334     public static void generateConflictPair(final ConflictType conflictType, final ConflictRule conflictRule,
335             final boolean permitted, final Lane lane1, final Length longitudinalPosition1, final Length length1,
336             final GTUDirectionality direction1, final OTSLine3D geometry1, final GTUType gtuType1, final Lane lane2,
337             final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
338             final OTSLine3D geometry2, final GTUType gtuType2, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
339             throws NetworkException
340     {
341         // lane, longitudinalPosition, length and geometry are checked in AbstractLaneBasedObject
342         Throw.whenNull(conflictType, "Conflict type may not be null.");
343 
344         Object cloneLock = new Object();
345         Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule,
346                 simulator, gtuType1, permitted, cloneLock);
347         Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
348                 simulator, gtuType2, permitted, cloneLock);
349         conf1.otherConflict = conf2;
350         conf2.otherConflict = conf1;
351     }
352 
353     /** {@inheritDoc} */
354     @Override
355     public String toString()
356     {
357         return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
358     }
359 
360     /**
361      * Clone of other conflict.
362      */
363     private Conflict otherClone;
364 
365     /** {@inheritDoc} */
366     @Override
367     public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
368             throws NetworkException
369     {
370         Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
371         Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
372                 "simulator should be a DEVSSimulator");
373         Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
374                 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
375                 this.cloneLock);
376         synchronized (this.cloneLock)
377         {
378             // couple both clones
379             if (this.otherClone == null || this.otherClone.simulator != newSimulator)
380             {
381                 // other clone will do it
382                 this.otherConflict.otherClone = out;
383             }
384             else
385             {
386                 out.otherConflict = this.otherClone;
387                 this.otherClone.otherConflict = out;
388             }
389             // reset successful clone of pair, or remove otherClone from other simulator (or was already null)
390             this.otherClone = null;
391         }
392         return out;
393     }
394 
395     /**
396      * Light-weight lane based object to indicate the end of a conflict. It is used to perceive conflicts when a GTU is on the
397      * conflict area, and hence the conflict lane based object is usptream.
398      * <p>
399      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
400      * <br>
401      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
402      * <p>
403      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 dec. 2016 <br>
404      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
405      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
406      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
407      */
408     public class ConflictEnd extends AbstractLaneBasedObject
409     {
410         /** */
411         private static final long serialVersionUID = 20161214L;
412 
413         /** Conflict. */
414         private final Conflict conflict;
415 
416         /**
417          * @param conflict Conflict; conflict
418          * @param lane Lane; lane
419          * @param direction LongitudinalDirectionality; valid direction
420          * @param longitudinalPosition Length; position
421          * @throws NetworkException on network exception
422          * @throws OTSGeometryException does not happen
423          */
424         ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
425                 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
426         {
427             super(conflict.getId() + "End", lane, direction, longitudinalPosition,
428                     new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
429             this.conflict = conflict;
430         }
431 
432         /**
433          * @return conflict
434          */
435         public final Conflict getConflict()
436         {
437             return this.conflict;
438         }
439 
440         /** {@inheritDoc} */
441         @Override
442         public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
443                 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
444         {
445             // Constructor of Conflict creates these.
446             return null;
447         }
448 
449         /** {@inheritDoc} */
450         @Override
451         public final String toString()
452         {
453             return "ConflictEnd [conflict=" + this.conflict + "]";
454         }
455     }
456 
457     /**
458      * HeadwayGTU that is returned by base iterators for upstream and downstream GTUs. This class is used with both
459      * {@code UpstreamNeighborsIterable} and {@code DownstreamNeighborsIterable} which work with HeadwayGTU. The role of this
460      * class is however to simply provide the GTU itself such that other specific HeadwayGTU types can be created with it.
461      * Therefore, it extends HeadwayGTUReal which simply wraps the GTU. As the HeadwayGTUReal class has the actual GTU hidden,
462      * this class can provide it.
463      * <p>
464      * FIXME: why not create a getter for the gtu in the super class?
465      * <p>
466      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
467      * <br>
468      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
469      * <p>
470      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
471      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
472      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
473      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
474      */
475     private class ConflictGtu extends HeadwayGTUReal
476     {
477         /** */
478         private static final long serialVersionUID = 20180221L;
479 
480         /** Visible pointer to the GTU (which HeadwayGTUReal has not). */
481         private final LaneBasedGTU gtu;
482 
483         /**
484          * Constructor.
485          * @param gtu LaneBasedGTU; gtu
486          * @param overlapFront Length; front overlap
487          * @param overlap Length; overlap
488          * @param overlapRear Length; rear overlap
489          * @throws GTUException on exception
490          */
491         ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
492                 throws GTUException
493         {
494             super(gtu, overlapFront, overlap, overlapRear, true);
495             this.gtu = gtu;
496         }
497 
498         /**
499          * Constructor.
500          * @param gtu LaneBasedGTU; gtu
501          * @param distance Length; distance
502          * @throws GTUException on exception
503          */
504         ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
505         {
506             super(gtu, distance, true);
507             this.gtu = gtu;
508         }
509     }
510 
511     /**
512      * HeadwayGtuType that generates ConflictGtu's, for use within the base iterators for upstream and downstream neighbors.
513      * This result is used by secondary iterators (ConflictGtuIterable) to provide the requested specific HeadwatGtuType.
514      * <p>
515      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
516      * <br>
517      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
518      * <p>
519      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
520      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
521      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
522      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
523      */
524     private class ConflictGtuType implements HeadwayGtuType
525     {
526         /** Constructor. */
527         ConflictGtuType()
528         {
529             //
530         }
531 
532         /** {@inheritDoc} */
533         @Override
534         public ConflictGtu createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
535                 final Length distance, final boolean downstream) throws GTUException
536         {
537             return new ConflictGtu(perceivedGtu, distance);
538         }
539 
540         /** {@inheritDoc} */
541         @Override
542         public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
543                 final Length distance) throws GTUException, ParameterException
544         {
545             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming downstream
546         }
547 
548         /** {@inheritDoc} */
549         @Override
550         public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
551                 final Length distance) throws GTUException, ParameterException
552         {
553             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming upstream
554         }
555 
556         /** {@inheritDoc} */
557         @Override
558         public ConflictGtu createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
559                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
560         {
561             throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
562         }
563     }
564 
565     /**
566      * HeadwayGtuType that changes a negative headway in to an overlapping headway, by forwarding the request to a wrapped
567      * HeadwayGtuType. This is used for downstream GTUs of the conflict, accounting also for the length of the conflict. Hence,
568      * overlap information concerns the conflict and a downstream GTU (downstream of the start of the conflict).
569      * <p>
570      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
571      * <br>
572      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
573      * <p>
574      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
575      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
576      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
577      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
578      */
579     private class OverlapHeadway implements HeadwayGtuType
580     {
581         /** Wrapped headway type. */
582         private HeadwayGtuType wrappedType;
583 
584         /**
585          * Constructor.
586          * @param wrappedType HeadwayGtuType; wrapped headway type
587          */
588         OverlapHeadway(final HeadwayGtuType wrappedType)
589         {
590             this.wrappedType = wrappedType;
591         }
592 
593         /** {@inheritDoc} */
594         @Override
595         public HeadwayGTU createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
596                 final boolean downstream) throws GTUException, ParameterException
597         {
598             if (dist.ge(getLength()))
599             {
600                 // GTU fully downstream of the conflict
601                 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
602             }
603             else
604             {
605                 Length overlapRear = dist;
606                 Length overlap = getLength(); // start with conflict length
607                 Length overlapFront = dist.plus(perceivedGtu.getLength()).minus(getLength());
608                 if (overlapFront.lt0())
609                 {
610                     overlap = overlap.plus(overlapFront); // subtract front being before the conflict end
611                 }
612                 if (overlapRear.gt0())
613                 {
614                     overlap = overlap.minus(overlapRear); // subtract rear being past the conflict start
615                 }
616                 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
617             }
618         }
619 
620         /** {@inheritDoc} */
621         @Override
622         public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
623                 final Length distance) throws GTUException, ParameterException
624         {
625             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
626         }
627 
628         /** {@inheritDoc} */
629         @Override
630         public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
631                 final Length distance) throws GTUException, ParameterException
632         {
633             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
634         }
635 
636         /** {@inheritDoc} */
637         @Override
638         public HeadwayGTU createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
639                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
640         {
641             return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
642         }
643     }
644 
645     /**
646      * Iterable for upstream and downstream GTUs of a conflict, which uses a base iterable.
647      * <p>
648      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
649      * <br>
650      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
651      * <p>
652      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
653      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
654      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
655      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
656      */
657     private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
658     {
659         /** HeadwayGTU type. */
660         private final HeadwayGtuType headwayGtuType;
661 
662         /** Guaranteed visibility. */
663         private final Length visibility;
664 
665         /** Downstream (or upstream) neighbors. */
666         private final boolean downstream;
667 
668         /** Base iterator of the base iterable. */
669         private final Iterator<HeadwayGTU> baseIterator;
670 
671         /**
672          * @param perceivingGtu LaneBasedGTU; perceiving GTU
673          * @param headwayGtuType HeadwayGtuType; HeadwayGTU type
674          * @param visibility Length; guaranteed visibility
675          * @param downstream boolean; downstream (or upstream) neighbors
676          * @param base AbstractPerceptionIterable&lt;HeadwayGTU, LaneBasedGTU, Integer&gt;; base iterable from the conflict
677          */
678         ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
679                 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
680         {
681             super(perceivingGtu);
682             this.headwayGtuType = headwayGtuType;
683             this.visibility = visibility;
684             this.downstream = downstream;
685             this.baseIterator = base.iterator();
686         }
687 
688         /** {@inheritDoc} */
689         @Override
690         protected Iterator<PrimaryIteratorEntry> primaryIterator()
691         {
692             /**
693              * Iterator that iterates over PrimaryIteratorEntry objects.
694              */
695             class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
696             {
697                 /** Next entry. */
698                 private PrimaryIteratorEntry next;
699 
700                 /** {@inheritDoc} */
701                 @SuppressWarnings("synthetic-access")
702                 @Override
703                 public boolean hasNext()
704                 {
705                     if (this.next == null)
706                     {
707                         if (ConflictGtuIterable.this.baseIterator.hasNext())
708                         {
709                             // ConflictGtuIterable is a private class, only used with ConflictGtuType
710                             ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
711                             if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
712                             {
713                                 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
714                             }
715                         }
716                     }
717                     return this.next != null;
718                 }
719 
720                 /** {@inheritDoc} */
721                 @Override
722                 public PrimaryIteratorEntry next()
723                 {
724                     if (hasNext())
725                     {
726                         PrimaryIteratorEntry out = this.next;
727                         this.next = null;
728                         return out;
729                     }
730                     throw new NoSuchElementException();
731                 }
732             }
733             return new ConflictGtuIterator();
734         }
735 
736         /** {@inheritDoc} */
737         @Override
738         protected HeadwayGTU perceive(final LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
739                 throws GTUException, ParameterException
740         {
741             return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
742         }
743     }
744 
745 }