feat(math): added to_point method into the InnerSpace trait and added tangent evaluation to the Bezier curve struct (changed point to vecs inside the struct as well)

This commit is contained in:
lisk77 2025-07-26 01:14:47 +02:00
parent d04c706a94
commit 05a4679f38
3 changed files with 929 additions and 831 deletions

View file

@ -1,21 +1,18 @@
use crate::Point; use crate::{InnerSpace, Point};
pub struct Bezier<P: Point> { pub struct Bezier<V: InnerSpace> {
points: Vec<P>, points: Vec<V>,
degree: usize degree: usize,
} }
impl<P: Point + Clone> Bezier<P> { impl<V: InnerSpace + Clone> Bezier<V> {
pub fn new(points: Vec<P>) -> Self { pub fn new(points: Vec<V>) -> Self {
let degree = points.len() - 1; let degree = points.len() - 1;
Self { Self { points, degree }
points,
degree
}
} }
pub fn evaluate(&self, t: f32) -> P { pub fn evaluate(&self, t: f32) -> V {
let mut new_points = self.points.clone(); let mut new_points = self.points.clone();
for i in 0..self.degree { for i in 0..self.degree {
for j in 0..(self.degree - i) { for j in 0..(self.degree - i) {
@ -24,4 +21,22 @@ impl<P: Point + Clone> Bezier<P> {
} }
new_points[0].clone() new_points[0].clone()
} }
pub fn evaluate_tangent(&self, t: f32) -> V {
let n = self.degree as f32;
let mut d_pts: Vec<V> = self
.points
.windows(2)
.map(|w| ((w[1] - w[0]) * n))
.collect::<Vec<V>>();
for i in 0..(self.degree - 1) {
for j in 0..(self.degree - 1 - i) {
d_pts[j] = d_pts[j].lerp(&d_pts[j + 1], t);
}
}
d_pts[0].clone().normalize()
}
} }

View file

@ -1,5 +1,7 @@
use crate::InnerSpace; use rand::seq::index::IndexVecIntoIter;
use crate::vector::{v2, v3}; use crate::vector::{v2, v3};
use crate::InnerSpace;
pub trait Point { pub trait Point {
fn lerp(&self, other: &Self, t: f32) -> Self; fn lerp(&self, other: &Self, t: f32) -> Self;
@ -9,7 +11,7 @@ pub trait Point {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub struct p2 { pub struct p2 {
x: f32, x: f32,
y: f32 y: f32,
} }
impl p2 { impl p2 {
@ -34,7 +36,7 @@ impl p2 {
pub struct p3 { pub struct p3 {
x: f32, x: f32,
y: f32, y: f32,
z: f32 z: f32,
} }
impl p3 { impl p3 {
@ -43,7 +45,11 @@ impl p3 {
} }
pub fn from_vec(v: v3) -> Self { pub fn from_vec(v: v3) -> Self {
Self { x: v.x(), y: v.y(), z: v.z() } Self {
x: v.x(),
y: v.y(),
z: v.z(),
}
} }
pub fn x(&self) -> f32 { pub fn x(&self) -> f32 {

View file

@ -1,16 +1,17 @@
use crate::point::{p2, p3}; use crate::point::{p2, p3};
use crate::quaternion::Quat; use crate::quaternion::Quat;
use crate::Point;
use std::ops::*; use std::ops::*;
pub trait InnerSpace: pub trait InnerSpace:
std::fmt::Debug + std::fmt::Debug
Copy + + Copy
Clone + + Clone
Neg<Output = Self> + + Neg<Output = Self>
Mul<f32, Output = Self> + + Mul<f32, Output = Self>
Div<f32, Output = Self> + + Div<f32, Output = Self>
Add<Self, Output = Self> + + Add<Self, Output = Self>
Sub<Self, Output = Self> + Sub<Self, Output = Self>
{ {
fn dot(&self, other: &Self) -> f32; fn dot(&self, other: &Self) -> f32;
fn dist(&self, other: &Self) -> f32; fn dist(&self, other: &Self) -> f32;
@ -21,6 +22,7 @@ pub trait InnerSpace:
fn project_onto(&self, other: &Self) -> Self; fn project_onto(&self, other: &Self) -> Self;
fn reflect(&self, normal: &Self) -> Self; fn reflect(&self, normal: &Self) -> Self;
fn lerp(&self, other: &Self, t: f32) -> Self; fn lerp(&self, other: &Self, t: f32) -> Self;
fn to_point(&self) -> impl Point;
} }
// ################################################## // ##################################################
@ -31,6 +33,7 @@ pub trait InnerSpace:
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[allow(non_camel_case_types)]
pub struct v2 { pub struct v2 {
x: f32, x: f32,
y: f32, y: f32,
@ -165,6 +168,7 @@ impl Into<v2> for [f32;2] {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[allow(non_camel_case_types)]
pub struct v2i { pub struct v2i {
x: i64, x: i64,
y: i64, y: i64,
@ -180,7 +184,21 @@ impl v2i {
} }
pub fn from_point(p: p2) -> Self { pub fn from_point(p: p2) -> Self {
Self { x: p.x() as i64, y: p.y() as i64 } Self {
x: p.x() as i64,
y: p.y() as i64,
}
}
pub fn as_point(&self) -> p2 {
p2::new(self.x as f32, self.y as f32)
}
pub fn from_vec2(v: v2) -> Self {
Self {
x: v.x as i64,
y: v.y as i64,
}
} }
pub fn as_vec2(&self) -> v2 { pub fn as_vec2(&self) -> v2 {
@ -376,6 +394,7 @@ impl Into<[f32;2]> for v2i {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[allow(non_camel_case_types)]
pub struct v3 { pub struct v3 {
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,
@ -383,10 +402,26 @@ pub struct v3 {
} }
impl v3 { impl v3 {
pub const X: v3 = v3 { x: 1.0, y: 0.0, z: 0.0 }; pub const X: v3 = v3 {
pub const Y: v3 = v3 { x: 0.0, y: 1.0, z: 0.0 }; x: 1.0,
pub const Z: v3 = v3 { x: 0.0, y: 0.0, z: 1.0 }; y: 0.0,
pub const ZERO: v3 = v3 { x: 0.0, y: 0.0, z: 0.0 }; z: 0.0,
};
pub const Y: v3 = v3 {
x: 0.0,
y: 1.0,
z: 0.0,
};
pub const Z: v3 = v3 {
x: 0.0,
y: 0.0,
z: 1.0,
};
pub const ZERO: v3 = v3 {
x: 0.0,
y: 0.0,
z: 0.0,
};
pub const fn new(x: f32, y: f32, z: f32) -> Self { pub const fn new(x: f32, y: f32, z: f32) -> Self {
v3 { x, y, z } v3 { x, y, z }
@ -400,6 +435,10 @@ impl v3 {
} }
} }
pub fn as_point(&self) -> p3 {
p3::new(self.x as f32, self.y as f32, self.z as f32)
}
pub fn x(&self) -> f32 { pub fn x(&self) -> f32 {
self.x self.x
} }
@ -535,10 +574,10 @@ impl Into<v3> for [f32;3] {
} }
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[allow(non_camel_case_types)]
pub struct v3i { pub struct v3i {
pub x: i64, pub x: i64,
pub y: i64, pub y: i64,
@ -728,6 +767,7 @@ impl From<v3> for v3i {
#[repr(C)] #[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[allow(non_camel_case_types)]
pub struct v4 { pub struct v4 {
x: f32, x: f32,
y: f32, y: f32,
@ -736,12 +776,37 @@ pub struct v4 {
} }
impl v4 { impl v4 {
pub const X: v4 = v4 { x: 1.0, y: 0.0, z: 0.0, w: 0.0 }; pub const X: v4 = v4 {
pub const Y: v4 = v4 { x: 0.0, y: 1.0, z: 0.0, w: 0.0 }; x: 1.0,
pub const Z: v4 = v4 { x: 0.0, y: 0.0, z: 1.0, w: 0.0 }; y: 0.0,
pub const W: v4 = v4 { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; z: 0.0,
w: 0.0,
};
pub const Y: v4 = v4 {
x: 0.0,
y: 1.0,
z: 0.0,
w: 0.0,
};
pub const Z: v4 = v4 {
x: 0.0,
y: 0.0,
z: 1.0,
w: 0.0,
};
pub const W: v4 = v4 {
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0,
};
pub const ZERO: v4 = v4 { x: 0.0, y: 0.0, z: 0.0, w: 0.0 }; pub const ZERO: v4 = v4 {
x: 0.0,
y: 0.0,
z: 0.0,
w: 0.0,
};
pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self { pub const fn new(x: f32, y: f32, z: f32, w: f32) -> Self {
v4 { x, y, z, w } v4 { x, y, z, w }
@ -938,6 +1003,10 @@ impl InnerSpace for v2 {
fn lerp(&self, other: &Self, t: f32) -> Self { fn lerp(&self, other: &Self, t: f32) -> Self {
*self * (1.0 - t) + *other * t *self * (1.0 - t) + *other * t
} }
fn to_point(&self) -> impl Point {
p2::new(self.x, self.y)
}
} }
impl InnerSpace for v3 { impl InnerSpace for v3 {
@ -990,6 +1059,10 @@ impl InnerSpace for v3 {
fn lerp(&self, other: &Self, t: f32) -> Self { fn lerp(&self, other: &Self, t: f32) -> Self {
*self * (1.0 - t) + *other * t *self * (1.0 - t) + *other * t
} }
fn to_point(&self) -> impl Point {
p3::new(self.x, self.y, self.z)
}
} }
impl InnerSpace for v4 { impl InnerSpace for v4 {
@ -1045,6 +1118,10 @@ impl InnerSpace for v4 {
fn lerp(&self, other: &Self, t: f32) -> Self { fn lerp(&self, other: &Self, t: f32) -> Self {
*self * (1.0 - t) + *other * t *self * (1.0 - t) + *other * t
} }
fn to_point(&self) -> impl Point {
p3::new(self.x / self.w, self.y / self.w, self.z / self.w)
}
} }
macro_rules! generate_swizzles2 { macro_rules! generate_swizzles2 {