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