Skip to main content

geop_core_geometry/nurb_surface/
translate.rs

1use geop_core_math::{scalars::Scalar, vector::Vector3};
2
3use super::NurbSurface;
4
5impl<S: Scalar> NurbSurface<S, 4> {
6    /// This surface shifted by `offset` — same shape and parametrization,
7    /// every point moved by `offset`. Translates each (homogeneous) control
8    /// point by `offset * weight`, leaving weights and knot vectors
9    /// untouched.
10    pub fn translate(&self, offset: Vector3<S>) -> Self {
11        let control_points = self
12            .control_points
13            .iter()
14            .map(|cp| {
15                let w = cp[3];
16                geop_core_math::vector::Vector4::from_array([
17                    cp[0].add(offset[0].mul(w)),
18                    cp[1].add(offset[1].mul(w)),
19                    cp[2].add(offset[2].mul(w)),
20                    w,
21                ])
22            })
23            .collect();
24        Self {
25            degree_u: self.degree_u,
26            degree_v: self.degree_v,
27            num_u: self.num_u,
28            num_v: self.num_v,
29            control_points,
30            knot_vector_u: self.knot_vector_u.clone(),
31            knot_vector_v: self.knot_vector_v.clone(),
32            // Every control point moved by exactly `offset`, so the box
33            // moves by `offset` too — cheaper than rescanning the points.
34            aabb: [
35                self.aabb[0].add(offset[0]),
36                self.aabb[1].add(offset[1]),
37                self.aabb[2].add(offset[2]),
38            ],
39        }
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use geop_core_math::for_all_scalars;
46    use geop_core_math::{scalars::Scalar, vector::Vector3};
47
48    use super::super::NurbSurface3D;
49
50    fn check_translate_shifts_evaluated_points<S: Scalar>() {
51        let p = |x: f64, y: f64, z: f64| {
52            geop_core_math::vector::Vector4::from_array([
53                S::from_f64(x),
54                S::from_f64(y),
55                S::from_f64(z),
56                S::ONE,
57            ])
58        };
59        let surface = NurbSurface3D::try_new(
60            1,
61            1,
62            vec![
63                p(0.0, 0.0, 0.0),
64                p(0.0, 1.0, 0.0),
65                p(1.0, 0.0, 0.0),
66                p(1.0, 1.0, 0.0),
67            ],
68            vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
69            vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
70        )
71        .unwrap();
72        let offset = Vector3::from_array([S::from_f64(2.0), S::from_f64(3.0), S::from_f64(-1.0)]);
73        let shifted = surface.translate(offset);
74        let a = shifted
75            .evaluate(S::from_f64(0.3), S::from_f64(0.7))
76            .unwrap();
77        let b = surface
78            .evaluate(S::from_f64(0.3), S::from_f64(0.7))
79            .unwrap()
80            .add(&offset);
81        assert!(a.could_be_equal(&b));
82    }
83    #[test]
84    fn translate_shifts_evaluated_points() {
85        for_all_scalars!(check_translate_shifts_evaluated_points);
86    }
87}