chaos_framework/util/
math.rs

1use std::{f32::consts::PI, ops::{Add, Mul, Sub}};
2use glam::{vec2, vec3, vec4, Vec2, Vec3, Vec4};
3use rand::prelude::*;
4
5/* i really have no idea how to deal with indentation when generics come into place */
6
7
8pub fn distance(a: f32, b: f32) -> f32 {
9    return f32::sqrt(a*a + b*b);
10}
11
12pub fn lerp
13    <T: Sub<Output = T> + Add<Output = T> + Mul<Output = T> + Copy + Mul<f32, Output = T>>
14    (min: T, max: T, t: f32) -> T 
15{
16    return min + (max - min) * t;
17}
18
19// generates a random value T between n1: T and n2: T
20pub fn rand_betw
21<
22    T: std::cmp::PartialOrd +
23    rand::distributions::uniform::SampleUniform,
24>
25(
26    n1: T, 
27    n2: T
28) -> T {
29    let mut r = thread_rng();
30    r.gen_range(n1..n2)
31}
32
33pub fn rand_vec2() -> Vec2 {
34    vec2(rand_betw(0.0, 1.0), rand_betw(0.0, 1.0))
35}
36
37pub fn rand_vec3() -> Vec3 {
38    vec3(rand_betw(0.0, 1.0), rand_betw(0.0, 1.0), rand_betw(0.0, 1.0))
39}
40
41pub fn rand_vec4() -> Vec4 {
42    vec4(rand_betw(0.0, 1.0), rand_betw(0.0, 1.0), rand_betw(0.0, 1.0), rand_betw(0.0, 1.0))
43}
44
45/* make it so that input x yields in a smooth output y */
46pub struct SecondOrderDynamics<T> { 
47    // previous inputs
48    xp: T, 
49    y: T, 
50    yd: T,
51
52    //constants
53    k1: f32,
54    k2: f32, 
55    k3: f32,
56
57    t_critical: f32,
58}
59
60impl SecondOrderDynamics<Vec3> {
61    pub fn new(f: f32, z: f32, r: f32, x0: Vec3) -> Self {
62        let k1 = z / (PI * f);
63        let k2 = 1.0 / ((2.0 * PI * f) * (2.0 * PI * f));
64        let k3 = r * z / (2.0 * PI * f);
65        
66        let xp = x0;
67        let y = x0;
68        let yd = vec3(0.0, 0.0, 0.0);
69
70        // critical timestep threshold where the simulation would
71        // become unstable past it
72
73        let t_critical = (f32::sqrt(4.0*k2 + k1 * k1) - k1) * 0.8; // multiply by an arbitrary value to be safe
74
75        Self {
76            k1,
77            k2,
78            k3,
79
80            xp,
81            y,
82            yd,
83
84            t_critical,
85        }
86    }
87
88    pub fn update(&mut self, mut timestep: f32, x: Vec3) -> Vec3 {
89        let xd = (x - self.xp) / timestep;
90        self.xp = x;
91
92        let iterations = f32::ceil(timestep / self.t_critical); // take extra iterations if t > tcrit
93        timestep = timestep / iterations; // lower timesteps
94
95        for _ in 0..iterations as usize {
96            self.y = self.y + timestep * self.yd;
97            self.yd = self.yd + timestep * (x + self.k3*xd - self.y - self.k1*self.yd) / self.k2;
98        }
99
100        self.y
101    }
102}