1use axiolid_core::{Frame3, Point2, Point3, Scalar, Vec2, Vec3};
25use core::f64::consts::{PI, TAU};
26
27use crate::quadric_section::RuledCarrier;
28use crate::torus_section::TorusCarrier;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[cfg_attr(
33 feature = "serde",
34 derive(serde::Serialize, serde::Deserialize),
35 serde(deny_unknown_fields)
36)]
37pub enum Basis {
38 Power,
40 Fourier,
43}
44
45impl Basis {
46 fn values_into(self, x: Scalar, out: &mut [Scalar]) {
49 let n = out.len();
50 match self {
51 Basis::Power => {
52 let mut p = 1.0;
53 for slot in out.iter_mut() {
54 *slot = p;
55 p *= x;
56 }
57 }
58 Basis::Fourier => {
59 if n > 0 {
60 out[0] = 1.0;
61 }
62 let mut k = 1;
63 while 2 * k - 1 < n {
64 let w = k as Scalar;
65 let (s, c) = (w * x).sin_cos();
66 out[2 * k - 1] = c;
67 if 2 * k < n {
68 out[2 * k] = s;
69 }
70 k += 1;
71 }
72 }
73 }
74 }
75
76 fn terms(self, x: Scalar, n: usize) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>) {
78 let (mut f, mut d, mut dd) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
79 match self {
80 Basis::Power => {
81 let mut p = 1.0;
82 for slot in f.iter_mut() {
83 *slot = p;
84 p *= x;
85 }
86 for k in 1..n {
87 d[k] = k as Scalar * f[k - 1];
88 }
89 for k in 2..n {
90 dd[k] = (k * (k - 1)) as Scalar * f[k - 2];
91 }
92 }
93 Basis::Fourier => {
94 if n > 0 {
95 f[0] = 1.0;
96 }
97 let mut k = 1;
98 while 2 * k - 1 < n {
99 let w = k as Scalar;
100 let (s, c) = (w * x).sin_cos();
101 f[2 * k - 1] = c;
102 d[2 * k - 1] = -w * s;
103 dd[2 * k - 1] = -w * w * c;
104 if 2 * k < n {
105 f[2 * k] = s;
106 d[2 * k] = w * c;
107 dd[2 * k] = -w * w * s;
108 }
109 k += 1;
110 }
111 }
112 }
113 (f, d, dd)
114 }
115}
116
117#[derive(Debug, Clone, PartialEq)]
121#[cfg_attr(
122 feature = "serde",
123 derive(serde::Serialize, serde::Deserialize),
124 serde(deny_unknown_fields)
125)]
126pub struct SeriesField2 {
127 pub u: Basis,
129 pub v: Basis,
131 pub coefficients: Vec<Vec<Scalar>>,
133}
134
135#[derive(Debug, Clone, PartialEq)]
138#[cfg_attr(
139 feature = "serde",
140 derive(serde::Serialize, serde::Deserialize),
141 serde(deny_unknown_fields)
142)]
143pub enum Field2 {
144 Series(SeriesField2),
146 Patches(PatchField2),
148}
149
150impl Field2 {
151 #[must_use]
153 pub fn value(&self, p: Point2) -> Scalar {
154 match self {
155 Self::Series(f) => f.value(p),
156 Self::Patches(f) => f.jet(p).value,
157 }
158 }
159
160 #[must_use]
162 pub fn jet(&self, p: Point2) -> Jet2 {
163 match self {
164 Self::Series(f) => f.jet(p),
165 Self::Patches(f) => f.jet(p),
166 }
167 }
168
169 #[must_use]
172 pub fn magnitude(&self) -> Scalar {
173 match self {
174 Self::Series(f) => f.magnitude(),
175 Self::Patches(f) => f.magnitude(),
176 }
177 }
178
179 #[must_use]
185 pub fn scale_at(&self, p: Point2) -> Scalar {
186 match self {
187 Self::Series(f) => {
188 let (n, m) = f.size();
189 let (fu, _, _) = f.u.terms(p.x, n);
190 let (fv, _, _) = f.v.terms(p.y, m);
191 let mut sum = 0.0;
192 for (i, row) in f.coefficients.iter().enumerate() {
193 for (j, &c) in row.iter().enumerate() {
194 sum += (c * fu[i] * fv[j]).abs();
195 }
196 }
197 sum
198 }
199 Self::Patches(f) => f.magnitude(),
201 }
202 }
203
204 #[must_use]
206 pub fn is_finite(&self) -> bool {
207 match self {
208 Self::Series(f) => f.is_finite(),
209 Self::Patches(f) => f.is_finite(),
210 }
211 }
212}
213
214#[derive(Debug, Clone, PartialEq)]
220#[cfg_attr(
221 feature = "serde",
222 derive(serde::Serialize, serde::Deserialize),
223 serde(deny_unknown_fields)
224)]
225pub struct PatchField2 {
226 pub u_breaks: Vec<Scalar>,
228 pub v_breaks: Vec<Scalar>,
230 pub u_degree: usize,
232 pub v_degree: usize,
234 pub patches: Vec<Vec<Scalar>>,
237}
238
239fn bernstein(n: usize, s: Scalar) -> [Vec<Scalar>; 3] {
241 let basis = |n: usize| -> Vec<Scalar> {
242 let mut b = vec![0.0; n + 1];
244 b[0] = 1.0;
245 for k in 1..=n {
246 let mut prev = 0.0;
247 for slot in b.iter_mut().take(k + 1) {
248 let here = *slot;
249 *slot = here * (1.0 - s) + prev * s;
250 prev = here;
251 }
252 }
253 b
254 };
255 let b0 = basis(n);
256 let mut b1 = vec![0.0; n + 1];
257 let mut b2 = vec![0.0; n + 1];
258 if n >= 1 {
259 let lower = basis(n - 1);
260 for a in 0..=n {
261 let left = if a >= 1 { lower[a - 1] } else { 0.0 };
262 let right = if a < n { lower[a] } else { 0.0 };
263 b1[a] = n as Scalar * (left - right);
264 }
265 }
266 if n >= 2 {
267 let lower = basis(n - 2);
268 let at = |k: isize| {
269 if k >= 0 && (k as usize) <= n - 2 {
270 lower[k as usize]
271 } else {
272 0.0
273 }
274 };
275 for a in 0..=n {
276 let a = a as isize;
277 b2[a as usize] = (n * (n - 1)) as Scalar * (at(a - 2) - 2.0 * at(a - 1) + at(a));
278 }
279 }
280 [b0, b1, b2]
281}
282
283#[allow(clippy::needless_range_loop)] fn restrict(c: &[Scalar], s0: Scalar, s1: Scalar) -> Vec<Scalar> {
288 let n = c.len();
289 let left = |c: &[Scalar], s: Scalar| -> Vec<Scalar> {
292 let mut w = c.to_vec();
293 let mut out = vec![0.0; n];
294 out[0] = w[0];
295 for k in 1..n {
296 for i in 0..n - k {
297 w[i] = w[i] * (1.0 - s) + w[i + 1] * s;
298 }
299 out[k] = w[0];
300 }
301 out
302 };
303 let right = |c: &[Scalar], s: Scalar| -> Vec<Scalar> {
305 let mut w = c.to_vec();
306 let mut out = vec![0.0; n];
307 out[n - 1] = w[n - 1];
308 for k in 1..n {
309 for i in 0..n - k {
310 w[i] = w[i] * (1.0 - s) + w[i + 1] * s;
311 }
312 out[n - 1 - k] = w[n - 1 - k];
313 }
314 out
315 };
316 if s1 <= s0 {
317 let mut w = c.to_vec();
319 for k in 1..n {
320 for i in 0..n - k {
321 w[i] = w[i] * (1.0 - s0) + w[i + 1] * s0;
322 }
323 }
324 return vec![w[0]; n];
325 }
326 if s0 == 0.0 && s1 == 1.0 {
327 return c.to_vec();
328 }
329 if s1.abs() >= (1.0 - s0).abs() {
332 let over = left(c, s1);
333 right(&over, s0 / s1)
334 } else {
335 let over = right(c, s0);
336 left(&over, (s1 - s0) / (1.0 - s0))
337 }
338}
339
340impl PatchField2 {
341 fn cells(&self) -> (usize, usize) {
342 (self.u_breaks.len() - 1, self.v_breaks.len() - 1)
343 }
344
345 fn cell_of(breaks: &[Scalar], x: Scalar) -> usize {
347 let n = breaks.len() - 1;
348 let mut i = 0;
349 while i + 1 < n && x >= breaks[i + 1] {
350 i += 1;
351 }
352 i
353 }
354
355 #[must_use]
358 pub fn jet(&self, p: Point2) -> Jet2 {
359 let (_, m) = self.cells();
360 let i = Self::cell_of(&self.u_breaks, p.x);
361 let j = Self::cell_of(&self.v_breaks, p.y);
362 let (hu, hv) = (
363 self.u_breaks[i + 1] - self.u_breaks[i],
364 self.v_breaks[j + 1] - self.v_breaks[j],
365 );
366 let s = (p.x - self.u_breaks[i]) / hu;
369 let t = (p.y - self.v_breaks[j]) / hv;
370 let bu = bernstein(self.u_degree, s);
371 let bv = bernstein(self.v_degree, t);
372 let c = &self.patches[i * m + j];
373 let q = self.v_degree + 1;
374 let mut jet = Jet2 {
375 value: 0.0,
376 gradient: Vec2::ZERO,
377 uu: 0.0,
378 uv: 0.0,
379 vv: 0.0,
380 };
381 for a in 0..=self.u_degree {
382 for b in 0..=self.v_degree {
383 let k = c[a * q + b];
384 jet.value += k * bu[0][a] * bv[0][b];
385 jet.gradient.x += k * bu[1][a] * bv[0][b];
386 jet.gradient.y += k * bu[0][a] * bv[1][b];
387 jet.uu += k * bu[2][a] * bv[0][b];
388 jet.uv += k * bu[1][a] * bv[1][b];
389 jet.vv += k * bu[0][a] * bv[2][b];
390 }
391 }
392 jet.gradient.x /= hu;
393 jet.gradient.y /= hv;
394 jet.uu /= hu * hu;
395 jet.uv /= hu * hv;
396 jet.vv /= hv * hv;
397 jet
398 }
399
400 #[must_use]
402 pub fn magnitude(&self) -> Scalar {
403 self.patches
404 .iter()
405 .flatten()
406 .fold(0.0, |m: Scalar, c| m.max(c.abs()))
407 }
408
409 #[must_use]
411 pub fn is_finite(&self) -> bool {
412 self.patches.iter().flatten().all(|c| c.is_finite())
413 && self
414 .u_breaks
415 .iter()
416 .chain(&self.v_breaks)
417 .all(|b| b.is_finite())
418 }
419
420 #[must_use]
423 pub fn bound(&self, cell: &Cell) -> Range {
424 let (n, m) = self.cells();
425 let q = self.v_degree + 1;
426 let mut out: Option<Range> = None;
427 for i in 0..n {
428 let (a0, a1) = (self.u_breaks[i], self.u_breaks[i + 1]);
429 let reach_lo = if i == 0 { Scalar::NEG_INFINITY } else { a0 };
431 let reach_hi = if i + 1 == n { Scalar::INFINITY } else { a1 };
432 if reach_hi < cell.lo.x || reach_lo > cell.hi.x {
433 continue;
434 }
435 let (s0, s1) = (
436 (cell.lo.x.max(reach_lo) - a0) / (a1 - a0),
437 (cell.hi.x.min(reach_hi) - a0) / (a1 - a0),
438 );
439 for j in 0..m {
440 let (b0, b1) = (self.v_breaks[j], self.v_breaks[j + 1]);
441 let reach_lo = if j == 0 { Scalar::NEG_INFINITY } else { b0 };
442 let reach_hi = if j + 1 == m { Scalar::INFINITY } else { b1 };
443 if reach_hi < cell.lo.y || reach_lo > cell.hi.y {
444 continue;
445 }
446 let (t0, t1) = (
447 (cell.lo.y.max(reach_lo) - b0) / (b1 - b0),
448 (cell.hi.y.min(reach_hi) - b0) / (b1 - b0),
449 );
450 let c = &self.patches[i * m + j];
451 let mut rows: Vec<Vec<Scalar>> = (0..=self.u_degree)
453 .map(|a| restrict(&c[a * q..(a + 1) * q], t0, t1))
454 .collect();
455 for b in 0..q {
456 let column: Vec<Scalar> = rows.iter().map(|r| r[b]).collect();
457 let restricted = restrict(&column, s0, s1);
458 for (a, value) in restricted.into_iter().enumerate() {
459 rows[a][b] = value;
460 }
461 }
462 let (mut lo, mut hi) = (Scalar::INFINITY, Scalar::NEG_INFINITY);
463 let mut size: Scalar = 0.0;
464 for value in rows.iter().flatten() {
465 lo = lo.min(*value);
466 hi = hi.max(*value);
467 size = size.max(value.abs());
468 }
469 let r = Range { lo, hi }
470 .widen(64.0 * Scalar::EPSILON * size * (q + self.u_degree + 1) as Scalar);
471 out = Some(match out {
472 None => r,
473 Some(o) => Range {
474 lo: o.lo.min(r.lo),
475 hi: o.hi.max(r.hi),
476 },
477 });
478 }
479 }
480 out.unwrap_or(Range::point(0.0))
481 }
482
483 #[must_use]
486 pub fn partial(&self, along_u: bool) -> Self {
487 let (n, m) = self.cells();
488 let (p, q) = (self.u_degree, self.v_degree);
489 let mut patches = Vec::with_capacity(self.patches.len());
490 for i in 0..n {
491 for j in 0..m {
492 let c = &self.patches[i * m + j];
493 let at = |a: usize, b: usize| c[a * (q + 1) + b];
494 if along_u {
495 let h = self.u_breaks[i + 1] - self.u_breaks[i];
496 if p == 0 {
497 patches.push(vec![0.0; q + 1]);
498 continue;
499 }
500 let mut d = vec![0.0; p * (q + 1)];
501 for a in 0..p {
502 for b in 0..=q {
503 d[a * (q + 1) + b] = p as Scalar * (at(a + 1, b) - at(a, b)) / h;
504 }
505 }
506 patches.push(d);
507 } else {
508 let h = self.v_breaks[j + 1] - self.v_breaks[j];
509 if q == 0 {
510 patches.push(vec![0.0; p + 1]);
511 continue;
512 }
513 let mut d = vec![0.0; (p + 1) * q];
514 for a in 0..=p {
515 for b in 0..q {
516 d[a * q + b] = q as Scalar * (at(a, b + 1) - at(a, b)) / h;
517 }
518 }
519 patches.push(d);
520 }
521 }
522 }
523 let (u_degree, v_degree) = if along_u {
524 (p.saturating_sub(1), q)
525 } else {
526 (p, q.saturating_sub(1))
527 };
528 Self {
529 u_breaks: self.u_breaks.clone(),
530 v_breaks: self.v_breaks.clone(),
531 u_degree,
532 v_degree,
533 patches,
534 }
535 }
536}
537
538#[derive(Debug, Clone, Copy, PartialEq)]
540pub struct Jet2 {
541 pub value: Scalar,
543 pub gradient: Vec2,
545 pub uu: Scalar,
547 pub uv: Scalar,
549 pub vv: Scalar,
551}
552
553impl SeriesField2 {
554 fn size(&self) -> (usize, usize) {
555 let n = self.coefficients.len();
556 let m = self.coefficients.iter().map(Vec::len).max().unwrap_or(0);
557 (n, m)
558 }
559
560 #[must_use]
562 pub fn value(&self, p: Point2) -> Scalar {
563 let (n, m) = self.size();
566 let (mut su, mut sv) = ([0.0; 16], [0.0; 16]);
567 let (mut hu, mut hv) = (Vec::new(), Vec::new());
568 let fu: &mut [Scalar] = if n <= 16 {
569 &mut su[..n]
570 } else {
571 hu.resize(n, 0.0);
572 &mut hu
573 };
574 let fv: &mut [Scalar] = if m <= 16 {
575 &mut sv[..m]
576 } else {
577 hv.resize(m, 0.0);
578 &mut hv
579 };
580 self.u.values_into(p.x, fu);
581 self.v.values_into(p.y, fv);
582 let mut value = 0.0;
583 for (i, row) in self.coefficients.iter().enumerate() {
584 for (j, &c) in row.iter().enumerate() {
585 if c == 0.0 {
586 continue;
587 }
588 value += c * fu[i] * fv[j];
589 }
590 }
591 value
592 }
593
594 #[must_use]
596 pub fn jet(&self, p: Point2) -> Jet2 {
597 let (n, m) = self.size();
598 let (fu, du, ddu) = self.u.terms(p.x, n);
599 let (fv, dv, ddv) = self.v.terms(p.y, m);
600 let mut jet = Jet2 {
601 value: 0.0,
602 gradient: Vec2::ZERO,
603 uu: 0.0,
604 uv: 0.0,
605 vv: 0.0,
606 };
607 for (i, row) in self.coefficients.iter().enumerate() {
608 for (j, &c) in row.iter().enumerate() {
609 if c == 0.0 {
610 continue;
611 }
612 jet.value += c * fu[i] * fv[j];
613 jet.gradient.x += c * du[i] * fv[j];
614 jet.gradient.y += c * fu[i] * dv[j];
615 jet.uu += c * ddu[i] * fv[j];
616 jet.uv += c * du[i] * dv[j];
617 jet.vv += c * fu[i] * ddv[j];
618 }
619 }
620 jet
621 }
622
623 #[must_use]
626 pub fn magnitude(&self) -> Scalar {
627 self.coefficients.iter().flatten().map(|c| c.abs()).sum()
628 }
629
630 #[must_use]
632 pub fn is_finite(&self) -> bool {
633 self.coefficients.iter().flatten().all(|c| c.is_finite())
634 }
635}
636
637#[derive(Debug, Clone, Copy, PartialEq)]
645pub struct Range {
646 pub lo: Scalar,
648 pub hi: Scalar,
650}
651
652impl Range {
653 pub fn point(x: Scalar) -> Self {
655 Self { lo: x, hi: x }
656 }
657
658 pub fn new(a: Scalar, b: Scalar) -> Self {
660 Self {
661 lo: a.min(b),
662 hi: a.max(b),
663 }
664 }
665
666 fn add(self, o: Self) -> Self {
667 Self {
668 lo: self.lo + o.lo,
669 hi: self.hi + o.hi,
670 }
671 }
672
673 fn mul(self, o: Self) -> Self {
674 let p = [
675 self.lo * o.lo,
676 self.lo * o.hi,
677 self.hi * o.lo,
678 self.hi * o.hi,
679 ];
680 Self {
681 lo: p.iter().copied().fold(Scalar::INFINITY, Scalar::min),
682 hi: p.iter().copied().fold(Scalar::NEG_INFINITY, Scalar::max),
683 }
684 }
685
686 fn scale(self, c: Scalar) -> Self {
687 Self::new(self.lo * c, self.hi * c)
688 }
689
690 fn intersect(self, o: Self) -> Self {
691 Self {
692 lo: self.lo.max(o.lo),
693 hi: self.hi.min(o.hi),
694 }
695 }
696
697 fn widen(self, by: Scalar) -> Self {
698 Self {
699 lo: self.lo - by,
700 hi: self.hi + by,
701 }
702 }
703
704 pub fn straddles_zero(self) -> bool {
706 self.lo <= 0.0 && self.hi >= 0.0
707 }
708}
709
710fn cos_range(a: Scalar, b: Scalar) -> Range {
712 if b - a >= TAU {
713 return Range { lo: -1.0, hi: 1.0 };
714 }
715 let (ca, cb) = (a.cos(), b.cos());
716 let mut r = Range::new(ca, cb);
717 let m = (a / TAU).ceil();
719 if m * TAU <= b {
720 r.hi = 1.0;
721 }
722 let m = ((a - PI) / TAU).ceil();
723 if PI + m * TAU <= b {
724 r.lo = -1.0;
725 }
726 r
727}
728
729fn term_range(basis: Basis, k: usize, a: Scalar, b: Scalar) -> Range {
731 match basis {
732 Basis::Power => {
733 if k == 0 {
734 return Range::point(1.0);
735 }
736 let (pa, pb) = (a.powi(k as i32), b.powi(k as i32));
737 if k % 2 == 1 || a >= 0.0 || b <= 0.0 {
739 Range::new(pa, pb)
740 } else {
741 Range {
742 lo: 0.0,
743 hi: pa.max(pb),
744 }
745 }
746 }
747 Basis::Fourier => {
748 if k == 0 {
749 return Range::point(1.0);
750 }
751 let w = k.div_ceil(2) as Scalar;
752 if k % 2 == 1 {
753 cos_range(w * a, w * b)
754 } else {
755 cos_range(w * a - 0.5 * PI, w * b - 0.5 * PI)
757 }
758 }
759 }
760}
761
762#[derive(Debug, Clone, Copy, PartialEq)]
764pub struct Cell {
765 pub lo: Point2,
767 pub hi: Point2,
769}
770
771impl Cell {
772 pub fn centre(&self) -> Point2 {
774 (self.lo + self.hi) * 0.5
775 }
776}
777
778fn naive(field: &SeriesField2, cell: &Cell) -> Range {
780 let mut total = Range::point(0.0);
781 let (n, m) = size(field);
782 let ru: Vec<Range> = (0..n)
783 .map(|k| term_range(field.u, k, cell.lo.x, cell.hi.x))
784 .collect();
785 let rv: Vec<Range> = (0..m)
786 .map(|k| term_range(field.v, k, cell.lo.y, cell.hi.y))
787 .collect();
788 for (i, row) in field.coefficients.iter().enumerate() {
789 for (j, &c) in row.iter().enumerate() {
790 if c != 0.0 {
791 total = total.add(ru[i].mul(rv[j]).scale(c));
792 }
793 }
794 }
795 total
796}
797
798fn margin(field: &SeriesField2, cell: &Cell) -> Scalar {
801 let (n, m) = size(field);
802 let reach = |basis: Basis, x: Scalar, terms: usize| match basis {
804 Basis::Fourier => 1.0,
805 Basis::Power => (1.0 + x.abs()).powi(terms.saturating_sub(1) as i32),
806 };
807 let scale = field.magnitude()
808 * reach(field.u, cell.lo.x.abs().max(cell.hi.x.abs()), n)
809 * reach(field.v, cell.lo.y.abs().max(cell.hi.y.abs()), m);
810 64.0 * Scalar::EPSILON * scale
811}
812
813pub fn bound(field: &Field2, du: &Field2, dv: &Field2, cell: &Cell) -> Range {
816 match (field, du, dv) {
817 (Field2::Series(f), Field2::Series(fu), Field2::Series(fv)) => {
818 let direct = naive(f, cell);
819 let c = cell.centre();
820 let (hu, hv) = (0.5 * (cell.hi.x - cell.lo.x), 0.5 * (cell.hi.y - cell.lo.y));
821 let mean = Range::point(f.value(c))
822 .add(naive(fu, cell).mul(Range { lo: -hu, hi: hu }))
823 .add(naive(fv, cell).mul(Range { lo: -hv, hi: hv }));
824 direct.intersect(mean).widen(margin(f, cell))
825 }
826 _ => bound_simple(field, cell),
827 }
828}
829
830pub fn bound_simple(field: &Field2, cell: &Cell) -> Range {
832 match field {
833 Field2::Series(f) => naive(f, cell).widen(margin(f, cell)),
834 Field2::Patches(f) => f.bound(cell),
835 }
836}
837
838pub fn size(field: &SeriesField2) -> (usize, usize) {
840 (
841 field.coefficients.len(),
842 field.coefficients.iter().map(Vec::len).max().unwrap_or(0),
843 )
844}
845
846pub fn partial(field: &Field2, along_u: bool) -> Field2 {
848 match field {
849 Field2::Series(f) => Field2::Series(series_partial(f, along_u)),
850 Field2::Patches(f) => Field2::Patches(f.partial(along_u)),
851 }
852}
853
854fn series_partial(field: &SeriesField2, along_u: bool) -> SeriesField2 {
855 let (n, m) = size(field);
856 let mut out = vec![vec![0.0; m]; n];
857 let basis = if along_u { field.u } else { field.v };
858 let map = |k: usize| -> Option<(usize, Scalar)> {
859 match basis {
860 Basis::Power => (k > 0).then(|| (k - 1, k as Scalar)),
861 Basis::Fourier => {
862 if k == 0 {
863 None
864 } else {
865 let w = k.div_ceil(2) as Scalar;
866 if k % 2 == 1 {
867 Some((k + 1, -w))
869 } else {
870 Some((k - 1, w))
872 }
873 }
874 }
875 }
876 };
877 for (i, row) in field.coefficients.iter().enumerate() {
878 for (j, &c) in row.iter().enumerate() {
879 if c == 0.0 {
880 continue;
881 }
882 if along_u {
883 if let Some((k, f)) = map(i) {
884 grow(&mut out, k, j);
885 out[k][j] += c * f;
886 }
887 } else if let Some((k, f)) = map(j) {
888 grow(&mut out, i, k);
889 out[i][k] += c * f;
890 }
891 }
892 }
893 SeriesField2 {
894 u: field.u,
895 v: field.v,
896 coefficients: out,
897 }
898}
899
900pub fn grow(c: &mut Vec<Vec<Scalar>>, i: usize, j: usize) {
902 if c.len() <= i {
903 let m = c.first().map_or(0, Vec::len);
904 c.resize(i + 1, vec![0.0; m]);
905 }
906 if c[0].len() <= j {
907 for row in c.iter_mut() {
908 row.resize(j + 1, 0.0);
909 }
910 }
911 for row in c.iter_mut() {
912 if row.len() <= j {
913 row.resize(j + 1, 0.0);
914 }
915 }
916}
917
918#[derive(Debug, Clone, Copy, PartialEq, Eq)]
920#[cfg_attr(
921 feature = "serde",
922 derive(serde::Serialize, serde::Deserialize),
923 serde(deny_unknown_fields)
924)]
925pub enum Axis {
926 U,
928 V,
930}
931
932#[derive(Debug, Clone, Copy, PartialEq)]
945#[cfg_attr(
946 feature = "serde",
947 derive(serde::Serialize, serde::Deserialize),
948 serde(deny_unknown_fields)
949)]
950pub struct ImplicitCell {
951 pub axis: Axis,
953 pub from: Scalar,
955 pub to: Scalar,
957 pub low: Scalar,
959 pub high: Scalar,
961 pub bridge: Option<(Scalar, Scalar)>,
964}
965
966impl ImplicitCell {
967 #[must_use]
971 pub fn bridge(from: Point2, to: Point2, start: Vec2, end: Vec2) -> Self {
972 let share = |d: Vec2, along_u: bool| {
973 let l = d.length();
974 if l == 0.0 {
975 0.0
976 } else if along_u {
977 d.x.abs() / l
978 } else {
979 d.y.abs() / l
980 }
981 };
982 let chord = to - from;
983 let along_u = share(start, true)
984 .min(share(end, true))
985 .min(share(chord, true))
986 >= share(start, false)
987 .min(share(end, false))
988 .min(share(chord, false));
989 let slope = |d: Vec2| {
990 let (free, solved) = if along_u { (d.x, d.y) } else { (d.y, d.x) };
991 if free == 0.0 {
992 0.0
993 } else {
994 solved / free
995 }
996 };
997 let (axis, f0, f1, w0, w1) = if along_u {
998 (Axis::U, from.x, to.x, from.y, to.y)
999 } else {
1000 (Axis::V, from.y, to.y, from.x, to.x)
1001 };
1002 Self {
1003 axis,
1004 from: f0,
1005 to: f1,
1006 low: w0,
1007 high: w1,
1008 bridge: Some((slope(start), slope(end))),
1009 }
1010 }
1011
1012 fn hermite(&self, s: Scalar) -> (Scalar, Scalar, Scalar) {
1015 let (m0, m1) = self.bridge.unwrap_or((0.0, 0.0));
1016 let span = self.to - self.from;
1017 let (a, b) = (m0 * span, m1 * span);
1018 let (w0, w1) = (self.low, self.high);
1019 let (s2, s3) = (s * s, s * s * s);
1020 let value = (2.0 * s3 - 3.0 * s2 + 1.0) * w0
1021 + (s3 - 2.0 * s2 + s) * a
1022 + (-2.0 * s3 + 3.0 * s2) * w1
1023 + (s3 - s2) * b;
1024 let first = (6.0 * s2 - 6.0 * s) * w0
1025 + (3.0 * s2 - 4.0 * s + 1.0) * a
1026 + (-6.0 * s2 + 6.0 * s) * w1
1027 + (3.0 * s2 - 2.0 * s) * b;
1028 let second = (12.0 * s - 6.0) * w0
1029 + (6.0 * s - 4.0) * a
1030 + (-12.0 * s + 6.0) * w1
1031 + (6.0 * s - 2.0) * b;
1032 (value, first, second)
1033 }
1034
1035 fn local(&self, free: Scalar) -> Scalar {
1037 let span = self.to - self.from;
1038 if span == 0.0 {
1039 0.0
1040 } else {
1041 (free - self.from) / span
1042 }
1043 }
1044
1045 #[must_use]
1047 pub fn part(&self, s0: Scalar, s1: Scalar) -> Self {
1048 let (f0, f1) = (self.free(s0), self.free(s1));
1049 match self.bridge {
1050 Some(_) => {
1051 let span = self.to - self.from;
1052 let slope = |s: Scalar| {
1053 if span == 0.0 {
1054 0.0
1055 } else {
1056 self.hermite(s).1 / span
1057 }
1058 };
1059 Self {
1060 from: f0,
1061 to: f1,
1062 low: self.hermite(s0).0,
1063 high: self.hermite(s1).0,
1064 bridge: Some((slope(s0), slope(s1))),
1065 ..*self
1066 }
1067 }
1068 None => Self {
1069 from: f0,
1070 to: f1,
1071 ..*self
1072 },
1073 }
1074 }
1075
1076 #[must_use]
1078 pub fn reversed(&self) -> Self {
1079 match self.bridge {
1080 Some((m0, m1)) => Self {
1081 from: self.to,
1082 to: self.from,
1083 low: self.high,
1084 high: self.low,
1085 bridge: Some((m1, m0)),
1086 ..*self
1087 },
1088 None => Self {
1089 from: self.to,
1090 to: self.from,
1091 ..*self
1092 },
1093 }
1094 }
1095
1096 #[must_use]
1099 pub fn solved_range(&self) -> (Scalar, Scalar) {
1100 match self.bridge {
1101 Some((m0, m1)) => {
1102 let span = self.to - self.from;
1103 let c = [
1104 self.low,
1105 self.low + m0 * span / 3.0,
1106 self.high - m1 * span / 3.0,
1107 self.high,
1108 ];
1109 (
1110 c.iter().copied().fold(Scalar::INFINITY, Scalar::min),
1111 c.iter().copied().fold(Scalar::NEG_INFINITY, Scalar::max),
1112 )
1113 }
1114 None => (self.low.min(self.high), self.low.max(self.high)),
1115 }
1116 }
1117
1118 fn place(&self, free: Scalar, solved: Scalar) -> Point2 {
1120 match self.axis {
1121 Axis::U => Point2::new(free, solved),
1122 Axis::V => Point2::new(solved, free),
1123 }
1124 }
1125
1126 fn free(&self, s: Scalar) -> Scalar {
1128 self.from + (self.to - self.from) * s
1129 }
1130}
1131
1132#[derive(Debug, Clone, PartialEq)]
1137#[cfg_attr(
1138 feature = "serde",
1139 derive(serde::Serialize, serde::Deserialize),
1140 serde(deny_unknown_fields)
1141)]
1142pub struct ImplicitCurve2 {
1143 pub field: Field2,
1145 pub cells: Vec<ImplicitCell>,
1147}
1148
1149impl ImplicitCurve2 {
1150 #[must_use]
1152 pub fn end(&self) -> Scalar {
1153 self.cells.len() as Scalar
1154 }
1155
1156 #[must_use]
1158 pub fn solve_cell(&self, cell: &ImplicitCell, free: Scalar) -> Option<Scalar> {
1159 self.solve(cell, free)
1160 }
1161
1162 fn locate(&self, t: Scalar) -> Option<(&ImplicitCell, Scalar)> {
1164 if !t.is_finite() || self.cells.is_empty() {
1165 return None;
1166 }
1167 let last = self.cells.len() - 1;
1168 let slack = 1e-12 * (1.0 + self.end());
1169 if t < -slack || t > self.end() + slack {
1170 return None;
1171 }
1172 let index = (t.floor().max(0.0) as usize).min(last);
1173 let s = (t - index as Scalar).clamp(0.0, 1.0);
1174 Some((&self.cells[index], s))
1175 }
1176
1177 fn solve(&self, cell: &ImplicitCell, free: Scalar) -> Option<Scalar> {
1180 if cell.bridge.is_some() {
1181 return Some(cell.hermite(cell.local(free)).0);
1182 }
1183 let at = |w: Scalar| self.field.jet(cell.place(free, w));
1184 let along = |jet: &Jet2| match cell.axis {
1185 Axis::U => jet.gradient.y,
1186 Axis::V => jet.gradient.x,
1187 };
1188 let (mut lo, mut hi) = (cell.low, cell.high);
1189 let (f_lo, f_hi) = (at(lo).value, at(hi).value);
1190 if f_lo == 0.0 {
1191 return Some(lo);
1192 }
1193 if f_hi == 0.0 {
1194 return Some(hi);
1195 }
1196 let scale = 1e-13 * self.field.magnitude().max(1.0);
1200 if f_lo.signum() == f_hi.signum() {
1201 return if f_lo.abs() <= scale && f_lo.abs() <= f_hi.abs() {
1202 Some(lo)
1203 } else if f_hi.abs() <= scale {
1204 Some(hi)
1205 } else {
1206 None
1207 };
1208 }
1209 let rising = f_hi > f_lo;
1210 let mut w = 0.5 * (lo + hi);
1211 for _ in 0..200 {
1212 let jet = at(w);
1213 let f = jet.value;
1214 if f == 0.0 {
1215 return Some(w);
1216 }
1217 if (f > 0.0) == rising {
1218 hi = w;
1219 } else {
1220 lo = w;
1221 }
1222 let slope = along(&jet);
1223 let newton = w - f / slope;
1224 let next = if slope != 0.0 && newton > lo && newton < hi {
1225 newton
1226 } else {
1227 0.5 * (lo + hi)
1228 };
1229 if (next - w).abs() <= 4.0 * Scalar::EPSILON * (1.0 + w.abs())
1230 || hi - lo <= 4.0 * Scalar::EPSILON * (1.0 + w.abs())
1231 {
1232 return Some(next);
1233 }
1234 w = next;
1235 }
1236 Some(w)
1237 }
1238
1239 #[must_use]
1241 pub fn point(&self, t: Scalar) -> Option<Point2> {
1242 let (cell, s) = self.locate(t)?;
1243 let free = cell.free(s);
1244 Some(cell.place(free, self.solve(cell, free)?))
1245 }
1246
1247 fn slopes(&self, t: Scalar) -> Option<(&ImplicitCell, Scalar, Scalar, Scalar)> {
1250 let (cell, s) = self.locate(t)?;
1251 if cell.bridge.is_some() {
1252 let span = cell.to - cell.from;
1253 if span == 0.0 {
1254 return Some((cell, 0.0, 0.0, span));
1255 }
1256 let (_, d1, d2) = cell.hermite(s);
1257 return Some((cell, d1 / span, d2 / (span * span), span));
1258 }
1259 let free = cell.free(s);
1260 let solved = self.solve(cell, free)?;
1261 let jet = self.field.jet(cell.place(free, solved));
1262 let (f_free, f_solved, f_ff, f_fs, f_ss) = match cell.axis {
1263 Axis::U => (jet.gradient.x, jet.gradient.y, jet.uu, jet.uv, jet.vv),
1264 Axis::V => (jet.gradient.y, jet.gradient.x, jet.vv, jet.uv, jet.uu),
1265 };
1266 if f_solved == 0.0 {
1267 return None;
1268 }
1269 let first = -f_free / f_solved;
1270 let second = -(f_ff + 2.0 * f_fs * first + f_ss * first * first) / f_solved;
1271 Some((cell, first, second, cell.to - cell.from))
1272 }
1273
1274 #[must_use]
1276 pub fn derivative(&self, t: Scalar) -> Option<Vec2> {
1277 let (cell, first, _, rate) = self.slopes(t)?;
1278 let d = match cell.axis {
1279 Axis::U => Vec2::new(1.0, first),
1280 Axis::V => Vec2::new(first, 1.0),
1281 };
1282 Some(d * rate)
1283 }
1284
1285 #[must_use]
1287 pub fn second_derivative(&self, t: Scalar) -> Option<Vec2> {
1288 let (cell, _, second, rate) = self.slopes(t)?;
1289 let d = match cell.axis {
1290 Axis::U => Vec2::new(0.0, second),
1291 Axis::V => Vec2::new(second, 0.0),
1292 };
1293 Some(d * (rate * rate))
1294 }
1295
1296 #[must_use]
1299 pub fn parameter_of(&self, p: Point2) -> Option<Scalar> {
1300 let mut best: Option<(Scalar, Scalar)> = None;
1301 for (index, cell) in self.cells.iter().enumerate() {
1302 let (free, solved) = match cell.axis {
1303 Axis::U => (p.x, p.y),
1304 Axis::V => (p.y, p.x),
1305 };
1306 let (lo, hi) = (cell.from.min(cell.to), cell.from.max(cell.to));
1307 let slack = 1e-9 * (1.0 + lo.abs().max(hi.abs()));
1308 if free < lo - slack || free > hi + slack {
1309 continue;
1310 }
1311 let span = cell.to - cell.from;
1312 let s = if span == 0.0 {
1313 0.0
1314 } else {
1315 ((free - cell.from) / span).clamp(0.0, 1.0)
1316 };
1317 let Some(on) = self.solve(cell, cell.free(s)) else {
1318 continue;
1319 };
1320 let miss = (on - solved).abs();
1321 if best.is_none_or(|(m, _)| miss < m) {
1322 best = Some((miss, index as Scalar + s));
1323 }
1324 }
1325 best.map(|(_, t)| t)
1326 }
1327
1328 #[must_use]
1330 pub fn shifted(&self, du: Scalar, dv: Scalar) -> Self {
1331 let cells = self
1332 .cells
1333 .iter()
1334 .map(|cell| {
1335 let (df, ds) = match cell.axis {
1336 Axis::U => (du, dv),
1337 Axis::V => (dv, du),
1338 };
1339 ImplicitCell {
1340 from: cell.from + df,
1341 to: cell.to + df,
1342 low: cell.low + ds,
1343 high: cell.high + ds,
1344 ..*cell
1345 }
1346 })
1347 .collect();
1348 Self {
1349 field: self.field.clone(),
1350 cells,
1351 }
1352 }
1353
1354 #[must_use]
1358 pub fn closure(&self, periodic_u: bool, periodic_v: bool) -> Option<Vec2> {
1359 let (a, b) = (self.point(0.0)?, self.point(self.end())?);
1360 let d = b - a;
1361 let snap = |x: Scalar, periodic: bool| {
1362 if periodic {
1363 (x / TAU).round() * TAU
1364 } else {
1365 0.0
1366 }
1367 };
1368 let offset = Vec2::new(snap(d.x, periodic_u), snap(d.y, periodic_v));
1369 let miss = (d - offset).length();
1370 (miss <= 1e-8 * (1.0 + a.x.abs().max(a.y.abs()))).then_some(offset)
1371 }
1372
1373 #[must_use]
1377 pub fn sub(&self, t0: Scalar, t1: Scalar, closure: Option<Vec2>) -> Option<Self> {
1378 let n = self.end();
1379 if t0 > t1 {
1380 let offset = closure?;
1381 let first = self.sub(t0, n, None);
1383 let second = self
1384 .sub(0.0, t1, None)
1385 .map(|c| c.shifted(offset.x, offset.y));
1386 return match (first, second) {
1387 (Some(mut a), Some(b)) => {
1388 a.cells.extend(b.cells);
1389 Some(a)
1390 }
1391 (a, b) => a.or(b),
1392 };
1393 }
1394 let (t0, t1) = (t0.clamp(0.0, n), t1.clamp(0.0, n));
1395 let mut cells = Vec::new();
1396 for (index, cell) in self.cells.iter().enumerate() {
1397 let (c0, c1) = (index as Scalar, index as Scalar + 1.0);
1398 let (a, b) = (t0.max(c0), t1.min(c1));
1399 if b - a <= 1e-12 {
1400 continue;
1401 }
1402 cells.push(cell.part(a - c0, b - c0));
1403 }
1404 (!cells.is_empty()).then(|| Self {
1405 field: self.field.clone(),
1406 cells,
1407 })
1408 }
1409
1410 #[must_use]
1412 pub fn rotated(&self, t: Scalar, closure: Vec2) -> Option<Self> {
1413 let n = self.end();
1414 if t <= 1e-12 || t >= n - 1e-12 {
1415 return Some(self.clone());
1416 }
1417 let index = (t.floor() as usize).min(self.cells.len() - 1);
1418 let s = t - index as Scalar;
1419 let cell = self.cells[index];
1420 let shift = |c: ImplicitCell| {
1421 let (df, ds) = match c.axis {
1422 Axis::U => (closure.x, closure.y),
1423 Axis::V => (closure.y, closure.x),
1424 };
1425 ImplicitCell {
1426 from: c.from + df,
1427 to: c.to + df,
1428 low: c.low + ds,
1429 high: c.high + ds,
1430 ..c
1431 }
1432 };
1433 let mut cells = Vec::with_capacity(self.cells.len() + 1);
1434 if s < 1.0 - 1e-12 {
1435 cells.push(cell.part(s, 1.0));
1436 }
1437 cells.extend(self.cells[index + 1..].iter().copied());
1438 cells.extend(self.cells[..index].iter().copied().map(shift));
1439 if s > 1e-12 {
1440 cells.push(shift(cell.part(0.0, s)));
1441 }
1442 Some(Self {
1443 field: self.field.clone(),
1444 cells,
1445 })
1446 }
1447
1448 #[must_use]
1452 pub fn clipped(&self, lo: Point2, hi: Point2) -> Vec<Self> {
1453 let outside = |t: Scalar| -> Scalar {
1454 self.point(t).map_or(Scalar::INFINITY, |p| {
1455 (lo.x - p.x).max(p.x - hi.x).max(lo.y - p.y).max(p.y - hi.y)
1456 })
1457 };
1458 let n = self.end();
1459 let steps = 16 * self.cells.len().max(1);
1460 let mut out = Vec::new();
1461 let mut start: Option<Scalar> = None;
1462 let mut previous = (0.0, outside(0.0) <= 0.0);
1463 if previous.1 {
1464 start = Some(0.0);
1465 }
1466 for k in 1..=steps {
1467 let t = n * k as Scalar / steps as Scalar;
1468 let inside = outside(t) <= 0.0;
1469 if inside != previous.1 {
1470 let (mut a, mut b) = (previous.0, t);
1472 for _ in 0..80 {
1473 let m = 0.5 * (a + b);
1474 if (outside(m) <= 0.0) == previous.1 {
1475 a = m;
1476 } else {
1477 b = m;
1478 }
1479 }
1480 let cross = 0.5 * (a + b);
1481 if inside {
1482 start = Some(cross);
1483 } else if let Some(s) = start.take() {
1484 out.extend(self.sub(s, cross, None));
1485 }
1486 }
1487 previous = (t, inside);
1488 }
1489 if let Some(s) = start {
1490 out.extend(self.sub(s, n, None));
1491 }
1492 out
1493 }
1494
1495 #[must_use]
1497 pub fn reversed(&self) -> Self {
1498 Self {
1499 field: self.field.clone(),
1500 cells: self
1501 .cells
1502 .iter()
1503 .rev()
1504 .map(ImplicitCell::reversed)
1505 .collect(),
1506 }
1507 }
1508
1509 #[must_use]
1521 pub fn turning_points(&self, lo: Scalar, hi: Scalar) -> Vec<Scalar> {
1522 let (lo, hi) = (lo.min(hi), lo.max(hi));
1523 let du = partial(&self.field, true);
1524 let dv = partial(&self.field, false);
1525 let mut out = Vec::new();
1526 for (index, cell) in self.cells.iter().enumerate() {
1527 let (t0, t1) = (index as Scalar, index as Scalar + 1.0);
1528 if t0 > lo && t0 < hi {
1529 out.push(t0);
1530 }
1531 if t1 <= lo || t0 >= hi || cell.bridge.is_some() {
1533 continue;
1534 }
1535 let (d_free, d_solved) = match cell.axis {
1536 Axis::U => (&du, &dv),
1537 Axis::V => (&dv, &du),
1538 };
1539 let s0 = (lo - t0).max(0.0);
1540 let s1 = (hi - t0).min(1.0);
1541 self.turns_in(cell, d_free, d_solved, s0, s1, 0, &mut |s| out.push(t0 + s));
1542 }
1543 out.sort_by(Scalar::total_cmp);
1544 out.dedup_by(|a, b| (*a - *b).abs() <= 1e-12);
1545 out
1546 }
1547
1548 fn hull(
1551 &self,
1552 cell: &ImplicitCell,
1553 d_free: &Field2,
1554 d_solved: &Field2,
1555 s0: Scalar,
1556 s1: Scalar,
1557 ) -> Option<Cell> {
1558 let (f0, f1) = (cell.free(s0), cell.free(s1));
1559 let w0 = self.solve(cell, f0)?;
1560 if cell.bridge.is_some() {
1561 let (w_lo, w_hi) = cell.part(s0, s1).solved_range();
1563 let (a, b) = (cell.place(f0.min(f1), w_lo), cell.place(f0.max(f1), w_hi));
1564 return Some(Cell {
1565 lo: a.min(b),
1566 hi: a.max(b),
1567 });
1568 }
1569 let bracket = |f_lo: Scalar, f_hi: Scalar, w_lo: Scalar, w_hi: Scalar| {
1570 let (a, b) = match cell.axis {
1571 Axis::U => (Point2::new(f_lo, w_lo), Point2::new(f_hi, w_hi)),
1572 Axis::V => (Point2::new(w_lo, f_lo), Point2::new(w_hi, f_hi)),
1573 };
1574 Cell { lo: a, hi: b }
1575 };
1576 let (f_lo, f_hi) = (f0.min(f1), f0.max(f1));
1577 let whole = bracket(f_lo, f_hi, cell.low, cell.high);
1578 let free = bound_simple(d_free, &whole);
1579 let solved = bound_simple(d_solved, &whole);
1580 let floor = solved.lo.abs().min(solved.hi.abs());
1581 let reach = if solved.straddles_zero() || floor == 0.0 {
1582 Scalar::INFINITY
1583 } else {
1584 free.lo.abs().max(free.hi.abs()) / floor * (f_hi - f_lo)
1585 };
1586 let (w_lo, w_hi) = ((w0 - reach).max(cell.low), (w0 + reach).min(cell.high));
1587 Some(bracket(f_lo, f_hi, w_lo, w_hi))
1588 }
1589
1590 #[allow(clippy::too_many_arguments)]
1591 fn turns_in(
1592 &self,
1593 cell: &ImplicitCell,
1594 d_free: &Field2,
1595 d_solved: &Field2,
1596 s0: Scalar,
1597 s1: Scalar,
1598 depth: u32,
1599 found: &mut dyn FnMut(Scalar),
1600 ) {
1601 let Some(hull) = self.hull(cell, d_free, d_solved, s0, s1) else {
1602 return;
1603 };
1604 if !bound_simple(d_free, &hull).straddles_zero() {
1605 return;
1606 }
1607 let g = |s: Scalar| -> Option<Scalar> {
1608 let free = cell.free(s);
1609 let solved = self.solve(cell, free)?;
1610 Some(d_free.value(cell.place(free, solved)))
1611 };
1612 if depth >= 40 || s1 - s0 <= 1e-12 {
1613 if let (Some(a), Some(b)) = (g(s0), g(s1)) {
1615 if (a < 0.0) != (b < 0.0) && a != 0.0 {
1616 found(0.5 * (s0 + s1));
1617 }
1618 }
1619 return;
1620 }
1621 let m = 0.5 * (s0 + s1);
1622 self.turns_in(cell, d_free, d_solved, s0, m, depth + 1, found);
1623 self.turns_in(cell, d_free, d_solved, m, s1, depth + 1, found);
1624 }
1625
1626 #[must_use]
1628 pub fn is_finite(&self) -> bool {
1629 self.field.is_finite()
1630 && self.cells.iter().all(|c| {
1631 c.from.is_finite() && c.to.is_finite() && c.low.is_finite() && c.high.is_finite()
1632 })
1633 }
1634}
1635
1636#[derive(Debug, Clone, PartialEq)]
1639#[cfg_attr(
1640 feature = "serde",
1641 derive(serde::Serialize, serde::Deserialize),
1642 serde(deny_unknown_fields)
1643)]
1644pub enum Carrier {
1645 Plane(Frame3),
1647 Ruled(RuledCarrier),
1649 Sphere {
1651 frame: Frame3,
1653 radius: Scalar,
1655 },
1656 Torus(TorusCarrier),
1658 Spline(Box<crate::spline_surface::BSplineSurface>),
1660}
1661
1662#[derive(Debug, Clone, Copy, PartialEq)]
1664pub struct SurfaceJet {
1665 pub point: Point3,
1667 pub u: Vec3,
1669 pub v: Vec3,
1671 pub uu: Vec3,
1673 pub uv: Vec3,
1675 pub vv: Vec3,
1677}
1678
1679impl Carrier {
1680 #[must_use]
1682 pub fn jet(&self, u: Scalar, v: Scalar) -> SurfaceJet {
1683 let (su, cu) = u.sin_cos();
1684 match self {
1685 Carrier::Plane(f) => SurfaceJet {
1686 point: f.origin + f.x * u + f.y * v,
1687 u: f.x,
1688 v: f.y,
1689 uu: Vec3::ZERO,
1690 uv: Vec3::ZERO,
1691 vv: Vec3::ZERO,
1692 },
1693 Carrier::Ruled(k) => {
1694 let f = &k.frame;
1695 let (rx, ry) = (k.x_radius + k.slope * v, k.y_radius + k.slope * v);
1696 SurfaceJet {
1697 point: f.origin + f.x * (rx * cu) + f.y * (ry * su) + f.z * v,
1698 u: f.x * (-rx * su) + f.y * (ry * cu),
1699 v: f.x * (k.slope * cu) + f.y * (k.slope * su) + f.z,
1700 uu: f.x * (-rx * cu) + f.y * (-ry * su),
1701 uv: f.x * (-k.slope * su) + f.y * (k.slope * cu),
1702 vv: Vec3::ZERO,
1703 }
1704 }
1705 Carrier::Sphere {
1706 frame: f,
1707 radius: r,
1708 } => {
1709 let (sv, cv) = v.sin_cos();
1710 let ring = f.x * cu + f.y * su;
1711 let ring_u = f.x * (-su) + f.y * cu;
1712 SurfaceJet {
1713 point: f.origin + ring * (r * cv) + f.z * (r * sv),
1714 u: ring_u * (r * cv),
1715 v: ring * (-r * sv) + f.z * (r * cv),
1716 uu: ring * (-r * cv),
1717 uv: ring_u * (-r * sv),
1718 vv: ring * (-r * cv) + f.z * (-r * sv),
1719 }
1720 }
1721 Carrier::Torus(t) => {
1722 let f = &t.frame;
1723 let (sv, cv) = v.sin_cos();
1724 let r = t.minor_radius;
1725 let ring = t.major_radius + r * cv;
1726 let dir = f.x * cu + f.y * su;
1727 let dir_u = f.x * (-su) + f.y * cu;
1728 SurfaceJet {
1729 point: f.origin + dir * ring + f.z * (r * sv),
1730 u: dir_u * ring,
1731 v: dir * (-r * sv) + f.z * (r * cv),
1732 uu: dir * (-ring),
1733 uv: dir_u * (-r * sv),
1734 vv: dir * (-r * cv) + f.z * (-r * sv),
1735 }
1736 }
1737 Carrier::Spline(b) => b.jet(u, v).unwrap_or(SurfaceJet {
1738 point: Point3::splat(Scalar::NAN),
1739 u: Vec3::splat(Scalar::NAN),
1740 v: Vec3::splat(Scalar::NAN),
1741 uu: Vec3::splat(Scalar::NAN),
1742 uv: Vec3::splat(Scalar::NAN),
1743 vv: Vec3::splat(Scalar::NAN),
1744 }),
1745 }
1746 }
1747
1748 #[must_use]
1754 pub fn parameters(&self, p: Point3) -> (Scalar, Scalar) {
1755 let local = |f: &Frame3| {
1756 let d = p - f.origin;
1757 (d.dot(f.x), d.dot(f.y), d.dot(f.z))
1758 };
1759 match self {
1760 Carrier::Plane(f) => {
1761 let (x, y, _) = local(f);
1762 (x, y)
1763 }
1764 Carrier::Ruled(k) => {
1765 let (x, y, z) = local(&k.frame);
1766 let (rx, ry) = (k.x_radius + k.slope * z, k.y_radius + k.slope * z);
1767 ((y / ry).atan2(x / rx), z)
1768 }
1769 Carrier::Sphere { frame, .. } => {
1770 let (x, y, z) = local(frame);
1771 (y.atan2(x), z.atan2(x.hypot(y)))
1772 }
1773 Carrier::Torus(t) => {
1774 let (x, y, z) = local(&t.frame);
1775 (y.atan2(x), z.atan2(x.hypot(y) - t.major_radius))
1776 }
1777 Carrier::Spline(_) => (Scalar::NAN, Scalar::NAN),
1778 }
1779 }
1780
1781 #[must_use]
1783 pub fn periodic(&self) -> (bool, bool) {
1784 match self {
1785 Carrier::Plane(_) | Carrier::Spline(_) => (false, false),
1786 Carrier::Ruled(_) | Carrier::Sphere { .. } => (true, false),
1787 Carrier::Torus(_) => (true, true),
1788 }
1789 }
1790
1791 #[must_use]
1793 pub fn is_finite(&self) -> bool {
1794 let frame = |f: &Frame3| {
1795 f.origin.is_finite() && f.x.is_finite() && f.y.is_finite() && f.z.is_finite()
1796 };
1797 match self {
1798 Carrier::Plane(f) => frame(f),
1799 Carrier::Ruled(k) => k.is_finite(),
1800 Carrier::Sphere { frame: f, radius } => frame(f) && radius.is_finite(),
1801 Carrier::Torus(t) => {
1802 frame(&t.frame) && t.major_radius.is_finite() && t.minor_radius.is_finite()
1803 }
1804 Carrier::Spline(b) => {
1805 b.control_points.iter().flatten().all(|p| p.is_finite())
1806 && b.weights
1807 .as_ref()
1808 .is_none_or(|w| w.iter().flatten().all(|x| x.is_finite()))
1809 }
1810 }
1811 }
1812}
1813
1814#[derive(Debug, Clone, PartialEq)]
1817#[cfg_attr(
1818 feature = "serde",
1819 derive(serde::Serialize, serde::Deserialize),
1820 serde(deny_unknown_fields)
1821)]
1822pub struct ImplicitSection3 {
1823 pub carrier: Carrier,
1825 pub curve: ImplicitCurve2,
1827}
1828
1829impl ImplicitSection3 {
1830 #[must_use]
1832 pub fn point(&self, t: Scalar) -> Option<Point3> {
1833 let p = self.curve.point(t)?;
1834 Some(self.carrier.jet(p.x, p.y).point)
1835 }
1836
1837 #[must_use]
1839 pub fn tangent(&self, t: Scalar) -> Option<Vec3> {
1840 let p = self.curve.point(t)?;
1841 let d = self.curve.derivative(t)?;
1842 let jet = self.carrier.jet(p.x, p.y);
1843 Some(jet.u * d.x + jet.v * d.y)
1844 }
1845
1846 #[must_use]
1848 pub fn bend(&self, t: Scalar) -> Option<Vec3> {
1849 let p = self.curve.point(t)?;
1850 let d = self.curve.derivative(t)?;
1851 let dd = self.curve.second_derivative(t)?;
1852 let jet = self.carrier.jet(p.x, p.y);
1853 Some(
1854 jet.uu * (d.x * d.x)
1855 + jet.uv * (2.0 * d.x * d.y)
1856 + jet.vv * (d.y * d.y)
1857 + jet.u * dd.x
1858 + jet.v * dd.y,
1859 )
1860 }
1861
1862 #[must_use]
1864 pub fn is_finite(&self) -> bool {
1865 self.carrier.is_finite() && self.curve.is_finite()
1866 }
1867}
1868
1869#[derive(Debug, Clone, PartialEq)]
1881#[cfg_attr(
1882 feature = "serde",
1883 derive(serde::Serialize, serde::Deserialize),
1884 serde(deny_unknown_fields)
1885)]
1886pub struct LiftedCurve2 {
1887 pub curve: Box<crate::Curve3>,
1889 pub carrier: Carrier,
1891 pub start: Scalar,
1893 pub end: Scalar,
1895 pub guide: Vec<Point2>,
1897}
1898
1899impl LiftedCurve2 {
1900 #[must_use]
1902 pub fn guide_at(&self, t: Scalar) -> Option<Point2> {
1903 let n = self.guide.len();
1904 if n == 0 {
1905 return None;
1906 }
1907 if n == 1 || self.end == self.start {
1908 return Some(self.guide[0]);
1909 }
1910 let x = ((t - self.start) / (self.end - self.start) * (n - 1) as Scalar)
1911 .clamp(0.0, (n - 1) as Scalar);
1912 let i = (x.floor() as usize).min(n - 2);
1913 let f = x - i as Scalar;
1914 Some(self.guide[i] + (self.guide[i + 1] - self.guide[i]) * f)
1915 }
1916
1917 #[must_use]
1920 pub fn unwrap_at(&self, t: Scalar, point: Point3) -> Option<Point2> {
1921 let (u, v) = self.carrier.parameters(point);
1922 if !u.is_finite() || !v.is_finite() {
1923 return None;
1924 }
1925 let near = self.guide_at(t)?;
1926 let (pu, pv) = self.carrier.periodic();
1927 let snap = |x: Scalar, g: Scalar, periodic: bool| {
1928 if periodic {
1929 x + ((g - x) / TAU).round() * TAU
1930 } else {
1931 x
1932 }
1933 };
1934 Some(Point2::new(snap(u, near.x, pu), snap(v, near.y, pv)))
1935 }
1936
1937 #[must_use]
1939 pub fn is_finite(&self) -> bool {
1940 self.carrier.is_finite()
1941 && self.start.is_finite()
1942 && self.end.is_finite()
1943 && self.guide.iter().all(|p| p.is_finite())
1944 }
1945}