use num_traits::{One, Zero};
use core::ops::{Add, Div, Mul, Sub};
#[inline]
pub fn are_collinear<T>(p_1: (T, T), p_2: (T, T), p_3: (T, T)) -> bool
where
T: Copy + Sub<Output = T> + Mul<Output = T> + Zero + PartialEq,
{
let cross = (p_2.0 - p_1.0) * (p_3.1 - p_1.1) - (p_2.1 - p_1.1) * (p_3.0 - p_1.0);
cross == T::zero()
}
#[inline]
pub fn is_valid_triangle<T>(p_1: (T, T), p_2: (T, T), p_3: (T, T)) -> bool
where
T: Copy + Sub<Output = T> + Mul<Output = T> + Zero + PartialEq,
{
!are_collinear(p_1, p_2, p_3)
}
#[inline]
pub fn satisfies_triangle_inequality<T>(q_1: T, q_2: T, q_3: T) -> bool
where
T: Copy + Add<Output = T> + Mul<Output = T> + Div<Output = T> + Zero + PartialOrd,
{
q_1 >= T::zero() && q_2 >= T::zero() && q_3 >= T::zero()
}
#[inline]
pub fn is_valid_quadrance<T>(q: T) -> bool
where
T: Copy + Zero + PartialOrd,
{
q >= T::zero()
}
#[inline]
pub fn is_valid_spread<T>(s: T) -> bool
where
T: Copy + Zero + One + PartialOrd,
{
s >= T::zero() && s <= T::one()
}
#[inline]
pub fn perimeter_squared<T>(q_1: T, q_2: T, q_3: T) -> T
where
T: Copy + Add<Output = T> + Mul<Output = T>,
{
q_1 + q_2 + q_3
}
#[inline]
pub fn is_acute_triangle<T>(s_1: T, s_2: T, s_3: T) -> bool
where
T: Copy + One + PartialOrd,
{
s_1 < T::one() && s_2 < T::one() && s_3 < T::one()
}
#[inline]
pub fn is_right_triangle<T>(s_1: T, s_2: T, s_3: T) -> bool
where
T: Copy + One + PartialEq,
{
s_1 == T::one() || s_2 == T::one() || s_3 == T::one()
}
#[inline]
pub fn is_obtuse_triangle<T>(s_1: T, s_2: T, s_3: T) -> bool
where
T: Copy + Add<Output = T> + Div<Output = T> + One + PartialOrd,
{
let half = T::one() / (T::one() + T::one());
s_1 > half || s_2 > half || s_3 > half
}
#[inline]
pub fn are_lines_parallel<T>(l_1: (T, T, T), l_2: (T, T, T)) -> bool
where
T: Copy + Sub<Output = T> + Mul<Output = T> + Zero + PartialEq,
{
let cross = l_1.0 * l_2.1 - l_1.1 * l_2.0;
cross == T::zero()
}
#[inline]
pub fn are_lines_perpendicular<T>(l_1: (T, T, T), l_2: (T, T, T)) -> bool
where
T: Copy + Mul<Output = T> + Add<Output = T> + Zero + PartialEq,
{
let dot = l_1.0 * l_2.0 + l_1.1 * l_2.1;
dot == T::zero()
}
#[inline]
pub fn point_on_line<T>(point: (T, T), line: (T, T, T)) -> bool
where
T: Copy + Mul<Output = T> + Add<Output = T> + Zero + PartialEq,
{
let result = line.0 * point.0 + line.1 * point.1 + line.2;
result == T::zero()
}
#[inline]
pub fn point_in_triangle<T>(point: (T, T), p_1: (T, T), p_2: (T, T), p_3: (T, T)) -> bool
where
T: Copy
+ Sub<Output = T>
+ Mul<Output = T>
+ Add<Output = T>
+ Div<Output = T>
+ Zero
+ PartialOrd
+ One,
{
let x = point.0;
let y = point.1;
let x1 = p_1.0;
let y1 = p_1.1;
let x2 = p_2.0;
let y2 = p_2.1;
let x3 = p_3.0;
let y3 = p_3.1;
let denominator = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
if denominator == T::zero() {
return false;
}
let a = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / denominator;
let b = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) / denominator;
let c = T::one() - a - b;
a >= T::zero() && b >= T::zero() && c >= T::zero()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_are_collinear() {
let p1 = (0, 0);
let p2 = (1, 1);
let p3 = (2, 2);
assert!(are_collinear(p1, p2, p3));
}
#[test]
fn test_not_collinear() {
let p1 = (0, 0);
let p2 = (1, 0);
let p3 = (0, 1);
assert!(!are_collinear(p1, p2, p3));
}
#[test]
fn test_is_valid_triangle() {
let p1 = (0, 0);
let p2 = (1, 0);
let p3 = (0, 1);
assert!(is_valid_triangle(p1, p2, p3));
}
#[test]
fn test_is_valid_triangle_false() {
let p1 = (0, 0);
let p2 = (1, 1);
let p3 = (2, 2);
assert!(!is_valid_triangle(p1, p2, p3));
}
#[test]
fn test_is_valid_quadrance() {
assert!(is_valid_quadrance(4));
assert!(is_valid_quadrance(0));
assert!(!is_valid_quadrance(-1));
}
#[test]
fn test_is_valid_spread() {
assert!(is_valid_spread(0.0));
assert!(is_valid_spread(0.5));
assert!(is_valid_spread(1.0));
assert!(!is_valid_spread(-0.1));
assert!(!is_valid_spread(1.1));
}
#[test]
fn test_is_right_triangle() {
assert!(is_right_triangle(1.0, 0.0, 0.0));
assert!(is_right_triangle(0.0, 1.0, 0.0));
assert!(is_right_triangle(0.0, 0.0, 1.0));
assert!(!is_right_triangle(0.3, 0.3, 0.3));
}
#[test]
fn test_are_lines_parallel() {
let l1 = (1, 1, 0);
let l2 = (2, 2, 1);
assert!(are_lines_parallel(l1, l2));
}
#[test]
fn test_are_lines_perpendicular() {
let l1 = (1, 0, 0);
let l2 = (0, 1, 0);
assert!(are_lines_perpendicular(l1, l2));
}
#[test]
fn test_point_on_line() {
let point = (1, 1);
let line = (1, -1, 0);
assert!(point_on_line(point, line));
}
#[test]
fn test_point_in_triangle() {
let point = (0.5, 0.25);
let p1 = (0.0, 0.0);
let p2 = (1.0, 0.0);
let p3 = (0.0, 1.0);
assert!(point_in_triangle(point, p1, p2, p3));
}
#[test]
fn test_point_not_in_triangle() {
let point = (1.0, 1.0);
let p1 = (0.0, 0.0);
let p2 = (1.0, 0.0);
let p3 = (0.0, 1.0);
assert!(!point_in_triangle(point, p1, p2, p3));
}
#[test]
fn test_satisfies_triangle_inequality() {
assert!(satisfies_triangle_inequality(9.0, 16.0, 25.0));
assert!(satisfies_triangle_inequality(1.0, 1.0, 1.0));
assert!(satisfies_triangle_inequality(0.0, 1.0, 1.0));
}
#[test]
fn test_satisfies_triangle_inequality_negative() {
assert!(!satisfies_triangle_inequality(-1.0, 1.0, 1.0));
assert!(!satisfies_triangle_inequality(1.0, -1.0, 1.0));
assert!(!satisfies_triangle_inequality(1.0, 1.0, -1.0));
assert!(!satisfies_triangle_inequality(-1.0, -1.0, -1.0));
}
#[test]
fn test_satisfies_triangle_inequality_zero() {
assert!(satisfies_triangle_inequality(0.0, 0.0, 0.0));
}
#[test]
fn test_perimeter_squared() {
let result = perimeter_squared(9, 16, 25);
assert_eq!(result, 50); }
#[test]
fn test_perimeter_squared_zero() {
let result = perimeter_squared(0, 0, 0);
assert_eq!(result, 0);
}
#[test]
fn test_perimeter_squared_equal_sides() {
let result = perimeter_squared(4, 4, 4);
assert_eq!(result, 12); }
#[test]
fn test_is_acute_triangle() {
assert!(is_acute_triangle(0.3, 0.3, 0.3));
assert!(is_acute_triangle(0.5, 0.5, 0.5));
assert!(is_acute_triangle(0.9, 0.8, 0.7));
}
#[test]
fn test_is_acute_triangle_false() {
assert!(!is_acute_triangle(1.0, 0.3, 0.3));
assert!(!is_acute_triangle(0.3, 1.0, 0.3));
assert!(!is_acute_triangle(0.3, 0.3, 1.0));
}
#[test]
fn test_is_obtuse_triangle() {
assert!(is_obtuse_triangle(0.6, 0.3, 0.3));
assert!(is_obtuse_triangle(0.3, 0.6, 0.3));
assert!(is_obtuse_triangle(0.3, 0.3, 0.6));
assert!(is_obtuse_triangle(0.9, 0.1, 0.1));
}
#[test]
fn test_is_obtuse_triangle_false() {
assert!(!is_obtuse_triangle(0.4, 0.4, 0.4));
assert!(!is_obtuse_triangle(0.3, 0.3, 0.3));
assert!(is_obtuse_triangle(1.0, 0.3, 0.3));
}
#[test]
fn test_is_acute_triangle_integer() {
assert!(is_acute_triangle(0, 0, 0));
}
#[test]
fn test_is_right_triangle_integer() {
assert!(is_right_triangle(1, 0, 0));
assert!(is_right_triangle(0, 1, 0));
assert!(is_right_triangle(0, 0, 1));
}
#[test]
fn test_are_lines_not_parallel() {
let l1 = (1, 0, 0);
let l2 = (0, 1, 0);
assert!(!are_lines_parallel(l1, l2));
}
#[test]
fn test_are_lines_not_perpendicular() {
let l1 = (1, 1, 0);
let l2 = (1, 0, 0);
assert!(!are_lines_perpendicular(l1, l2));
}
#[test]
fn test_point_not_on_line() {
let point = (1, 2);
let line = (1, -1, 0);
assert!(!point_on_line(point, line));
}
#[test]
fn test_point_on_line_edge() {
let point = (0, 0);
let line = (1, 1, 0); assert!(point_on_line(point, line));
}
#[test]
fn test_point_in_triangle_edge() {
let point = (0.5, 0.0);
let p1 = (0.0, 0.0);
let p2 = (1.0, 0.0);
let p3 = (0.0, 1.0);
assert!(point_in_triangle(point, p1, p2, p3));
}
#[test]
fn test_point_in_triangle_vertex() {
let point = (0.0, 0.0);
let p1 = (0.0, 0.0);
let p2 = (1.0, 0.0);
let p3 = (0.0, 1.0);
assert!(point_in_triangle(point, p1, p2, p3));
}
}