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      * @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.getSourceId();
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         conf1.init(); // fire events and register on lane
481         Conflict/network/lane/conflict/Conflict.html#Conflict">Conflict conf2 = new Conflict(lane2, longitudinalPosition2, length2, direction2, geometry2, conflictType, conflictRule,
482                 simulator, gtuType2, permitted, cloneLock);
483         conf2.init(); // fire events and register on lane
484         conf1.otherConflict = conf2;
485         conf2.otherConflict = conf1;
486     }
487 
488     /** {@inheritDoc} */
489     @Override
490     public String toString()
491     {
492         return "Conflict [conflictType=" + this.conflictType + ", conflictRule=" + this.conflictRule + "]";
493     }
494 
495     /**
496      * Clone of other conflict.
497      */
498     private Conflict otherClone;
499 
500     /** {@inheritDoc} */
501     @Override
502     public Conflict clone(final CrossSectionElement newCSE, final SimulatorInterface.TimeDoubleUnit newSimulator)
503             throws NetworkException
504     {
505         Throw.when(!(newCSE instanceof Lane), NetworkException.class, "sensors can only be cloned for Lanes");
506         Throw.when(!(newSimulator instanceof DEVSSimulatorInterface.TimeDoubleUnit), NetworkException.class,
507                 "simulator should be a DEVSSimulator");
508         Conflictad/network/lane/conflict/Conflict.html#Conflict">Conflict out = new Conflict((Lane) newCSE, getLongitudinalPosition(), this.length, this.direction, getGeometry(),
509                 this.conflictType, this.conflictRule.clone(newSimulator), newSimulator, this.gtuType, this.permitted,
510                 this.cloneLock);
511         out.init();
512         synchronized (this.cloneLock)
513         {
514             // couple both clones
515             if (this.otherClone == null || this.otherClone.simulator != newSimulator)
516             {
517                 // other clone will do it
518                 this.otherConflict.otherClone = out;
519             }
520             else
521             {
522                 out.otherConflict = this.otherClone;
523                 this.otherClone.otherConflict = out;
524             }
525             // reset successful clone of pair, or remove otherClone from other simulator (or was already null)
526             this.otherClone = null;
527         }
528         return out;
529     }
530 
531     /**
532      * Light-weight lane based object to indicate the end of a conflict. It is used to perceive conflicts when a GTU is on the
533      * conflict area, and hence the conflict lane based object is usptream.
534      * <p>
535      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
536      * <br>
537      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
538      * <p>
539      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 dec. 2016 <br>
540      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
541      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
542      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
543      */
544     public class ConflictEnd extends AbstractLaneBasedObject
545     {
546         /** */
547         private static final long serialVersionUID = 20161214L;
548 
549         /** Conflict. */
550         private final Conflict conflict;
551 
552         /**
553          * @param conflict Conflict; conflict
554          * @param lane Lane; lane
555          * @param direction LongitudinalDirectionality; valid direction
556          * @param longitudinalPosition Length; position
557          * @throws NetworkException on network exception
558          * @throws OTSGeometryException does not happen
559          */
560         ConflictEnd(final Conflict conflict, final Lane lane, final LongitudinalDirectionality direction,
561                 final Length longitudinalPosition) throws NetworkException, OTSGeometryException
562         {
563             super(conflict.getId() + "End", lane, direction, longitudinalPosition,
564                     new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(1, 0, 0)));
565             this.conflict = conflict;
566         }
567 
568         /**
569          * @return conflict
570          */
571         public final Conflict getConflict()
572         {
573             return this.conflict;
574         }
575 
576         /** {@inheritDoc} */
577         @Override
578         public final AbstractLaneBasedObject clone(final CrossSectionElement newCSE,
579                 final SimulatorInterface.TimeDoubleUnit newSimulator) throws NetworkException
580         {
581             // Constructor of Conflict creates these.
582             return null;
583         }
584 
585         /** {@inheritDoc} */
586         @Override
587         public final String toString()
588         {
589             return "ConflictEnd [conflict=" + this.conflict + "]";
590         }
591     }
592 
593     /**
594      * HeadwayGTU that is returned by base iterators for upstream and downstream GTUs. This class is used with both
595      * {@code UpstreamNeighborsIterable} and {@code DownstreamNeighborsIterable} which work with HeadwayGTU. The role of this
596      * class is however to simply provide the GTU itself such that other specific HeadwayGTU types can be created with it.
597      * Therefore, it extends HeadwayGTUReal which simply wraps the GTU. As the HeadwayGTUReal class has the actual GTU hidden,
598      * this class can provide it.
599      * <p>
600      * FIXME: why not create a getter for the gtu in the super class?
601      * <p>
602      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
603      * <br>
604      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
605      * <p>
606      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
607      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
608      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
609      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
610      */
611     private class ConflictGtu extends HeadwayGTUReal
612     {
613         /** */
614         private static final long serialVersionUID = 20180221L;
615 
616         /** Visible pointer to the GTU (which HeadwayGTUReal has not). */
617         private final LaneBasedGTU gtu;
618 
619         /**
620          * Constructor.
621          * @param gtu LaneBasedGTU; gtu
622          * @param overlapFront Length; front overlap
623          * @param overlap Length; overlap
624          * @param overlapRear Length; rear overlap
625          * @throws GTUException on exception
626          */
627         ConflictGtu(final LaneBasedGTU gtu, final Length overlapFront, final Length overlap, final Length overlapRear)
628                 throws GTUException
629         {
630             super(gtu, overlapFront, overlap, overlapRear, true);
631             this.gtu = gtu;
632         }
633 
634         /**
635          * Constructor.
636          * @param gtu LaneBasedGTU; gtu
637          * @param distance Length; distance
638          * @throws GTUException on exception
639          */
640         ConflictGtu(final LaneBasedGTU gtu, final Length distance) throws GTUException
641         {
642             super(gtu, distance, true);
643             this.gtu = gtu;
644         }
645     }
646 
647     /**
648      * HeadwayGtuType that generates ConflictGtu's, for use within the base iterators for upstream and downstream neighbors.
649      * This result is used by secondary iterators (ConflictGtuIterable) to provide the requested specific HeadwatGtuType.
650      * <p>
651      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
652      * <br>
653      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
654      * <p>
655      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
656      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
657      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
658      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
659      */
660     private class ConflictGtuType implements HeadwayGtuType
661     {
662         /** Constructor. */
663         ConflictGtuType()
664         {
665             //
666         }
667 
668         /** {@inheritDoc} */
669         @Override
670         public ConflictGtu createHeadwayGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
671                 final Length distance, final boolean downstream) throws GTUException
672         {
673             return new ConflictGtu(perceivedGtu, distance);
674         }
675 
676         /** {@inheritDoc} */
677         @Override
678         public HeadwayGTU createDownstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
679                 final Length distance) throws GTUException, ParameterException
680         {
681             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming downstream
682         }
683 
684         /** {@inheritDoc} */
685         @Override
686         public HeadwayGTU createUpstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
687                 final Length distance) throws GTUException, ParameterException
688         {
689             return new ConflictGtu(perceivedGtu, distance); // actually do not change it, called by iterable assuming upstream
690         }
691 
692         /** {@inheritDoc} */
693         @Override
694         public ConflictGtu createParallelGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
695                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
696         {
697             throw new UnsupportedOperationException("ConflictGtuType is a pass-through type, no actual perception is allowed.");
698         }
699     }
700 
701     /**
702      * HeadwayGtuType that changes a negative headway in to an overlapping headway, by forwarding the request to a wrapped
703      * HeadwayGtuType. This is used for downstream GTUs of the conflict, accounting also for the length of the conflict. Hence,
704      * overlap information concerns the conflict and a downstream GTU (downstream of the start of the conflict).
705      * <p>
706      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
707      * <br>
708      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
709      * <p>
710      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
711      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
712      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
713      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
714      */
715     private class OverlapHeadway implements HeadwayGtuType
716     {
717         /** Wrapped headway type. */
718         private HeadwayGtuType wrappedType;
719 
720         /**
721          * Constructor.
722          * @param wrappedType HeadwayGtuType; wrapped headway type
723          */
724         OverlapHeadway(final HeadwayGtuType wrappedType)
725         {
726             this.wrappedType = wrappedType;
727         }
728 
729         /** {@inheritDoc} */
730         @Override
731         public HeadwayGTU createHeadwayGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu, final Length dist,
732                 final boolean downstream) throws GTUException, ParameterException
733         {
734             if (dist.ge(getLength()))
735             {
736                 // GTU fully downstream of the conflict
737                 return this.wrappedType.createHeadwayGtu(perceivingGtu, perceivedGtu, dist.minus(getLength()), downstream);
738             }
739             else
740             {
741                 Length overlapRear = dist;
742                 Length overlap = getLength(); // start with conflict length
743                 @SuppressWarnings("synthetic-access")
744                 Lane lane = downstream ? Conflict.this.downstreamLanes.get(perceivedGtu)
745                         : Conflict.this.upstreamLanes.get(perceivedGtu);
746                 Length overlapFront = dist.plus(perceivedGtu.getProjectedLength(lane)).minus(getLength());
747                 if (overlapFront.lt0())
748                 {
749                     overlap = overlap.plus(overlapFront); // subtract front being before the conflict end
750                 }
751                 if (overlapRear.gt0())
752                 {
753                     overlap = overlap.minus(overlapRear); // subtract rear being past the conflict start
754                 }
755                 return createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
756             }
757         }
758 
759         /** {@inheritDoc} */
760         @Override
761         public HeadwayGTU createDownstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
762                 final Length distance) throws GTUException, ParameterException
763         {
764             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
765         }
766 
767         /** {@inheritDoc} */
768         @Override
769         public HeadwayGTU createUpstreamGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
770                 final Length distance) throws GTUException, ParameterException
771         {
772             throw new UnsupportedOperationException("OverlapHeadway is a pass-through type, no actual perception is allowed.");
773         }
774 
775         /** {@inheritDoc} */
776         @Override
777         public HeadwayGTU createParallelGtu(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU perceivedGtu,
778                 final Length overlapFront, final Length overlap, final Length overlapRear) throws GTUException
779         {
780             return this.wrappedType.createParallelGtu(perceivingGtu, perceivedGtu, overlapFront, overlap, overlapRear);
781         }
782     }
783 
784     /**
785      * Iterable for upstream and downstream GTUs of a conflict, which uses a base iterable.
786      * <p>
787      * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
788      * <br>
789      * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
790      * <p>
791      * @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018 <br>
792      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
793      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
794      * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
795      */
796     private class ConflictGtuIterable extends AbstractPerceptionReiterable<HeadwayGTU, LaneBasedGTU>
797     {
798         /** HeadwayGTU type. */
799         private final HeadwayGtuType headwayGtuType;
800 
801         /** Guaranteed visibility. */
802         private final Length visibility;
803 
804         /** Downstream (or upstream) neighbors. */
805         private final boolean downstream;
806 
807         /** Base iterator of the base iterable. */
808         private final Iterator<HeadwayGTU> baseIterator;
809 
810         /**
811          * @param perceivingGtu LaneBasedGTU; perceiving GTU
812          * @param headwayGtuType HeadwayGtuType; HeadwayGTU type
813          * @param visibility Length; guaranteed visibility
814          * @param downstream boolean; downstream (or upstream) neighbors
815          * @param base AbstractPerceptionIterable&lt;HeadwayGTU, LaneBasedGTU, Integer&gt;; base iterable from the conflict
816          */
817         ConflictGtuIterable(final LaneBasedGTU perceivingGtu, final HeadwayGtuType headwayGtuType, final Length visibility,
818                 final boolean downstream, final AbstractPerceptionIterable<HeadwayGTU, LaneBasedGTU, Integer> base)
819         {
820             super(perceivingGtu);
821             this.headwayGtuType = headwayGtuType;
822             this.visibility = visibility;
823             this.downstream = downstream;
824             this.baseIterator = base.iterator();
825         }
826 
827         /** {@inheritDoc} */
828         @Override
829         protected Iterator<PrimaryIteratorEntry> primaryIterator()
830         {
831             /**
832              * Iterator that iterates over PrimaryIteratorEntry objects.
833              */
834             class ConflictGtuIterator implements Iterator<PrimaryIteratorEntry>
835             {
836                 /** Next entry. */
837                 private PrimaryIteratorEntry next;
838 
839                 /** {@inheritDoc} */
840                 @SuppressWarnings("synthetic-access")
841                 @Override
842                 public boolean hasNext()
843                 {
844                     if (this.next == null)
845                     {
846                         if (ConflictGtuIterable.this.baseIterator.hasNext())
847                         {
848                             // ConflictGtuIterable is a private class, only used with ConflictGtuType
849                             ConflictGtu gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
850                             if (gtu.gtu.getId().equals(getGtu().getId()))
851                             {
852                                 if (ConflictGtuIterable.this.baseIterator.hasNext())
853                                 {
854                                     gtu = (ConflictGtu) ConflictGtuIterable.this.baseIterator.next();
855                                 }
856                                 else
857                                 {
858                                     return false;
859                                 }
860                             }
861                             if (gtu.getDistance() == null || gtu.getDistance().le(ConflictGtuIterable.this.visibility))
862                             {
863                                 this.next = new PrimaryIteratorEntry(gtu.gtu, gtu.getDistance());
864                             }
865                         }
866                     }
867                     return this.next != null;
868                 }
869 
870                 /** {@inheritDoc} */
871                 @Override
872                 public PrimaryIteratorEntry next()
873                 {
874                     if (hasNext())
875                     {
876                         PrimaryIteratorEntry out = this.next;
877                         this.next = null;
878                         return out;
879                     }
880                     throw new NoSuchElementException();
881                 }
882             }
883             return new ConflictGtuIterator();
884         }
885 
886         /** {@inheritDoc} */
887         @Override
888         protected HeadwayGTU perceive(final LaneBasedGTUeBasedGTU.html#LaneBasedGTU">LaneBasedGTU perceivingGtu, final LaneBasedGTU object, final Length distance)
889                 throws GTUException, ParameterException
890         {
891             return this.headwayGtuType.createHeadwayGtu(perceivingGtu, object, distance, this.downstream);
892         }
893     }
894 
895 }