# HG changeset patch # User unc0rr # Date 1541450188 -3600 # Node ID 37c99587825dd5dfb783c2c5e66afd30e661ad02 # Parent 417d81c72119747720b9bb40aaf98ded16532903 Implement BeizerCurveSegments, no tests diff -r 417d81c72119 -r 37c99587825d rust/fpnum/src/lib.rs --- a/rust/fpnum/src/lib.rs Mon Nov 05 23:15:56 2018 +0300 +++ b/rust/fpnum/src/lib.rs Mon Nov 05 21:36:28 2018 +0100 @@ -47,11 +47,11 @@ } #[inline] - pub fn round(&self) -> i64 { + pub fn round(&self) -> i32 { if self.is_negative { - -((self.value >> 32) as i64) + -((self.value >> 32) as i32) } else { - (self.value >> 32) as i64 + (self.value >> 32) as i32 } } diff -r 417d81c72119 -r 37c99587825d rust/integral-geometry/src/lib.rs --- a/rust/integral-geometry/src/lib.rs Mon Nov 05 23:15:56 2018 +0300 +++ b/rust/integral-geometry/src/lib.rs Mon Nov 05 21:36:28 2018 +0100 @@ -1,12 +1,12 @@ +#[macro_use] extern crate fpnum; -use fpnum::distance; +use fpnum::{distance, FPNum, FPPoint}; use std::{ cmp::max, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Range, RangeInclusive, Sub, SubAssign} }; - #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Point { pub x: i32, @@ -99,6 +99,11 @@ pub fn cotangent(self) -> i32 { self.x / self.y } + + #[inline] + pub fn to_fppoint(&self) -> FPPoint { + FPPoint::new(self.x.into(), self.y.into()) + } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] @@ -731,6 +736,56 @@ } } +pub struct BezierCurveSegments { + segment: Line, + c1: FPPoint, + c2: FPPoint, + offset: FPNum, + delta: FPNum, +} + +impl BezierCurveSegments { + pub fn new(segment: Line, p1: Point, p2: Point, delta: FPNum) -> Self { + Self { + segment, + c1: (segment.start - p1).to_fppoint(), + c2: (segment.end - p2).to_fppoint(), + offset: fp!(0), + delta, + } + } +} + +impl Iterator for BezierCurveSegments { + type Item = Point; + + fn next(&mut self) -> Option { + if self.offset < fp!(1) { + let offset_sq = self.offset * self.offset; + let offset_cub = offset_sq * self.offset; + + let r1 = fp!(1) - self.offset * 3 + offset_sq * 3 - offset_cub; + let r2 = self.offset * 3 - offset_sq * 6 + offset_cub * 3; + let r3 = offset_sq * 3 - offset_cub * 3; + + let x = r1 * self.segment.start.x + + r2 * self.c1.x() + + r3 * self.c2.x() + + offset_cub * self.segment.end.x; + let y = r1 * self.segment.start.y + + r2 * self.c1.y() + + r3 * self.c2.y() + + offset_cub * self.segment.end.y; + + self.offset += self.delta; + + Some(Point::new(x.round(), y.round())) + } else { + None + } + } +} + #[cfg(test)] mod tests { use super::*;