1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_point::Point2;
5
6#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct QuadraticBezier2 {
9 start: Point2,
10 control: Point2,
11 end: Point2,
12}
13
14impl QuadraticBezier2 {
15 #[must_use]
17 pub const fn new(start: Point2, control: Point2, end: Point2) -> Self {
18 Self {
19 start,
20 control,
21 end,
22 }
23 }
24
25 #[must_use]
27 pub const fn point_at(self, t: f64) -> Point2 {
28 let left = self.start.lerp(self.control, t);
29 let right = self.control.lerp(self.end, t);
30 left.lerp(right, t)
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq)]
36pub struct CubicBezier2 {
37 start: Point2,
38 control_a: Point2,
39 control_b: Point2,
40 end: Point2,
41}
42
43impl CubicBezier2 {
44 #[must_use]
46 pub const fn new(start: Point2, control_a: Point2, control_b: Point2, end: Point2) -> Self {
47 Self {
48 start,
49 control_a,
50 control_b,
51 end,
52 }
53 }
54
55 #[must_use]
57 pub const fn point_at(self, t: f64) -> Point2 {
58 let left = self.start.lerp(self.control_a, t);
59 let middle = self.control_a.lerp(self.control_b, t);
60 let right = self.control_b.lerp(self.end, t);
61 let left = left.lerp(middle, t);
62 let right = middle.lerp(right, t);
63 left.lerp(right, t)
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::{CubicBezier2, QuadraticBezier2};
70 use use_point::Point2;
71
72 #[test]
73 fn evaluates_quadratic_curves() {
74 let curve = QuadraticBezier2::new(
75 Point2::new(0.0, 0.0),
76 Point2::new(1.0, 2.0),
77 Point2::new(2.0, 0.0),
78 );
79
80 assert_eq!(curve.point_at(0.5), Point2::new(1.0, 1.0));
81 }
82
83 #[test]
84 fn evaluates_cubic_endpoints() {
85 let curve = CubicBezier2::new(
86 Point2::new(0.0, 0.0),
87 Point2::new(1.0, 2.0),
88 Point2::new(2.0, 2.0),
89 Point2::new(3.0, 0.0),
90 );
91
92 assert_eq!(curve.point_at(0.0), Point2::new(0.0, 0.0));
93 assert_eq!(curve.point_at(1.0), Point2::new(3.0, 0.0));
94 }
95}