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(), GTUType.VEHICLE);
175     }
176 
177     /**
178      * Make sure the conflict can provide the given upstream visibility.
179      * @param visibility Length; visibility to guarantee
180      */
181     private void provideUpstreamVisibility(final Length visibility)
182     {
183         if (visibility.gt(this.maxUpstreamVisibility))
184         {
185             this.maxUpstreamVisibility = visibility;
186             this.upstreamTime = null;
187             this.downstreamTime = null;
188         }
189     }
190 
191     /**
192      * Make sure the conflict can provide the given downstream visibility.
193      * @param visibility Length; visibility to guarantee
194      */
195     private void provideDownstreamVisibility(final Length visibility)
196     {
197         if (visibility.gt(this.maxDownstreamVisibility))
198         {
199             this.maxDownstreamVisibility = visibility;
200             this.upstreamTime = null;
201             this.downstreamTime = null;
202         }
203     }
204 
205     /**
206      * Provides the upstream GTUs.
207      * @param perceivingGtu LaneBasedGTU; perceiving GTU
208      * @param headwayGtuType HeadwayGtuType; headway GTU type to use
209      * @param visibility Length; distance over which GTU's are provided
210      * @return PerceptionIterable&lt;HeadwayGtU&gt;; iterable over the upstream GTUs
211      */
212     public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getUpstreamGtus(final LaneBasedGTU perceivingGtu,
213             final HeadwayGtuType headwayGtuType, final Length visibility)
214     {
215         provideUpstreamVisibility(visibility);
216         Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
217         if (this.upstreamTime == null || !time.eq(this.upstreamTime))
218         {
219             // setup a base iterable to provide the GTUs
220             this.upstreamGtus =
221                     new UpstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition, this.maxUpstreamVisibility,
222                             RelativePosition.REFERENCE_POSITION, this.conflictGtuType, RelativeLane.CURRENT);
223             this.upstreamTime = time;
224         }
225         // return iterable that uses the base iterable
226         return new ConflictGtuIterable(perceivingGtu, headwayGtuType, visibility, false, this.upstreamGtus);
227     }
228 
229     /**
230      * Provides the downstream GTUs.
231      * @param perceivingGtu LaneBasedGTU; perceiving GTU
232      * @param headwayGtuType HeadwayGtuType; headway GTU type to use
233      * @param visibility Length; distance over which GTU's are provided
234      * @return PerceptionIterable&lt;HeadwayGtU&gt;; iterable over the downstream GTUs
235      */
236     public PerceptionCollectable<HeadwayGTU, LaneBasedGTU> getDownstreamGtus(final LaneBasedGTU perceivingGtu,
237             final HeadwayGtuType headwayGtuType, final Length visibility)
238     {
239         provideDownstreamVisibility(visibility);
240         Time time = this.getLane().getParentLink().getSimulator().getSimulatorTime();
241         if (this.downstreamTime == null || !time.eq(this.downstreamTime))
242         {
243             // setup a base iterable to provide the GTUs
244             boolean ignoreIfUpstream = false;
245             this.downstreamGtus = new DownstreamNeighborsIterable(perceivingGtu, this.root, this.rootPosition,
246                     this.maxDownstreamVisibility, RelativePosition.REFERENCE_POSITION, this.conflictGtuType, null,
247                     RelativeLane.CURRENT, ignoreIfUpstream);
248             this.downstreamTime = time;
249         }
250         // return iterable that uses the base iterable
251         return new ConflictGtuIterable(perceivingGtu, new OverlapHeadway(headwayGtuType), visibility, true,
252                 this.downstreamGtus);
253     }
254 
255     /**
256      * @return conflictType.
257      */
258     public ConflictType getConflictType()
259     {
260         return this.conflictType;
261     }
262 
263     /**
264      * @return conflictRule.
265      */
266     public ConflictRule getConflictRule()
267     {
268         return this.conflictRule;
269     }
270 
271     /**
272      * @return conflictPriority.
273      */
274     public ConflictPriority conflictPriority()
275     {
276         return this.conflictRule.determinePriority(this);
277     }
278 
279     /**
280      * @return length.
281      */
282     public Length getLength()
283     {
284         return this.length;
285     }
286 
287     /**
288      * @return otherConflict.
289      */
290     public Conflict getOtherConflict()
291     {
292         return this.otherConflict;
293     }
294 
295     /**
296      * @return gtuType.
297      */
298     public GTUType getGtuType()
299     {
300         return this.gtuType;
301     }
302 
303     /**
304      * If permitted, traffic upstream of traffic lights may not be ignored, as these can have green light.
305      * @return permitted.
306      */
307     public boolean isPermitted()
308     {
309         return this.permitted;
310     }
311 
312     /**
313      * Creates a pair of conflicts.
314      * @param conflictType ConflictType; conflict type, i.e. crossing, merge or split
315      * @param conflictRule ConflictRule; conflict rule
316      * @param permitted boolean; whether the conflict is permitted in traffic light control
317      * @param lane1 Lane; lane of conflict 1
318      * @param longitudinalPosition1 Length; longitudinal position of conflict 1
319      * @param length1 Length; {@code Length} of conflict 1
320      * @param direction1 GTUDirectionality; GTU direction of conflict 1
321      * @param geometry1 OTSLine3D; geometry of conflict 1
322      * @param gtuType1 GTUType; gtu type of conflict 1
323      * @param lane2 Lane; lane of conflict 2
324      * @param longitudinalPosition2 Length; longitudinal position of conflict 2
325      * @param length2 Length; {@code Length} of conflict 2
326      * @param direction2 GTUDirectionality; GTU direction of conflict 2
327      * @param geometry2 OTSLine3D; geometry of conflict 2
328      * @param gtuType2 GTUType; gtu type of conflict 2
329      * @param simulator DEVSSimulatorInterface.TimeDoubleUnit; the simulator for animation and timed events
330      * @throws NetworkException if the combination of conflict type and both conflict rules is not correct
331      */
332     @SuppressWarnings("checkstyle:parameternumber")
333     public static void generateConflictPair(final ConflictType conflictType, final ConflictRule conflictRule,
334             final boolean permitted, final Lane lane1, final Length longitudinalPosition1, final Length length1,
335             final GTUDirectionality direction1, final OTSLine3D geometry1, final GTUType gtuType1, final Lane lane2,
336             final Length longitudinalPosition2, final Length length2, final GTUDirectionality direction2,
337             final OTSLine3D geometry2, final GTUType gtuType2, final DEVSSimulatorInterface.TimeDoubleUnit simulator)
338             throws NetworkException
339     {
340         // lane, longitudinalPosition, length and geometry are checked in AbstractLaneBasedObject
341         Throw.whenNull(conflictType, "Conflict type may not be null.");
342 
343         Object cloneLock = new Object();
344         Conflict conf1 = new Conflict(lane1, longitudinalPosition1, length1, direction1, geometry1, conflictType, conflictRule,
345                 simulator, gtuType1, permitted, cloneLock);
346         Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
347                 simulator, gtuType2, permitted, cloneLock);
348         conf1.otherConflict = conf2;
349         conf2.otherConflict = conf1;
350     }
351 
352     /** {@inheritDoc} */
353     @Override
354     public String toString()
355     {
356         return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
357     }
358 
359     /**
360      * Clone of other conflict.
361      */
362     private Conflict otherClone;
363 
364     /** {@inheritDoc} */
365     @Override
366     public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
367             throws NetworkException
368     {
369         Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
370         Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
371                 "simulator should be a DEVSSimulator");
372         Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
373                 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
374                 this.cloneLock);
375         synchronized (this.cloneLock)
376         {
377             // couple both clones
378             if (this.otherClone == null || this.otherClone.simulator != newSimulator)
379             {
380                 // other clone will do it
381                 this.otherConflict.otherClone = out;
382             }
383             else
384             {
385                 out.otherConflict = this.otherClone;
386                 this.otherClone.otherConflict = out;
387             }
388             // reset successful clone of pair, or remove otherClone from other simulator (or was already null)
389             this.otherClone = null;
390         }
391         return out;
392     }
393 
394     /**
395      * Light-weight lane based object to indicate the end of a conflict. It is used to perceive conflicts when a GTU is on the
396      * conflict area, and hence the conflict lane based object is usptream.
397      * <p>
398      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
399      * <br>
400      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
401      * <p>
402      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 dec. 2016 <br>
403      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
404      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
405      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
406      */
407     public class ConflictEnd extends AbstractLaneBasedObject
408     {
409         /** */
410         private static final long serialVersionUID = 20161214L;
411 
412         /** Conflict. */
413         private final Conflict conflict;
414 
415         /**
416          * @param conflict Conflict; conflict
417          * @param lane Lane; lane
418          * @param direction LongitudinalDirectionality; valid direction
419          * @param longitudinalPosition Length; position
420          * @throws NetworkException on network exception
421          * @throws OTSGeometryException does not happen
422          */
423         ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
424                 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
425         {
426             super(conflict.getId() + "End", lane, direction, longitudinalPosition,
427                     new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
428             this.conflict = conflict;
429         }
430 
431         /**
432          * @return conflict
433          */
434         public final Conflict getConflict()
435         {
436             return this.conflict;
437         }
438 
439         /** {@inheritDoc} */
440         @Override
441         public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
442                 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
443         {
444             // Constructor of Conflict creates these.
445             return null;
446         }
447 
448         /** {@inheritDoc} */
449         @Override
450         public final String toString()
451         {
452             return "ConflictEnd [conflict=" + this.conflict + "]";
453         }
454     }
455 
456     /**
457      * HeadwayGTU that is returned by base iterators for upstream and downstream GTUs. This class is used with both
458      * {@code UpstreamNeighborsIterable} and {@code DownstreamNeighborsIterable} which work with HeadwayGTU. The role of this
459      * class is however to simply provide the GTU itself such that other specific HeadwayGTU types can be created with it.
460      * Therefore, it extends HeadwayGTUReal which simply wraps the GTU. As the HeadwayGTUReal class has the actual GTU hidden,
461      * this class can provide it.
462      * <p>
463      * FIXME: why not create a getter for the gtu in the super class?
464      * <p>
465      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
466      * <br>
467      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
468      * <p>
469      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
470      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
471      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
472      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
473      */
474     private class ConflictGtu extends HeadwayGTUReal
475     {
476         /** */
477         private static final long serialVersionUID = 20180221L;
478 
479         /** Visible pointer to the GTU (which HeadwayGTUReal has not). */
480         private final LaneBasedGTU gtu;
481 
482         /**
483          * Constructor.
484          * @param gtu LaneBasedGTU; gtu
485          * @param overlapFront Length; front overlap
486          * @param overlap Length; overlap
487          * @param overlapRear Length; rear overlap
488          * @throws GTUException on exception
489          */
490         ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
491                 throws GTUException
492         {
493             super(gtu, overlapFront, overlap, overlapRear, true);
494             this.gtu = gtu;
495         }
496 
497         /**
498          * Constructor.
499          * @param gtu LaneBasedGTU; gtu
500          * @param distance Length; distance
501          * @throws GTUException on exception
502          */
503         ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
504         {
505             super(gtu, distance, true);
506             this.gtu = gtu;
507         }
508     }
509 
510     /**
511      * HeadwayGtuType that generates ConflictGtu's, for use within the base iterators for upstream and downstream neighbors.
512      * This result is used by secondary iterators (ConflictGtuIterable) to provide the requested specific HeadwatGtuType.
513      * <p>
514      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
515      * <br>
516      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
517      * <p>
518      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
519      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
520      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
521      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
522      */
523     private class ConflictGtuType implements HeadwayGtuType
524     {
525         /** Constructor. */
526         ConflictGtuType()
527         {
528             //
529         }
530 
531         /** {@inheritDoc} */
532         @Override
533         public ConflictGtu createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
534                 final Length distance, final boolean downstream) throws GTUException
535         {
536             return new ConflictGtu(perceivedGtu, distance);
537         }
538 
539         /** {@inheritDoc} */
540         @Override
541         public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
542                 final Length distance) throws GTUException, ParameterException
543         {
544             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming downstream
545         }
546 
547         /** {@inheritDoc} */
548         @Override
549         public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
550                 final Length distance) throws GTUException, ParameterException
551         {
552             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming upstream
553         }
554 
555         /** {@inheritDoc} */
556         @Override
557         public ConflictGtu createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
558                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
559         {
560             throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
561         }
562     }
563 
564     /**
565      * HeadwayGtuType that changes a negative headway in to an overlapping headway, by forwarding the request to a wrapped
566      * HeadwayGtuType. This is used for downstream GTUs of the conflict, accounting also for the length of the conflict. Hence,
567      * overlap information concerns the conflict and a downstream GTU (downstream of the start of the conflict).
568      * <p>
569      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
570      * <br>
571      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
572      * <p>
573      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
574      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
575      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
576      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
577      */
578     private class OverlapHeadway implements HeadwayGtuType
579     {
580         /** Wrapped headway type. */
581         private HeadwayGtuType wrappedType;
582 
583         /**
584          * Constructor.
585          * @param wrappedType HeadwayGtuType; wrapped headway type
586          */
587         OverlapHeadway(final HeadwayGtuType wrappedType)
588         {
589             this.wrappedType = wrappedType;
590         }
591 
592         /** {@inheritDoc} */
593         @Override
594         public HeadwayGTU createHeadwayGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
595                 final boolean downstream) throws GTUException, ParameterException
596         {
597             if (dist.ge(getLength()))
598             {
599                 // GTU fully downstream of the conflict
600                 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
601             }
602             else
603             {
604                 Length overlapRear = dist;
605                 Length overlap = getLength(); // start with conflict length
606                 Length overlapFront = dist.plus(perceivedGtu.getLength()).minus(getLength());
607                 if (overlapFront.lt0())
608                 {
609                     overlap = overlap.plus(overlapFront); // subtract front being before the conflict end
610                 }
611                 if (overlapRear.gt0())
612                 {
613                     overlap = overlap.minus(overlapRear); // subtract rear being past the conflict start
614                 }
615                 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
616             }
617         }
618 
619         /** {@inheritDoc} */
620         @Override
621         public HeadwayGTU createDownstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
622                 final Length distance) throws GTUException, ParameterException
623         {
624             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
625         }
626 
627         /** {@inheritDoc} */
628         @Override
629         public HeadwayGTU createUpstreamGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
630                 final Length distance) throws GTUException, ParameterException
631         {
632             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
633         }
634 
635         /** {@inheritDoc} */
636         @Override
637         public HeadwayGTU createParallelGtu(final LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
638                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
639         {
640             return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
641         }
642     }
643 
644     /**
645      * Iterable for upstream and downstream GTUs of a conflict, which uses a base iterable.
646      * <p>
647      * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
648      * <br>
649      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
650      * <p>
651      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
652      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
653      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
654      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
655      */
656     private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
657     {
658         /** HeadwayGTU type. */
659         private final HeadwayGtuType headwayGtuType;
660 
661         /** Guaranteed visibility. */
662         private final Length visibility;
663 
664         /** Downstream (or upstream) neighbors. */
665         private final boolean downstream;
666 
667         /** Base iterator of the base iterable. */
668         private final Iterator<HeadwayGTU> baseIterator;
669 
670         /**
671          * @param perceivingGtu LaneBasedGTU; perceiving GTU
672          * @param headwayGtuType HeadwayGtuType; HeadwayGTU type
673          * @param visibility Length; guaranteed visibility
674          * @param downstream boolean; downstream (or upstream) neighbors
675          * @param base AbstractPerceptionIterable&lt;HeadwayGTU, LaneBasedGTU, Integer&gt;; base iterable from the conflict
676          */
677         ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
678                 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
679         {
680             super(perceivingGtu);
681             this.headwayGtuType = headwayGtuType;
682             this.visibility = visibility;
683             this.downstream = downstream;
684             this.baseIterator = base.iterator();
685         }
686 
687         /** {@inheritDoc} */
688         @Override
689         protected Iterator<PrimaryIteratorEntry> primaryIterator()
690         {
691             /**
692              * Iterator that iterates over PrimaryIteratorEntry objects.
693              */
694             class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
695             {
696                 /** Next entry. */
697                 private PrimaryIteratorEntry next;
698 
699                 /** {@inheritDoc} */
700                 @SuppressWarnings("synthetic-access")
701                 @Override
702                 public boolean hasNext()
703                 {
704                     if (this.next == null)
705                     {
706                         if (ConflictGtuIterable.this.baseIterator.hasNext())
707                         {
708                             // ConflictGtuIterable is a private class, only used with ConflictGtuType
709                             ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
710                             if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
711                             {
712                                 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
713                             }
714                         }
715                     }
716                     return this.next != null;
717                 }
718 
719                 /** {@inheritDoc} */
720                 @Override
721                 public PrimaryIteratorEntry next()
722                 {
723                     if (hasNext())
724                     {
725                         PrimaryIteratorEntry out = this.next;
726                         this.next = null;
727                         return out;
728                     }
729                     throw new NoSuchElementException();
730                 }
731             }
732             return new ConflictGtuIterator();
733         }
734 
735         /** {@inheritDoc} */
736         @Override
737         protected HeadwayGTU perceive(final LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
738                 throws GTUException, ParameterException
739         {
740             return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
741         }
742     }
743 
744 }