View Javadoc
1   package org.opentrafficsim.road.gtu.perception.object;
2   
3   import java.util.Optional;
4   
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.djutils.exceptions.Try;
7   import org.opentrafficsim.base.geometry.OtsLine2d;
8   import org.opentrafficsim.core.network.LateralDirectionality;
9   import org.opentrafficsim.road.gtu.LaneBasedGtu;
10  import org.opentrafficsim.road.gtu.perception.PerceptionCollectable;
11  import org.opentrafficsim.road.gtu.perception.categories.neighbors.PerceivedGtuType;
12  import org.opentrafficsim.road.network.CrossSectionLink;
13  import org.opentrafficsim.road.network.Lane;
14  import org.opentrafficsim.road.network.conflict.Conflict;
15  import org.opentrafficsim.road.network.conflict.ConflictPriority;
16  import org.opentrafficsim.road.network.conflict.ConflictRule;
17  import org.opentrafficsim.road.network.conflict.ConflictType;
18  import org.opentrafficsim.road.network.speed.SpeedLimit;
19  
20  /**
21   * Interface for perceived {@code Conflict} objects. A standard implementation is provided under {@code of(...)} which wraps a
22   * {@code Conflict} and returns most values as is.
23   * <p>
24   * Copyright (c) 2024-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 Wouter Schakel
29   */
30  public interface PerceivedConflict extends PerceivedLaneBasedObject
31  {
32  
33      /**
34       * Returns the conflict type.
35       * @return conflict type
36       */
37      ConflictType getConflictType();
38  
39      /**
40       * Returns whether this is a crossing conflict.
41       * @return whether this is a crossing conflict
42       */
43      boolean isCrossing();
44  
45      /**
46       * Returns whether this is a merge conflict.
47       * @return whether this is a merge conflict
48       */
49      boolean isMerge();
50  
51      /**
52       * Returns whether this is a split conflict.
53       * @return whether this is a split conflict
54       */
55      boolean isSplit();
56  
57      /**
58       * Returns the conflict priority.
59       * @return conflict priority
60       */
61      ConflictPriority getConflictPriority();
62  
63      /**
64       * Returns the length of the conflict on the conflicting lane.
65       * @return length of the conflict on the conflicting lane
66       */
67      Length getConflictingLength();
68  
69      /**
70       * Returns a set of conflicting GTU's upstream of the <i>start</i> of the conflict ordered close to far from the conflict.
71       * @return set of conflicting GTU's upstream of the <i>start</i> of the conflict ordered close to far from the conflict
72       */
73      PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getUpstreamConflictingGtus();
74  
75      /**
76       * Returns a set of conflicting GTU's downstream of the <i>start</i> of the conflict ordered close to far from the conflict.
77       * Distance is given relative to the <i>end</i> of the conflict, or null for conflicting vehicles on the conflict. In the
78       * latter case the overlap is used.
79       * @return set of conflicting GTU's downstream of the <i>start</i> of the conflict ordered close to far from the conflict
80       */
81      PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getDownstreamConflictingGtus();
82  
83      /**
84       * Returns the visibility on the conflicting lane within which conflicting vehicles are visible. All upstream conflicting
85       * GTUs have a distance smaller than the visibility. Depending on a limited visibility, a certain (lower) speed may be
86       * required while approaching the conflict.
87       * @return visibility on the conflicting lane within which conflicting vehicles are visible
88       */
89      Length getConflictingVisibility();
90  
91      /**
92       * Returns the speed limit on the conflicting lane.
93       * @return speed limit on the conflicting lane
94       */
95      SpeedLimit getConflictingSpeedLimit();
96  
97      /**
98       * Returns the conflicting link.
99       * @return the conflicting link
100      */
101     CrossSectionLink getConflictingLink();
102 
103     /**
104      * Returns the stop line.
105      * @return stop line
106      */
107     PerceivedObject getStopLine();
108 
109     /**
110      * Returns the turn direction of this conflict relative to the other conflict. This is NONE for crossing conflicts.
111      * @return turn direction of this conflict relative to the other conflict
112      */
113     LateralDirectionality getTurn();
114 
115     /**
116      * Returns the stop line on the conflicting lane.
117      * @return stop line
118      */
119     PerceivedObject getConflictingStopLine();
120 
121     /**
122      * Returns the conflict rule type.
123      * @return conflict rule type
124      */
125     Class<? extends ConflictRule> getConflictRuleType();
126 
127     /**
128      * Returns the distance of a traffic light upstream on the conflicting lane.
129      * @return distance of a traffic light upstream on the conflicting lane, empty if no traffic light
130      */
131     Optional<Length> getConflictingTrafficLightDistance();
132 
133     /**
134      * Whether the conflict is permitted by the traffic light.
135      * @return whether the conflict is permitted by the traffic light
136      */
137     boolean isPermitted();
138 
139     /**
140      * Returns the width at the given fraction.
141      * @param fraction fraction from 0 to 1
142      * @return width at the given fraction
143      */
144     Length getWidthAtFraction(double fraction);
145 
146     /**
147      * Returns a standard implementation of this interface that wraps a {@code Conflict} and uses a given perceived GTU type to
148      * perceive the upstream and downstream GTUs.
149      * @param perceivingGtu perceiving GTU
150      * @param conflict conflict to perceive
151      * @param perceivedGtuType perceived GTU type
152      * @param distance distance from perceiving GTU to conflict
153      * @param conflictingVisibility visibility range at other conflict
154      * @return perceived conflict
155      */
156     @SuppressWarnings("methodlength")
157     static PerceivedConflict of(final LaneBasedGtu perceivingGtu, final Conflict conflict,
158             final PerceivedGtuType perceivedGtuType, final Length distance, final Length conflictingVisibility)
159     {
160         final Kinematics kinematics = Kinematics.staticAhead(distance);
161         // TODO stop lines (current models happen not to use this, but should be possible)
162         final PerceivedObject stopLine =
163                 new PerceivedObjectBase("stopLineId", ObjectType.STOPLINE, Length.ZERO, Kinematics.staticAhead(Length.ZERO));
164         final PerceivedObject conflictingStopLine = new PerceivedObjectBase("conflictingStopLineId", ObjectType.STOPLINE,
165                 Length.ZERO, Kinematics.staticAhead(Length.ZERO));
166         final SpeedLimit conflictingSpeedLimit = Try.assign(() -> conflict.getOtherConflict().getLane().getSpeedLimit().get(),
167                 "Unable to obtain higest speed limit on conflicting lane.");
168         final Length conflictingTrafficLightDistance =
169                 conflict.getOtherConflict().getTrafficLightDistance(conflictingVisibility);
170 
171         final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> upstreamConflictingGTUs =
172                 conflict.getOtherConflict().getUpstreamGtus(perceivingGtu, perceivedGtuType, conflictingVisibility);
173         final PerceptionCollectable<PerceivedGtu, LaneBasedGtu> downstreamConflictingGTUs =
174                 conflict.getOtherConflict().getDownstreamGtus(perceivingGtu, perceivedGtuType, conflictingVisibility);
175 
176         Length pos1a = conflict.getLongitudinalPosition();
177         Length pos2a = conflict.getOtherConflict().getLongitudinalPosition();
178         Length pos1b = Length.min(pos1a.plus(conflict.getLength()), conflict.getLane().getLength());
179         Length pos2b = Length.min(pos2a.plus(conflict.getOtherConflict().getLength()),
180                 conflict.getOtherConflict().getLane().getLength());
181         OtsLine2d line1 = conflict.getLane().getCenterLine();
182         OtsLine2d line2 = conflict.getOtherConflict().getLane().getCenterLine();
183         double dStart = line1.getLocation(pos1a).distance(line2.getLocation(pos2a));
184         double dEnd = line1.getLocation(pos1b).distance(line2.getLocation(pos2b));
185         double startWidth = dStart + .5 * conflict.getLane().getWidth(pos1a).si
186                 + .5 * conflict.getOtherConflict().getLane().getWidth(pos2a).si;
187         double endWidth = dEnd + .5 * conflict.getLane().getWidth(pos1b).si
188                 + .5 * conflict.getOtherConflict().getLane().getWidth(pos2b).si;
189 
190         return new PerceivedConflict()
191         {
192             @Override
193             public Lane getLane()
194             {
195                 return conflict.getLane();
196             }
197 
198             @Override
199             public ObjectType getObjectType()
200             {
201                 return ObjectType.CONFLICT;
202             }
203 
204             @Override
205             public Length getLength()
206             {
207                 return conflict.getLength();
208             }
209 
210             @Override
211             public Kinematics getKinematics()
212             {
213                 return kinematics;
214             }
215 
216             @Override
217             public String getId()
218             {
219                 return conflict.getId();
220             }
221 
222             @Override
223             public ConflictType getConflictType()
224             {
225                 return conflict.getConflictType();
226             }
227 
228             @Override
229             public boolean isCrossing()
230             {
231                 return conflict.getConflictType().isCrossing();
232             }
233 
234             @Override
235             public boolean isMerge()
236             {
237                 return conflict.getConflictType().isMerge();
238             }
239 
240             @Override
241             public boolean isSplit()
242             {
243                 return conflict.getConflictType().isSplit();
244             }
245 
246             @Override
247             public ConflictPriority getConflictPriority()
248             {
249                 return conflict.conflictPriority();
250             }
251 
252             @Override
253             public Length getConflictingLength()
254             {
255                 return conflict.getOtherConflict().getLength();
256             }
257 
258             @Override
259             public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getUpstreamConflictingGtus()
260             {
261                 return upstreamConflictingGTUs;
262             }
263 
264             @Override
265             public PerceptionCollectable<PerceivedGtu, LaneBasedGtu> getDownstreamConflictingGtus()
266             {
267                 return downstreamConflictingGTUs;
268             }
269 
270             @Override
271             public Length getConflictingVisibility()
272             {
273                 return conflictingVisibility;
274             }
275 
276             @Override
277             public SpeedLimit getConflictingSpeedLimit()
278             {
279                 return conflictingSpeedLimit;
280             }
281 
282             @Override
283             public CrossSectionLink getConflictingLink()
284             {
285                 return conflict.getOtherConflict().getLane().getLink();
286             }
287 
288             @Override
289             public PerceivedObject getStopLine()
290             {
291                 return stopLine;
292             }
293 
294             @Override
295             public LateralDirectionality getTurn()
296             {
297                 return conflict.getTurn();
298             }
299 
300             @Override
301             public PerceivedObject getConflictingStopLine()
302             {
303                 return conflictingStopLine;
304             }
305 
306             @Override
307             public Class<? extends ConflictRule> getConflictRuleType()
308             {
309                 return conflict.getConflictRule().getClass();
310             }
311 
312             @Override
313             public Optional<Length> getConflictingTrafficLightDistance()
314             {
315                 return Optional.of(conflictingTrafficLightDistance);
316             }
317 
318             @Override
319             public boolean isPermitted()
320             {
321                 return conflict.isPermitted();
322             }
323 
324             @Override
325             public Length getWidthAtFraction(final double fraction)
326             {
327                 return Length.ofSI((1.0 - fraction) * startWidth + fraction * endWidth);
328             }
329         };
330     }
331 
332 }