1   package org.opentrafficsim.road.gtu.lane.tactical.util;
2   
3   import java.io.Serializable;
4   
5   import org.djunits.unit.DurationUnit;
6   import org.djunits.unit.LengthUnit;
7   import org.djunits.value.vdouble.scalar.Acceleration;
8   import org.djunits.value.vdouble.scalar.Duration;
9   import org.djunits.value.vdouble.scalar.Length;
10  import org.djunits.value.vdouble.scalar.Speed;
11  import org.opentrafficsim.base.parameters.ParameterException;
12  import org.opentrafficsim.base.parameters.Parameters;
13  import org.opentrafficsim.road.gtu.lane.tactical.following.CarFollowingModel;
14  import org.opentrafficsim.road.network.speed.SpeedLimitInfo;
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  public final class AnticipationInfo implements Serializable
28  {
29  
30      
31      private static final long serialVersionUID = 20160811L;
32  
33      
34      private final Duration duration;
35  
36      
37      private final Speed endSpeed;
38  
39      
40  
41  
42  
43      public AnticipationInfo(final Duration duration, final Speed endSpeed)
44      {
45          this.duration = duration;
46          this.endSpeed = endSpeed;
47      }
48  
49      
50  
51  
52      public Duration getDuration()
53      {
54          return this.duration;
55      }
56  
57      
58  
59  
60      public Speed getEndSpeed()
61      {
62          return this.endSpeed;
63      }
64  
65      
66  
67  
68  
69  
70  
71  
72      public static AnticipationInfo anticipateMovement(final Length distance, final Speed initialSpeed,
73              final Acceleration acceleration)
74      {
75          return anticipateMovementSpeedLimited(distance, initialSpeed, acceleration, Speed.POSITIVE_INFINITY);
76      }
77  
78      
79  
80  
81  
82  
83  
84  
85  
86      public static AnticipationInfo anticipateMovementSpeedLimited(final Length distance, final Speed initialSpeed,
87              final Acceleration acceleration, final Speed maxSpeed)
88      {
89          if (distance.lt0())
90          {
91              return new AnticipationInfo(Duration.ZERO, initialSpeed);
92          }
93          
94          if (acceleration.eq(Acceleration.ZERO))
95          {
96              if (initialSpeed.gt0())
97              {
98                  return new AnticipationInfo(distance.divideBy(initialSpeed), initialSpeed);
99              }
100             
101             return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
102         }
103         
104         double tmp = initialSpeed.si * initialSpeed.si + 2.0 * acceleration.si * distance.si;
105         if (tmp < 0)
106         {
107             
108             return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
109         }
110         
111         Duration d = new Duration((Math.sqrt(tmp) - initialSpeed.si) / acceleration.si, DurationUnit.SI);
112         
113         Speed endSpeed = initialSpeed.plus(acceleration.multiplyBy(d));
114         if (endSpeed.le(maxSpeed))
115         {
116             return new AnticipationInfo(d, endSpeed);
117         }
118         
119         Duration d1 = maxSpeed.minus(initialSpeed).divideBy(acceleration);
120         Length x2 = new Length(distance.si - initialSpeed.si * d1.si - .5 * acceleration.si * d1.si * d1.si, LengthUnit.SI);
121         return new AnticipationInfo(d1.plus(x2.divideBy(maxSpeed)), maxSpeed);
122     }
123 
124     
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135     public static AnticipationInfo anticipateMovementFreeAcceleration(final Length distance, final Speed initialSpeed,
136             final Parameters parameters, final CarFollowingModel carFollowingModel, final SpeedLimitInfo speedLimitInfo,
137             final Duration timeStep) throws ParameterException
138     {
139         if (distance.lt0())
140         {
141             return new AnticipationInfo(Duration.ZERO, initialSpeed);
142         }
143         Duration out = Duration.ZERO;
144         if (distance.lt0())
145         {
146             return new AnticipationInfo(out, initialSpeed);
147         }
148         Length xCumul = Length.ZERO;
149         Speed speed = initialSpeed;
150         while (xCumul.lt(distance))
151         {
152             Acceleration a = CarFollowingUtil.freeAcceleration(carFollowingModel, parameters, speed, speedLimitInfo);
153             Length add = new Length(speed.si * timeStep.si + .5 * a.si * timeStep.si * timeStep.si, LengthUnit.SI);
154             Length remain = distance.minus(xCumul);
155             if (add.lt(remain))
156             {
157                 xCumul = xCumul.plus(add);
158                 speed = speed.plus(a.multiplyBy(timeStep));
159                 out = out.plus(timeStep);
160             }
161             else
162             {
163                 Duration timeInStep;
164                 double tmp = Math.sqrt(2 * a.si * remain.si + speed.si * speed.si) - speed.si;
165                 if (tmp < 0.000001)
166                 {
167                     
168                     timeInStep = remain.divideBy(speed);
169                 }
170                 else
171                 {
172                     timeInStep = new Duration(tmp / a.si, DurationUnit.SI);
173                     speed = speed.plus(a.multiplyBy(timeInStep));
174                 }
175                 out = out.plus(timeInStep);
176                 return new AnticipationInfo(out, speed);
177             }
178         }
179         
180         throw new RuntimeException("Distance for anticipation of conflict movement is surpassed.");
181     }
182 
183     
184     @Override
185     public String toString()
186     {
187         return "AnticipationInfo [duration = " + this.duration + ", endSpeed = " + this.endSpeed + "]";
188     }
189 
190 }