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