Skip to main content

use_bezier/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4use use_point::Point2;
5
6/// A quadratic Bezier curve in 2D.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct QuadraticBezier2 {
9    start: Point2,
10    control: Point2,
11    end: Point2,
12}
13
14impl QuadraticBezier2 {
15    /// Creates a quadratic Bezier curve.
16    #[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    /// Evaluates the curve at `t`.
26    #[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/// A cubic Bezier curve in 2D.
35#[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    /// Creates a cubic Bezier curve.
45    #[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    /// Evaluates the curve at `t`.
56    #[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}