use crate::geom::Point; #[derive(Debug, Clone, Copy, PartialEq)] pub struct Arc { pub start: Point, pub mid: Point, pub end: Point, } impl Arc { pub const fn new(start: Point, mid: Point, end: Point) -> Self { Self { start, mid, end } } pub fn centre_and_radius(&self) -> Option<(Point, f64)> { let (ax, ay) = (self.start.x, self.start.y); let (bx, by) = (self.mid.x, self.mid.y); let (cx, cy) = (self.end.x, self.end.y); let d = 2.0 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)); if d.abs() < f64::EPSILON { return None; } let ax2_ay2 = ax * ax + ay * ay; let bx2_by2 = bx * bx + by * by; let cx2_cy2 = cx * cx + cy * cy; let ux = (ax2_ay2 * (by - cy) + bx2_by2 * (cy - ay) + cx2_cy2 * (ay - by)) / d; let uy = (ax2_ay2 * (cx - bx) + bx2_by2 * (ax - cx) + cx2_cy2 * (bx - ax)) / d; let centre = Point::new(ux, uy); let r = centre.distance_to(self.start); Some((centre, r)) } /// Sweep direction from start → end through mid, as +1 (CCW) or -1 (CW). pub fn sweep_sign(&self) -> f64 { let (ax, ay) = (self.start.x, self.start.y); let (bx, by) = (self.mid.x, self.mid.y); let (cx, cy) = (self.end.x, self.end.y); let cross = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax); if cross >= 0.0 { 1.0 } else { -1.0 } } }