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