use std::{
array::{self, from_fn},
hash::{Hash, Hasher},
ops::{Add, AddAssign, Div, Index, IndexMut, Mul, Neg, Sub, SubAssign},
};
use crate::{
geometry::{point::Point, spatial_element::SpatialElement},
numeric::scalar::Scalar,
operations::Zero,
};
pub trait VectorOps<T, const N: usize>: Sized
where
T: Scalar,
{
type Cross;
fn dot(&self, other: &Self) -> T;
fn cross(&self, other: &Self) -> Self::Cross;
fn scale(&self, s: &T) -> Self;
fn axpy(&mut self, a: &T, x: &Self);
fn any_perpendicular(&self) -> Vector<T, N>;
fn norm2(&self) -> T;
fn lerp(&self, with: &Self, u: &T) -> Self;
}
#[derive(Clone, Debug)]
pub struct Vector<T: Scalar, const N: usize>(pub Point<T, N>);
impl<T: Scalar, const N: usize> SpatialElement<T, N> for Vector<T, N> {
type With<U: Scalar> = Vector<U, N>;
fn new(coords: [T; N]) -> Vector<T, N> {
Vector(Point { coords })
}
fn from_vals<V>(vals: [V; N]) -> Vector<T, N>
where
V: Into<T>,
{
Vector(Point::<T, N>::from_vals(vals.map(|v| v.into())))
}
fn coords(&self) -> &[T; N] {
&self.0.coords
}
fn coords_mut(&mut self) -> &mut [T; N] {
&mut self.0.coords
}
fn iter(&self) -> std::slice::Iter<'_, T> {
self.0.coords.iter()
}
fn cast<U: Scalar>(&self) -> Self::With<U>
where
U: From<T>,
{
Vector::<U, N>::from_vals(from_fn(|i| U::from(self.0.coords[i].clone())))
}
}
impl<T: Scalar, const N: usize> Default for Vector<T, N> {
fn default() -> Self {
Vector::from(Point::default())
}
}
impl<T: Scalar, const N: usize> From<Point<T, N>> for Vector<T, N> {
fn from(p: Point<T, N>) -> Self {
Vector(p)
}
}
impl<T: Scalar, const N: usize> From<Vector<T, N>> for Point<T, N> {
fn from(v: Vector<T, N>) -> Self {
v.0
}
}
impl<T: Scalar, const N: usize> Index<usize> for Vector<T, N> {
type Output = T;
fn index(&self, i: usize) -> &Self::Output {
&self.0.coords[i]
}
}
impl<T: Scalar, const N: usize> IndexMut<usize> for Vector<T, N> {
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
&mut self.0.coords[i]
}
}
impl<'a, 'b, T, const N: usize> Add<&'b Vector<T, N>> for &'a Vector<T, N>
where
T: Scalar + for<'c> AddAssign<&'c T>,
{
type Output = Vector<T, N>;
fn add(self, rhs: &'b Vector<T, N>) -> Self::Output {
let mut out = self.clone();
for i in 0..N {
out[i] += &rhs[i];
}
out
}
}
impl<T, const N: usize> Add for Vector<T, N>
where
T: Scalar,
for<'a, 'b> &'a Vector<T, N>: Add<&'b Vector<T, N>, Output = Vector<T, N>>,
{
type Output = Vector<T, N>;
fn add(self, rhs: Vector<T, N>) -> Self::Output {
<&Vector<T, N> as Add<&Vector<T, N>>>::add(&self, &rhs)
}
}
impl<'a, 'b, T, const N: usize> Sub<&'b Vector<T, N>> for &'a Vector<T, N>
where
T: Scalar + for<'c> SubAssign<&'c T>,
{
type Output = Vector<T, N>;
fn sub(self, rhs: &'b Vector<T, N>) -> Self::Output {
let mut out = self.clone();
for i in 0..N {
out[i] -= &rhs[i];
}
out
}
}
impl<T, const N: usize> Sub for Vector<T, N>
where
T: Scalar,
for<'a, 'b> &'a Vector<T, N>: Sub<&'b Vector<T, N>, Output = Vector<T, N>>,
{
type Output = Vector<T, N>;
fn sub(self, rhs: Vector<T, N>) -> Self::Output {
<&Vector<T, N> as Sub<&Vector<T, N>>>::sub(&self, &rhs)
}
}
impl<T> VectorOps<T, 2> for Vector<T, 2>
where
T: Scalar,
for<'a> &'a T: Add<&'a T, Output = T>
+ Sub<&'a T, Output = T>
+ Mul<&'a T, Output = T>
+ Div<&'a T, Output = T>,
{
type Cross = T;
fn dot(&self, o: &Self) -> T {
&self[0] * &o[0] + &self[1] * &o[1]
}
fn cross(&self, o: &Self) -> T {
&self[0] * &o[1] - &self[1] * &o[0]
}
fn scale(&self, s: &T) -> Self {
Self::from(Point::<T, 2>::from_vals([&self[0] * &s, &self[1] * &s]))
}
fn axpy(&mut self, a: &T, x: &Self) {
for i in 0..2 {
let ax_i = &x[i] * a;
self[i] = &self[i] + &ax_i;
}
}
fn any_perpendicular(&self) -> Vector<T, 2> {
unimplemented!("any_perpendicular is not implemented for 2D vectors");
}
fn norm2(&self) -> T {
self[0].clone() * self[0].clone() + self[1].clone() * self[1].clone()
}
fn lerp(&self, _with: &Self, _u: &T) -> Self {
unimplemented!()
}
}
impl<T> VectorOps<T, 3> for Vector<T, 3>
where
T: Scalar,
for<'a> &'a T: Add<&'a T, Output = T>
+ Sub<&'a T, Output = T>
+ Mul<&'a T, Output = T>
+ Div<&'a T, Output = T>,
{
type Cross = Vector<T, 3>;
fn dot(&self, o: &Self) -> T {
&self[0] * &o[0] + &self[1] * &o[1] + &self[2] * &o[2]
}
fn cross(&self, o: &Self) -> Self::Cross {
Vector::from(Point::<T, 3>::from_vals([
&(&self[1] * &o[2]) - &(&self[2] * &o[1]),
&(&self[2] * &o[0]) - &(&self[0] * &o[2]),
&(&self[0] * &o[1]) - &(&self[1] * &o[0]),
]))
}
fn scale(&self, s: &T) -> Self {
Self::from(Point::<T, 3>::from_vals([
&self[0] * &s,
&self[1] * &s,
&self[2] * &s,
]))
}
fn axpy(&mut self, a: &T, x: &Self) {
for i in 0..3 {
let ax_i = &x[i] * a;
self[i] = &self[i] + &ax_i;
}
}
fn any_perpendicular(&self) -> Vector<T, 3> {
if self[0].abs() < self[1].abs() && self[0].abs() < self[2].abs() {
self.cross(&Vector::new([T::one(), T::zero(), T::zero()]))
} else if self[1].abs() < self[2].abs() {
self.cross(&Vector::new([T::zero(), T::one(), T::zero()]))
} else {
self.cross(&Vector::new([T::zero(), T::zero(), T::one()]))
}
}
fn norm2(&self) -> T {
self[0].clone() * self[0].clone()
+ self[1].clone() * self[1].clone()
+ self[2].clone() * self[2].clone()
}
fn lerp(&self, with: &Self, u: &T) -> Self {
let one = T::one();
let w0 = &one - u;
let w1 = u.clone();
&self.scale(&w0) + &with.scale(&w1)
}
}
impl<T, const N: usize> Zero for Vector<T, N>
where
T: Scalar,
{
fn zero() -> Self {
Vector::from(Point {
coords: array::from_fn(|_| T::zero()),
})
}
fn is_zero(&self) -> bool {
self.0.coords.iter().all(|c| c.is_zero())
}
fn is_positive(&self) -> bool {
self.0.coords.iter().all(|c| c.is_positive())
}
fn is_negative(&self) -> bool {
!self.is_positive() && !self.is_zero()
}
fn is_positive_or_zero(&self) -> bool {
self.is_positive() || self.is_zero()
}
fn is_negative_or_zero(&self) -> bool {
self.is_negative() || self.is_zero()
}
}
impl<T: Scalar, const N: usize> Into<[T; N]> for Vector<T, N> {
fn into(self) -> [T; N] {
self.0.coords
}
}
impl<T: Scalar, const N: usize> From<[T; N]> for Vector<T, N> {
fn from(coords: [T; N]) -> Self {
Vector(Point { coords })
}
}
impl<T: Scalar, const N: usize> Hash for Vector<T, N> {
fn hash<H: Hasher>(&self, state: &mut H) {
for coord in &self.0.coords {
coord.hash(state);
}
}
}
impl<T: Scalar, const N: usize> PartialEq for Vector<T, N> {
fn eq(&self, other: &Self) -> bool {
if self.0.coords.len() != other.0.coords.len() {
return false;
}
for i in 0..N {
if self.0.coords[i] != other.0.coords[i] {
return false;
}
}
true
}
}
impl<T: Scalar, const N: usize> PartialOrd for Vector<T, N> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.0.coords.len() != other.0.coords.len() {
return None;
}
for i in 0..N {
match self.0.coords[i].partial_cmp(&other.0.coords[i]) {
Some(std::cmp::Ordering::Equal) => continue,
Some(ordering) => return Some(ordering),
None => return None,
}
}
Some(std::cmp::Ordering::Equal)
}
}
impl<T: Scalar, const N: usize> Eq for Vector<T, N> {}
impl<T: Scalar, const N: usize> Neg for Vector<T, N>
where
for<'a> &'a T: Mul<Output = T>,
{
type Output = Self;
fn neg(self) -> Self {
Vector::from(Point::<T, N>::from_vals(from_fn(|i| {
&self[i] * &T::from_num_den(-1, 1)
})))
}
}
pub type Vector2<T> = Vector<T, 2>;
pub type Vector3<T> = Vector<T, 3>;