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