geomutil_util 0.1.2

A Rust library providing basic geometric types.
Documentation
use crate::{EPS, Edge2, Point2};
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
pub struct Triangle2 {
    pub a: Point2,
    pub b: Point2,
    pub c: Point2,
    circumcenter: Point2,
    circumradius_squared: f32,
}

impl Eq for Triangle2 {}

impl Triangle2 {
    pub fn new(a: Point2, b: Point2, c: Point2) -> Option<Self> {
        let mut t = Self {
            a,
            b,
            c,
            ..Default::default()
        };
        t.circumcenter = t.calc_circumcenter()?;
        t.circumradius_squared = t.calc_circumradius_squared();
        Some(t)
    }

    fn calc_circumcenter(&self) -> Option<Point2> {
        let a = self.a;
        let b = self.b;
        let c = self.c;
        let d = 2.0 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));

        if d.abs() == 0.0 {
            return None;
        }

        let a_len_sq = a.length_squared();
        let b_len_sq = b.length_squared();
        let c_len_sq = c.length_squared();

        let ux = (a_len_sq * (b.y - c.y) + b_len_sq * (c.y - a.y) + c_len_sq * (a.y - b.y)) / d;
        let uy = (a_len_sq * (c.x - b.x) + b_len_sq * (a.x - c.x) + c_len_sq * (b.x - a.x)) / d;

        Some(Point2::from([ux, uy]))
    }

    pub fn circumcenter(&self) -> Point2 {
        self.circumcenter
    }

    fn calc_circumradius_squared(&self) -> f32 {
        self.circumcenter.distance_squared(self.a)
    }

    pub fn circumcircle_radius_squared(&self) -> f32 {
        self.circumradius_squared
    }

    pub fn circumcircle_radius(&self) -> f32 {
        self.circumradius_squared.sqrt()
    }

    pub fn is_inside_circumcircle(&self, p: Point2) -> bool {
        let d = self.circumcenter.distance_squared(p);
        d <= self.circumradius_squared + EPS
    }

    pub fn has_point(&self, p: &Point2) -> bool {
        self.a.eq(p) || self.b.eq(p) || self.c.eq(p)
    }

    pub fn edges(&self) -> [Edge2; 3] {
        [
            Edge2::new(self.a, self.b),
            Edge2::new(self.b, self.c),
            Edge2::new(self.c, self.a),
        ]
    }

    pub fn perimeter(&self) -> f32 {
        self.edges().iter().map(|e| e.length()).sum()
    }

    pub fn area(&self) -> f32 {
        let edges = self.edges();
        let a = edges[0].length();
        let b = edges[1].length();
        let c = edges[2].length();
        let s = 0.5f32 * (a + b + c);
        (s * (s - a) * (s - b) * (s - c)).sqrt()
    }
}