1 package org.opentrafficsim.road.gtu.tactical.util;
2
3 import org.djunits.unit.DurationUnit;
4 import org.djunits.unit.LengthUnit;
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.djunits.value.vdouble.scalar.Speed;
9 import org.opentrafficsim.base.OtsRuntimeException;
10 import org.opentrafficsim.base.parameters.ParameterException;
11 import org.opentrafficsim.road.gtu.tactical.TacticalContext;
12
13
14
15
16
17
18
19
20
21
22
23
24
25 public record AnticipationInfo(Duration duration, Speed endSpeed)
26 {
27
28
29
30
31
32
33
34
35 public static AnticipationInfo anticipateMovement(final Length distance, final Speed initialSpeed,
36 final Acceleration acceleration)
37 {
38 return anticipateMovementSpeedLimited(distance, initialSpeed, acceleration, Speed.POSITIVE_INFINITY);
39 }
40
41
42
43
44
45
46
47
48
49 public static AnticipationInfo anticipateMovementSpeedLimited(final Length distance, final Speed initialSpeed,
50 final Acceleration acceleration, final Speed maxSpeed)
51 {
52 if (distance.lt0())
53 {
54 return new AnticipationInfo(Duration.ZERO, initialSpeed);
55 }
56
57 if (acceleration.eq(Acceleration.ZERO))
58 {
59 if (initialSpeed.gt0())
60 {
61 return new AnticipationInfo(distance.divide(initialSpeed), initialSpeed);
62 }
63
64 return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
65 }
66
67 double tmp = initialSpeed.si * initialSpeed.si + 2.0 * acceleration.si * distance.si;
68 if (tmp < 0)
69 {
70
71 return new AnticipationInfo(new Duration(Double.POSITIVE_INFINITY, DurationUnit.SI), Speed.ZERO);
72 }
73
74 Duration d = new Duration((Math.sqrt(tmp) - initialSpeed.si) / acceleration.si, DurationUnit.SI);
75
76 Speed endSpeed = initialSpeed.plus(acceleration.times(d));
77 if (endSpeed.le(maxSpeed))
78 {
79 return new AnticipationInfo(d, endSpeed);
80 }
81
82 Duration d1 = maxSpeed.minus(initialSpeed).divide(acceleration);
83 Length x2 = new Length(distance.si - initialSpeed.si * d1.si - .5 * acceleration.si * d1.si * d1.si, LengthUnit.SI);
84 return new AnticipationInfo(d1.plus(x2.divide(maxSpeed)), maxSpeed);
85 }
86
87
88
89
90
91
92
93
94
95 public static AnticipationInfo anticipateMovementFreeAcceleration(final TacticalContext context, final Length distance,
96 final Duration timeStep) throws ParameterException
97 {
98 Duration out = Duration.ZERO;
99 if (distance.lt0())
100 {
101 return new AnticipationInfo(out, context.getSpeed());
102 }
103 Length xCumul = Length.ZERO;
104 Speed speed = context.getSpeed();
105 while (xCumul.lt(distance))
106 {
107 Acceleration a = CarFollowingUtil.freeAcceleration(context, speed);
108 Length add = new Length(speed.si * timeStep.si + .5 * a.si * timeStep.si * timeStep.si, LengthUnit.SI);
109 Length remain = distance.minus(xCumul);
110 if (add.lt(remain))
111 {
112 xCumul = xCumul.plus(add);
113 speed = speed.plus(a.times(timeStep));
114 out = out.plus(timeStep);
115 }
116 else
117 {
118 Duration timeInStep;
119 double tmp = Math.sqrt(2 * a.si * remain.si + speed.si * speed.si) - speed.si;
120 if (tmp < 0.000001)
121 {
122
123 timeInStep = remain.divide(speed);
124 }
125 else
126 {
127 timeInStep = new Duration(tmp / a.si, DurationUnit.SI);
128 speed = speed.plus(a.times(timeInStep));
129 }
130 out = out.plus(timeInStep);
131 return new AnticipationInfo(out, speed);
132 }
133 }
134
135 throw new OtsRuntimeException("Distance for anticipation of conflict movement is surpassed.");
136 }
137
138 }