geop_core_geometry/nurb_surface/
reverse.rs1use geop_core_math::{scalars::Scalar, vector::Vector};
2
3use super::NurbSurface;
4
5impl<S: Scalar, const D: usize> NurbSurface<S, 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<S> = 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<S, 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::for_all_scalars;
59 use geop_core_math::{scalars::Scalar, vector::Vector4};
60
61 fn saddle<S: Scalar>() -> NurbSurface3D<S> {
63 let p = |x: f64, y: f64, z: f64| {
64 Vector4::from_array([S::from_f64(x), S::from_f64(y), S::from_f64(z), S::ONE])
65 };
66 NurbSurface3D::try_new(
67 1,
68 1,
69 vec![p(0., 0., 0.), p(0., 2., 1.), p(2., 0., 1.), p(2., 2., 0.)],
70 vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
71 vec![S::ZERO, S::ZERO, S::ONE, S::ONE],
72 )
73 .unwrap()
74 }
75
76 fn check_reverse_u_traces_the_same_surface<S: Scalar>() {
79 let s = saddle::<S>();
80 let r = s.reverse_u();
81 let (lo, hi) = s.domain_u();
82 assert!(r.domain_u().0.could_be_equal(lo) && r.domain_u().1.could_be_equal(hi));
83
84 for &(u, v) in &[(0.25, 0.4), (0.5, 0.5), (0.8, 0.1)] {
85 let (u, v) = (S::from_f64(u), S::from_f64(v));
86 let original = s.evaluate(u, v).unwrap();
87 let mirrored = r.evaluate(lo.add(hi).sub(u), v).unwrap();
88 for c in 0..3 {
89 assert!(
90 original[c].could_be_equal(mirrored[c]),
91 "coord {c}: {original:?} vs {mirrored:?}"
92 );
93 }
94 }
95 }
96 #[test]
97 fn reverse_u_traces_the_same_surface() {
98 for_all_scalars!(check_reverse_u_traces_the_same_surface);
99 }
100
101 fn check_reverse_u_flips_the_normal<S: Scalar>() {
103 let s = saddle::<S>();
104 let r = s.reverse_u();
105 let (lo, hi) = s.domain_u();
106 let (u, v) = (S::from_f64(0.3), S::from_f64(0.7));
107 let n0 = s.normal(u, v).unwrap();
108 let n1 = r.normal(lo.add(hi).sub(u), v).unwrap();
109 for c in 0..3 {
110 assert!(
111 n0[c].could_be_equal(n1[c].neg()),
112 "coord {c}: {n0:?} vs {n1:?}"
113 );
114 }
115 }
116 #[test]
117 fn reverse_u_flips_the_normal() {
118 for_all_scalars!(check_reverse_u_flips_the_normal);
119 }
120}