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