From d0e9a1b456efd95b46f95b5b52dc83a4dd7e0e46 Mon Sep 17 00:00:00 2001 From: lisk77 Date: Mon, 31 Mar 2025 00:02:56 +0200 Subject: [PATCH] feat: added a `Bezier` struct for a general bezier curve implementation --- crates/comet_math/src/bezier.rs | 154 ++++---------------------------- crates/comet_math/src/point.rs | 62 +++++++++++-- crates/comet_math/src/vector.rs | 59 +++++++++++- 3 files changed, 130 insertions(+), 145 deletions(-) diff --git a/crates/comet_math/src/bezier.rs b/crates/comet_math/src/bezier.rs index 68ae091..3f364b1 100644 --- a/crates/comet_math/src/bezier.rs +++ b/crates/comet_math/src/bezier.rs @@ -1,145 +1,27 @@ -use num_traits::Pow; +use crate::Point; -use crate::point::{Point2, Point3}; -use crate::vector::{Vec2, Vec3}; -use crate::utilities::{lerp2, lerp3, fac}; - -pub trait ParameterCurve2 { - //fn arcLen(&self) -> f32; - fn getPoint(&self, t: f32) -> Point2; +pub struct Bezier { + points: Vec

, + degree: usize } -pub trait ParameterCurve3 { - //fn arcLen(&self) -> f32; - fn getPoint(&self, t: f32) -> Point3; -} +impl Bezier

{ + pub fn new(points: Vec

) -> Self { + let degree = points.len() - 1; -/// A general Bézier Curve in 2D -/// WORK IN PROGRESS: DOES NOT WORK (use cBezier2 instead) -#[repr(C)] -pub struct Bezier2 { - points: Vec, - degree: u8 -} - -impl Bezier2 { - pub fn new(points: Vec) -> Self { - let n = points.len() as u8; - Self { points: points, degree: n } + Self { + points, + degree + } } -} - -/// A general Bézier Curve in 3D -/// WORK IN PROGRESS: DOES NOT WORK (use cBezier3 instead) -#[repr(C)] -pub struct Bezier3 { - points: Vec, - degree: u8 -} - -impl Bezier3 { - pub fn new(points: Vec) -> Self { - let n = points.len() as u8; - Self { points: points, degree: n } - } -} - -/// A cubic Bézier Curve in 2D -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct cBezier2 { - p0: Point2, - p1: Point2, - p2: Point2, - p3: Point2 -} - -impl cBezier2 { - pub fn new(p0: Point2, p1: Point2, p2: Point2, p3: Point2) -> Self { - Self { p0, p1, p2, p3 } - } -} - -impl ParameterCurve2 for cBezier2 { - fn getPoint(&self, t: f32) -> Point2 { - let tSquared = t * t; - let tCubed = tSquared * t; - let vP0 = Vec2::from_point(self.p0); - let vP1 = Vec2::from_point(self.p1); - let vP2 = Vec2::from_point(self.p2); - let vP3 = Vec2::from_point(self.p3); - - Point2::from_vec( - vP0 * (-tCubed + 3.0 * tSquared - 3.0 * t + 1.0 ) + - vP1 * (3.0 * tCubed - 6.0 * tSquared + 3.0 * t ) + - vP2 * (-3.0 * tCubed + 3.0 * tSquared ) + - vP3 * tCubed - ) - } -} - -/// A cubic Bézier Curve in 3D -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct cBezier3 { - p0: Point3, - p1: Point3, - p2: Point3, - p3: Point3 -} - -impl cBezier3 { - pub fn new(p0: Point3, p1: Point3, p2: Point3, p3: Point3) -> Self { - Self { p0, p1, p2, p3 } - } -} - -impl ParameterCurve2 for Bezier2 { - fn getPoint(&self, t: f32) -> Point2 { - let n = self.points.len(); - let mut points = self.points.clone(); - - for k in 1..n { - for i in 0..n - k { - points[i] = Point2::from_vec(lerp2(Vec2::from_point(points[i]), Vec2::from_point(points[i + 1]), t)); + pub fn evaluate(&self, t: f32) -> P { + let mut new_points = self.points.clone(); + for i in 0..self.degree { + for j in 0..(self.degree - i) { + new_points[j] = new_points[j].lerp(&new_points[j + 1], t); } } - - points[0] + new_points[0].clone() } -} - -impl ParameterCurve3 for Bezier3 { - fn getPoint(&self, t: f32) -> Point3 { - let n = self.points.len(); - let mut points = self.points.clone(); - - for k in 1..n { - for i in 0..n - k { - points[i] = Point3::from_vec(lerp3(Vec3::from_point(points[i]), Vec3::from_point(points[i + 1]), t)); - } - } - - points[0] - } -} - -impl ParameterCurve3 for cBezier3 { - fn getPoint(&self, t: f32) -> Point3 { - let tSquared = t * t; - let tCubed = tSquared * t; - let vP0 = Vec3::from_point(self.p0); - let vP1 = Vec3::from_point(self.p1); - let vP2 = Vec3::from_point(self.p2); - let vP3 = Vec3::from_point(self.p3); - - Point3::from_vec( - vP0 * (-tCubed + 3.0 * tSquared - 3.0 * t + 1.0 ) + - vP1 * (3.0 * tCubed - 6.0 * tSquared + 3.0 * t ) + - vP2 * (-3.0 * tCubed + 3.0 * tSquared ) + - vP3 * tCubed - ) - } - -} +} \ No newline at end of file diff --git a/crates/comet_math/src/point.rs b/crates/comet_math/src/point.rs index a11840e..68f9ade 100644 --- a/crates/comet_math/src/point.rs +++ b/crates/comet_math/src/point.rs @@ -1,5 +1,11 @@ +use crate::InnerSpace; use crate::vector::{Vec2, Vec3}; +pub trait Point { + fn lerp(&self, other: &Self, t: f32) -> Self; + fn to_vec(&self) -> impl InnerSpace; +} + #[derive(Debug, Clone, Copy, PartialEq)] pub struct Point2 { x: f32, @@ -22,10 +28,6 @@ impl Point2 { Self { x: v.x(), y: v.y() } } - pub fn to_vec(&self) -> Vec2 { - Vec2::new(self.x, self.y) - } - pub fn x(&self) -> f32 { self.x } @@ -44,10 +46,6 @@ impl Point3 { Self { x: v.x(), y: v.y(), z: v.z() } } - pub fn to_vec(&self) -> Vec3 { - Vec3::new(self.x, self.y, self.z) - } - pub fn x(&self) -> f32 { self.x } @@ -60,3 +58,51 @@ impl Point3 { self.z } } + +impl Point for Point2 { + fn lerp(&self, other: &Self, t: f32) -> Self { + let x = self.x + (other.x - self.x) * t; + let y = self.y + (other.y - self.y) * t; + Self { x, y } + } + + fn to_vec(&self) -> Vec2 { + Vec2::new(self.x, self.y) + } +} +impl Point for Point3 { + fn lerp(&self, other: &Self, t: f32) -> Self { + let x = self.x + (other.x - self.x) * t; + let y = self.y + (other.y - self.y) * t; + let z = self.z + (other.z - self.z) * t; + Self { x, y, z } + } + + fn to_vec(&self) -> Vec3 { + Vec3::new(self.x, self.y, self.z) + } +} + +impl Into for Point2 { + fn into(self) -> Vec2 { + self.to_vec() + } +} + +impl Into for Point3 { + fn into(self) -> Vec3 { + self.to_vec() + } +} + +impl From for Point2 { + fn from(v: Vec2) -> Self { + Self::from_vec(v) + } +} + +impl From for Point3 { + fn from(v: Vec3) -> Self { + Self::from_vec(v) + } +} \ No newline at end of file diff --git a/crates/comet_math/src/vector.rs b/crates/comet_math/src/vector.rs index ae921b5..3d4f624 100644 --- a/crates/comet_math/src/vector.rs +++ b/crates/comet_math/src/vector.rs @@ -2,7 +2,16 @@ use crate::point::{Point2, Point3}; use crate::quaternion::Quat; use std::ops::*; -pub trait InnerSpace { +pub trait InnerSpace: + std::fmt::Debug + + Copy + + Clone + + Neg + + Mul + + Div + + Add + + Sub +{ fn dot(&self, other: &Self) -> f32; fn dist(&self, other: &Self) -> f32; fn angle(&self, other: &Self) -> f32; @@ -93,6 +102,17 @@ impl SubAssign for Vec2 { } } +impl Neg for Vec2 { + type Output = Self; + + fn neg(self) -> Self::Output { + Self { + x: -self.x, + y: -self.y, + } + } +} + impl Mul for Vec2 { type Output = Vec2; @@ -505,6 +525,17 @@ impl Into<[f32;3]> for Vec3 { } } +impl Into for [f32;3] { + fn into(self) -> Vec3 { + Vec3 { + x: self[0], + y: self[1], + z: self[2], + } + } +} + + #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -793,6 +824,19 @@ impl SubAssign for Vec4 { } } +impl Neg for Vec4 { + type Output = Self; + + fn neg(self) -> Self::Output { + Self { + x: -self.x, + y: -self.y, + z: -self.z, + w: -self.w, + } + } +} + impl Mul for Vec4 { type Output = Vec4; @@ -828,6 +872,19 @@ impl MulAssign for Vec4 { } } +impl Div for Vec4 { + type Output = Vec4; + + fn div(self, other: f32) -> Vec4 { + Vec4 { + x: self.x / other, + y: self.y / other, + z: self.z / other, + w: self.w / other, + } + } +} + impl Into<[f32;4]> for Vec4 { fn into(self) -> [f32;4] { [self.x, self.y, self.z, self.w]