use core::cmp::{Eq, PartialEq};
use core::fmt;
use core::hash::Hash;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use num_traits::{Float, NumCast, Signed};
#[repr(C)]
pub struct Vector2D<T> {
pub x: T,
pub y: T,
}
impl<T: Copy> Copy for Vector2D<T> {}
impl<T: Clone> Clone for Vector2D<T> {
fn clone(&self) -> Self {
Vector2D {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Vector2D<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let (x, y) = serde::Deserialize::deserialize(deserializer)?;
Ok(Vector2D {
x,
y,
})
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Vector2D<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(&self.x, &self.y).serialize(serializer)
}
}
#[cfg(feature = "arbitrary")]
impl<'a, T> arbitrary::Arbitrary<'a> for Vector2D<T>
where
T: arbitrary::Arbitrary<'a>,
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self>
{
let (x, y) = arbitrary::Arbitrary::arbitrary(u)?;
Ok(Vector2D {
x,
y,
})
}
}
impl<T: Eq> Eq for Vector2D<T> {}
impl<T: PartialEq> PartialEq for Vector2D<T> {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl<T: Hash> Hash for Vector2D<T> {
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
self.x.hash(h);
self.y.hash(h);
}
}
impl<T: fmt::Debug> fmt::Debug for Vector2D<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("").field(&self.x).field(&self.y).finish()
}
}
impl<T: Default> Default for Vector2D<T> {
fn default() -> Self {
Vector2D::new(Default::default(), Default::default())
}
}
impl<T> Vector2D<T> {
#[inline]
pub const fn new(x: T, y: T) -> Self {
Vector2D {
x,
y,
}
}
#[inline]
pub fn splat(v: T) -> Self
where
T: Clone,
{
Vector2D {
x: v.clone(),
y: v,
}
}
pub fn abs(self) -> Self
where
T: Signed,
{
Vector2D::new(self.x.abs(), self.y.abs())
}
#[inline]
pub fn dot(self, other: Self) -> T
where
T: Add<Output = T> + Mul<Output = T>,
{
self.x * other.x + self.y * other.y
}
#[inline]
pub fn cross(self, other: Self) -> T
where
T: Sub<Output = T> + Mul<Output = T>,
{
self.x * other.y - self.y * other.x
}
#[inline]
pub fn component_mul(self, other: Self) -> Self
where
T: Mul<Output = T>,
{
Vector2D::new(self.x * other.x, self.y * other.y)
}
#[inline]
pub fn component_div(self, other: Self) -> Self
where
T: Div<Output = T>,
{
Vector2D::new(self.x / other.x, self.y / other.y)
}
}
impl<T: Copy> Vector2D<T> {
#[inline]
pub fn yx(self) -> Self {
Vector2D::new(self.y, self.x)
}
#[inline]
pub fn to_untyped(self) -> Vector2D<T> {
Vector2D::new(self.x, self.y)
}
#[inline]
pub fn to_array(self) -> [T; 2] {
[self.x, self.y]
}
#[inline]
pub fn to_tuple(self) -> (T, T) {
(self.x, self.y)
}
}
impl<T> Vector2D<T>
where
T: Copy + Mul<T, Output = T> + Add<T, Output = T>,
{
#[inline]
pub fn square_length(self) -> T {
self.x * self.x + self.y * self.y
}
#[inline]
pub fn project_onto_vector(self, onto: Self) -> Self
where
T: Sub<T, Output = T> + Div<T, Output = T>,
{
onto * (self.dot(onto) / onto.square_length())
}
}
impl<T: Float> Vector2D<T> {
#[inline]
pub fn length(self) -> T {
self.square_length().sqrt()
}
#[inline]
#[must_use]
pub fn normalize(self) -> Self {
self / self.length()
}
#[inline]
#[must_use]
pub fn try_normalize(self) -> Option<Self> {
let len = self.length();
if len == T::zero() {
None
} else {
Some(self / len)
}
}
#[inline]
#[must_use]
pub fn robust_normalize(self) -> Self {
let length = self.length();
if length.is_infinite() {
let scaled = self / T::max_value();
scaled / scaled.length()
} else {
self / length
}
}
#[inline]
pub fn with_max_length(self, max_length: T) -> Self {
let square_length = self.square_length();
if square_length > max_length * max_length {
return self * (max_length / square_length.sqrt());
}
self
}
#[inline]
pub fn with_min_length(self, min_length: T) -> Self {
let square_length = self.square_length();
if square_length < min_length * min_length {
return self * (min_length / square_length.sqrt());
}
self
}
#[inline]
pub fn clamp_length(self, min: T, max: T) -> Self {
debug_assert!(min <= max);
self.with_min_length(min).with_max_length(max)
}
#[inline]
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite()
}
}
impl<T: NumCast + Copy> Vector2D<T> {
#[inline]
pub fn cast<NewT: NumCast>(self) -> Vector2D<NewT> {
self.try_cast().unwrap()
}
pub fn try_cast<NewT: NumCast>(self) -> Option<Vector2D<NewT>> {
match (NumCast::from(self.x), NumCast::from(self.y)) {
(Some(x), Some(y)) => Some(Vector2D::new(x, y)),
_ => None,
}
}
#[inline]
pub fn to_f32(self) -> Vector2D<f32> {
self.cast()
}
#[inline]
pub fn to_f64(self) -> Vector2D<f64> {
self.cast()
}
#[inline]
pub fn to_usize(self) -> Vector2D<usize> {
self.cast()
}
#[inline]
pub fn to_u32(self) -> Vector2D<u32> {
self.cast()
}
#[inline]
pub fn to_i32(self) -> Vector2D<i32> {
self.cast()
}
#[inline]
pub fn to_i64(self) -> Vector2D<i64> {
self.cast()
}
}
impl<T: Neg> Neg for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn neg(self) -> Self::Output {
Vector2D::new(-self.x, -self.y)
}
}
impl<T: Add> Add for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn add(self, other: Self) -> Self::Output {
Vector2D::new(self.x + other.x, self.y + other.y)
}
}
impl<T: Add + Copy> Add<&Self> for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn add(self, other: &Self) -> Self::Output {
Vector2D::new(self.x + other.x, self.y + other.y)
}
}
impl<T: Copy + Add<T, Output = T>> AddAssign for Vector2D<T> {
#[inline]
fn add_assign(&mut self, other: Self) {
*self = *self + other
}
}
impl<T: Sub> Sub for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn sub(self, other: Self) -> Self::Output {
Vector2D::new(self.x - other.x, self.y - other.y)
}
}
impl<T: Copy + Sub<T, Output = T>> SubAssign<Vector2D<T>> for Vector2D<T> {
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = *self - other
}
}
impl<T: Copy + Mul> Mul<T> for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn mul(self, scale: T) -> Self::Output {
Vector2D::new(self.x * scale, self.y * scale)
}
}
impl<T: Copy + Mul<T, Output = T>> MulAssign<T> for Vector2D<T> {
#[inline]
fn mul_assign(&mut self, scale: T) {
*self = *self * scale
}
}
impl<T: Copy + Div> Div<T> for Vector2D<T> {
type Output = Vector2D<T::Output>;
#[inline]
fn div(self, scale: T) -> Self::Output {
Vector2D::new(self.x / scale, self.y / scale)
}
}
impl<T: Copy + Div<T, Output = T>> DivAssign<T> for Vector2D<T> {
#[inline]
fn div_assign(&mut self, scale: T) {
*self = *self / scale
}
}
impl<T> Into<[T; 2]> for Vector2D<T> {
fn into(self) -> [T; 2] {
[self.x, self.y]
}
}
impl<T> From<[T; 2]> for Vector2D<T> {
fn from([x, y]: [T; 2]) -> Self {
Vector2D::new(x, y)
}
}
impl<T> Into<(T, T)> for Vector2D<T> {
fn into(self) -> (T, T) {
(self.x, self.y)
}
}
impl<T> From<(T, T)> for Vector2D<T> {
fn from(tuple: (T, T)) -> Self {
Vector2D::new(tuple.0, tuple.1)
}
}
#[cfg(test)]
mod vector2d {
use crate::foundation::Vector2D;
#[cfg(feature = "mint")]
use mint;
type Vec2 = Vector2D<f32>;
#[test]
pub fn test_scalar_mul() {
let p1: Vec2 = Vector2D::new(3.0, 5.0);
let result = p1 * 5.0;
assert_eq!(result, Vec2::new(15.0, 25.0));
}
#[test]
pub fn test_dot() {
let p1: Vec2 = Vector2D::new(2.0, 7.0);
let p2: Vec2 = Vector2D::new(13.0, 11.0);
assert_eq!(p1.dot(p2), 103.0);
}
#[test]
pub fn test_cross() {
let p1: Vec2 = Vector2D::new(4.0, 7.0);
let p2: Vec2 = Vector2D::new(13.0, 8.0);
let r = p1.cross(p2);
assert_eq!(r, -59.0);
}
#[cfg(feature = "mint")]
#[test]
pub fn test_mint() {
let v1 = Vec2::new(1.0, 3.0);
let vm: mint::Vector2<_> = v1.into();
let v2 = Vec2::from(vm);
assert_eq!(v1, v2);
}
#[test]
pub fn test_swizzling() {
let p: Vector2D<i32> = Vector2D::new(1, 2);
assert_eq!(p.yx(), Vector2D::new(2, 1));
}
}