#[cfg(feature = "serde")]
use crate::serialize::arrays;
use crate::{error::Result, prelude::*};
use num_traits::Signed;
#[cfg(feature = "serde")]
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{fmt, ops::MulAssign};
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[must_use]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + DeserializeOwned"))]
pub struct Point<T = i32, const N: usize = 2>(
#[cfg_attr(feature = "serde", serde(with = "arrays"))] pub(crate) [T; N],
);
#[macro_export]
macro_rules! point {
() => {
$crate::prelude::Point::origin()
};
($x:expr) => {
$crate::prelude::Point::from_x($x)
};
($x:expr, $y:expr$(,)?) => {
$crate::prelude::Point::from_xy($x, $y)
};
($x:expr, $y:expr, $z:expr$(,)?) => {
$crate::prelude::Point::from_xyz($x, $y, $z)
};
}
impl<T, const N: usize> Point<T, N> {
#[inline]
pub const fn new(coords: [T; N]) -> Self {
Self(coords)
}
#[inline]
pub fn origin() -> Self
where
T: Default,
{
Self::new([(); N].map(|_| T::default()))
}
}
impl<T> Point<T, 1> {
#[inline]
pub const fn from_x(x: T) -> Self {
Self([x])
}
}
impl<T> Point<T> {
#[inline]
pub const fn from_xy(x: T, y: T) -> Self {
Self([x, y])
}
}
impl<T> Point<T, 3> {
#[inline]
pub const fn from_xyz(x: T, y: T, z: T) -> Self {
Self([x, y, z])
}
}
impl<T: Copy, const N: usize> Point<T, N> {
pub fn from_vector(v: Vector<T, N>) -> Self {
Self::new(v.coords())
}
#[inline]
pub fn coords(&self) -> [T; N] {
self.0
}
#[inline]
pub fn coords_mut(&mut self) -> &mut [T; N] {
&mut self.0
}
#[inline]
pub fn x(&self) -> T {
self.0[0]
}
#[inline]
pub fn set_x(&mut self, x: T) {
self.0[0] = x;
}
#[inline]
pub fn y(&self) -> T {
self.0[1]
}
#[inline]
pub fn set_y(&mut self, y: T) {
self.0[1] = y;
}
#[inline]
pub fn z(&self) -> T {
self.0[2]
}
#[inline]
pub fn set_z(&mut self, z: T) {
self.0[2] = z;
}
#[inline]
pub fn to_vec(self) -> Vec<T> {
self.0.to_vec()
}
}
impl<T: Num, const N: usize> Point<T, N> {
#[inline]
pub fn offset<P, const M: usize>(&mut self, offsets: P)
where
P: Into<Point<T, M>>,
{
let offsets = offsets.into();
for (v, o) in self.iter_mut().zip(offsets) {
*v += o;
}
}
#[inline]
pub fn offset_x(&mut self, offset: T) {
self.0[0] += offset;
}
#[inline]
pub fn offset_y(&mut self, offset: T) {
self.0[1] += offset;
}
#[inline]
pub fn offset_z(&mut self, offset: T) {
self.0[2] += offset;
}
pub fn scale<U>(&mut self, s: U)
where
T: MulAssign<U>,
U: Num,
{
*self *= s;
}
pub fn wrap(&mut self, wrap: [T; N], size: T)
where
T: Signed,
{
for (v, w) in self.iter_mut().zip(wrap) {
let w = w + size;
if *v > w {
*v = -size;
} else if *v < -size {
*v = w;
}
}
}
}
impl<T: Num + Float, const N: usize> Point<T, N> {
pub fn dist<P>(&self, p: P) -> T
where
P: Into<Point<T, N>>,
{
(*self - p.into()).mag()
}
pub fn lerp<P>(&self, o: P, amt: T) -> Self
where
P: Into<Point<T, N>>,
{
let o = o.into();
let lerp = |start, stop, amt| amt * (stop - start) + start;
let amt = num_traits::clamp(amt, T::zero(), T::one());
let mut coords = [T::zero(); N];
for ((c, &v), o) in coords.iter_mut().zip(self.iter()).zip(o) {
*c = lerp(v, o, amt);
}
Self::new(coords)
}
pub fn approx_eq(&self, other: Point<T, N>, epsilon: T) -> bool {
let mut approx_eq = true;
for (&v, o) in self.iter().zip(other) {
approx_eq &= (v - o).abs() < epsilon;
}
approx_eq
}
}
impl Draw for Point<i32> {
fn draw(&self, s: &mut PixState) -> Result<()> {
s.point(*self)
}
}
impl<T: Default, const N: usize> Default for Point<T, N> {
fn default() -> Self {
Self::origin()
}
}
impl<T, const N: usize> fmt::Display for Point<T, N>
where
[T; N]: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}