42 lines
1.4 KiB
Rust
42 lines
1.4 KiB
Rust
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 }
|
|
}
|
|
}
|