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