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