use line intersection to improve precision

This commit is contained in:
numzero 2026-10-20 01:38:57 +03:00
parent cf30027976
commit 9fd50e75fa

View File

@ -70,17 +70,28 @@ impl BevelGearShape {
let angle = 2.0 * PI / self.points.len() as f32; let angle = 2.0 * PI / self.points.len() as f32;
for (k, pt) in self.points.iter_mut().enumerate() { for (k, pt) in self.points.iter_mut().enumerate() {
let dir = Vec2::from_angle(k as f32 * angle); let dir = Vec2::from_angle(k as f32 * angle);
for line in cutting_line.iter().zip(&cutting_line[1..]) { for (&a, &b) in cutting_line.iter().zip(&cutting_line[1..]) {
if line.0.dot(dir) <= 0. || line.1.dot(dir) <= 0. { if let Some(intersect) = intersect_ray_segment(dir, (a, b))
continue; && intersect > 0.
} {
if line.0.dot(dir.perp()) < 0. || line.1.dot(dir.perp()) > 0. { *pt = pt.min(intersect);
continue;
}
*pt = pt.min(f32::min(line.0.length(), line.1.length()));
} }
} }
} }
}
}
/// Computes the intersection point of a line (from the origin along `dir`) and a line segment (from `a` to `b`).
/// Returns the distance from the origin, in multiples of `dir`.
fn intersect_ray_segment(dir: Vec2, (a, b): (Vec2, Vec2)) -> Option<f32> {
const EPS: f32 = 1e-4;
let den = dir.perp_dot(b - a);
if den.abs() < EPS {
// parallel or almost parallel
return None;
}
let u = a.perp_dot(dir) / den; // intersection = a + u * (b - a)
(0.0..1.0).contains(&u).then(|| a.perp_dot(b - a) / den)
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]