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