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