ncollide3d/procedural/
bezier.rs#[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 + Copy>(
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 + Copy>(
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 + Copy,
{
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 + Copy>(
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 + Copy>(
control_points: &[Point<N>],
nupoints: usize,
nvpoints: usize,
usubdivs: usize,
vsubdivs: usize,
) -> TriMesh<N>
where
N: RealField + Copy,
{
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
}