use super::*;
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct vec2<T>(pub T, pub T);
impl<T: std::fmt::Display> std::fmt::Display for vec2<T> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "({}, {})", self.0, self.1)
}
}
impl<T> From<[T; 2]> for vec2<T> {
fn from(v: [T; 2]) -> vec2<T> {
let [x, y] = v;
vec2(x, y)
}
}
pub struct XY<T> {
#[allow(missing_docs)]
pub x: T,
#[allow(missing_docs)]
pub y: T,
}
impl<T> Deref for XY<T> {
type Target = [T; 2];
fn deref(&self) -> &[T; 2] {
unsafe { std::mem::transmute(self) }
}
}
impl<T> DerefMut for XY<T> {
fn deref_mut(&mut self) -> &mut [T; 2] {
unsafe { std::mem::transmute(self) }
}
}
impl<T> Deref for vec2<T> {
type Target = XY<T>;
fn deref(&self) -> &XY<T> {
unsafe { std::mem::transmute(self) }
}
}
impl<T> DerefMut for vec2<T> {
fn deref_mut(&mut self) -> &mut XY<T> {
unsafe { std::mem::transmute(self) }
}
}
impl<T> vec2<T> {
pub fn extend(self, z: T) -> vec3<T> {
vec3(self.0, self.1, z)
}
pub fn map<U, F: Fn(T) -> U>(self, f: F) -> vec2<U> {
vec2(f(self.0), f(self.1))
}
pub fn zip<U>(self, v: vec2<U>) -> vec2<(T, U)> {
vec2((self.0, v.0), (self.1, v.1))
}
}
impl<T: Clone> vec2<T> {
pub fn splat(value: T) -> Self {
Self(value.clone(), value)
}
}
impl<T: UNum> vec2<T> {
pub const ZERO: Self = vec2(T::ZERO, T::ZERO);
pub const UNIT_X: Self = Self(T::ONE, T::ZERO);
pub const UNIT_Y: Self = Self(T::ZERO, T::ONE);
}
impl<T: Num> vec2<T> {
pub fn dot(a: Self, b: Self) -> T {
a.x * b.x + a.y * b.y
}
pub fn skew(a: Self, b: Self) -> T {
a.x * b.y - a.y * b.x
}
}
impl<T: Neg<Output = T>> vec2<T> {
pub fn rotate_90(self) -> Self {
let vec2(x, y) = self;
vec2(-y, x)
}
}
impl<T: Float> vec2<T> {
pub fn normalize(self) -> Self {
self / self.len()
}
pub fn normalize_or_zero(self) -> Self {
let len = self.len();
if len.approx_eq(&T::ZERO) {
vec2::ZERO
} else {
self / len
}
}
pub fn len(self) -> T {
T::sqrt(self.len_sqr())
}
pub fn len_sqr(self) -> T {
vec2::dot(self, self)
}
pub fn rotate(self, angle: Angle<T>) -> Self {
let (sin, cos) = angle.sin_cos();
Self(self.x * cos - self.y * sin, self.x * sin + self.y * cos)
}
pub fn clamp_len(self, len_range: impl FixedRangeBounds<T>) -> Self {
let len = self.len();
let target_len = len.clamp_range(len_range);
if len == target_len {
self
} else {
self * target_len / len
}
}
pub fn clamp_coordinates(
self,
x_range: impl FixedRangeBounds<T>,
y_range: impl FixedRangeBounds<T>,
) -> Self {
vec2(self.x.clamp_range(x_range), self.y.clamp_range(y_range))
}
pub fn clamp_aabb(self, aabb: Aabb2<T>) -> Self {
let start = aabb.bottom_left();
let end = aabb.top_right();
self.clamp_coordinates(start.x..=end.x, start.y..=end.y)
}
pub fn arg(self) -> Angle<T> {
Angle::atan2(self.y, self.x)
}
pub fn transform(self, transform: mat3<T>) -> Self {
(transform * self.extend(T::ONE)).into_2d()
}
pub fn aspect(self) -> T {
self.x / self.y
}
}
#[test]
fn test_clamp_zero_len() {
vec2::ZERO.clamp_len(..=R64::ONE);
}