use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Default)]
pub struct CurvePos {
pub x: f32,
pub y: f32,
}
impl Eq for CurvePos {}
impl CurvePos {
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
}
pub(crate) fn quadratic_bezier(points: [CurvePos; 3], t: f32) -> CurvePos {
let h = 1.0 - t;
let a = t * t;
let b = 2.0 * t * h;
let c = h * h;
CurvePos {
x: points[2].x * a + points[1].x * b + points[0].x * c,
y: points[2].y * a + points[1].y * b + points[0].y * c,
}
}
#[cfg(test)]
mod tests {
use super::*;
use egui::{Color32, Pos2, Stroke, epaint::QuadraticBezierShape};
#[test]
fn samples_exactly_like_epaint() {
let points = [
CurvePos::new(0.0, 1.0),
CurvePos::new(0.37, 0.11),
CurvePos::new(1.0, 0.0),
];
let shape = QuadraticBezierShape::from_points_stroke(
points.map(|p| Pos2::new(p.x, p.y)),
false,
Color32::TRANSPARENT,
Stroke::default(),
);
for i in 0..=1000 {
let t = i as f32 / 1000.0;
let ours = quadratic_bezier(points, t);
let theirs = shape.sample(t);
assert_eq!((ours.x, ours.y), (theirs.x, theirs.y), "t = {t}");
}
}
#[test]
fn serializes_like_pos2() {
let pos = CurvePos::new(1.5, 0.25);
assert_eq!(
serde_json::to_string(&pos).expect("serializes"),
serde_json::to_string(&Pos2::new(1.5, 0.25)).expect("serializes")
);
}
}