pub use crate::markers::{Local, Meters, Pixels, Screen, World};
use core::marker::PhantomData;
use crate::angle::{Degrees, Radians};
use crate::math;
#[cfg(feature = "unit_vec")]
use crate::unit_vec::UnitVec2;
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub struct Vec2<Unit: Copy = (), Space: Copy = ()> {
pub x: f32,
pub y: f32,
#[cfg_attr(feature = "serde", serde(skip))]
_unit: PhantomData<Unit>,
#[cfg_attr(feature = "serde", serde(skip))]
_space: PhantomData<Space>,
}
pub type Vec2f32 = Vec2<(),()>;
pub type Vec2Meters = Vec2<Meters,()>;
pub type Vec2Pixels = Vec2<Pixels,()>;
pub type Vec2World = Vec2<(),World>;
pub type Vec2Local = Vec2<(),Local>;
pub type Vec2Screen = Vec2<(),Screen>;
pub type Vec2MetersWorld = Vec2<Meters,World>;
pub type Vec2PixelsScreen = Vec2<Pixels,Screen>;
impl<Unit: Copy, Space: Copy> Vec2<Unit, Space> {
pub const ZERO: Self = Self { x: 0.0, y: 0.0, _unit: PhantomData, _space: PhantomData };
#[inline]
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y, _unit: PhantomData, _space: PhantomData }
}
#[inline]
pub const fn dot(self, other: Self) -> f32 {
self.x * other.x + self.y * other.y
}
#[inline]
pub const fn yx(self) -> Self {
Self { x: self.y, y: self.x, _unit: PhantomData, _space: PhantomData }
}
#[inline]
pub const fn cross(self, rhs: Self) -> f32 {
self.x * rhs.y - self.y * rhs.x
}
#[inline]
pub const fn length_squared(self) -> f32 {
self.dot(self)
}
#[inline]
pub fn length(self) -> f32 {
math::sqrt(self.length_squared())
}
#[inline]
pub fn normalize(self) -> Self {
let len_sq = self.length_squared();
if len_sq == 0.0 {
Self::ZERO
} else {
self / math::sqrt(len_sq)
}
}
#[inline]
pub fn try_normalize(self) -> Option<Self> {
let len_sq = self.length_squared();
if len_sq > 0.0 {
Some(self * (1.0 / math::sqrt(len_sq)))
} else {
None
}
}
#[inline]
pub fn checked_div_scalar(self, rhs: f32) -> Option<Self> {
if rhs == 0.0 || !rhs.is_finite() {
None
} else {
Some(self / rhs)
}
}
pub fn reflect(self, normal: Self) -> Self {
self - normal * (2.0 * self.dot(normal))
}
#[inline]
#[cfg(feature = "unit_vec")]
pub fn reflect_unit(self, normal: UnitVec2<Unit, Space>) -> Self {
self.reflect(normal.as_vec())
}
pub fn refract(self, normal: Self, eta: f32) -> Self {
let dot_ni = normal.dot(self);
let k = 1.0 - eta * eta * (1.0 - dot_ni * dot_ni);
if k < 0.0 {
Self::ZERO
} else {
self * eta - normal * (eta * dot_ni * math::sqrt(k))
}
}
pub fn try_refract(self, normal: Self, eta: f32) -> Option<Self> {
let dot_ni = normal.dot(self);
let k = 1.0 - eta * eta * (1.0 - dot_ni * dot_ni);
if k < 0.0 {
None
} else {
Some(self * eta - normal * (eta * dot_ni * math::sqrt(k)))
}
}
#[inline]
#[cfg(feature = "unit_vec")]
pub fn refract_unit(self, normal: UnitVec2<Unit, Space>, eta: f32) -> Self {
self.refract(normal.as_vec(), eta)
}
#[inline]
#[cfg(feature = "unit_vec")]
pub fn try_refract_unit(self, normal: UnitVec2<Unit, Space>, eta: f32) -> Option<Self> {
self.try_refract(normal.as_vec(), eta)
}
pub fn reflect_incident(i: Self, n: Self) -> Self {
i - n * (2.0 * i.dot(n))
}
pub fn refract_gl(i: Self, n: Self, eta: f32) -> Self {
let dot_ni = i.dot(n);
let k = 1.0 - eta * eta * (1.0 - dot_ni * dot_ni);
if k < 0.0 {
Self::ZERO
} else {
i * eta - n * (eta * dot_ni + math::sqrt(k))
}
}
pub fn try_refract_gl(i: Self, n: Self, eta: f32) -> Option<Self> {
let dot_ni = i.dot(n);
let k = 1.0 - eta * eta * (1.0 - dot_ni * dot_ni);
if k < 0.0 {
None
} else {
Some(i * eta - n * (eta * dot_ni + math::sqrt(k)))
}
}
#[inline]
pub fn refract_incident(i: Self, n: Self, eta: f32) -> Self {
Self::refract_gl(i, n, eta)
}
#[inline]
pub fn try_refract_incident(i: Self, n: Self, eta: f32) -> Option<Self> {
Self::try_refract_gl(i, n, eta)
}
pub fn aspect_ratio(self) -> f32 {
if self.y.abs() < 0.0001 {
0.0
} else {
self.x / self.y
}
}
pub fn lerp(self, other: Self, t: f32) -> Self {
Self {
x: self.x + (other.x - self.x) * t,
y: self.y + (other.y - self.y) * t,
_unit: PhantomData,
_space: PhantomData,
}
}
pub fn angle_between(self, other: Self) -> f32 {
let dot = self.dot(other);
let len_product = self.length() * other.length();
if len_product == 0.0 {
0.0
} else {
math::acos((dot / len_product).clamp(-1.0, 1.0))
}
}
pub fn project_onto(self, other: Self) -> Self {
let other_len_sq = other.length_squared();
if other_len_sq == 0.0 {
Self::ZERO
} else {
other * (self.dot(other) / other_len_sq)
}
}
pub fn perp(self) -> Self {
Self {
x: -self.y,
y: self.x,
_unit: PhantomData,
_space: PhantomData,
}
}
pub fn normalize_or_zero(self) -> Self {
let len = self.length();
if len == 0.0 { Self::ZERO } else { self / len }
}
pub fn distance(self, other: Self) -> f32 {
(self - other).length()
}
pub fn clamp(self, min: Self, max: Self) -> Self {
Self {
x: self.x.max(min.x).min(max.x),
y: self.y.max(min.y).min(max.y),
_unit: PhantomData,
_space: PhantomData,
}
}
pub const fn min(self, other: Self) -> Self {
Self {
x: self.x.min(other.x),
y: self.y.min(other.y),
_unit: PhantomData,
_space: PhantomData,
}
}
pub const fn max(self, other: Self) -> Self {
Self {
x: self.x.max(other.x),
y: self.y.max(other.y),
_unit: PhantomData,
_space: PhantomData,
}
}
pub fn is_nan(self) -> bool {
self.x.is_nan() || self.y.is_nan()
}
pub fn is_finite(self) -> bool {
self.x.is_finite() && self.y.is_finite()
}
pub const fn from_array(e: [f32; 2]) -> Self {
Self { x: e[0], y: e[1], _unit: PhantomData, _space: PhantomData }
}
pub fn rotate(self, angle: Radians) -> Self {
let (sin, cos) = math::sin_cos(angle.0);
Self {
x: self.x * cos - self.y * sin,
y: self.x * sin + self.y * cos,
_unit: core::marker::PhantomData,
_space: core::marker::PhantomData,
}
}
pub fn rotate_deg(self, angle: Degrees) -> Self {
self.rotate(angle.to_radians())
}
}
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
impl<Unit: Copy, Space: Copy> Add for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> AddAssign for Vec2<Unit, Space> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl<Unit: Copy, Space: Copy> Sub for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> SubAssign for Vec2<Unit, Space> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl<Unit: Copy, Space: Copy> Mul<f32> for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn mul(self, rhs: f32) -> Self::Output {
Self {
x: self.x * rhs,
y: self.y * rhs,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> Mul<Vec2<Unit, Space>> for f32 {
type Output = Vec2<Unit, Space>;
#[inline]
fn mul(self, rhs: Vec2<Unit, Space>) -> Self::Output {
Vec2 {
x: self * rhs.x,
y: self * rhs.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> MulAssign<f32> for Vec2<Unit, Space> {
#[inline]
fn mul_assign(&mut self, rhs: f32) {
self.x *= rhs;
self.y *= rhs;
}
}
impl<Unit: Copy, Space: Copy> Mul<Vec2<Unit, Space>> for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self::Output {
Self {
x: self.x * rhs.x,
y: self.y * rhs.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> MulAssign<Vec2<Unit, Space>> for Vec2<Unit, Space> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
self.x *= rhs.x;
self.y *= rhs.y;
}
}
impl<Unit: Copy, Space: Copy> Div<f32> for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn div(self, rhs: f32) -> Self::Output {
Self {
x: self.x / rhs,
y: self.y / rhs,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> DivAssign<f32> for Vec2<Unit, Space> {
#[inline]
fn div_assign(&mut self, rhs: f32) {
self.x /= rhs;
self.y /= rhs;
}
}
impl<Unit: Copy, Space: Copy> Div<Vec2<Unit, Space>> for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self::Output {
Self {
x: self.x / rhs.x,
y: self.y / rhs.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Unit: Copy, Space: Copy> DivAssign<Vec2<Unit, Space>> for Vec2<Unit, Space> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
self.x /= rhs.x;
self.y /= rhs.y;
}
}
impl<Unit: Copy, Space: Copy> Neg for Vec2<Unit, Space> {
type Output = Self;
#[inline]
fn neg(self) -> Self::Output {
Self {
x: -self.x,
y: -self.y,
_unit: PhantomData,
_space: PhantomData,
}
}
}
impl<Space: Copy> Vec2<Meters, Space> {
pub fn to_pixels(self, scale: f32) -> Vec2<Pixels, Space> {
Vec2 { x: self.x * scale, y: self.y * scale, _unit: PhantomData, _space: PhantomData }
}
}
impl<Space: Copy> Vec2<Pixels, Space> {
pub fn to_meters(self, scale: f32) -> Vec2<Meters, Space> {
Vec2 { x: self.x / scale, y: self.y / scale, _unit: PhantomData, _space: PhantomData }
}
}