i_float 3.0.0

This fixed float math library provides an efficient and deterministic solution for arithmetic and geometric operations.
Documentation
use crate::int::number::int::IntNumber;
use crate::int::number::wide_int::WideIntNumber;
use crate::int::point::IntPoint;
use core::cmp::Ordering;

pub struct Triangle;

impl Triangle {
    #[inline(always)]
    pub fn area_two<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> T::Wide {
        (p1 - p0).cross_product(p2 - p0)
    }

    #[inline(always)]
    pub fn is_clockwise<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> bool {
        Self::area_two(p0, p1, p2) < T::Wide::ZERO
    }

    #[inline(always)]
    pub fn is_cw_or_line<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> bool {
        Self::area_two(p0, p1, p2) <= T::Wide::ZERO
    }

    #[inline(always)]
    pub fn is_not_line<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> bool {
        Self::area_two(p0, p1, p2) != T::Wide::ZERO
    }

    #[inline(always)]
    pub fn is_line<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> bool {
        Self::area_two(p0, p1, p2) == T::Wide::ZERO
    }

    #[inline(always)]
    pub fn clock_direction<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> T::Wide {
        Self::area_two(p0, p2, p1).signum()
    }

    #[inline]
    pub fn is_contain<T: IntNumber>(
        p: IntPoint<T>,
        p0: IntPoint<T>,
        p1: IntPoint<T>,
        p2: IntPoint<T>,
    ) -> bool {
        let q0 = (p - p1).cross_product(p0 - p1);
        let q1 = (p - p2).cross_product(p1 - p2);
        let q2 = (p - p0).cross_product(p2 - p0);

        let has_neg = q0 < T::Wide::ZERO || q1 < T::Wide::ZERO || q2 < T::Wide::ZERO;
        let has_pos = q0 > T::Wide::ZERO || q1 > T::Wide::ZERO || q2 > T::Wide::ZERO;

        !(has_neg && has_pos)
    }

    #[inline]
    pub fn is_not_contain<T: IntNumber>(
        p: IntPoint<T>,
        p0: IntPoint<T>,
        p1: IntPoint<T>,
        p2: IntPoint<T>,
    ) -> bool {
        let q0 = (p - p1).cross_product(p0 - p1);
        let q1 = (p - p2).cross_product(p1 - p2);
        let q2 = (p - p0).cross_product(p2 - p0);

        let has_neg = q0 <= T::Wide::ZERO || q1 <= T::Wide::ZERO || q2 <= T::Wide::ZERO;
        let has_pos = q0 >= T::Wide::ZERO || q1 >= T::Wide::ZERO || q2 >= T::Wide::ZERO;

        has_neg && has_pos
    }
    #[inline]
    pub fn is_contain_exclude_borders<T: IntNumber>(
        p: IntPoint<T>,
        p0: IntPoint<T>,
        p1: IntPoint<T>,
        p2: IntPoint<T>,
    ) -> bool {
        let q0 = (p - p1).cross_product(p0 - p1);
        let q1 = (p - p2).cross_product(p1 - p2);
        let q2 = (p - p0).cross_product(p2 - p0);

        let has_neg = q0 < T::Wide::ZERO || q1 < T::Wide::ZERO || q2 < T::Wide::ZERO;
        let has_pos = q0 > T::Wide::ZERO || q1 > T::Wide::ZERO || q2 > T::Wide::ZERO;

        !(has_neg && has_pos) && q0 != T::Wide::ZERO && q1 != T::Wide::ZERO && q2 != T::Wide::ZERO
    }

    #[inline(always)]
    pub fn clock_order<T: IntNumber>(p0: IntPoint<T>, p1: IntPoint<T>, p2: IntPoint<T>) -> Ordering {
        Self::area_two(p0, p1, p2).cmp(&T::Wide::ZERO)
    }
}