use crate::point2f::Point2f;
use crate::sizef::Sizef;
use crate::vector2i::Vector2i;
use std::ops::{Add, Div, Mul, Neg, Sub};
#[cfg(all(windows, feature = "d2d"))]
use winapi::um::dcommon::D2D_VECTOR_2F;
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct Vector2f {
pub x: f32,
pub y: f32,
}
pub const ZERO: Vector2f = Vector2f::ZERO;
pub const ONE: Vector2f = Vector2f::ONE;
impl Vector2f {
pub const ZERO: Vector2f = Vector2f { x: 0.0, y: 0.0 };
pub const ONE: Vector2f = Vector2f { x: 1.0, y: 1.0 };
pub const UP: Vector2f = Vector2f { x: 0.0, y: -1.0 };
pub const RIGHT: Vector2f = Vector2f { x: 1.0, y: 0.0 };
pub const DOWN: Vector2f = Vector2f { x: 0.0, y: 1.0 };
pub const LEFT: Vector2f = Vector2f { x: -1.0, y: 0.0 };
#[inline]
pub fn new(x: f32, y: f32) -> Self {
Vector2f { x, y }
}
#[inline]
pub fn to_i32(self) -> Vector2i {
Vector2i {
x: self.x as i32,
y: self.y as i32,
}
}
#[inline]
pub fn to_point(self) -> Point2f {
Point2f::ORIGIN + self
}
#[inline]
pub fn to_size(self) -> Sizef {
Sizef {
width: self.x,
height: self.y,
}
}
#[inline]
pub fn rounded(self) -> Vector2f {
Vector2f {
x: self.x.round(),
y: self.y.round(),
}
}
#[inline]
pub fn dot(self, rhs: Vector2f) -> f32 {
self.x * rhs.x + self.y * rhs.y
}
#[inline]
pub fn len_squared(self) -> f32 {
self.dot(self)
}
#[inline]
pub fn len(self) -> f32 {
self.len_squared().sqrt()
}
#[inline]
pub fn abs(self) -> Self {
Vector2f {
x: self.x.abs(),
y: self.y.abs(),
}
}
#[inline]
pub fn reciprocal(self) -> Self {
Vector2f {
x: 1.0 / self.x,
y: 1.0 / self.y,
}
}
#[inline]
pub fn is_approx_eq(self, other: impl Into<Vector2f>, epsilon: f32) -> bool {
let other = other.into();
return (self.x - other.x).abs() <= epsilon && (self.y - other.y).abs() <= epsilon;
}
}
impl<V> Add<V> for Vector2f
where
V: Into<Vector2f>,
{
type Output = Vector2f;
#[inline]
fn add(self, rhs: V) -> Vector2f {
let rhs = rhs.into();
Vector2f {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl<V> Sub<V> for Vector2f
where
V: Into<Vector2f>,
{
type Output = Vector2f;
#[inline]
fn sub(self, rhs: V) -> Vector2f {
let rhs = rhs.into();
Vector2f {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl Neg for Vector2f {
type Output = Vector2f;
#[inline]
fn neg(self) -> Vector2f {
Vector2f {
x: -self.x,
y: -self.y,
}
}
}
impl<V> Mul<V> for Vector2f
where
V: Into<Vector2f>,
{
type Output = Vector2f;
#[inline]
fn mul(self, rhs: V) -> Self {
let rhs = rhs.into();
Vector2f {
x: self.x * rhs.x,
y: self.y * rhs.y,
}
}
}
impl Mul<Vector2f> for f32 {
type Output = Vector2f;
#[inline]
fn mul(self, rhs: Vector2f) -> Vector2f {
Vector2f {
x: self * rhs.x,
y: self * rhs.y,
}
}
}
impl<V> Div<V> for Vector2f
where
V: Into<Vector2f>,
{
type Output = Vector2f;
#[inline]
fn div(self, rhs: V) -> Vector2f {
self * rhs.into().reciprocal()
}
}
impl Div<Vector2f> for f32 {
type Output = Vector2f;
#[inline]
fn div(self, rhs: Vector2f) -> Vector2f {
self * rhs.reciprocal()
}
}
impl From<f32> for Vector2f {
#[inline]
fn from(s: f32) -> Vector2f {
Vector2f::new(s, s)
}
}
impl From<[f32; 2]> for Vector2f {
#[inline]
fn from(v: [f32; 2]) -> Vector2f {
Vector2f::new(v[0], v[1])
}
}
impl From<Vector2f> for [f32; 2] {
#[inline]
fn from(v: Vector2f) -> [f32; 2] {
[v.x, v.y]
}
}
#[cfg(all(windows, feature = "d2d"))]
impl From<Vector2f> for D2D_VECTOR_2F {
#[inline]
fn from(vec: Vector2f) -> D2D_VECTOR_2F {
D2D_VECTOR_2F { x: vec.x, y: vec.y }
}
}
#[cfg(all(windows, feature = "d2d"))]
impl From<D2D_VECTOR_2F> for Vector2f {
#[inline]
fn from(vec: D2D_VECTOR_2F) -> Vector2f {
Vector2f { x: vec.x, y: vec.y }
}
}
#[cfg(feature = "mint")]
impl From<Vector2f> for mint::Vector2<f32> {
#[inline]
fn from(p: Vector2f) -> mint::Vector2<f32> {
mint::Vector2 { x: p.x, y: p.y }
}
}
#[cfg(feature = "mint")]
impl From<mint::Vector2<f32>> for Vector2f {
#[inline]
fn from(p: mint::Vector2<f32>) -> Vector2f {
Vector2f { x: p.x, y: p.y }
}
}
#[cfg(feature = "kurbo")]
impl From<kurbo::Vec2> for Vector2f {
#[inline]
fn from(p: kurbo::Vec2) -> Vector2f {
Vector2f {
x: p.x as f32,
y: p.y as f32,
}
}
}
#[cfg(all(test, windows, feature = "d2d"))]
#[test]
fn vec2f_d2d_bin_compat() {
use std::mem::size_of_val;
fn ptr_eq<T>(a: &T, b: &T) -> bool {
(a as *const T) == (b as *const T)
}
let vec = Vector2f::ZERO;
let d2d = unsafe { &*((&vec) as *const _ as *const D2D_VECTOR_2F) };
assert!(ptr_eq(&vec.x, &d2d.x));
assert!(ptr_eq(&vec.y, &d2d.y));
assert_eq!(size_of_val(&vec), size_of_val(d2d));
}