makepad_vector/geometry/
cubic_segment.rs1use crate::geometry::{Point, Transform, Transformation};
2use crate::internal_iter::InternalIterator;
3
4#[derive(Clone, Copy, Debug, PartialEq)]
6#[repr(C)]
7pub struct CubicSegment {
8 pub p0: Point,
9 pub p1: Point,
10 pub p2: Point,
11 pub p3: Point
12}
13
14impl CubicSegment {
15 pub fn new(p0: Point, p1: Point, p2: Point, p3: Point) -> CubicSegment {
17 CubicSegment { p0, p1, p2, p3 }
18 }
19
20 pub fn is_approximately_linear(self, epsilon: f64) -> bool {
22 let v1 = self.p1 - self.p0;
23 let v2 = self.p2 - self.p0;
24 if let Some(vx) = (self.p3 - self.p0).normalize() {
25 v1.cross(vx).abs() < epsilon && v2.cross(vx).abs() < epsilon
28 } else {
29 v1.length() < epsilon && v2.length() < epsilon
32 }
33 }
34
35 pub fn split(self, t: f64) -> (CubicSegment, CubicSegment) {
37 let p01 = self.p0.lerp(self.p1, t);
38 let p12 = self.p1.lerp(self.p2, t);
39 let p23 = self.p2.lerp(self.p3, t);
40 let p012 = p01.lerp(p12, t);
41 let p123 = p12.lerp(p23, t);
42 let p0123 = p012.lerp(p123, t);
43 (
44 CubicSegment::new(self.p0, p01, p012, p0123),
45 CubicSegment::new(p0123, p123, p23, self.p3),
46 )
47 }
48
49 pub fn linearize(self, epsilon: f64) -> Linearize {
52 Linearize {
53 segment: self,
54 epsilon,
55 }
56 }
57}
58
59impl Transform for CubicSegment {
60 fn transform<T>(self, t: &T) -> CubicSegment
61 where
62 T: Transformation,
63 {
64 CubicSegment::new(
65 self.p0.transform(t),
66 self.p1.transform(t),
67 self.p2.transform(t),
68 self.p3.transform(t),
69 )
70 }
71
72 fn transform_mut<T>(&mut self, t: &T)
73 where
74 T: Transformation,
75 {
76 *self = self.transform(t);
77 }
78}
79
80#[derive(Clone, Copy)]
83pub struct Linearize {
84 segment: CubicSegment,
85 epsilon: f64,
86}
87
88impl InternalIterator for Linearize {
89 type Item = Point;
90
91 fn for_each<F>(self, f: &mut F) -> bool
92 where
93 F: FnMut(Point) -> bool,
94 {
95 if self.segment.is_approximately_linear(self.epsilon) {
96 return f(self.segment.p3);
97 }
98 let (segment_0, segment_1) = self.segment.split(0.5);
99 if !segment_0.linearize(self.epsilon).for_each(f) {
100 return false;
101 }
102 segment_1.linearize(self.epsilon).for_each(f)
103 }
104}