rcgal 0.2.2

Rust Computational Geometry Algorithms Library.
Documentation
use super::{
    line_segment_2::LineSegment2, number_type::NumberType, point_2::Point2, util_enum::Orientation,
};

#[derive(Clone, Debug, PartialEq)]
pub struct Triangle2<T: NumberType> {
    a: Point2<T>,
    b: Point2<T>,
    c: Point2<T>,
    orientation: Orientation,
}

impl<T: NumberType> Triangle2<T> {
    pub fn new(a: Point2<T>, b: Point2<T>, c: Point2<T>) -> Self {
        let orientation = Self::calculate_orientation(&a, &b, &c);
        Self {
            a,
            b,
            c,
            orientation,
        }
    }

    pub fn a(&self) -> Point2<T> {
        self.a.clone()
    }

    pub fn b(&self) -> Point2<T> {
        self.b.clone()
    }

    pub fn c(&self) -> Point2<T> {
        self.c.clone()
    }

    pub fn vertices(&self) -> [Point2<T>; 3] {
        [self.a.clone(), self.b.clone(), self.c.clone()]
    }

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

    pub fn orientation(&self) -> Orientation {
        self.orientation
    }

    fn calculate_orientation(a: &Point2<T>, b: &Point2<T>, c: &Point2<T>) -> Orientation {
        let cross_product = (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x());
        if cross_product > T::zero() {
            Orientation::CounterClockwise
        } else {
            Orientation::Clockwise
        }
    }

    pub fn reverse_orientation(&mut self) {
        self.orientation = match self.orientation {
            Orientation::Clockwise => Orientation::CounterClockwise,
            Orientation::CounterClockwise => Orientation::Clockwise,
        };
    }

    pub fn area(&self) -> T {
        let a = self.a();
        let b = self.b();
        let c = self.c();
        let cross = (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x());
        let area = cross.abs() / T::from_f64(2.0);
        match self.orientation {
            Orientation::Clockwise => -area,
            Orientation::CounterClockwise => area,
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_triangle2_reverse_orientation() {
        let a = Point2::new(0.0, 0.0);
        let b = Point2::new(1.0, 0.0);
        let c = Point2::new(0.0, 1.0);
        let mut triangle = Triangle2::new(a, b, c);
        assert_eq!(triangle.orientation(), Orientation::CounterClockwise);
        triangle.reverse_orientation();
        assert_eq!(triangle.orientation(), Orientation::Clockwise);
    }

    #[test]
    fn test_triangle2_vertices() {
        let a = Point2::new(0.0, 0.0);
        let b = Point2::new(1.0, 0.0);
        let c = Point2::new(0.0, 1.0);
        let triangle = Triangle2::new(a.clone(), b.clone(), c.clone());
        assert_eq!(triangle.vertices(), [a, b, c]);
    }

    #[test]
    fn test_triangle2_edges() {
        let a = Point2::new(0.0, 0.0);
        let b = Point2::new(1.0, 0.0);
        let c = Point2::new(0.0, 1.0);
        let triangle = Triangle2::new(a.clone(), b.clone(), c.clone());
        assert_eq!(
            triangle.edges(),
            [
                LineSegment2::new(a.clone(), b.clone()),
                LineSegment2::new(b.clone(), c.clone()),
                LineSegment2::new(c.clone(), a.clone())
            ]
        );

        let triangle = Triangle2::new(a.clone(), c.clone(), b.clone());
        assert_eq!(
            triangle.edges(),
            [
                LineSegment2::new(a.clone(), c.clone()),
                LineSegment2::new(c.clone(), b.clone()),
                LineSegment2::new(b.clone(), a.clone())
            ]
        );
    }
}