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