Implement BeizerCurveSegments, no tests
authorunc0rr
Mon, 05 Nov 2018 21:36:28 +0100
changeset 14160 37c99587825d
parent 14159 417d81c72119
child 14161 3078123e84ea
Implement BeizerCurveSegments, no tests
rust/fpnum/src/lib.rs
rust/integral-geometry/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
         }
     }
 
--- 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<Self::Item> {
+        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::*;