#[cfg(test)]
mod test;
use std::cmp::Ordering;
use std::ops::{
Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
};
macro_rules! fn_simple_as {
($func:ident, $type:ty) => {
pub fn $func(&self) -> Vector2D<$type> {
Vector2D {
x: self.x as $type,
y: self.y as $type,
}
}
};
}
macro_rules! fn_lower_bounded_as {
($func:ident, $dst_type:ty, $lower_bound:expr) => {
pub fn $func(&self) -> Vector2D<$dst_type> {
Vector2D {
x: self.x.max($lower_bound) as $dst_type,
y: self.y.max($lower_bound) as $dst_type,
}
}
};
}
macro_rules! fn_bounded_as {
($func:ident, $dst_type:ty, $lower_bound:expr, $upper_bound:expr) => {
pub fn $func(&self) -> Vector2D<$dst_type> {
Vector2D {
x: self.x.min($upper_bound).max($lower_bound) as $dst_type,
y: self.y.min($upper_bound).max($lower_bound) as $dst_type,
}
}
};
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Vector2D<T> {
pub x: T,
pub y: T,
}
impl<T: Copy + Clone> Vector2D<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn from_vec2d<U: Into<T> + Copy + Clone>(src: Vector2D<U>) -> Vector2D<T> {
Vector2D {
x: src.x.into(),
y: src.y.into(),
}
}
pub fn into_vec2d<U: From<T>>(self) -> Vector2D<U> {
Vector2D {
x: self.x.into(),
y: self.y.into(),
}
}
}
impl<T> Default for Vector2D<T>
where
T: Default,
{
fn default() -> Self {
Self {
x: T::default(),
y: T::default(),
}
}
}
impl<T: Default> Vector2D<T> {
pub fn horizontal(self) -> Self {
Self {
x: self.x,
y: Default::default(),
}
}
pub fn vertical(self) -> Self {
Self {
x: Default::default(),
y: self.y,
}
}
}
impl<T> Vector2D<T>
where
T: Mul<T, Output = T> + Copy + Clone,
{
pub fn mul_components(self, other: Self) -> Self {
Self {
x: self.x * other.x,
y: self.y * other.y,
}
}
}
impl<T> Vector2D<T>
where
T: Div<T, Output = T> + Copy + Clone,
{
pub fn div_components(self, other: Self) -> Self {
Self {
x: self.x / other.x,
y: self.y / other.y,
}
}
}
impl<T, U> Neg for Vector2D<T>
where
T: Neg<Output = U> + Copy + Clone,
{
type Output = Vector2D<U>;
fn neg(self) -> Self::Output {
Self::Output {
x: -self.x,
y: -self.y,
}
}
}
impl<T> Vector2D<T>
where
T: Neg<Output = T> + Copy + Clone,
{
pub fn normal(self) -> Self {
Self {
x: -self.y,
y: self.x,
}
}
}
impl<T, U, V> Vector2D<T>
where
T: Mul<T, Output = U> + Copy + Clone,
U: Add<U, Output = V> + Copy + Clone,
{
pub fn dot(v1: Self, v2: Self) -> V {
v1.x * v2.x + v1.y * v2.y
}
pub fn length_squared(self) -> V {
self.x * self.x + self.y * self.y
}
}
impl<T> Vector2D<T>
where
T: Sub<T, Output = T> + Mul<T, Output = T> + Add<T, Output = T> + Copy + Clone,
{
pub fn lerp(start: Self, end: Self, progress: T) -> Self {
start + ((end - start) * progress)
}
}
impl<T, U> From<Vector2D<T>> for (U, U)
where
U: From<T> + Copy + Clone,
{
fn from(src: Vector2D<T>) -> (U, U) {
(U::from(src.x), U::from(src.y))
}
}
impl<T, U> From<(U, U)> for Vector2D<T>
where
T: From<U>,
U: Copy + Clone,
{
fn from(src: (U, U)) -> Vector2D<T> {
Vector2D {
x: src.0.into(),
y: src.1.into(),
}
}
}
impl<T, U> From<[U; 2]> for Vector2D<T>
where
T: From<U>,
U: Copy + Clone,
{
fn from(src: [U; 2]) -> Vector2D<T> {
Vector2D {
x: src[0].into(),
y: src[1].into(),
}
}
}
impl<T> Index<usize> for Vector2D<T> {
type Output = T;
fn index(&self, idx: usize) -> &Self::Output {
match idx {
0 => &self.x,
1 => &self.y,
_ => panic!("Index '{}' was out of range for Vector2D", idx),
}
}
}
impl<T> IndexMut<usize> for Vector2D<T> {
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
match idx {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("Index '{}' was out of range for Vector2D", idx),
}
}
}
impl Vector2D<f32> {
pub fn length(self) -> f32 {
f32::sqrt(self.length_squared())
}
pub fn normalise(self) -> Self {
let len = self.length();
if len == 0.0 {
self
} else {
self / len
}
}
pub fn angle(self) -> f32 {
self.y.atan2(self.x)
}
fn_simple_as!(as_i32s, i32);
fn_simple_as!(as_i64s, i64);
fn_simple_as!(as_isizes, isize);
fn_lower_bounded_as!(as_u32s, u32, 0.0);
fn_lower_bounded_as!(as_u64s, u64, 0.0);
fn_lower_bounded_as!(as_usizes, usize, 0.0);
}
impl Vector2D<f64> {
pub fn length(self) -> f64 {
f64::sqrt(self.length_squared())
}
pub fn normalise(self) -> Self {
let len = self.length();
if len == 0.0 {
self
} else {
self / len
}
}
pub fn angle(self) -> f64 {
self.y.atan2(self.x)
}
fn_simple_as!(as_i32s, i32);
fn_simple_as!(as_i64s, i64);
fn_simple_as!(as_isize, isize);
fn_simple_as!(as_f32, f32);
fn_lower_bounded_as!(as_u32s, u32, 0.0);
fn_lower_bounded_as!(as_u64s, u64, 0.0);
fn_lower_bounded_as!(as_usizes, usize, 0.0);
}
impl Vector2D<i32> {
fn_simple_as!(as_isizes, isize);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_lower_bounded_as!(as_u32s, u32, 0);
fn_lower_bounded_as!(as_u64s, u64, 0);
fn_lower_bounded_as!(as_usizes, usize, 0);
}
impl Vector2D<i64> {
fn_bounded_as!(as_i32s, i32, i32::MIN.into(), i32::MAX.into());
fn_simple_as!(as_i64s, isize);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_lower_bounded_as!(as_u32s, u32, 0);
fn_lower_bounded_as!(as_u64s, u64, 0);
fn_lower_bounded_as!(as_usizes, usize, 0);
}
impl Vector2D<isize> {
fn_simple_as!(as_i32s, i32);
fn_simple_as!(as_i64s, i64);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_lower_bounded_as!(as_u32s, u32, 0);
fn_lower_bounded_as!(as_u64s, u64, 0);
fn_lower_bounded_as!(as_usizes, usize, 0);
}
impl Vector2D<u32> {
fn_bounded_as!(as_i32s, i32, 0, i32::MAX as u32);
fn_simple_as!(as_i64s, i64);
fn_simple_as!(as_isizes, isize);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_simple_as!(as_usizes, usize);
}
impl Vector2D<u64> {
fn_bounded_as!(as_i32s, i32, 0, i32::MAX as u64);
fn_bounded_as!(as_i64s, i64, 0, i64::MAX as u64);
fn_simple_as!(as_isizes, isize);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_simple_as!(as_u32s, u32);
fn_simple_as!(as_usizes, usize);
}
impl Vector2D<usize> {
fn_simple_as!(as_i32s, i32);
fn_simple_as!(as_i64s, i64);
fn_bounded_as!(as_isizes, isize, 0, isize::MAX as usize);
fn_simple_as!(as_f32s, f32);
fn_simple_as!(as_f64s, f64);
fn_simple_as!(as_u32s, u32);
fn_simple_as!(as_u64s, u64);
}
impl<T> Vector2D<T>
where
T: PartialOrd + Copy + Clone,
{
fn min_t(v1: T, v2: T) -> T {
match v1.partial_cmp(&v2) {
None => v1,
Some(Ordering::Less) => v1,
Some(_) => v2,
}
}
fn max_t(v1: T, v2: T) -> T {
match v1.partial_cmp(&v2) {
None => v1,
Some(Ordering::Greater) => v1,
Some(_) => v2,
}
}
fn clamp_t(v: T, min: T, max: T) -> T {
Self::max_t(Self::min_t(v, max), min)
}
pub fn min_each(self, value: T) -> Self {
Self {
x: Self::min_t(self.x, value),
y: Self::min_t(self.y, value),
}
}
pub fn max_each(self, value: T) -> Self {
Self {
x: Self::max_t(self.x, value),
y: Self::max_t(self.y, value),
}
}
pub fn clamp_each(self, min: T, max: T) -> Self {
Self {
x: Self::clamp_t(self.x, min, max),
y: Self::clamp_t(self.y, min, max),
}
}
}
impl<T, O> Add<Vector2D<T>> for Vector2D<T>
where
T: Add<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn add(self, rhs: Vector2D<T>) -> Self::Output {
Vector2D {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<T, O> Add<&Vector2D<T>> for &Vector2D<T>
where
T: Add<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn add(self, rhs: &Vector2D<T>) -> Self::Output {
Vector2D {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<T> AddAssign<Vector2D<T>> for Vector2D<T>
where
T: Add<T, Output = T> + Copy + Clone,
{
fn add_assign(&mut self, rhs: Vector2D<T>) {
self.x = self.x + rhs.x;
self.y = self.y + rhs.y;
}
}
impl<T, O> Sub<Vector2D<T>> for Vector2D<T>
where
T: Sub<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn sub(self, rhs: Vector2D<T>) -> Self::Output {
Vector2D {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<T, O> Sub<&Vector2D<T>> for &Vector2D<T>
where
T: Sub<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn sub(self, rhs: &Vector2D<T>) -> Self::Output {
Vector2D {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl<T> SubAssign<Vector2D<T>> for Vector2D<T>
where
T: Sub<T, Output = T> + Copy + Clone,
{
fn sub_assign(&mut self, rhs: Vector2D<T>) {
self.x = self.x - rhs.x;
self.y = self.y - rhs.y;
}
}
impl<T, O> Mul<T> for Vector2D<T>
where
T: Mul<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn mul(self, rhs: T) -> Self::Output {
Vector2D {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl<T, O> Mul<T> for &Vector2D<T>
where
T: Mul<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn mul(self, rhs: T) -> Self::Output {
Self::Output {
x: self.x * rhs,
y: self.y * rhs,
}
}
}
impl<T> MulAssign<T> for Vector2D<T>
where
T: Mul<T, Output = T> + Copy + Clone,
{
fn mul_assign(&mut self, rhs: T) {
self.x = self.x * rhs;
self.y = self.y * rhs;
}
}
impl<T, O> Div<T> for Vector2D<T>
where
T: Div<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn div(self, rhs: T) -> Self::Output {
Self::Output {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl<T, O> Div<T> for &Vector2D<T>
where
T: Div<T, Output = O> + Copy + Clone,
{
type Output = Vector2D<O>;
fn div(self, rhs: T) -> Self::Output {
Self::Output {
x: self.x / rhs,
y: self.y / rhs,
}
}
}
impl<T> DivAssign<T> for Vector2D<T>
where
T: Div<T, Output = T> + Copy + Clone,
{
fn div_assign(&mut self, rhs: T) {
self.x = self.x / rhs;
self.y = self.y / rhs;
}
}