1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#[cfg(feature = "dim3")]
use super::TriMesh;
use crate::math::Point;
use na::{self, RealField};
use std::iter;
use std::ptr;
#[doc(hidden)]
pub fn bezier_curve_at<N: RealField>(
control_points: &[Point<N>],
t: N,
cache: &mut Vec<Point<N>>,
) -> Point<N> {
if control_points.len() > cache.len() {
let diff = control_points.len() - cache.len();
cache.extend(iter::repeat(Point::origin()).take(diff))
}
let cache = &mut cache[..];
let _1: N = na::convert(1.0);
let t_1 = _1 - t;
unsafe {
ptr::copy_nonoverlapping(
control_points.as_ptr(),
cache.as_mut_ptr(),
control_points.len(),
);
}
for i in 1usize..control_points.len() {
for j in 0usize..control_points.len() - i {
cache[j] = cache[j] * t_1 + cache[j + 1].coords * t;
}
}
cache[0].clone()
}
#[cfg(feature = "dim3")]
#[doc(hidden)]
pub fn bezier_surface_at<N: RealField>(
control_points: &[Point<N>],
nupoints: usize,
nvpoints: usize,
u: N,
v: N,
ucache: &mut Vec<Point<N>>,
vcache: &mut Vec<Point<N>>,
) -> Point<N>
where
N: RealField,
{
if vcache.len() < nvpoints {
let diff = nvpoints - vcache.len();
vcache.extend(iter::repeat(Point::origin()).take(diff));
}
let vcache = &mut vcache[..];
for i in 0..nvpoints {
let start = i * nupoints;
let end = start + nupoints;
vcache[i] = bezier_curve_at(&control_points[start..end], u, ucache);
}
bezier_curve_at(&vcache[0..nvpoints], v, ucache)
}
pub fn bezier_curve<N: RealField>(control_points: &[Point<N>], nsubdivs: usize) -> Vec<Point<N>> {
let mut coords = Vec::with_capacity(nsubdivs);
let mut cache = Vec::new();
let tstep = na::convert(1.0 / (nsubdivs as f64));
let mut t = na::zero::<N>();
while t <= na::one() {
coords.push(bezier_curve_at(control_points, t, &mut cache));
t = t + tstep;
}
coords
}
#[cfg(feature = "dim3")]
pub fn bezier_surface<N: RealField>(
control_points: &[Point<N>],
nupoints: usize,
nvpoints: usize,
usubdivs: usize,
vsubdivs: usize,
) -> TriMesh<N>
where
N: RealField,
{
assert!(nupoints * nvpoints == control_points.len());
let mut surface = super::unit_quad(usubdivs, vsubdivs);
{
let uvs = &surface.uvs.as_ref().unwrap()[..];
let coords = &mut surface.coords[..];
let mut ucache = Vec::new();
let mut vcache = Vec::new();
for j in 0..vsubdivs + 1 {
for i in 0..usubdivs + 1 {
let id = i + j * (usubdivs + 1);
coords[id] = bezier_surface_at(
control_points,
nupoints,
nvpoints,
uvs[id].x,
uvs[id].y,
&mut ucache,
&mut vcache,
)
}
}
surface.normals = None;
}
surface
}