Skip to main content

geop_core_geometry/nurb_curve/
sweep.rs

1use crate::nurb_surface::NurbSurface3D;
2use geop_core_math::{scalars::Scalar, vector::Vector3};
3
4use super::NurbCurve;
5
6impl NurbCurve<4> {
7    /// The ruled surface swept out by translating this curve along
8    /// `offset`: `Scalar(t, s) = self.evaluate(t) + s * offset`. Degree
9    /// `(self.degree, 1)` — same knot vector as `self` in `t`, `s ∈ [0,
10    /// 1]` — control points `[cp_i, cp_i + offset]` row-major per original
11    /// control point `cp_i`.
12    pub fn sweep(&self, offset: Vector3) -> NurbSurface3D {
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![Scalar::ZERO, Scalar::ZERO, Scalar::ONE, Scalar::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::{scalars::Scalar, vector::Vector3};
33
34    use super::super::NurbCurve3D;
35
36    #[test]
37    fn sweep_matches_curve_plus_offset() {
38        let curve = NurbCurve3D::try_new(
39            1,
40            vec![
41                geop_core_math::vector::Vector4::from_array([
42                    Scalar::ZERO,
43                    Scalar::ZERO,
44                    Scalar::ZERO,
45                    Scalar::ONE,
46                ]),
47                geop_core_math::vector::Vector4::from_array([
48                    Scalar::ONE,
49                    Scalar::ZERO,
50                    Scalar::ZERO,
51                    Scalar::ONE,
52                ]),
53            ],
54            vec![Scalar::ZERO, Scalar::ZERO, Scalar::ONE, Scalar::ONE],
55        )
56        .unwrap();
57        let offset = Vector3::from_array([Scalar::ZERO, Scalar::ZERO, Scalar::from_f64(2.0)]);
58        let surface = curve.sweep(offset);
59
60        for t in [0.0, 0.4, 1.0] {
61            let a = surface.evaluate(Scalar::from_f64(t), Scalar::ZERO).unwrap();
62            let b = curve.evaluate(Scalar::from_f64(t)).unwrap();
63            assert!(a.could_be_equal(&b));
64
65            let a_top = surface.evaluate(Scalar::from_f64(t), Scalar::ONE).unwrap();
66            let b_top = curve.evaluate(Scalar::from_f64(t)).unwrap().add(&offset);
67            assert!(a_top.could_be_equal(&b_top));
68        }
69    }
70}