elevator_core/
movement.rs1#[must_use]
10pub fn braking_distance(velocity: f64, deceleration: f64) -> f64 {
11 if deceleration <= 0.0 {
12 return 0.0;
13 }
14 let speed = velocity.abs();
15 speed * speed / (2.0 * deceleration)
16}
17
18#[derive(Debug, Clone, Copy)]
20pub struct MovementResult {
21 pub position: f64,
23 pub velocity: f64,
25 pub arrived: bool,
27}
28
29#[must_use]
39pub fn tick_movement(
40 position: f64,
41 velocity: f64,
42 target_position: f64,
43 max_speed: f64,
44 acceleration: f64,
45 deceleration: f64,
46 dt: f64,
47) -> MovementResult {
48 const EPSILON: f64 = 1e-9;
49
50 let displacement = target_position - position;
51
52 if displacement.abs() < EPSILON && velocity.abs() < EPSILON {
54 return MovementResult {
55 position: target_position,
56 velocity: 0.0,
57 arrived: true,
58 };
59 }
60
61 let sign = displacement.signum();
62 let distance_remaining = displacement.abs();
63 let speed = velocity.abs();
64 let stopping_distance = speed * speed / (2.0 * deceleration);
65
66 let new_velocity = if stopping_distance >= distance_remaining - EPSILON {
67 let v = (-deceleration * dt).mul_add(velocity.signum(), velocity);
69 if velocity > 0.0 && v < 0.0 || velocity < 0.0 && v > 0.0 {
71 0.0
72 } else {
73 v
74 }
75 } else if speed < max_speed {
76 let v = (acceleration * dt).mul_add(sign, velocity);
78 if v.abs() > max_speed {
80 sign * max_speed
81 } else {
82 v
83 }
84 } else {
85 sign * max_speed
87 };
88
89 let new_pos = new_velocity.mul_add(dt, position);
90
91 let new_displacement = target_position - new_pos;
93 if new_displacement.abs() < EPSILON || (new_displacement.signum() - sign).abs() > EPSILON {
94 return MovementResult {
95 position: target_position,
96 velocity: 0.0,
97 arrived: true,
98 };
99 }
100
101 MovementResult {
102 position: new_pos,
103 velocity: new_velocity,
104 arrived: false,
105 }
106}