1use crate::geo::*;
2use super::basis::*;
3
4use smallvec::*;
5
6pub fn subdivide_n<TPoint, const N: usize>(t: f64, points: [TPoint; N]) -> ([TPoint; N], [TPoint; N])
11where
12 TPoint: Coordinate,
13{
14 let num_weights = (N * (N+1))/2;
16
17 let mut weights = Vec::with_capacity(num_weights);
20
21 weights.extend(points);
23
24 let mut last_pos = 0;
26
27 for depth in (1..N).into_iter().rev() {
28 for p in 0..depth {
30 let wn = weights[last_pos+p]*(1.0-t) + weights[last_pos+p+1]*t;
31 weights.push(wn);
32 }
33
34 last_pos += depth+1;
36 }
37
38 let mut first_weights = SmallVec::<[_; N]>::new();
41 let mut second_weights = SmallVec::<[_; N]>::new();
42
43 let mut last_pos = 0;
44 for depth in (0..N).into_iter().rev() {
45 first_weights.push(weights[last_pos]);
46 second_weights.push(weights[last_pos+depth]);
47
48 last_pos += depth + 1;
49 }
50
51 if let (Ok(first_weights), Ok(second_weights)) = (first_weights.into_inner(), second_weights.into_inner()) {
53 let mut second_weights: [TPoint; N] = second_weights;
54 second_weights.reverse();
55
56 (first_weights, second_weights)
57 } else {
58 unreachable!()
59 }
60}
61
62pub fn subdivide4<Point: Coordinate>(t: f64, w1: Point, w2: Point, w3: Point, w4: Point) ->
67 ((Point, Point, Point, Point), (Point, Point, Point, Point)) {
68 let wn1 = w1*(1.0-t) + w2*t;
70 let wn2 = w2*(1.0-t) + w3*t;
71 let wn3 = w3*(1.0-t) + w4*t;
72
73 let wnn1 = wn1*(1.0-t) + wn2*t;
75 let wnn2 = wn2*(1.0-t) + wn3*t;
76
77 let p = de_casteljau2(t, wnn1, wnn2);
79
80 ((w1, wn1, wnn1, p), (p, wnn2, wn3, w4))
82}
83
84#[cfg(test)]
85mod test {
86 use super::*;
87
88 pub fn approx_equal(a: f64, b: f64) -> bool {
89 f64::floor(f64::abs(a-b)*10000.0) == 0.0
90 }
91
92 #[test]
93 fn subdivide_n_1() {
94 let (w1, w2, w3, w4) = (1.0, 2.0, 3.0, 4.0);
96
97 let ([wa1, wa2, wa3, wa4], [wb1, wb2, wb3, wb4]) = subdivide_n(0.33, [w1, w2, w3, w4]);
99 let ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)) = subdivide4(0.33, w1, w2, w3, w4);
100
101 debug_assert!(approx_equal(wa1, waa1), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
102 debug_assert!(approx_equal(wa2, waa2), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
103 debug_assert!(approx_equal(wa3, waa3), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
104 debug_assert!(approx_equal(wa4, waa4), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
105
106 debug_assert!(approx_equal(wb1, wbb1), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
107 debug_assert!(approx_equal(wb2, wbb2), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
108 debug_assert!(approx_equal(wb3, wbb3), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
109 debug_assert!(approx_equal(wb4, wbb4), "{:?} != {:?}", ((wa1, wa2, wa3, wa4), (wb1, wb2, wb3, wb4)), ((waa1, waa2, waa3, waa4), (wbb1, wbb2, wbb3, wbb4)));
110
111 for x in 0..100 {
113 let t = (x as f64)/100.0;
114
115 let original = basis(t*0.33, w1, w2, w3, w4);
116 let subdivision = basis(t, wa1, wa2, wa3, wa4);
117
118 assert!(approx_equal(original, subdivision));
119 }
120 }
121
122}