leptos_motion_core/
math.rs

1//! Mathematical utilities for animations
2
3
4
5/// Clamp a value between min and max
6pub fn clamp(value: f64, min: f64, max: f64) -> f64 {
7    if min > max {
8        panic!("min must be less than or equal to max");
9    }
10    value.max(min).min(max)
11}
12
13/// Map a value from one range to another
14pub fn map_range(value: f64, from_min: f64, from_max: f64, to_min: f64, to_max: f64) -> f64 {
15    let from_range = from_max - from_min;
16    let to_range = to_max - to_min;
17    
18    if from_range == 0.0 {
19        return to_min;
20    }
21    
22    let normalized = (value - from_min) / from_range;
23    to_min + (normalized * to_range)
24}
25
26/// Calculate distance between two 2D points
27pub fn distance_2d(x1: f64, y1: f64, x2: f64, y2: f64) -> f64 {
28    let dx = x2 - x1;
29    let dy = y2 - y1;
30    (dx * dx + dy * dy).sqrt()
31}
32
33/// Smooth step function (3t² - 2t³)
34pub fn smooth_step(t: f64) -> f64 {
35    let t = clamp(t, 0.0, 1.0);
36    t * t * (3.0 - 2.0 * t)
37}
38
39/// Smoother step function (6t⁵ - 15t⁴ + 10t³)
40pub fn smoother_step(t: f64) -> f64 {
41    let t = clamp(t, 0.0, 1.0);
42    t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48    use approx::assert_relative_eq;
49    
50    #[test]
51    fn test_clamp() {
52        assert_eq!(clamp(5.0, 0.0, 10.0), 5.0);
53        assert_eq!(clamp(-1.0, 0.0, 10.0), 0.0);
54        assert_eq!(clamp(15.0, 0.0, 10.0), 10.0);
55    }
56    
57    #[test]
58    fn test_map_range() {
59        assert_relative_eq!(map_range(0.5, 0.0, 1.0, 0.0, 100.0), 50.0);
60        assert_relative_eq!(map_range(2.0, 0.0, 4.0, 10.0, 20.0), 15.0);
61        assert_relative_eq!(map_range(0.0, 0.0, 0.0, 0.0, 100.0), 0.0); // Edge case
62    }
63    
64    #[test]
65    fn test_distance_2d() {
66        assert_relative_eq!(distance_2d(0.0, 0.0, 3.0, 4.0), 5.0);
67        assert_relative_eq!(distance_2d(0.0, 0.0, 0.0, 0.0), 0.0);
68    }
69    
70    #[test]
71    fn test_smooth_step() {
72        assert_eq!(smooth_step(0.0), 0.0);
73        assert_eq!(smooth_step(1.0), 1.0);
74        assert_relative_eq!(smooth_step(0.5), 0.5);
75        
76        // Should be smoother than linear
77        let linear_quarter = 0.25;
78        let smooth_quarter = smooth_step(0.25);
79        assert!(smooth_quarter < linear_quarter);
80    }
81    
82    #[test]
83    fn test_smoother_step() {
84        assert_eq!(smoother_step(0.0), 0.0);
85        assert_eq!(smoother_step(1.0), 1.0);
86        assert_relative_eq!(smoother_step(0.5), 0.5);
87    }
88}