axiolid_curve/
torus_section.rs1use axiolid_core::{Frame3, Point3, Scalar, Vec3};
24
25use crate::quadric_section::{Branch, Trig2};
26
27#[derive(Debug, Clone, Copy, PartialEq)]
31#[cfg_attr(
32 feature = "serde",
33 derive(serde::Serialize, serde::Deserialize),
34 serde(deny_unknown_fields)
35)]
36pub struct AngleGraph2 {
37 pub a: Trig2,
39 pub b: Trig2,
41 pub c: Trig2,
43 pub branch: Branch,
45}
46
47impl AngleGraph2 {
48 #[must_use]
50 pub fn angle(&self, t: Scalar) -> Option<Scalar> {
51 let (a, b, c) = (self.a.value(t), self.b.value(t), self.c.value(t));
52 let rr = a * a + b * b;
53 if rr == 0.0 {
54 return None;
55 }
56 let e = rr - c * c;
57 let size =
60 |t: &Trig2| t.constant.abs() + t.cos.abs() + t.sin.abs() + t.cos2.abs() + t.sin2.abs();
61 let scale = size(&self.a).powi(2) + size(&self.b).powi(2) + size(&self.c).powi(2);
62 if e < -1e-12 * scale {
63 return None;
64 }
65 let root = e.max(0.0).sqrt();
66 let s = self.branch.sign();
67 let u = (b * c + s * a * root).atan2(a * c - s * b * root);
68 u.is_finite().then_some(u)
69 }
70
71 #[must_use]
74 pub fn slope(&self, t: Scalar) -> Option<Scalar> {
75 let u = self.angle(t)?;
76 let (s, c) = u.sin_cos();
77 let f_t = self.a.derivative(t) * c + self.b.derivative(t) * s - self.c.derivative(t);
78 let f_u = -self.a.value(t) * s + self.b.value(t) * c;
79 let slope = -f_t / f_u;
80 slope.is_finite().then_some(slope)
81 }
82
83 #[must_use]
85 pub fn bend(&self, t: Scalar) -> Option<Scalar> {
86 let u = self.angle(t)?;
87 let p = self.slope(t)?;
88 let (s, c) = u.sin_cos();
89 let (a, b) = (self.a.value(t), self.b.value(t));
90 let (da, db) = (self.a.derivative(t), self.b.derivative(t));
91 let f_u = -a * s + b * c;
92 let f_tt = self.a.second(t) * c + self.b.second(t) * s - self.c.second(t);
93 let f_tu = -da * s + db * c;
94 let f_uu = -a * c - b * s;
95 let bend = -(f_tt + 2.0 * f_tu * p + f_uu * p * p) / f_u;
96 bend.is_finite().then_some(bend)
97 }
98
99 #[must_use]
101 pub fn is_finite(&self) -> bool {
102 self.a.is_finite() && self.b.is_finite() && self.c.is_finite()
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq)]
109#[cfg_attr(
110 feature = "serde",
111 derive(serde::Serialize, serde::Deserialize),
112 serde(deny_unknown_fields)
113)]
114pub struct TorusCarrier {
115 pub frame: Frame3,
117 pub major_radius: Scalar,
119 pub minor_radius: Scalar,
121}
122
123impl TorusCarrier {
124 #[must_use]
126 pub fn point(&self, u: Scalar, v: Scalar) -> Point3 {
127 let (su, cu) = u.sin_cos();
128 let (sv, cv) = v.sin_cos();
129 let ring = self.major_radius + self.minor_radius * cv;
130 self.frame.origin
131 + self.frame.x * (ring * cu)
132 + self.frame.y * (ring * su)
133 + self.frame.z * (self.minor_radius * sv)
134 }
135
136 #[must_use]
138 pub fn partials(&self, u: Scalar, v: Scalar) -> (Vec3, Vec3) {
139 let (su, cu) = u.sin_cos();
140 let (sv, cv) = v.sin_cos();
141 let ring = self.major_radius + self.minor_radius * cv;
142 let r = self.minor_radius;
143 (
144 self.frame.x * (-ring * su) + self.frame.y * (ring * cu),
145 self.frame.x * (-r * sv * cu) + self.frame.y * (-r * sv * su) + self.frame.z * (r * cv),
146 )
147 }
148}
149
150#[derive(Debug, Clone, Copy, PartialEq)]
153#[cfg_attr(
154 feature = "serde",
155 derive(serde::Serialize, serde::Deserialize),
156 serde(deny_unknown_fields)
157)]
158pub struct TorusSection3 {
159 pub torus: TorusCarrier,
161 pub graph: AngleGraph2,
163}
164
165impl TorusSection3 {
166 #[must_use]
168 pub fn point(&self, t: Scalar) -> Option<Point3> {
169 Some(self.torus.point(self.graph.angle(t)?, t))
170 }
171
172 #[must_use]
174 pub fn tangent(&self, t: Scalar) -> Option<Vec3> {
175 let u = self.graph.angle(t)?;
176 let (pu, pv) = self.torus.partials(u, t);
177 Some(pu * self.graph.slope(t)? + pv)
178 }
179
180 #[must_use]
182 pub fn bend(&self, t: Scalar) -> Option<Vec3> {
183 let u = self.graph.angle(t)?;
184 let p = self.graph.slope(t)?;
185 let q = self.graph.bend(t)?;
186 let (su, cu) = u.sin_cos();
187 let (sv, cv) = t.sin_cos();
188 let (x, y, z) = (self.torus.frame.x, self.torus.frame.y, self.torus.frame.z);
189 let r = self.torus.minor_radius;
190 let ring = self.torus.major_radius + r * cv;
191 let p_u = x * (-ring * su) + y * (ring * cu);
192 let p_uu = x * (-ring * cu) + y * (-ring * su);
193 let p_uv = x * (r * sv * su) + y * (-r * sv * cu);
194 let p_vv = x * (-r * cv * cu) + y * (-r * cv * su) + z * (-r * sv);
195 Some(p_uu * (p * p) + p_uv * (2.0 * p) + p_vv + p_u * q)
196 }
197}