View Javadoc
1   package org.opentrafficsim.road.gtu.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.vector.LengthVector;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.base.OtsRuntimeException;
11  import org.opentrafficsim.core.network.LateralDirectionality;
12  import org.opentrafficsim.road.gtu.LaneBasedGtu;
13  import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
14  import org.opentrafficsim.road.network.CrossSectionLink;
15  import org.opentrafficsim.road.network.Lane;
16  import org.opentrafficsim.road.network.conflict.ConflictPriority;
17  import org.opentrafficsim.road.network.conflict.ConflictRule;
18  import org.opentrafficsim.road.network.conflict.ConflictType;
19  import org.opentrafficsim.road.network.speed.SpeedLimit;
20  
21  /**
22   * Perceived intersection conflict with given input values.
23   * <p>
24   * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
25   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
26   * </p>
27   * @author Alexander Verbraeck
28   * @author Peter Knoppers
29   * @author Wouter Schakel
30   */
31  public class PerceivedConflictFull extends PerceivedLaneBasedObjectBase implements PerceivedConflict
32  {
33  
34      /** Conflict type. */
35      private final ConflictType conflictType;
36  
37      /** Conflict priority. */
38      private final ConflictPriority conflictPriority;
39  
40      /** Length of the conflict in the conflicting directions. */
41      private final Length conflictingLength;
42  
43      /**
44       * Set of conflicting GTU's <i>completely</i> upstream of the <i>start</i> of the conflict ordered close to far from the
45       * start of the conflict. Distance and overlap info concerns the conflict.
46       */
47      private final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> upstreamConflictingGTUs;
48  
49      /**
50       * Set of conflicting GTU's (partially) downstream of the <i>start</i> of the conflict ordered close to far from the start
51       * of conflict. Distance and overlap info concerns the conflict.
52       */
53      private final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> downstreamConflictingGTUs;
54  
55      /** Visibility on the conflicting lane within which conflicting vehicles are visible. */
56      private final Length conflictingVisibility;
57  
58      /** Speed limit on the conflicting lane. */
59      private final SpeedLimit conflictingSpeedLimit;
60  
61      /** Link of conflicting conflict. */
62      private final CrossSectionLink conflictingLink;
63  
64      /** Stop line on the own lane. */
65      private final PerceivedObject stopLine;
66  
67      /** Stop line on the conflicting lane. */
68      private final PerceivedObject conflictingStopLine;
69  
70      /** Turn direction. */
71      private final LateralDirectionality turn;
72  
73      /** Type of conflict rule. */
74      private final Class<? extends ConflictRule> conflictRuleType;
75  
76      /** Distance of traffic light upstream on conflicting lane. */
77      private Length conflictingTrafficLightDistance = null;
78  
79      /** Whether the conflict is permitted by the traffic light. */
80      private boolean permitted = false;
81  
82      /** Width progression of conflict. */
83      private final Width width;
84  
85      /**
86       * Constructor.
87       * @param id id
88       * @param distance distance to conflict
89       * @param length length of the conflict
90       * @param conflictType conflict type
91       * @param conflictPriority conflict priority
92       * @param conflictRuleType conflict rule type
93       * @param conflictingLength length of the conflict on the conflicting lane
94       * @param upstreamConflictingGTUs conflicting GTU's upstream of the &lt;i&gt;start&lt;/i&gt; of the conflict
95       * @param downstreamConflictingGTUs conflicting GTU's downstream of the &lt;i&gt;start&lt;/i&gt; of the conflict
96       * @param conflictingVisibility visibility on the conflicting lane within which conflicting vehicles are visible
97       * @param conflictingSpeedLimit speed limit on the conflicting lane
98       * @param conflictingLink conflicting link
99       * @param width width progression of conflict
100      * @param stopLine stop line on the own lane
101      * @param conflictingStopLine stop line on the conflicting lane
102      * @param turn turn direction relative to other conflict
103      * @param lane the lane
104      */
105     @SuppressWarnings("parameternumber")
106     public PerceivedConflictFull(final String id, final Length distance, final Length length, final ConflictType conflictType,
107             final ConflictPriority conflictPriority, final Class<? extends ConflictRule> conflictRuleType,
108             final Length conflictingLength, final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> upstreamConflictingGTUs,
109             final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> downstreamConflictingGTUs,
110             final Length conflictingVisibility, final SpeedLimit conflictingSpeedLimit, final CrossSectionLink conflictingLink,
111             final Width width, final PerceivedObject stopLine, final PerceivedObject conflictingStopLine,
112             final LateralDirectionality turn, final Lane lane)
113     {
114         super(id, ObjectType.CONFLICT, length, Kinematics.staticAhead(distance), lane);
115         Throw.whenNull(conflictType, "Conflict type may not be null.");
116         Throw.whenNull(conflictPriority, "Conflict priority may not be null.");
117         Throw.whenNull(conflictRuleType, "Conflict rule type may not be null.");
118         Throw.whenNull(conflictingLength, "Conflict length may not be null.");
119         Throw.whenNull(upstreamConflictingGTUs, "Upstreaem conflicting GTU's may not be null.");
120         Throw.whenNull(downstreamConflictingGTUs, "Downstream conflicting GTU's may not be null.");
121         Throw.whenNull(width, "Width may not be null.");
122         Throw.whenNull(conflictingVisibility, "Conflict visibility may not be null.");
123         Throw.whenNull(conflictingSpeedLimit, "Conflict speed limit may not be null.");
124         Throw.whenNull(turn, "turn");
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         this.turn = turn;
138     }
139 
140     @Override
141     public ConflictType getConflictType()
142     {
143         return this.conflictType;
144     }
145 
146     @Override
147     public boolean isCrossing()
148     {
149         return this.conflictType.equals(ConflictType.CROSSING);
150     }
151 
152     @Override
153     public boolean isMerge()
154     {
155         return this.conflictType.equals(ConflictType.MERGE);
156     }
157 
158     @Override
159     public boolean isSplit()
160     {
161         return this.conflictType.equals(ConflictType.SPLIT);
162     }
163 
164     @Override
165     public ConflictPriority getConflictPriority()
166     {
167         return this.conflictPriority;
168     }
169 
170     @Override
171     public Length getConflictingLength()
172     {
173         return this.conflictingLength;
174     }
175 
176     @Override
177     public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getUpstreamConflictingGtus()
178     {
179         return this.upstreamConflictingGTUs;
180     }
181 
182     @Override
183     public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getDownstreamConflictingGtus()
184     {
185         return this.downstreamConflictingGTUs;
186     }
187 
188     @Override
189     public Length getConflictingVisibility()
190     {
191         return this.conflictingVisibility;
192     }
193 
194     @Override
195     public SpeedLimit getConflictingSpeedLimit()
196     {
197         return this.conflictingSpeedLimit;
198     }
199 
200     @Override
201     public CrossSectionLink getConflictingLink()
202     {
203         return this.conflictingLink;
204     }
205 
206     @Override
207     public PerceivedObject getStopLine()
208     {
209         return this.stopLine;
210     }
211 
212     @Override
213     public PerceivedObject getConflictingStopLine()
214     {
215         return this.conflictingStopLine;
216     }
217 
218     @Override
219     public LateralDirectionality getTurn()
220     {
221         return this.turn;
222     }
223 
224     @Override
225     public Class<? extends ConflictRule> getConflictRuleType()
226     {
227         return this.conflictRuleType;
228     }
229 
230     @Override
231     public Optional<Length> getConflictingTrafficLightDistance()
232     {
233         return Optional.of(this.conflictingTrafficLightDistance);
234     }
235 
236     @Override
237     public boolean isPermitted()
238     {
239         return this.permitted;
240     }
241 
242     /**
243      * Set the distance of a traffic light upstream on the conflicting lane.
244      * @param trafficLightDistance distance of a traffic light upstream on the conflicting lane.
245      * @param permittedConflict whether the conflict is permitted by the traffic light
246      */
247     public void setConflictingTrafficLight(final Length trafficLightDistance, final boolean permittedConflict)
248     {
249         this.conflictingTrafficLightDistance = trafficLightDistance;
250         this.permitted = permittedConflict;
251     }
252 
253     @Override
254     public Length getWidthAtFraction(final double fraction)
255     {
256         try
257         {
258             return this.width.getWidth(fraction);
259         }
260         catch (ValueRuntimeException exception)
261         {
262             throw new OtsRuntimeException("Unexpected exception: fraction could not be interpolated.", exception);
263         }
264     }
265 
266     /**
267      * Width progression of conflict.
268      * <p>
269      * Copyright (c) 2013-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
270      * <br>
271      * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
272      * </p>
273      * @author Alexander Verbraeck
274      * @author Peter Knoppers
275      * @author Wouter Schakel
276      */
277     public static class Width
278     {
279 
280         /** Fractions, from 0 to 1. */
281         private final double[] fractions;
282 
283         /** Vector with widths. */
284         private final LengthVector width;
285 
286         /**
287          * Constructor.
288          * @param fractions fractions, from 0 to 1
289          * @param width vector of equal length with widths
290          */
291         public Width(final double[] fractions, final LengthVector width)
292         {
293             Throw.whenNull(fractions, "Fractions may not be null.");
294             Throw.whenNull(width, "Width may not be null.");
295             Throw.when(fractions.length != width.size(), IllegalArgumentException.class,
296                     "Array and vector are not of equal length.");
297             Throw.when(fractions.length < 2, IllegalArgumentException.class, "Input should at least contain 2 values.");
298             Throw.when(fractions[0] != 0.0 || fractions[fractions.length - 1] != 1.0, IllegalArgumentException.class,
299                     "Fractions should range from 0 to 1.");
300             for (int i = 1; i < fractions.length; i++)
301             {
302                 Throw.when(fractions[i] <= fractions[i - 1], IllegalArgumentException.class, "Fractions are not increasing.");
303             }
304             this.fractions = fractions;
305             this.width = width;
306         }
307 
308         /**
309          * Returns the width at the given fraction.
310          * @param fraction fraction from 0 to 1
311          * @return width at the given fraction
312          * @throws ValueRuntimeException when index is out of bounds
313          */
314         public Length getWidth(final double fraction) throws ValueRuntimeException
315         {
316             Throw.when(fraction < 0.0 || fraction > 1.0, IllegalArgumentException.class, "Fraction should be between 0 and 1.");
317             if (fraction == 1.0)
318             {
319                 return this.width.get(this.width.size() - 1);
320             }
321             for (int i = 0; i < this.fractions.length - 1; i++)
322             {
323                 if (this.fractions[i] <= fraction && this.fractions[i + 1] > fraction)
324                 {
325                     double r = (fraction - this.fractions[i]) / (this.fractions[i + 1] - this.fractions[i]);
326                     return Length.interpolate(this.width.get(i), this.width.get(i + 1), r);
327                 }
328             }
329             throw new OtsRuntimeException("Unexpected exception: fraction could not be interpolated.");
330         }
331 
332         /**
333          * Returns a linear width progression.
334          * @param startWidth start width
335          * @param endWidth end width
336          * @return linear width progression
337          */
338         public static Width linear(final Length startWidth, final Length endWidth)
339         {
340             Throw.whenNull(startWidth, "Start width may not be null.");
341             Throw.whenNull(endWidth, "End width may not be null.");
342             try
343             {
344                 return new Width(new double[] {0.0, 1.0}, new LengthVector(new Length[] {startWidth, endWidth}, LengthUnit.SI));
345             }
346             catch (ValueRuntimeException exception)
347             {
348                 throw new OtsRuntimeException("Unexpected exception: widths could not be put in a vector.", exception);
349             }
350         }
351 
352     }
353 
354     @Override
355     public final String toString()
356     {
357         return String.format("Headway %s to object %s of type %s", getKinematics().getDistance(), getId(), getObjectType());
358     }
359 
360 }