View Javadoc
1   package org.opentrafficsim.road.gtu.lane.plan.operational;
2   
3   import org.djunits.value.vdouble.scalar.Acceleration;
4   import org.djunits.value.vdouble.scalar.Duration;
5   import org.djunits.value.vdouble.scalar.Length;
6   import org.djutils.exceptions.Throw;
7   import org.opentrafficsim.base.logger.Logger;
8   import org.opentrafficsim.core.gtu.GtuException;
9   import org.opentrafficsim.core.gtu.TurnIndicatorIntent;
10  import org.opentrafficsim.core.gtu.TurnIndicatorStatus;
11  import org.opentrafficsim.core.network.LateralDirectionality;
12  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
13  
14  /**
15   * Simplified plan containing an acceleration value and possible lane change direction.
16   * <p>
17   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
18   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
19   * </p>
20   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
21   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
22   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
23   */
24  
25  public class SimpleOperationalPlan
26  {
27  
28      /** Acceleration. */
29      private Acceleration acceleration;
30  
31      /** Duration of the plan. */
32      private final Duration duration;
33  
34      /** Deviation from center line. */
35      private final Length deviation;
36  
37      /** Lane change direction. */
38      private final LateralDirectionality laneChangeDirection;
39  
40      /** Indicator intent. */
41      private TurnIndicatorIntent indicatorIntent = TurnIndicatorIntent.NONE;
42  
43      /** Distance to object causing turn indicator intent. */
44      private Length indicatorObjectDistance = null;
45  
46      /**
47       * Constructor.
48       * @param acceleration acceleration
49       * @param duration duration
50       */
51      public SimpleOperationalPlan(final Acceleration acceleration, final Duration duration)
52      {
53          this(acceleration, duration, Length.ZERO, LateralDirectionality.NONE);
54      }
55  
56      /**
57       * Constructor.
58       * @param acceleration acceleration
59       * @param duration duration
60       * @param deviation deviation from center line, positive values is left
61       */
62      public SimpleOperationalPlan(final Acceleration acceleration, final Duration duration, final Length deviation)
63      {
64          this(acceleration, duration, deviation, LateralDirectionality.NONE);
65      }
66  
67      /**
68       * Constructor.
69       * @param acceleration acceleration
70       * @param duration duration
71       * @param laneChangeDirection lane change direction, may be {@code null}.
72       */
73      public SimpleOperationalPlan(final Acceleration acceleration, final Duration duration,
74              final LateralDirectionality laneChangeDirection)
75      {
76          this(acceleration, duration, Length.ZERO, laneChangeDirection);
77      }
78  
79      /**
80       * Constructor.
81       * @param acceleration acceleration
82       * @param duration duration
83       * @param deviation deviation from center line, positive values is left
84       * @param laneChangeDirection lane change direction, may be {@code null}.
85       */
86      public SimpleOperationalPlan(final Acceleration acceleration, final Duration duration, final Length deviation,
87              final LateralDirectionality laneChangeDirection)
88      {
89          Throw.whenNull(acceleration, "Acceleration may not be null.");
90          Throw.whenNull(duration, "Duration may not be null.");
91          Throw.whenNull(deviation, "Deviation may not be null.");
92          Throw.whenNull(laneChangeDirection, "Lane change direction may not be null.");
93          checkAcceleration(acceleration);
94          this.acceleration = Acceleration.max(Acceleration.ofSI(-100.0), acceleration);
95          this.duration = duration;
96          this.deviation = deviation;
97          this.laneChangeDirection = laneChangeDirection;
98      }
99  
100     /**
101      * Return acceleration.
102      * @return acceleration.
103      */
104     public final Acceleration getAcceleration()
105     {
106         return this.acceleration;
107     }
108 
109     /**
110      * Sets acceleration.
111      * @param acceleration acceleration
112      */
113     public final void setAcceleration(final Acceleration acceleration)
114     {
115         checkAcceleration(acceleration);
116         this.acceleration = acceleration;
117     }
118 
119     /**
120      * Return duration.
121      * @return duration.
122      */
123     public Duration getDuration()
124     {
125         return this.duration;
126     }
127 
128     /**
129      * Return deviation.
130      * @return deviation.
131      */
132     public Length getDeviation()
133     {
134         return this.deviation;
135     }
136 
137     /**
138      * Return whether this plan is a lane change plan.
139      * @return if lane change.
140      */
141     public final boolean isLaneChange()
142     {
143         return this.laneChangeDirection != LateralDirectionality.NONE;
144     }
145 
146     /**
147      * Return lane change direction.
148      * @return laneChangeDirection, may be NONE if no lane change.
149      */
150     public final LateralDirectionality getLaneChangeDirection()
151     {
152         return this.laneChangeDirection;
153     }
154 
155     /**
156      * Set minimum of current and given acceleration.
157      * @param a acceleration to set if lower than current acceleration
158      */
159     public final void minimizeAcceleration(final Acceleration a)
160     {
161         checkAcceleration(a);
162         this.acceleration = Acceleration.max(Acceleration.ofSI(-100.0), Acceleration.min(this.acceleration, a));
163     }
164 
165     /**
166      * Check acceleration level.
167      * @param a acceleration
168      */
169     private void checkAcceleration(final Acceleration a)
170     {
171         if (a.equals(Acceleration.NEGATIVE_INFINITY) || a.equals(Acceleration.NEG_MAXVALUE))
172         {
173             Logger.ots().error("Model has calculated a negative infinite or negative max value acceleration.");
174         }
175     }
176 
177     /**
178      * Returns indicator intent.
179      * @return indicatorIntent.
180      */
181     public final TurnIndicatorIntent getIndicatorIntent()
182     {
183         return this.indicatorIntent;
184     }
185 
186     /**
187      * Set left indicator intent. Any intent given with distance overrules this intent.
188      */
189     public final void setIndicatorIntentLeft()
190     {
191         if (this.indicatorObjectDistance != null)
192         {
193             return;
194         }
195         if (this.indicatorIntent.isRight())
196         {
197             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
198         }
199         else
200         {
201             this.indicatorIntent = TurnIndicatorIntent.LEFT;
202         }
203     }
204 
205     /**
206      * Set right indicator intent. Any intent given with distance overrules this intent.
207      */
208     public final void setIndicatorIntentRight()
209     {
210         if (this.indicatorObjectDistance != null)
211         {
212             return;
213         }
214         if (this.indicatorIntent.isLeft())
215         {
216             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
217         }
218         else
219         {
220             this.indicatorIntent = TurnIndicatorIntent.RIGHT;
221         }
222     }
223 
224     /**
225      * Set left indicator intent. Intent with smallest provided distance has priority.
226      * @param distance distance to object pertaining to the turn indicator intent
227      */
228     public final void setIndicatorIntentLeft(final Length distance)
229     {
230         if (compareAndIgnore(distance))
231         {
232             return;
233         }
234         if (this.indicatorIntent.isRight())
235         {
236             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
237         }
238         else
239         {
240             this.indicatorIntent = TurnIndicatorIntent.LEFT;
241         }
242 
243     }
244 
245     /**
246      * Set right indicator intent. Intent with smallest provided distance has priority.
247      * @param distance distance to object pertaining to the turn indicator intent
248      */
249     public final void setIndicatorIntentRight(final Length distance)
250     {
251         if (compareAndIgnore(distance))
252         {
253             return;
254         }
255         if (this.indicatorIntent.isLeft())
256         {
257             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
258         }
259         else
260         {
261             this.indicatorIntent = TurnIndicatorIntent.RIGHT;
262         }
263     }
264 
265     /**
266      * Compares distances and returns whether the given distance (and intent) can be ignored.
267      * @param distance distance to object of intent
268      * @return whether the given distance can be ignored
269      */
270     private boolean compareAndIgnore(final Length distance)
271     {
272         if (this.indicatorObjectDistance != null)
273         {
274             if (this.indicatorObjectDistance.lt(distance))
275             {
276                 // disregard input; the intent from larger distance
277                 return true;
278             }
279             if (this.indicatorObjectDistance.gt(distance))
280             {
281                 // disregard existing; the intent from larger distance
282                 this.indicatorIntent = TurnIndicatorIntent.NONE; // prevents a set to CONFLICTING
283             }
284         }
285         else
286         {
287             // disregard existing; the intent without distance
288             this.indicatorIntent = TurnIndicatorIntent.NONE; // prevents a set to CONFLICTING
289         }
290         return false;
291     }
292 
293     @Override
294     @SuppressWarnings("checkstyle:designforextension")
295     public String toString()
296     {
297         return "SimpleOperationalPlan [Acceleration=" + this.acceleration + ", change=" + this.laneChangeDirection
298                 + ", indicator intent=" + this.indicatorIntent + "]";
299     }
300 
301     /**
302      * Set turn indicator.
303      * @param gtu LaneBasedGtu to set the indicator on
304      * @throws GtuException if GTU does not support the indicator
305      */
306     public final void setTurnIndicator(final LaneBasedGtu gtu) throws GtuException
307     {
308         if (this.indicatorIntent.isLeft())
309         {
310             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.LEFT);
311         }
312         else if (this.indicatorIntent.isRight())
313         {
314             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.RIGHT);
315         }
316         else
317         {
318             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.NONE);
319         }
320     }
321 
322 }