75 lines
2.1 KiB
Rust
75 lines
2.1 KiB
Rust
use crate::core::pbrt::{Float, lerp};
|
|
use crate::geometry::{Bounds3f, Lerp, Point3f, Vector3f, VectorLike};
|
|
use num_traits::Num;
|
|
|
|
fn bounds_cubic_bezier(cp: &[Point3f]) -> Bounds3f {
|
|
Bounds3f::from_points(cp[0], cp[1]).union(Bounds3f::from_points(cp[2], cp[3]))
|
|
}
|
|
|
|
pub fn bound_cubic_bezier(cp: &[Point3f], u_min: Float, u_max: Float) -> Bounds3f {
|
|
if u_min == 0. && u_max == 1. {
|
|
return bounds_cubic_bezier(cp);
|
|
}
|
|
let cp_seg = cubic_bezier_control_points(cp, u_min, u_max);
|
|
bounds_cubic_bezier(&cp_seg)
|
|
}
|
|
|
|
pub fn cubic_bezier_control_points(cp: &[Point3f], u_min: Float, u_max: Float) -> [Point3f; 4] {
|
|
[
|
|
blossom_cubic_bezier(cp, u_min, u_max, u_min),
|
|
blossom_cubic_bezier(cp, u_min, u_min, u_max),
|
|
blossom_cubic_bezier(cp, u_min, u_max, u_max),
|
|
blossom_cubic_bezier(cp, u_max, u_max, u_max),
|
|
]
|
|
}
|
|
|
|
fn blossom_cubic_bezier<P, F>(p: &[P], u0: F, u1: F, u2: F) -> P
|
|
where
|
|
F: Copy + Num,
|
|
P: Lerp<F>,
|
|
{
|
|
let a: [P; 3] = [
|
|
lerp(u0, p[0], p[1]),
|
|
lerp(u0, p[1], p[2]),
|
|
lerp(u0, p[2], p[3]),
|
|
];
|
|
let b: [P; 2] = [lerp(u1, a[0], a[1]), lerp(u1, a[1], a[2])];
|
|
lerp(u2, b[0], b[1])
|
|
}
|
|
|
|
pub fn subdivide_cubic_bezier(cp: &[Point3f]) -> [Point3f; 7] {
|
|
let v: Vec<Vector3f> = cp.iter().map(|&p| p.into()).collect();
|
|
let v01 = (v[0] + v[1]) / 2.0;
|
|
let v12 = (v[1] + v[2]) / 2.0;
|
|
let v23 = (v[2] + v[3]) / 2.0;
|
|
|
|
let v012 = (v01 + v12) / 2.0;
|
|
let v123 = (v12 + v23) / 2.0;
|
|
|
|
let v0123 = (v012 + v123) / 2.0;
|
|
[
|
|
cp[0],
|
|
v01.into(),
|
|
v012.into(),
|
|
v0123.into(),
|
|
v123.into(),
|
|
v23.into(),
|
|
cp[3],
|
|
]
|
|
}
|
|
|
|
pub fn evaluate_cubic_bezier(cp: &[Point3f], u: Float) -> (Point3f, Vector3f) {
|
|
let cp1 = [
|
|
lerp(u, cp[0], cp[1]),
|
|
lerp(u, cp[1], cp[2]),
|
|
lerp(u, cp[2], cp[3]),
|
|
];
|
|
let cp2 = [lerp(u, cp1[0], cp1[1]), lerp(u, cp1[1], cp1[2])];
|
|
let deriv = if (cp2[1] - cp2[0]).norm_squared() > 0. {
|
|
(cp2[1] - cp2[0]) * 3.
|
|
} else {
|
|
cp[3] - cp[0]
|
|
};
|
|
|
|
(lerp(u, cp2[0], cp2[1]), deriv)
|
|
}
|