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