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 safe_decel = deceleration.max(EPSILON);
65 let stopping_distance = speed * speed / (2.0 * safe_decel);
66
67 let new_velocity = if stopping_distance >= distance_remaining - EPSILON {
68 let v = (-safe_decel * dt).mul_add(velocity.signum(), velocity);
70 if velocity > 0.0 && v < 0.0 || velocity < 0.0 && v > 0.0 {
72 0.0
73 } else {
74 v
75 }
76 } else if speed < max_speed {
77 let v = (acceleration * dt).mul_add(sign, velocity);
79 if v.abs() > max_speed {
81 sign * max_speed
82 } else {
83 v
84 }
85 } else {
86 sign * max_speed
88 };
89
90 let new_pos = new_velocity.mul_add(dt, position);
91
92 let new_displacement = target_position - new_pos;
94 if new_displacement.abs() < EPSILON || (new_displacement.signum() - sign).abs() > EPSILON {
95 return MovementResult {
96 position: target_position,
97 velocity: 0.0,
98 arrived: true,
99 };
100 }
101
102 MovementResult {
103 position: new_pos,
104 velocity: new_velocity,
105 arrived: false,
106 }
107}