geop_core_geometry/nurb_surface/
reverse.rs1use geop_core_math::{scalars::Scalar, vector::Vector};
2
3use super::NurbSurface;
4
5impl<const D: usize> NurbSurface<D> {
6 pub fn reverse_u(&self) -> Self {
19 let (lo, hi) = self.domain_u();
20 let span = lo.add(hi);
21
22 let knot_vector_u: Vec<Scalar> = self
25 .knot_vector_u
26 .iter()
27 .rev()
28 .map(|&k| span.sub(k))
29 .collect();
30
31 let mut control_points: Vec<Vector<D>> = Vec::with_capacity(self.control_points.len());
34 for i in (0..self.num_u).rev() {
35 for j in 0..self.num_v {
36 control_points.push(self.control_points[i * self.num_v + j]);
37 }
38 }
39
40 NurbSurface {
41 degree_u: self.degree_u,
42 degree_v: self.degree_v,
43 num_u: self.num_u,
44 num_v: self.num_v,
45 control_points,
46 knot_vector_u,
47 knot_vector_v: self.knot_vector_v.clone(),
48 aabb: self.aabb,
51 }
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use crate::nurb_surface::NurbSurface3D;
58 use geop_core_math::{scalars::Scalar, vector::Vector4};
59
60 fn saddle() -> NurbSurface3D {
62 let p = |x: f64, y: f64, z: f64| {
63 Vector4::from_array([
64 Scalar::from_f64(x),
65 Scalar::from_f64(y),
66 Scalar::from_f64(z),
67 Scalar::ONE,
68 ])
69 };
70 NurbSurface3D::try_new(
71 1,
72 1,
73 vec![p(0., 0., 0.), p(0., 2., 1.), p(2., 0., 1.), p(2., 2., 0.)],
74 vec![Scalar::ZERO, Scalar::ZERO, Scalar::ONE, Scalar::ONE],
75 vec![Scalar::ZERO, Scalar::ZERO, Scalar::ONE, Scalar::ONE],
76 )
77 .unwrap()
78 }
79
80 #[test]
83 fn reverse_u_traces_the_same_surface() {
84 let s = saddle();
85 let r = s.reverse_u();
86 let (lo, hi) = s.domain_u();
87 assert!(r.domain_u().0.could_be_equal(lo) && r.domain_u().1.could_be_equal(hi));
88
89 for &(u, v) in &[(0.25, 0.4), (0.5, 0.5), (0.8, 0.1)] {
90 let (u, v) = (Scalar::from_f64(u), Scalar::from_f64(v));
91 let original = s.evaluate(u, v).unwrap();
92 let mirrored = r.evaluate(lo.add(hi).sub(u), v).unwrap();
93 for c in 0..3 {
94 assert!(
95 original[c].could_be_equal(mirrored[c]),
96 "coord {c}: {original:?} vs {mirrored:?}"
97 );
98 }
99 }
100 }
101
102 #[test]
104 fn reverse_u_flips_the_normal() {
105 let s = saddle();
106 let r = s.reverse_u();
107 let (lo, hi) = s.domain_u();
108 let (u, v) = (Scalar::from_f64(0.3), Scalar::from_f64(0.7));
109 let n0 = s.normal(u, v).unwrap();
110 let n1 = r.normal(lo.add(hi).sub(u), v).unwrap();
111 for c in 0..3 {
112 assert!(
113 n0[c].could_be_equal(n1[c].neg()),
114 "coord {c}: {n0:?} vs {n1:?}"
115 );
116 }
117 }
118}