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.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  import nl.tudelft.simulation.language.Throw;
15  
16  /**
17   * Simplified plan containing an acceleration value and possible lane change direction.
18   * <p>
19   * Copyright (c) 2013-2018 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
51       * @param 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
60       * @param duration duration
61       * @param laneChangeDirection 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;
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       * @return duration.
85       */
86      public Duration getDuration()
87      {
88          return this.duration;
89      }
90  
91      /**
92       * @return if lane change.
93       */
94      public final boolean isLaneChange()
95      {
96          return this.laneChangeDirection != LateralDirectionality.NONE;
97      }
98  
99      /**
100      * @return laneChangeDirection, may be NONE if no lane change.
101      */
102     public final LateralDirectionality getLaneChangeDirection()
103     {
104         return this.laneChangeDirection;
105     }
106 
107     /**
108      * Set minimum of current and given acceleration.
109      * @param a acceleration to set if lower than current acceleration
110      */
111     public final void minimizeAcceleration(final Acceleration a)
112     {
113         checkAcceleration(a);
114         this.acceleration = Acceleration.min(this.acceleration, a);
115     }
116     
117     /**
118      * Check acceleration level.
119      * @param a acceleration
120      */
121     private void checkAcceleration(final Acceleration a)
122     {
123         if (a.equals(Acceleration.NEGATIVE_INFINITY) || a.equals(Acceleration.NEG_MAXVALUE))
124         {
125             throw new RuntimeException("Model has calculated a negative infinite or negative max value acceleration.");
126         }
127     }
128 
129     /**
130      * @return indicatorIntent.
131      */
132     public final TurnIndicatorIntent getIndicatorIntent()
133     {
134         return this.indicatorIntent;
135     }
136 
137     /**
138      * Set left indicator intent. Any intent given with distance overrules this intent.
139      */
140     public final void setIndicatorIntentLeft()
141     {
142         if (this.indicatorObjectDistance != null)
143         {
144             return;
145         }
146         if (this.indicatorIntent.isRight())
147         {
148             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
149         }
150         else
151         {
152             this.indicatorIntent = TurnIndicatorIntent.LEFT;
153         }
154     }
155 
156     /**
157      * Set right indicator intent. Any intent given with distance overrules this intent.
158      */
159     public final void setIndicatorIntentRight()
160     {
161         if (this.indicatorObjectDistance != null)
162         {
163             return;
164         }
165         if (this.indicatorIntent.isLeft())
166         {
167             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
168         }
169         else
170         {
171             this.indicatorIntent = TurnIndicatorIntent.RIGHT;
172         }
173     }
174 
175     /**
176      * Set left indicator intent. Intent with smallest provided distance has priority.
177      * @param distance distance to object pertaining to the turn indicator intent
178      */
179     public final void setIndicatorIntentLeft(final Length distance)
180     {
181         if (compareAndIgnore(distance))
182         {
183             return;
184         }
185         if (this.indicatorIntent.isRight())
186         {
187             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
188         }
189         else
190         {
191             this.indicatorIntent = TurnIndicatorIntent.LEFT;
192         }
193 
194     }
195 
196     /**
197      * Set right indicator intent. Intent with smallest provided distance has priority.
198      * @param distance distance to object pertaining to the turn indicator intent
199      */
200     public final void setIndicatorIntentRight(final Length distance)
201     {
202         if (compareAndIgnore(distance))
203         {
204             return;
205         }
206         if (this.indicatorIntent.isLeft())
207         {
208             this.indicatorIntent = TurnIndicatorIntent.CONFLICTING;
209         }
210         else
211         {
212             this.indicatorIntent = TurnIndicatorIntent.RIGHT;
213         }
214     }
215 
216     /**
217      * Compares distances and returns whether the given distance (and intent) can be ignored.
218      * @param distance distance to object of intent
219      * @return whether the given distance can be ignored
220      */
221     private boolean compareAndIgnore(final Length distance)
222     {
223         if (this.indicatorObjectDistance != null)
224         {
225             if (this.indicatorObjectDistance.lt(distance))
226             {
227                 // disregard input; the intent from larger distance
228                 return true;
229             }
230             if (this.indicatorObjectDistance.gt(distance))
231             {
232                 // disregard existing; the intent from larger distance
233                 this.indicatorIntent = TurnIndicatorIntent.NONE; // prevents a set to CONFLICTING
234             }
235         }
236         else
237         {
238             // disregard existing; the intent without distance
239             this.indicatorIntent = TurnIndicatorIntent.NONE; // prevents a set to CONFLICTING
240         }
241         return false;
242     }
243 
244     /** {@inheritDoc} */
245     @Override
246     @SuppressWarnings("checkstyle:designforextension")
247     public String toString()
248     {
249         return "SimpleOperationalPlan [Acceleration=" + this.acceleration + ", change=" + this.laneChangeDirection
250                 + ", indicator intent=" + this.indicatorIntent + "]";
251     }
252 
253     /**
254      * @param gtu LaneBasedGTU to set the indicator on
255      * @throws GTUException if GTU does not support the indicator
256      */
257     public final void setTurnIndicator(final LaneBasedGTU gtu) throws GTUException
258     {
259         if (this.indicatorIntent.isLeft())
260         {
261             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.LEFT);
262         }
263         else if (this.indicatorIntent.isRight())
264         {
265             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.RIGHT);
266         }
267         else
268         {
269             gtu.setTurnIndicatorStatus(TurnIndicatorStatus.NONE);
270         }
271     }
272 
273 }