View Javadoc
1   package org.opentrafficsim.road.gtu.lane.perception.headway;
2   
3   import org.djunits.unit.LengthUnit;
4   import org.djunits.value.ValueRuntimeException;
5   import org.djunits.value.storage.StorageType;
6   import org.djunits.value.vdouble.scalar.Length;
7   import org.djunits.value.vdouble.scalar.Speed;
8   import org.djunits.value.vdouble.vector.LengthVector;
9   import org.djunits.value.vdouble.vector.base.DoubleVector;
10  import org.djutils.exceptions.Throw;
11  import org.opentrafficsim.core.gtu.GtuException;
12  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
13  import org.opentrafficsim.road.gtu.lane.perception.PerceptionCollectable;
14  import org.opentrafficsim.road.network.lane.CrossSectionLink;
15  import org.opentrafficsim.road.network.lane.Lane;
16  import org.opentrafficsim.road.network.lane.conflict.ConflictPriority;
17  import org.opentrafficsim.road.network.lane.conflict.ConflictRule;
18  import org.opentrafficsim.road.network.lane.conflict.ConflictType;
19  
20  /**
21   * <p>
22   * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
23   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
24   * </p>
25   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
26   * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
27   * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
28   */
29  public class HeadwayConflict extends AbstractHeadwayLaneBasedObject
30  {
31  
32      /** */
33      private static final long serialVersionUID = 20160602L;
34  
35      /** Conflict type. */
36      private final ConflictType conflictType;
37  
38      /** Conflict priority. */
39      private final ConflictPriority conflictPriority;
40  
41      /** Length of the conflict in the conflicting directions. */
42      private final Length conflictingLength;
43  
44      /**
45       * Set of conflicting GTU's <i>completely</i> upstream of the <i>start</i> of the conflict ordered close to far from the
46       * start of the conflict. Distance and overlap info concerns the conflict.
47       */
48      private final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> upstreamConflictingGTUs;
49  
50      /**
51       * Set of conflicting GTU's (partially) downstream of the <i>start</i> of the conflict ordered close to far from the start
52       * of conflict. Distance and overlap info concerns the conflict.
53       */
54      private final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> downstreamConflictingGTUs;
55  
56      /** Visibility on the conflicting lane within which conflicting vehicles are visible. */
57      private final Length conflictingVisibility;
58  
59      /** Speed limit on the conflicting lane. */
60      private final Speed conflictingSpeedLimit;
61  
62      /** Link of conflicting conflict. */
63      private final CrossSectionLink conflictingLink;
64  
65      /** Stop line on the own lane. */
66      private final HeadwayStopLine stopLine;
67  
68      /** Stop line on the conflicting lane. */
69      private final HeadwayStopLine conflictingStopLine;
70  
71      /** Type of conflict rule. */
72      private final Class<? extends ConflictRule> conflictRuleType;
73  
74      /** Distance of traffic light upstream on conflicting lane. */
75      private Length conflictingTrafficLightDistance = null;
76  
77      /** Whether the conflict is permitted by the traffic light. */
78      private boolean permitted = false;
79  
80      /** Width progression of conflict. */
81      private final Width width;
82  
83      /**
84       * Constructor.
85       * @param conflictType ConflictType; conflict type
86       * @param conflictPriority ConflictPriority; conflict priority
87       * @param conflictRuleType Class&lt;? extends ConflictRule&gt;; conflict rule type
88       * @param id String; id
89       * @param distance Length; distance
90       * @param length Length; length of the conflict
91       * @param conflictingLength Length; length of the conflict on the conflicting lane
92       * @param upstreamConflictingGTUs PerceptionCollectable&lt;HeadwayGtu,LaneBasedGtu&gt;; conflicting GTU's upstream of the
93       *            &lt;i&gt;start&lt;/i&gt; of the conflict
94       * @param downstreamConflictingGTUs PerceptionCollectable&lt;HeadwayGtu,LaneBasedGtu&gt;; conflicting GTU's downstream of
95       *            the &lt;i&gt;start&lt;/i&gt; of the conflict
96       * @param conflictingVisibility Length; visibility on the conflicting lane within which conflicting vehicles are visible
97       * @param conflictingSpeedLimit Speed; speed limit on the conflicting lane
98       * @param conflictingLink CrossSectionLink; conflicting link
99       * @param width Width; width progression of conflict
100      * @param stopLine HeadwayStopLine; stop line on the own lane
101      * @param conflictingStopLine HeadwayStopLine; stop line on the conflicting lane
102      * @param lane Lane; the lane
103      * @throws GtuException when id is null, or parameters are inconsistent
104      */
105     @SuppressWarnings("checkstyle:parameternumber")
106     public HeadwayConflict(final ConflictType conflictType, final ConflictPriority conflictPriority,
107             final Class<? extends ConflictRule> conflictRuleType, final String id, final Length distance, final Length length,
108             final Length conflictingLength, final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> upstreamConflictingGTUs,
109             final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> downstreamConflictingGTUs, final Length conflictingVisibility,
110             final Speed conflictingSpeedLimit, final CrossSectionLink conflictingLink, final Width width,
111             final HeadwayStopLine stopLine, final HeadwayStopLine conflictingStopLine, final Lane lane) throws GtuException
112     {
113         super(ObjectType.CONFLICT, id, distance, length, lane);
114         Throw.whenNull(conflictType, "Conflict type may not be null.");
115         Throw.whenNull(conflictPriority, "Conflict priority may not be null.");
116         Throw.whenNull(conflictRuleType, "Conflict rule type may not be null.");
117         Throw.whenNull(id, "Conflict id may not be null.");
118         Throw.whenNull(distance, "Conflict distance may not be null.");
119         Throw.whenNull(conflictingLength, "Conflict length may not be null.");
120         Throw.whenNull(upstreamConflictingGTUs, "Upstreaem conflicting GTU's may not be null.");
121         Throw.whenNull(downstreamConflictingGTUs, "Downstream conflicting GTU's may not be null.");
122         Throw.whenNull(width, "Width may not be null.");
123         Throw.whenNull(conflictingVisibility, "Conflict visibility may not be null.");
124         Throw.whenNull(conflictingSpeedLimit, "Conflict speed limit may not be null.");
125         this.conflictType = conflictType;
126         this.conflictPriority = conflictPriority;
127         this.conflictRuleType = conflictRuleType;
128         this.conflictingLength = conflictingLength;
129         this.upstreamConflictingGTUs = upstreamConflictingGTUs;
130         this.downstreamConflictingGTUs = downstreamConflictingGTUs;
131         this.conflictingVisibility = conflictingVisibility;
132         this.conflictingSpeedLimit = conflictingSpeedLimit;
133         this.conflictingLink = conflictingLink;
134         this.width = width;
135         this.stopLine = stopLine;
136         this.conflictingStopLine = conflictingStopLine;
137     }
138 
139     /**
140      * Constructor without stop lines.
141      * @param conflictType ConflictType; conflict type
142      * @param conflictPriority ConflictPriority; conflict priority
143      * @param conflictRuleType Class&lt;? extends ConflictRule&gt;; conflict rule type
144      * @param id String; id
145      * @param distance Length; distance
146      * @param length Length; length of the conflict
147      * @param conflictingLength Length; length of the conflict on the conflicting lane
148      * @param upstreamConflictingGTUs PerceptionCollectable&lt;HeadwayGtu,LaneBasedGtu&gt;; conflicting GTU's upstream of the
149      *            &lt;i&gt;start&lt;/i&gt; of the conflict
150      * @param downstreamConflictingGTUs PerceptionCollectable&lt;HeadwayGtu,LaneBasedGtu&gt;; conflicting GTU's downstream of
151      *            the &lt;i&gt;start&lt;/i&gt; of the conflict
152      * @param conflictingVisibility Length; visibility on the conflicting lane within which conflicting vehicles are visible
153      * @param conflictingSpeedLimit Speed; speed limit on the conflicting lane
154      * @param conflictingLink CrossSectionLink; conflicting link
155      * @param width Width; width progression of conflict
156      * @param lane Lane; the lane
157      * @throws GtuException when id is null, or parameters are inconsistent
158      */
159     @SuppressWarnings("checkstyle:parameternumber")
160     public HeadwayConflict(final ConflictType conflictType, final ConflictPriority conflictPriority,
161             final Class<? extends ConflictRule> conflictRuleType, final String id, final Length distance, final Length length,
162             final Length conflictingLength, final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> upstreamConflictingGTUs,
163             final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> downstreamConflictingGTUs, final Length conflictingVisibility,
164             final Speed conflictingSpeedLimit, final CrossSectionLink conflictingLink, final Width width, final Lane lane)
165             throws GtuException
166     {
167         this(conflictType, conflictPriority, conflictRuleType, id, distance, length, conflictingLength, upstreamConflictingGTUs,
168                 downstreamConflictingGTUs, conflictingVisibility, conflictingSpeedLimit, conflictingLink, width, null, null,
169                 lane);
170     }
171 
172     /**
173      * Returns the conflict type.
174      * @return conflict type
175      */
176     public final ConflictType getConflictType()
177     {
178         return this.conflictType;
179     }
180 
181     /**
182      * Returns whether this is a crossing conflict.
183      * @return whether this is a crossing conflict
184      */
185     public final boolean isCrossing()
186     {
187         return this.conflictType.equals(ConflictType.CROSSING);
188     }
189 
190     /**
191      * Returns whether this is a merge conflict.
192      * @return whether this is a merge conflict
193      */
194     public final boolean isMerge()
195     {
196         return this.conflictType.equals(ConflictType.MERGE);
197     }
198 
199     /**
200      * Returns whether this is a split conflict.
201      * @return whether this is a split conflict
202      */
203     public final boolean isSplit()
204     {
205         return this.conflictType.equals(ConflictType.SPLIT);
206     }
207 
208     /**
209      * Returns the conflict priority.
210      * @return conflict priority
211      */
212     public final ConflictPriority getConflictPriority()
213     {
214         return this.conflictPriority;
215     }
216 
217     /**
218      * Returns the length of the conflict on the conflicting lane.
219      * @return length of the conflict on the conflicting lane
220      */
221     public final Length getConflictingLength()
222     {
223         return this.conflictingLength;
224     }
225 
226     /**
227      * Returns a set of conflicting GTU's upstream of the <i>start</i> of the conflict ordered close to far from the conflict.
228      * @return set of conflicting GTU's upstream of the <i>start</i> of the conflict ordered close to far from the conflict
229      */
230     public final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> getUpstreamConflictingGTUs()
231     {
232         return this.upstreamConflictingGTUs;
233     }
234 
235     /**
236      * Returns a set of conflicting GTU's downstream of the <i>start</i> of the conflict ordered close to far from the conflict.
237      * Distance is given relative to the <i>end</i> of the conflict, or null for conflicting vehicles on the conflict. In the
238      * latter case the overlap is used.
239      * @return set of conflicting GTU's downstream of the <i>start</i> of the conflict ordered close to far from the conflict
240      */
241     public final PerceptionCollectable<HeadwayGtu, LaneBasedGtu> getDownstreamConflictingGTUs()
242     {
243         return this.downstreamConflictingGTUs;
244     }
245 
246     /**
247      * Returns the visibility on the conflicting lane within which conflicting vehicles are visible. All upstream conflicting
248      * GTUs have a distance smaller than the visibility. Depending on a limited visibility, a certain (lower) speed may be
249      * required while approaching the conflict.
250      * @return visibility on the conflicting lane within which conflicting vehicles are visible
251      */
252     public final Length getConflictingVisibility()
253     {
254         return this.conflictingVisibility;
255     }
256 
257     /**
258      * Returns the speed limit on the conflicting lane.
259      * @return speed limit on the conflicting lane
260      */
261     public final Speed getConflictingSpeedLimit()
262     {
263         return this.conflictingSpeedLimit;
264     }
265 
266     /**
267      * Returns the conflicting link.
268      * @return the conflicting link
269      */
270     public final CrossSectionLink getConflictingLink()
271     {
272         return this.conflictingLink;
273     }
274 
275     /**
276      * Returns the stop line.
277      * @return stop line
278      */
279     public final HeadwayStopLine getStopLine()
280     {
281         return this.stopLine;
282     }
283 
284     /**
285      * Returns the stop line on the conflicting lane.
286      * @return stop line
287      */
288     public final HeadwayStopLine getConflictingStopLine()
289     {
290         return this.conflictingStopLine;
291     }
292 
293     /**
294      * Returns the conflict rule type.
295      * @return conflict rule type
296      */
297     public final Class<? extends ConflictRule> getConflictRuleType()
298     {
299         return this.conflictRuleType;
300     }
301 
302     /**
303      * Returns the distance of a traffic light upstream on the conflicting lane.
304      * @return distance of a traffic light upstream on the conflicting lane, or {@code null} if no traffic light
305      */
306     public final Length getConflictingTrafficLightDistance()
307     {
308         return this.conflictingTrafficLightDistance;
309     }
310 
311     /**
312      * Whether the conflict is permitted by the traffic light.
313      * @return whether the conflict is permitted by the traffic light
314      */
315     public final boolean isPermitted()
316     {
317         return this.permitted;
318     }
319 
320     /**
321      * Set the distance of a traffic light upstream on the conflicting lane.
322      * @param trafficLightDistance Length; distance of a traffic light upstream on the conflicting lane.
323      * @param permittedConflict boolean; whether the conflict is permitted by the traffic light
324      */
325     public final void setConflictingTrafficLight(final Length trafficLightDistance, final boolean permittedConflict)
326     {
327         this.conflictingTrafficLightDistance = trafficLightDistance;
328         this.permitted = permittedConflict;
329     }
330 
331     /**
332      * Returns the width at the given fraction.
333      * @param fraction double; fraction from 0 to 1
334      * @return Length; width at the given fraction
335      */
336     public final Length getWidthAtFraction(final double fraction)
337     {
338         try
339         {
340             return this.width.getWidth(fraction);
341         }
342         catch (ValueRuntimeException exception)
343         {
344             throw new RuntimeException("Unexpected exception: fraction could not be interpolated.", exception);
345         }
346     }
347 
348     /**
349      * Width progression of conflict.
350      * <p>
351      * Copyright (c) 2013-2023 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
352      * <br>
353      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
354      * </p>
355      * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
356      * @author <a href="https://tudelft.nl/staff/p.knoppers-1">Peter Knoppers</a>
357      * @author <a href="https://dittlab.tudelft.nl">Wouter Schakel</a>
358      */
359     public static class Width
360     {
361 
362         /** Fractions, from 0 to 1. */
363         private final double[] fractions;
364 
365         /** Vector with widths. */
366         private final LengthVector width;
367 
368         /**
369          * @param fractions double[]; fractions, from 0 to 1
370          * @param width LengthVector; vector of equal length with widths
371          */
372         public Width(final double[] fractions, final LengthVector width)
373         {
374             Throw.whenNull(fractions, "Fractions may not be null.");
375             Throw.whenNull(width, "Width may not be null.");
376             Throw.when(fractions.length != width.size(), IllegalArgumentException.class,
377                     "Array and vector are not of equal length.");
378             Throw.when(fractions.length < 2, IllegalArgumentException.class, "Input should at least contain 2 values.");
379             Throw.when(fractions[0] != 0.0 || fractions[fractions.length - 1] != 1.0, IllegalArgumentException.class,
380                     "Fractions should range from 0 to 1.");
381             for (int i = 1; i < fractions.length; i++)
382             {
383                 Throw.when(fractions[i] <= fractions[i - 1], IllegalArgumentException.class, "Fractions are not increasing.");
384             }
385             this.fractions = fractions;
386             this.width = width;
387         }
388 
389         /**
390          * Returns the width at the given fraction.
391          * @param fraction double; fraction from 0 to 1
392          * @return Length; width at the given fraction
393          * @throws ValueRuntimeException when index is out of bounds
394          */
395         public Length getWidth(final double fraction) throws ValueRuntimeException
396         {
397             Throw.when(fraction < 0.0 || fraction > 1.0, IllegalArgumentException.class, "Fraction should be between 0 and 1.");
398             if (fraction == 1.0)
399             {
400                 return this.width.get(this.width.size() - 1);
401             }
402             for (int i = 0; i < this.fractions.length - 1; i++)
403             {
404                 if (this.fractions[i] <= fraction && this.fractions[i + 1] > fraction)
405                 {
406                     double r = (fraction - this.fractions[i]) / (this.fractions[i + 1] - this.fractions[i]);
407                     return Length.interpolate(this.width.get(i), this.width.get(i + 1), r);
408                 }
409             }
410             throw new RuntimeException("Unexpected exception: fraction could not be interpolated.");
411         }
412 
413         /**
414          * Returns a linear width progression.
415          * @param startWidth Length; start width
416          * @param endWidth Length; end width
417          * @return Width; linear width progression
418          */
419         public static Width linear(final Length startWidth, final Length endWidth)
420         {
421             Throw.whenNull(startWidth, "Start width may not be null.");
422             Throw.whenNull(endWidth, "End width may not be null.");
423             try
424             {
425                 return new Width(new double[] {0.0, 1.0},
426                         DoubleVector.instantiate(new Length[] {startWidth, endWidth}, LengthUnit.SI, StorageType.DENSE));
427             }
428             catch (ValueRuntimeException exception)
429             {
430                 throw new RuntimeException("Unexpected exception: widths could not be put in a vector.", exception);
431             }
432         }
433 
434     }
435 
436     /** {@inheritDoc} */
437     @Override
438     public final String toString()
439     {
440         return String.format("Headway %s to object %s of type %s", getDistance(), getId(), getObjectType());
441     }
442 
443 }