use potlood::{Color, Paper, Pixel}; #[derive(Clone, Copy)] struct Point { x: f64, y: f64, } impl Point { fn new(x: f64, y: f64) -> Self { Self { x, y } } } fn lerp(a: f64, b: f64, t: f64) -> f64 { a + t * (b - a) } fn lerp_points(a: Point, b: Point, t: f64) -> Point { let x = lerp(a.x, b.x, t); let y = lerp(a.y, b.y, t); Point::new(x, y) } fn bezier( start: Point, start_handle: Point, end: Point, end_handle: Point, steps: usize, ) -> Vec { let mut curve = Vec::with_capacity(steps); for step in 0..=steps { let t = step as f64 / steps as f64; let m = lerp_points(start_handle, end_handle, t); let s = lerp_points(start, start_handle, t); let e = lerp_points(end_handle, end, t); let sm = lerp_points(s, m, t); let me = lerp_points(m, e, t); let point = lerp_points(sm, me, t); curve.push(point); } curve } fn main() { let width = 400; let height = 300; let padding = 20.0; let mut paper = Paper::new(width, height); // TODO: Is this necessary? paper.fill(Pixel::color(Color::Black)); let start = Point::new(padding, 10.0); let start_handle = Point::new(padding, height as f64 - 10.0); let end = Point::new(width as f64 - padding, height as f64 - 10.0); let end_handle = Point::new(width as f64 - padding, 10.0); for step in 0..=20 { let t = step as f64 / 20 as f64; let m = lerp_points(start_handle, end_handle, t); let s = lerp_points(start, start_handle, t); let e = lerp_points(end_handle, end, t); let sm = lerp_points(s, m, t); let me = lerp_points(m, e, t); paper.line( sm.x as usize, sm.y as usize, me.x as usize, me.y as usize, Pixel::color(Color::Grey), ); } paper.stroke( bezier(start, start_handle, end, end_handle, 50) .iter() .map(|point| (point.x as usize, point.y as usize)) .collect(), Pixel::color(Color::Red), ); for point in bezier(start, start_handle, end, end_handle, 50) { paper.set( point.x as usize, point.y as usize, Pixel::color(Color::Magenta), ); } for point in bezier(start, start_handle, end, end_handle, 25) { paper.set( point.x as usize, point.y as usize, Pixel::color(Color::White), ); } let mut draw_point = |p: Point, color| { paper .circle(p.x as usize, p.y as usize, 2, Pixel::color(color)) .unwrap() }; draw_point(start, Color::Blue); draw_point(start_handle, Color::Green); draw_point(end, Color::Blue); draw_point(end_handle, Color::Green); paper .generate("./bezier.ppm".to_string()) .expect("something went wrong"); }