use crate::{error::Result, prelude::*};
#[cfg(feature = "serde")]
use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
#[must_use]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + DeserializeOwned"))]
pub struct Tri<T = i32, const N: usize = 2>(pub(crate) [Point<T, N>; 3]);
#[macro_export]
macro_rules! tri {
($p1:expr, $p2:expr, $p3:expr$(,)?) => {
$crate::prelude::Tri::new($p1, $p2, $p3)
};
($x1:expr, $y1:expr, $x2:expr, $y2:expr, $x3:expr, $y3:expr$(,)?) => {
$crate::prelude::Tri::from_xy($x1, $y1, $x2, $y2, $x3, $y3)
};
($x1:expr, $y1:expr, $z1:expr, $x2:expr, $y2:expr, $z2:expr, $x3:expr, $y3:expr, $z3:expr$(,)?) => {
$crate::prelude::Tri::from_xyz($x1, $y1, $z2, $x2, $y2, $z2, $x3, $y3, $z3)
};
}
impl<T, const N: usize> Tri<T, N> {
pub fn new<P1, P2, P3>(p1: P1, p2: P2, p3: P3) -> Self
where
P1: Into<Point<T, N>>,
P2: Into<Point<T, N>>,
P3: Into<Point<T, N>>,
{
Self([p1.into(), p2.into(), p3.into()])
}
}
impl<T> Tri<T> {
#[inline]
pub const fn from_xy(x1: T, y1: T, x2: T, y2: T, x3: T, y3: T) -> Self {
Self([point!(x1, y1), point!(x2, y2), point!(x3, y3)])
}
}
impl<T: Copy> Tri<T> {
#[inline]
pub fn coords(&self) -> [T; 6] {
let [p1, p2, p3] = self.points();
let [x1, y1] = p1.coords();
let [x2, y2] = p2.coords();
let [x3, y3] = p3.coords();
[x1, y1, x2, y2, x3, y3]
}
}
impl<T> Tri<T, 3> {
#[allow(clippy::too_many_arguments)]
#[inline]
pub const fn from_xyz(x1: T, y1: T, z1: T, x2: T, y2: T, z2: T, x3: T, y3: T, z3: T) -> Self {
Self([point!(x1, y1, z1), point!(x2, y2, z2), point!(x3, y3, z3)])
}
}
impl<T: Copy> Tri<T, 3> {
#[inline]
pub fn coords(&self) -> [T; 9] {
let [p1, p2, p3] = self.points();
let [x1, y1, z1] = p1.coords();
let [x2, y2, z2] = p2.coords();
let [x3, y3, z3] = p3.coords();
[x1, y1, z1, x2, y2, z2, x3, y3, z3]
}
}
impl<T: Copy, const N: usize> Tri<T, N> {
#[inline]
pub fn p1(&self) -> Point<T, N> {
self.0[0]
}
#[inline]
pub fn set_p1<P>(&mut self, p: P)
where
P: Into<Point<T, N>>,
{
self.0[0] = p.into();
}
#[inline]
pub fn p2(&self) -> Point<T, N> {
self.0[1]
}
#[inline]
pub fn set_p2<P>(&mut self, p: P)
where
P: Into<Point<T, N>>,
{
self.0[1] = p.into();
}
#[inline]
pub fn p3(&self) -> Point<T, N> {
self.0[2]
}
#[inline]
pub fn set_p3<P>(&mut self, p: P)
where
P: Into<Point<T, N>>,
{
self.0[2] = p.into();
}
#[inline]
pub fn points(&self) -> [Point<T, N>; 3] {
self.0
}
#[inline]
pub fn points_mut(&mut self) -> &mut [Point<T, N>; 3] {
&mut self.0
}
pub fn to_vec(self) -> Vec<Point<T, N>> {
self.0.to_vec()
}
}
impl<T: Num> Contains<Point<T>> for Tri<T> {
fn contains(&self, p: Point<T>) -> bool {
let [p1, p2, p3] = self.points();
let b1 = ((p.x() - p2.x()) * (p1.y() - p2.y()) - (p.y() - p2.y()) * (p1.x() - p2.x()))
< T::zero();
let b2 = ((p.x() - p3.x()) * (p2.y() - p3.y()) - (p.y() - p3.y()) * (p2.x() - p3.x()))
< T::zero();
let b3 = ((p.x() - p1.x()) * (p3.y() - p1.y()) - (p.y() - p1.y()) * (p3.x() - p1.x()))
< T::zero();
(b1 == b2) && (b2 == b3)
}
}
impl Draw for Tri<i32> {
fn draw(&self, s: &mut PixState) -> Result<()> {
s.triangle(*self)
}
}
impl<T: Copy> From<[T; 6]> for Tri<T> {
#[inline]
fn from([x1, y1, x2, y2, x3, y3]: [T; 6]) -> Self {
Self::from_xy(x1, y1, x2, y2, x3, y3)
}
}
impl<T: Copy> From<[T; 9]> for Tri<T, 3> {
#[inline]
fn from([x1, y1, z1, x2, y2, z2, x3, y3, z3]: [T; 9]) -> Self {
Self::from_xyz(x1, y1, z1, x2, y2, z2, x3, y3, z3)
}
}
impl<T: Copy> From<[[T; 2]; 3]> for Tri<T> {
#[inline]
fn from([[x1, y1], [x2, y2], [x3, y3]]: [[T; 2]; 3]) -> Self {
Self::from_xy(x1, y1, x2, y2, x3, y3)
}
}
impl<T: Copy> From<[[T; 3]; 3]> for Tri<T, 3> {
#[inline]
fn from([[x1, y1, z1], [x2, y2, z2], [x3, y3, z3]]: [[T; 3]; 3]) -> Self {
Self::from_xyz(x1, y1, z1, x2, y2, z2, x3, y3, z3)
}
}