use crate::HisabError;
use glam::{Vec2, Vec3};
#[must_use]
#[inline]
pub fn derivative(f: impl Fn(f64) -> f64, x: f64, h: f64) -> f64 {
(f(x + h) - f(x - h)) / (2.0 * h)
}
#[must_use = "returns the computed integral"]
#[inline]
pub fn integral_trapezoidal(
f: impl Fn(f64) -> f64,
a: f64,
b: f64,
n: usize,
) -> Result<f64, HisabError> {
if n == 0 {
return Err(HisabError::ZeroSteps);
}
let h = (b - a) / n as f64;
let mut sum = 0.5 * (f(a) + f(b));
for i in 1..n {
sum += f(a + i as f64 * h);
}
Ok(sum * h)
}
#[inline(always)]
fn neumaier_add(sum: &mut f64, comp: &mut f64, v: f64) {
let t = *sum + v;
if sum.abs() >= v.abs() {
*comp += (*sum - t) + v;
} else {
*comp += (v - t) + *sum;
}
*sum = t;
}
#[must_use = "returns the computed integral"]
#[inline]
pub fn integral_simpson(
f: impl Fn(f64) -> f64,
a: f64,
b: f64,
n: usize,
) -> Result<f64, HisabError> {
let n = if n % 2 == 1 { n + 1 } else { n };
if n == 0 {
return Err(HisabError::ZeroSteps);
}
let h = (b - a) / n as f64;
let mut sum = f(a) + f(b);
let mut comp = 0.0_f64;
let mut i = 1;
while i < n {
neumaier_add(&mut sum, &mut comp, 4.0 * f(a + i as f64 * h));
neumaier_add(&mut sum, &mut comp, 2.0 * f(a + (i + 1) as f64 * h));
i += 2;
}
neumaier_add(&mut sum, &mut comp, -2.0 * f(b));
Ok((sum + comp) * h / 3.0)
}
#[must_use]
#[inline]
pub fn lerp(a: f64, b: f64, t: f64) -> f64 {
a + (b - a) * t
}
#[must_use]
#[inline]
pub fn bezier_quadratic(p0: Vec2, p1: Vec2, p2: Vec2, t: f32) -> Vec2 {
let u = 1.0 - t;
p0 * (u * u) + p1 * (2.0 * u * t) + p2 * (t * t)
}
#[must_use]
#[inline]
pub fn bezier_cubic(p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2, t: f32) -> Vec2 {
let u = 1.0 - t;
let u2 = u * u;
let t2 = t * t;
p0 * (u2 * u) + p1 * (3.0 * u2 * t) + p2 * (3.0 * u * t2) + p3 * (t2 * t)
}
#[must_use]
#[inline]
pub fn bezier_quadratic_3d(p0: Vec3, p1: Vec3, p2: Vec3, t: f32) -> Vec3 {
let u = 1.0 - t;
p0 * (u * u) + p1 * (2.0 * u * t) + p2 * (t * t)
}
#[must_use]
#[inline]
pub fn bezier_cubic_3d(p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, t: f32) -> Vec3 {
let u = 1.0 - t;
let u2 = u * u;
let t2 = t * t;
p0 * (u2 * u) + p1 * (3.0 * u2 * t) + p2 * (3.0 * u * t2) + p3 * (t2 * t)
}