1use axiolid_core::{Point3, Scalar, Vec3};
10
11use crate::implicit::SurfaceJet;
12use crate::spline::KnotSpec;
13
14#[derive(Debug, Clone, PartialEq)]
16#[cfg_attr(
17 feature = "serde",
18 derive(serde::Serialize, serde::Deserialize),
19 serde(deny_unknown_fields)
20)]
21pub struct BSplineSurface {
22 pub u_degree: u16,
24 pub v_degree: u16,
26 pub control_points: Vec<Vec<Point3>>,
28 pub u_knots: Vec<Scalar>,
30 pub u_multiplicities: Vec<u32>,
32 pub v_knots: Vec<Scalar>,
34 pub v_multiplicities: Vec<u32>,
36 pub weights: Option<Vec<Vec<Scalar>>>,
38 pub u_closed: bool,
40 pub v_closed: bool,
42 pub knot_spec: KnotSpec,
44 pub self_intersect: Option<bool>,
46}
47
48fn expand(knots: &[Scalar], multiplicities: &[u32]) -> Vec<Scalar> {
50 let mut out = Vec::new();
51 for (&k, &m) in knots.iter().zip(multiplicities) {
52 out.extend(core::iter::repeat_n(k, m as usize));
53 }
54 out
55}
56
57fn span(knots: &[Scalar], degree: usize, count: usize, t: Scalar) -> usize {
60 let mut s = degree;
61 for (k, knot) in knots.iter().enumerate().take(count).skip(degree) {
62 if *knot <= t {
63 s = k;
64 } else {
65 break;
66 }
67 }
68 s
69}
70
71#[allow(clippy::needless_range_loop)] fn basis(knots: &[Scalar], p: usize, s: usize, t: Scalar) -> [Vec<Scalar>; 3] {
76 let mut ndu = vec![vec![0.0; p + 1]; p + 1];
77 let mut left = vec![0.0; p + 1];
78 let mut right = vec![0.0; p + 1];
79 ndu[0][0] = 1.0;
80 for j in 1..=p {
81 left[j] = t - knots[s + 1 - j];
82 right[j] = knots[s + j] - t;
83 let mut saved = 0.0;
84 for r in 0..j {
85 ndu[j][r] = right[r + 1] + left[j - r];
86 let temp = if ndu[j][r] == 0.0 {
87 0.0
88 } else {
89 ndu[r][j - 1] / ndu[j][r]
90 };
91 ndu[r][j] = saved + right[r + 1] * temp;
92 saved = left[j - r] * temp;
93 }
94 ndu[j][j] = saved;
95 }
96 let orders = 2.min(p);
97 let mut ders = [vec![0.0; p + 1], vec![0.0; p + 1], vec![0.0; p + 1]];
98 for j in 0..=p {
99 ders[0][j] = ndu[j][p];
100 }
101 let mut a = [vec![0.0; p + 1], vec![0.0; p + 1]];
102 for r in 0..=p {
103 let (mut s1, mut s2) = (0usize, 1usize);
104 a[0][0] = 1.0;
105 for k in 1..=orders {
106 let mut d = 0.0;
107 let rk = r as isize - k as isize;
108 let pk = p as isize - k as isize;
109 if r >= k {
110 let denom = ndu[(pk + 1) as usize][rk as usize];
111 a[s2][0] = if denom == 0.0 { 0.0 } else { a[s1][0] / denom };
112 d = a[s2][0] * ndu[rk as usize][pk as usize];
113 }
114 let j1 = if rk >= -1 { 1 } else { (-rk) as usize };
115 let j2 = if (r as isize - 1) <= pk { k - 1 } else { p - r };
116 for j in j1..=j2 {
117 let denom = ndu[(pk + 1) as usize][(rk + j as isize) as usize];
118 a[s2][j] = if denom == 0.0 {
119 0.0
120 } else {
121 (a[s1][j] - a[s1][j - 1]) / denom
122 };
123 d += a[s2][j] * ndu[(rk + j as isize) as usize][pk as usize];
124 }
125 if r as isize <= pk {
126 let denom = ndu[(pk + 1) as usize][r];
127 a[s2][k] = if denom == 0.0 {
128 0.0
129 } else {
130 -a[s1][k - 1] / denom
131 };
132 d += a[s2][k] * ndu[r][pk as usize];
133 }
134 ders[k][r] = d;
135 core::mem::swap(&mut s1, &mut s2);
136 }
137 }
138 let mut factor = p as Scalar;
139 for k in 1..=orders {
140 for value in &mut ders[k] {
141 *value *= factor;
142 }
143 factor *= (p - k) as Scalar;
144 }
145 ders
146}
147
148impl BSplineSurface {
149 #[must_use]
152 pub fn domain(&self) -> Option<((Scalar, Scalar), (Scalar, Scalar))> {
153 let (p, q) = (usize::from(self.u_degree), usize::from(self.v_degree));
154 let rows = self.control_points.len();
155 let cols = self.control_points.first()?.len();
156 let (ku, kv) = (
157 expand(&self.u_knots, &self.u_multiplicities),
158 expand(&self.v_knots, &self.v_multiplicities),
159 );
160 if p == 0 || q == 0 || ku.len() != rows + p + 1 || kv.len() != cols + q + 1 {
161 return None;
162 }
163 Some(((ku[p], ku[rows]), (kv[q], kv[cols])))
164 }
165
166 #[must_use]
169 #[allow(clippy::needless_range_loop)]
170 pub fn jet(&self, u: Scalar, v: Scalar) -> Option<SurfaceJet> {
171 let (p, q) = (usize::from(self.u_degree), usize::from(self.v_degree));
172 let ((u0, u1), (v0, v1)) = self.domain()?;
173 let (rows, cols) = (self.control_points.len(), self.control_points[0].len());
174 let (ku, kv) = (
175 expand(&self.u_knots, &self.u_multiplicities),
176 expand(&self.v_knots, &self.v_multiplicities),
177 );
178 let (u, v) = (u.clamp(u0, u1), v.clamp(v0, v1));
179 let (su, sv) = (span(&ku, p, rows, u), span(&kv, q, cols, v));
180 let bu = basis(&ku, p, su, u);
181 let bv = basis(&kv, q, sv, v);
182 let mut a = [[Vec3::ZERO; 3]; 3];
184 let mut w = [[0.0; 3]; 3];
185 for i in 0..=p {
186 for j in 0..=q {
187 let (row, col) = (su - p + i, sv - q + j);
188 let weight = self.weights.as_ref().map_or(1.0, |net| net[row][col]);
189 let point = self.control_points[row][col] * weight;
190 for k in 0..3 {
191 for l in 0..3 - k {
192 let n = bu[k][i] * bv[l][j];
193 a[k][l] += point * n;
194 w[k][l] += weight * n;
195 }
196 }
197 }
198 }
199 if w[0][0] == 0.0 || !w[0][0].is_finite() {
200 return None;
201 }
202 let inv = 1.0 / w[0][0];
203 let s = a[0][0] * inv;
204 let s_u = (a[1][0] - s * w[1][0]) * inv;
205 let s_v = (a[0][1] - s * w[0][1]) * inv;
206 let s_uu = (a[2][0] - s_u * (2.0 * w[1][0]) - s * w[2][0]) * inv;
207 let s_vv = (a[0][2] - s_v * (2.0 * w[0][1]) - s * w[0][2]) * inv;
208 let s_uv = (a[1][1] - s_u * w[0][1] - s_v * w[1][0] - s * w[1][1]) * inv;
209 let jet = SurfaceJet {
210 point: s,
211 u: s_u,
212 v: s_v,
213 uu: s_uu,
214 uv: s_uv,
215 vv: s_vv,
216 };
217 (jet.point.is_finite() && jet.u.is_finite() && jet.v.is_finite()).then_some(jet)
218 }
219}