brep_cam/multiaxis/
orientation.rs1use super::slerp;
10use crate::kinematics::rotate;
11pub use crate::model::AxisMode;
12use crate::model::Point3;
13
14impl AxisMode {
15 pub fn axis_at(&self, cc: Point3, n: Point3, t: Point3) -> Option<Point3> {
19 match self {
20 AxisMode::Normal { lead_deg, tilt_deg } => {
21 let b = n.cross(t);
22 let a = rotate(b, lead_deg.to_radians(), n);
23 rotate(t, tilt_deg.to_radians(), a).normalized()
24 }
25 AxisMode::Point { point, away } => {
26 let d = if *away { cc.sub(*point) } else { point.sub(cc) };
27 d.normalized()
28 }
29 AxisMode::Line { origin, direction, away } => {
30 let d = direction.normalized()?;
31 let rel = cc.sub(*origin);
32 let perp = rel.sub(d.scale(rel.dot(d)));
33 let v = if *away { perp } else { perp.scale(-1.0) };
34 v.normalized()
35 }
36 AxisMode::FixedFromVertical { angle_deg, azimuth_deg } => {
37 let (s, c) = angle_deg.to_radians().sin_cos();
38 let (sa, ca) = azimuth_deg.to_radians().sin_cos();
39 Some(Point3::new(s * ca, s * sa, c))
40 }
41 }
42 }
43}
44
45pub fn smooth_axes(axes: &mut [Point3], max_rad: f64) -> usize {
48 let mut changed = 0;
49 let n = axes.len();
50 for round in 0..64 {
51 let mut round_changes = 0;
52 for k in 1..n {
53 let (i, j) = if round % 2 == 0 { (k - 1, k) } else { (n - k, n - k - 1) };
54 let angle = axes[i].dot(axes[j]).clamp(-1.0, 1.0).acos();
55 if angle > max_rad {
56 axes[j] = slerp(axes[i], axes[j], (max_rad / angle) * (1.0 - 1e-9));
57 round_changes += 1;
58 }
59 }
60 changed += round_changes;
61 if round_changes == 0 {
62 break;
63 }
64 }
65 changed
66}
67
68pub fn clamp_from_vertical(axis: Point3, max_rad: f64) -> (Point3, bool) {
71 let angle = axis.dot(Point3::Z).clamp(-1.0, 1.0).acos();
72 if angle <= max_rad {
73 return (axis, false);
74 }
75 (slerp(Point3::Z, axis, max_rad / angle), true)
76}