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
use std::iter;
use std::ptr;
use na;
use super::{TriMesh, Polyline};
use math::{Point, Vect};
#[doc(hidden)]
pub fn bezier_curve_at<P>(control_points: &[P], t: <P::Vect as Vect>::Scalar, cache: &mut Vec<P>) -> P
where P: Point {
if control_points.len() > cache.len() {
let diff = control_points.len() - cache.len();
cache.extend(iter::repeat(na::orig::<P>()).take(diff))
}
let cache = &mut cache[..];
let _1: <P::Vect as Vect>::Scalar = na::cast(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].as_vec() * t;
}
}
cache[0].clone()
}
#[doc(hidden)]
pub fn bezier_surface_at<P>(
control_points: &[P],
nupoints: usize,
nvpoints: usize,
u: <P::Vect as Vect>::Scalar,
v: <P::Vect as Vect>::Scalar,
ucache: &mut Vec<P>,
vcache: &mut Vec<P>)
-> P
where P: Point {
if vcache.len() < nvpoints {
let diff = nvpoints - vcache.len();
vcache.extend(iter::repeat(na::orig::<P>()).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<P>(control_points: &[P], nsubdivs: usize) -> Polyline<P>
where P: Point {
let mut coords = Vec::with_capacity(nsubdivs);
let mut cache = Vec::new();
let tstep = na::cast(1.0 / (nsubdivs as f64));
let mut t = na::zero::<<P::Vect as Vect>::Scalar>();
while t <= na::one() {
coords.push(bezier_curve_at(control_points, t, &mut cache));
t = t + tstep;
}
Polyline::new(coords, None)
}
pub fn bezier_surface<P>(
control_points: &[P],
nupoints: usize,
nvpoints: usize,
usubdivs: usize,
vsubdivs: usize)
-> TriMesh<P>
where P: Point {
assert!(nupoints * nvpoints == control_points.len());
let mut surface = super::unit_quad::<P>(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
}