use crate::prelude::*;
#[cfg(feature = "serde")]
use crate::serialize::arrays;
use num_traits::Signed;
use rand::distributions::uniform::SampleUniform;
#[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 Vector<T = f64, const N: usize = 2>(
#[cfg_attr(feature = "serde", serde(with = "arrays"))] pub(crate) [T; N],
);
#[macro_export]
macro_rules! vector {
() => {
$crate::prelude::Vector::origin()
};
($x:expr) => {
$crate::prelude::Vector::from_x($x)
};
($x:expr, $y:expr$(,)?) => {
$crate::prelude::Vector::from_xy($x, $y)
};
($x:expr, $y:expr, $z:expr$(,)?) => {
$crate::prelude::Vector::from_xyz($x, $y, $z)
};
}
impl<T, const N: usize> Vector<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> Vector<T, 1> {
#[inline]
pub const fn from_x(x: T) -> Self {
Self([x])
}
}
impl<T> Vector<T> {
#[inline]
pub const fn from_xy(x: T, y: T) -> Self {
Self([x, y])
}
}
impl<T> Vector<T, 3> {
#[inline]
pub const fn from_xyz(x: T, y: T, z: T) -> Self {
Self([x, y, z])
}
}
impl<T: Num + Float> Vector<T> {
pub fn rotated<V>(v: V, angle: T) -> Self
where
V: Into<Vector<T>>,
{
let mut v = v.into();
v.rotate(angle);
v
}
pub fn from_angle(angle: T, length: T) -> Self {
let (sin, cos) = angle.sin_cos();
Self::new([length * cos, length * sin])
}
pub fn heading(&self) -> T {
self.y().atan2(self.x())
}
pub fn rotate(&mut self, angle: T) {
let new_heading = self.heading() + angle;
let mag = self.mag();
let (sin, cos) = new_heading.sin_cos();
self.set_x(cos * mag);
self.set_y(sin * mag);
}
}
impl<T: Num + Float> Vector<T, 3> {
pub fn cross<V>(&self, v: V) -> Self
where
V: Into<Vector<T, 3>>,
{
let v = v.into();
Self::new([
self.y() * v.z() - self.z() * v.y(),
self.z() * v.x() - self.x() * v.z(),
self.x() * v.y() - self.y() * v.x(),
])
}
pub fn angle_between<V>(&self, v: V) -> T
where
V: Into<Vector<T, 3>>,
{
let v = v.into();
let dot_mag_product =
num_traits::clamp(self.dot(v) / (self.mag() * v.mag()), -T::one(), T::one());
dot_mag_product.acos() * self.cross(v).z().signum()
}
}
impl<T: Copy, const N: usize> Vector<T, N> {
#[inline]
pub fn from_point(p: Point<T, N>) -> Self {
Self::new(p.coords())
}
#[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 coords(&self) -> [T; N] {
self.0
}
#[inline]
pub fn coords_mut(&mut self) -> &mut [T; N] {
&mut self.0
}
#[inline]
pub fn to_vec(self) -> Vec<T> {
self.0.to_vec()
}
}
impl<T: Num, const N: usize> Vector<T, N> {
#[inline]
pub fn offset<V, const M: usize>(&mut self, offsets: V)
where
V: Into<Vector<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;
}
}
}
pub fn random() -> Self
where
T: SampleUniform,
{
let mut coords = [T::zero(); N];
for coord in &mut coords {
*coord = random!(T::one());
}
Self::new(coords)
}
}
impl<T: Num + Float, const N: usize> Vector<T, N> {
pub fn reflection<V>(v: V, normal: V) -> Self
where
V: Into<Vector<T, N>>,
{
let mut v = v.into();
v.reflect(normal);
v
}
pub fn normalized<V>(v: V) -> Self
where
V: Into<Vector<T, N>>,
{
let mut v = v.into();
v.normalize();
v
}
pub fn mag(&self) -> T {
self.mag_sq().sqrt()
}
pub fn mag_sq(&self) -> T {
let mut sum = T::zero();
for &v in self.iter() {
sum += v * v;
}
sum
}
pub fn dot<V>(&self, o: V) -> T
where
V: Into<Vector<T, N>>,
{
let o = o.into();
let mut sum = T::zero();
for (&v, o) in self.iter().zip(o) {
sum += v * o;
}
sum
}
pub fn reflect<V>(&mut self, normal: V)
where
V: Into<Vector<T, N>>,
{
let normal = Self::normalized(normal);
*self = normal * ((T::one() + T::one()) * self.dot(normal)) - *self;
}
pub fn set_mag(&mut self, mag: T) {
self.normalize();
*self *= mag;
}
pub fn dist<V>(&self, v: V) -> T
where
V: Into<Vector<T, N>>,
{
(*self - v.into()).mag()
}
pub fn normalize(&mut self) {
let len = self.mag();
if len != T::zero() {
*self *= len.recip();
}
}
pub fn limit(&mut self, max: T) {
let mag_sq = self.mag_sq();
if mag_sq > max * max {
*self /= mag_sq.sqrt();
*self *= max;
}
}
pub fn lerp<V>(&self, o: V, amt: T) -> Self
where
V: Into<Vector<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<V>(&self, other: V, epsilon: T) -> bool
where
V: Into<Vector<T, N>>,
{
let other = other.into();
let mut approx_eq = true;
for (&v, o) in self.iter().zip(other) {
approx_eq &= (v - o).abs() < epsilon;
}
approx_eq
}
}
impl<T: Default, const N: usize> Default for Vector<T, N> {
fn default() -> Self {
Self::origin()
}
}
impl<T, const N: usize> fmt::Display for Vector<T, N>
where
[T; N]: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl<T: Copy, const N: usize> From<Point<T, N>> for Vector<T, N> {
fn from(p: Point<T, N>) -> Self {
Self::from_point(p)
}
}
impl<T: Copy, const N: usize> From<&Point<T, N>> for Vector<T, N> {
fn from(p: &Point<T, N>) -> Self {
Self::from_point(*p)
}
}
impl<T: Copy, const N: usize> From<Vector<T, N>> for Point<T, N> {
fn from(v: Vector<T, N>) -> Self {
Self::from_vector(v)
}
}
impl<T: Copy, const N: usize> From<&Vector<T, N>> for Point<T, N> {
fn from(v: &Vector<T, N>) -> Self {
Self::from_vector(*v)
}
}