use std::{
cmp::Ordering,
fmt::Display,
ops::{
Add, AddAssign, Bound, Div, DivAssign, Index, IndexMut, Mul,
MulAssign, Neg, Range, RangeBounds, Rem, RemAssign, Sub, SubAssign,
},
};
use crate::{
Checked, Float, Goniometric, IntoFloat, Isqrt, LargeType, MapExt,
NormalLimits, Scale, Sqrt, Vec2RangeIter, Zero,
};
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
pub struct Vec2<T = usize> {
pub x: T,
pub y: T,
}
impl<T> Vec2<T> {
pub const fn new(x: T, y: T) -> Self {
Self { x, y }
}
pub fn w(&self) -> &T {
&self.x
}
pub fn h(&self) -> &T {
&self.y
}
pub fn w_mut(&mut self) -> &mut T {
&mut self.x
}
pub fn h_mut(&mut self) -> &mut T {
&mut self.y
}
pub fn set_w(&mut self, w: T) {
self.x = w;
}
pub fn set_h(&mut self, h: T) {
self.y = h;
}
pub fn sq_len(&self) -> <T::Output as Add>::Output
where
T: Copy + Mul<T>,
T::Output: Add<T::Output>,
{
self.dot(*self)
}
pub fn len(&self) -> <<T::Output as Add>::Output as Sqrt>::Output
where
T: Copy + Mul<T>,
T::Output: Add<T::Output>,
<T::Output as Add>::Output: Sqrt,
{
self.sq_len().sqrt()
}
pub fn ilen(&self) -> <T::Output as Add>::Output
where
T: Copy + Mul<T>,
T::Output: Add<T::Output>,
<T::Output as Add>::Output: Isqrt,
{
self.sq_len().isqrt()
}
pub fn dot<Right>(
self,
other: impl Into<Vec2<Right>>,
) -> <T::Output as Add>::Output
where
T: Mul<Right>,
T::Output: Add,
{
let o = other.into();
self.x * o.x + self.y * o.y
}
pub fn checked_add(self, other: impl Into<Vec2<T>>) -> Option<Vec2<T>>
where
T: Checked,
{
let o = other.into();
Some(Self::new(
self.x.checked_add(o.x)?,
self.y.checked_add(o.y)?,
))
}
pub fn checked_sub(self, other: impl Into<Vec2<T>>) -> Option<Vec2<T>>
where
T: Checked,
{
let o = other.into();
Some(Self::new(
self.x.checked_sub(o.x)?,
self.y.checked_sub(o.y)?,
))
}
pub fn checked_cmul(self, other: impl Into<Vec2<T>>) -> Option<Vec2<T>>
where
T: Checked,
{
let o = other.into();
Some(Self::new(
self.x.checked_mul(o.x)?,
self.y.checked_mul(o.y)?,
))
}
pub fn sum(self) -> T::Output
where
T: Add,
{
self.x + self.y
}
pub fn diff(self) -> T::Output
where
T: Sub,
{
self.x - self.y
}
pub fn abs_diff(self) -> T::Output
where
T: Sub + Ord,
{
if self.x < self.y {
self.y - self.x
} else {
self.x - self.y
}
}
pub fn prod(self) -> T::Output
where
T: Mul,
{
self.x * self.y
}
pub fn quot(self) -> T::Output
where
T: Div,
{
self.x / self.y
}
pub fn quot_rem(self) -> T::Output
where
T: Rem,
{
self.x % self.y
}
pub fn same(&self) -> bool
where
T: PartialEq,
{
self.x == self.y
}
pub fn different(&self) -> bool
where
T: PartialEq,
{
self.x != self.y
}
pub fn max_idx(&self) -> usize
where
T: Ord,
{
if self.y > self.x { 1 } else { 0 }
}
pub fn max(&self) -> &T
where
T: Ord,
{
if self.y > self.x { &self.y } else { &self.x }
}
pub fn max_mut(&mut self) -> &mut T
where
T: Ord,
{
if self.y > self.x {
&mut self.y
} else {
&mut self.x
}
}
pub fn min_idx(&self) -> usize
where
T: Ord,
{
if self.y < self.x { 1 } else { 0 }
}
pub fn min(&self) -> &T
where
T: Ord,
{
if self.y < self.x { &self.y } else { &self.x }
}
pub fn min_mut(&mut self) -> &mut T
where
T: Ord,
{
if self.y < self.x {
&mut self.y
} else {
&mut self.x
}
}
pub fn as_ref(&self) -> Vec2<&T> {
(&self.x, &self.y).into()
}
pub fn as_mut(&mut self) -> Vec2<&mut T> {
(&mut self.x, &mut self.y).into()
}
pub fn are_both(&self, mut f: impl FnMut(&T) -> bool) -> bool {
f(&self.x) && f(&self.y)
}
pub fn is_any(&self, mut f: impl FnMut(&T) -> bool) -> bool {
f(&self.x) || f(&self.y)
}
pub fn is_one(&self, f: impl FnMut(&T) -> bool) -> bool {
self.as_ref().map(f).one()
}
pub fn is_none(&self, f: impl FnMut(&T) -> bool) -> bool {
!self.is_any(f)
}
pub fn iter(&self) -> std::array::IntoIter<&T, 2> {
let r: [_; 2] = self.as_ref().into();
r.into_iter()
}
pub fn iter_mut(&mut self) -> std::array::IntoIter<&mut T, 2> {
let r: [_; 2] = self.as_mut().into();
r.into_iter()
}
pub fn swap(&mut self) {
std::mem::swap(&mut self.x, &mut self.y);
}
pub fn swapped(self) -> Self {
(self.y, self.x).into()
}
pub fn yx(self) -> Self {
self.swapped()
}
pub fn xy(self) -> Self {
self
}
pub fn sort(&mut self)
where
T: PartialOrd,
{
if self.x > self.y {
self.swap();
}
}
pub fn sorted(mut self) -> Self
where
T: PartialOrd,
{
self.sort();
self
}
pub fn clamp<'a>(&'a self, v: &'a T) -> &'a T
where
T: Ord,
{
let s = self.as_ref().sorted();
if v < s.x {
s.x
} else if v > s.y {
s.y
} else {
v
}
}
pub fn clamped(mut self, v: T) -> T
where
T: Ord,
{
self.sort();
if v < self.x {
self.x
} else if v > self.y {
self.y
} else {
v
}
}
pub fn pos_of_idx<I, R>(self, i: I) -> Vec2<R>
where
T: Copy,
I: Copy + Rem<T, Output = R> + Div<T, Output = R>,
{
(i % self.y, i / self.y).into()
}
pub fn idx_of_pos<R>(
self,
pos: impl Into<Vec2<R>>,
) -> <T::Output as Add<R>>::Output
where
T: Mul<R>,
T::Output: Add<R>,
{
let pos = pos.into();
self.x * pos.y + pos.x
}
pub fn angle(self) -> T::Output
where
T: Goniometric,
{
T::atan2(self.y, self.x)
}
pub fn polar(
self,
) -> (
<<<T as Mul>::Output as Add>::Output as Sqrt>::Output,
<T as Goniometric>::Output,
)
where
T: Copy + Mul + Goniometric,
<T as Mul>::Output: Add,
<<T as Mul>::Output as Add>::Output: Sqrt,
{
(self.len(), self.angle())
}
#[allow(clippy::type_complexity)]
pub fn normalized(
self,
) -> Vec2<
<T::Float as Div<
<<<T::Float as Mul>::Output as Add>::Output as Sqrt>::Output,
>>::Output,
>
where
T: IntoFloat,
T::Float: Copy + Mul,
<T::Float as Mul>::Output: Add<<T::Float as Mul>::Output>,
<<T::Float as Mul>::Output as Add>::Output: Sqrt,
<<<T::Float as Mul>::Output as Add>::Output as Sqrt>::Output: Copy,
T::Float:
Div<<<<T::Float as Mul>::Output as Add>::Output as Sqrt>::Output>,
{
let v = self.map(|a| a.into_float());
let len = v.len();
(v.x / len, v.y / len).into()
}
pub fn normalize(&mut self)
where
T: Copy + Float + Mul,
T::Output: Add<T::Output>,
<T::Output as Add>::Output: Sqrt,
<<T::Output as Add>::Output as Sqrt>::Output: Copy,
T: DivAssign<<<T::Output as Add>::Output as Sqrt>::Output>,
{
*self /= self.len();
}
pub fn to(self, other: impl Into<Vec2<T>>) -> Vec2RangeIter<T>
where
T: Copy,
{
Vec2RangeIter::new(self, other.into())
}
pub fn from_polar<L, A>(length: L, angle: A) -> Self
where
A: Copy + Float + Goniometric,
A::Output: Mul<L, Output = T>,
L: Copy,
{
Vec2::new(angle.cos(), angle.sin()) * length
}
pub fn size_contains(&self, pos: impl Into<Vec2<T>>) -> bool
where
T: PartialOrd + Zero,
{
let pos = pos.into();
pos.are_both(|a| *a >= T::ZERO) && pos.x < self.x && pos.y < self.y
}
pub fn scale<S>(self) -> Vec2<S>
where
T: Scale<S>,
{
(self.x.scale(), self.y.scale()).into()
}
pub fn change_range(self, ss: T, se: T, ds: T, de: T) -> Vec2<T>
where
T: LargeType + Copy + Sub<Output = T>,
T::Large: Add<Output = T::Large>
+ Sub<Output = T::Large>
+ Mul<Output = T::Large>
+ Div<Output = T::Large>,
{
self.map(|a| {
T::from_large(
(a.to_large() - ss.to_large()) * (de - ds).to_large()
/ (se - ss).to_large()
+ ds.to_large(),
)
})
}
pub fn norm_to_range(self, s: T, e: T) -> Vec2<T>
where
T: LargeType + Copy + NormalLimits + Sub<Output = T>,
T::Large: Add<Output = T::Large>
+ Sub<Output = T::Large>
+ Mul<Output = T::Large>
+ Div<Output = T::Large>,
{
self.change_range(T::NORM_MIN, T::NORM_MAX, s, e)
}
pub fn to_norm_range(self, s: T, e: T) -> Vec2<T>
where
T: LargeType + Copy + NormalLimits + Sub<Output = T>,
T::Large: Add<Output = T::Large>
+ Sub<Output = T::Large>
+ Mul<Output = T::Large>
+ Div<Output = T::Large>,
{
self.change_range(s, e, T::NORM_MIN, T::NORM_MAX)
}
pub fn cabs(self) -> Vec2<T>
where
T: PartialOrd + Zero + Neg<Output = T>,
{
self.map(|a| if a < T::ZERO { -a } else { a })
}
pub fn range(self) -> Range<T> {
self.into()
}
pub fn combine(
self,
other: impl Into<Vec2<T>>,
selector: impl Into<Vec2<bool>>,
) -> Self {
let s = selector.into();
let o = other.into();
Vec2::new(
if s.x { o.x } else { self.x },
if s.y { o.y } else { self.y },
)
}
}
impl Vec2<bool> {
pub fn both(self) -> bool {
self.x & self.y
}
pub fn any(self) -> bool {
self.x | self.y
}
pub fn one(self) -> bool {
self.different()
}
pub fn none(self) -> bool {
!self.any()
}
}
impl<T> Vec2<&T> {
pub fn cloned(self) -> Vec2<T>
where
T: Clone,
{
(self.x.clone(), self.y.clone()).into()
}
pub fn copied(self) -> Vec2<T>
where
T: Copy,
{
(*self.x, *self.y).into()
}
}
impl<T: Zero> Vec2<T> {
pub const ZERO: Vec2<T> = Vec2 {
x: T::ZERO,
y: T::ZERO,
};
}
impl<T> From<(T, T)> for Vec2<T> {
fn from((x, y): (T, T)) -> Self {
Self { x, y }
}
}
impl<T> From<[T; 2]> for Vec2<T> {
fn from([x, y]: [T; 2]) -> Self {
Self { x, y }
}
}
impl<T> From<Range<T>> for Vec2<T> {
fn from(value: Range<T>) -> Self {
Self {
x: value.start,
y: value.end,
}
}
}
impl<T> From<Vec2<T>> for (T, T) {
fn from(value: Vec2<T>) -> Self {
(value.x, value.y)
}
}
impl<T> From<Vec2<T>> for [T; 2] {
fn from(value: Vec2<T>) -> Self {
[value.x, value.y]
}
}
impl<T> From<Vec2<T>> for Range<T> {
fn from(value: Vec2<T>) -> Self {
value.x..value.y
}
}
impl<T> RangeBounds<T> for Vec2<T> {
fn start_bound(&self) -> Bound<&T> {
Bound::Included(&self.x)
}
fn end_bound(&self) -> Bound<&T> {
Bound::Excluded(&self.y)
}
}
impl<T> Index<usize> for Vec2<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
match index {
0 => &self.x,
1 => &self.y,
_ => panic!("Index `{index}` is out of bounds for Vec2."),
}
}
}
impl<T> IndexMut<usize> for Vec2<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
match index {
0 => &mut self.x,
1 => &mut self.y,
_ => panic!("Index `{index}` is out of bounds for Vec2."),
}
}
}
impl<Left, Right> PartialEq<(Right, Right)> for Vec2<Left>
where
Left: PartialEq<Right>,
{
fn eq(&self, (x, y): &(Right, Right)) -> bool {
self.x == *x && self.y == *y
}
}
impl<Left, Right> PartialEq<[Right; 2]> for Vec2<Left>
where
Left: PartialEq<Right>,
{
fn eq(&self, [x, y]: &[Right; 2]) -> bool {
self.x == *x && self.y == *y
}
}
impl<T> Display for Vec2<T>
where
T: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}, {}]", self.x, self.y)
}
}
impl<T> IntoIterator for Vec2<T> {
type Item = T;
type IntoIter = std::array::IntoIter<T, 2>;
fn into_iter(self) -> Self::IntoIter {
let r: [_; 2] = self.into();
r.into_iter()
}
}
impl<'a, T> IntoIterator for &'a Vec2<T> {
type Item = &'a T;
type IntoIter = std::array::IntoIter<&'a T, 2>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T> IntoIterator for &'a mut Vec2<T> {
type Item = &'a mut T;
type IntoIter = std::array::IntoIter<&'a mut T, 2>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T> Neg for Vec2<T>
where
T: Neg,
{
type Output = Vec2<T::Output>;
fn neg(self) -> Self::Output {
(-self.x, -self.y).into()
}
}
impl<T: PartialOrd> PartialOrd for Vec2<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self.x.partial_cmp(&other.x)?, self.y.partial_cmp(&other.y)?) {
(Ordering::Equal, Ordering::Equal) => Some(Ordering::Equal),
(
Ordering::Less | Ordering::Equal,
Ordering::Less | Ordering::Equal,
) => Some(Ordering::Less),
(
Ordering::Greater | Ordering::Equal,
Ordering::Greater | Ordering::Equal,
) => Some(Ordering::Greater),
_ => None,
}
}
}
impl<T> AsRef<Vec2<T>> for Vec2<T> {
fn as_ref(&self) -> &Vec2<T> {
self
}
}
macro_rules! op_single {
($op:ident, $fn:ident) => {
impl<Left, Right> $op<Right> for Vec2<Left>
where
Left: $op<Right>,
Right: Copy,
{
type Output = Vec2<Left::Output>;
fn $fn(self, rhs: Right) -> Self::Output {
(self.x.$fn(rhs), self.y.$fn(rhs)).into()
}
}
};
}
macro_rules! op_assign_single {
($op:ident, $fn:ident) => {
impl<Left, Right> $op<Right> for Vec2<Left>
where
Left: $op<Right>,
Right: Copy,
{
fn $fn(&mut self, rhs: Right) {
self.x.$fn(rhs);
self.y.$fn(rhs);
}
}
};
}
macro_rules! op_double {
($op:ident, $fn:ident) => {
impl<Left, Right> $op<Vec2<Right>> for Vec2<Left>
where
Left: $op<Right>,
{
type Output = Vec2<Left::Output>;
fn $fn(self, rhs: Vec2<Right>) -> Self::Output {
(self.x.$fn(rhs.x), self.y.$fn(rhs.y)).into()
}
}
impl<Left, Right> $op<(Right, Right)> for Vec2<Left>
where
Left: $op<Right>,
{
type Output = Vec2<Left::Output>;
fn $fn(self, (x, y): (Right, Right)) -> Self::Output {
(self.x.$fn(x), self.y.$fn(y)).into()
}
}
impl<Left, Right> $op<[Right; 2]> for Vec2<Left>
where
Left: $op<Right>,
{
type Output = Vec2<Left::Output>;
fn $fn(self, [x, y]: [Right; 2]) -> Self::Output {
(self.x.$fn(x), self.y.$fn(y)).into()
}
}
impl<Left, Right> $op<Range<Right>> for Vec2<Left>
where
Left: $op<Right>,
{
type Output = Vec2<Left::Output>;
fn $fn(self, rhs: Range<Right>) -> Self::Output {
(self.x.$fn(rhs.start), self.y.$fn(rhs.end)).into()
}
}
};
}
macro_rules! op_assign_double {
($op:ident, $fn:ident) => {
impl<Left, Right> $op<Vec2<Right>> for Vec2<Left>
where
Left: $op<Right>,
{
fn $fn(&mut self, rhs: Vec2<Right>) {
self.x.$fn(rhs.x);
self.y.$fn(rhs.y);
}
}
impl<Left, Right> $op<(Right, Right)> for Vec2<Left>
where
Left: $op<Right>,
{
fn $fn(&mut self, (x, y): (Right, Right)) {
self.x.$fn(x);
self.y.$fn(y);
}
}
impl<Left, Right> $op<[Right; 2]> for Vec2<Left>
where
Left: $op<Right>,
{
fn $fn(&mut self, [x, y]: [Right; 2]) {
self.x.$fn(x);
self.y.$fn(y);
}
}
};
}
op_single!(Mul, mul);
op_assign_single!(MulAssign, mul_assign);
op_single!(Div, div);
op_assign_single!(DivAssign, div_assign);
op_single!(Rem, rem);
op_assign_single!(RemAssign, rem_assign);
op_double!(Add, add);
op_assign_double!(AddAssign, add_assign);
op_double!(Sub, sub);
op_assign_double!(SubAssign, sub_assign);