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  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  public class SimpleOperationalPlan implements Serializable
30  {
31  
32      
33      private static final long serialVersionUID = 20160811L;
34  
35      
36      private Acceleration acceleration;
37  
38      
39      private final LateralDirectionality laneChangeDirection;
40  
41      
42      private TurnIndicatorIntent indicatorIntent = TurnIndicatorIntent.NONE;
43  
44      
45      private Length indicatorObjectDistance = null;
46  
47      
48      private final Duration duration;
49  
50      
51  
52  
53  
54      public SimpleOperationalPlan(final Acceleration acceleration, final Duration duration)
55      {
56          this(acceleration, duration, LateralDirectionality.NONE);
57      }
58  
59      
60  
61  
62  
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.instantiateSI(-100.0), acceleration);
72          this.duration = duration;
73          this.laneChangeDirection = laneChangeDirection;
74      }
75  
76      
77  
78  
79      public final Acceleration getAcceleration()
80      {
81          return this.acceleration;
82      }
83      
84      
85  
86  
87  
88      public final void setAcceleration(final Acceleration acceleration)
89      {
90          checkAcceleration(acceleration);
91          this.acceleration = acceleration;
92      }
93  
94      
95  
96  
97      public Duration getDuration()
98      {
99          return this.duration;
100     }
101 
102     
103 
104 
105     public final boolean isLaneChange()
106     {
107         return this.laneChangeDirection != LateralDirectionality.NONE;
108     }
109 
110     
111 
112 
113     public final LateralDirectionality getLaneChangeDirection()
114     {
115         return this.laneChangeDirection;
116     }
117 
118     
119 
120 
121 
122     public final void minimizeAcceleration(final Acceleration a)
123     {
124         checkAcceleration(a);
125         this.acceleration = Acceleration.max(Acceleration.instantiateSI(-100.0), Acceleration.min(this.acceleration, a)); 
126     }
127 
128     
129 
130 
131 
132     private void checkAcceleration(final Acceleration a)
133     {
134         if (a.equals(Acceleration.NEGATIVE_INFINITY) || a.equals(Acceleration.NEG_MAXVALUE))
135         {
136             SimLogger.always().error("Model has calculated a negative infinite or negative max value acceleration."); 
137         }
138     }
139 
140     
141 
142 
143     public final TurnIndicatorIntent getIndicatorIntent()
144     {
145         return this.indicatorIntent;
146     }
147 
148     
149 
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 
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 
188 
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 
209 
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 
229 
230 
231 
232     private boolean compareAndIgnore(final Length distance)
233     {
234         if (this.indicatorObjectDistance != null)
235         {
236             if (this.indicatorObjectDistance.lt(distance))
237             {
238                 
239                 return true;
240             }
241             if (this.indicatorObjectDistance.gt(distance))
242             {
243                 
244                 this.indicatorIntent = TurnIndicatorIntent.NONE; 
245             }
246         }
247         else
248         {
249             
250             this.indicatorIntent = TurnIndicatorIntent.NONE; 
251         }
252         return false;
253     }
254 
255     
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 
266 
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 }