geop_core_geometry/nurb_curve/
sweep.rs1use crate::nurb_surface::NurbSurface3D;
2use geop_core_math::{scalars::Scalar, vector::Vector3};
3
4use super::NurbCurve;
5
6impl<S: Scalar> NurbCurve<S, 4> {
7 pub fn sweep(&self, offset: Vector3<S>) -> NurbSurface3D<S> {
13 let shifted = self.translate(offset);
14 let mut control_points = Vec::with_capacity(self.control_points.len() * 2);
15 for i in 0..self.control_points.len() {
16 control_points.push(self.control_points[i]);
17 control_points.push(shifted.control_points[i]);
18 }
19 NurbSurface3D::try_new(
20 self.degree,
21 1,
22 control_points,
23 self.knot_vector.clone(),
24 vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
25 )
26 .expect("sweeping a valid curve always yields a valid ruled surface")
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use geop_core_math::for_all_scalars;
33 use geop_core_math::{scalars::Scalar, vector::Vector3};
34
35 use super::super::NurbCurve3D;
36
37 fn check_sweep_matches_curve_plus_offset<S: Scalar>() {
38 let curve = NurbCurve3D::try_new(
39 1,
40 vec![
41 geop_core_math::vector::Vector4::from_array([S::ZERO, S::ZERO, S::ZERO, S::ONE]),
42 geop_core_math::vector::Vector4::from_array([S::ONE, S::ZERO, S::ZERO, S::ONE]),
43 ],
44 vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
45 )
46 .unwrap();
47 let offset = Vector3::from_array([S::ZERO, S::ZERO, S::from_f64(2.0)]);
48 let surface = curve.sweep(offset);
49
50 for t in [0.0, 0.4, 1.0] {
51 let a = surface.evaluate(S::from_f64(t), S::ZERO).unwrap();
52 let b = curve.evaluate(S::from_f64(t)).unwrap();
53 assert!(a.could_be_equal(&b));
54
55 let a_top = surface.evaluate(S::from_f64(t), S::ONE).unwrap();
56 let b_top = curve.evaluate(S::from_f64(t)).unwrap().add(&offset);
57 assert!(a_top.could_be_equal(&b_top));
58 }
59 }
60 #[test]
61 fn sweep_matches_curve_plus_offset() {
62 for_all_scalars!(check_sweep_matches_curve_plus_offset);
63 }
64}