use point2i::Point2i;
use point2u::Point2u;
use vector2f::Vector2f;
use std::ops::{Add, Sub};
#[cfg(all(windows, feature = "d2d"))]
use winapi::um::dcommon::D2D_POINT_2F;
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
#[repr(C)]
pub struct Point2f {
pub x: f32,
pub y: f32,
}
pub const ORIGIN: Point2f = Point2f::ORIGIN;
impl Point2f {
pub const ORIGIN: Point2f = Point2f { x: 0.0, y: 0.0 };
#[inline]
pub fn new(x: f32, y: f32) -> Self {
Point2f { x, y }
}
#[inline]
pub fn to_i32(self) -> Point2i {
Point2i {
x: self.x as i32,
y: self.y as i32,
}
}
#[inline]
pub fn to_u32(self) -> Point2u {
Point2u {
x: self.x as u32,
y: self.y as u32,
}
}
#[inline]
pub fn rounded(self) -> Point2f {
Point2f {
x: self.x.round(),
y: self.y.round(),
}
}
#[inline]
pub fn is_approx_eq(self, other: impl Into<Point2f>, 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 Point2f
where
V: Into<Vector2f>,
{
type Output = Point2f;
#[inline]
fn add(self, rhs: V) -> Point2f {
let rhs = rhs.into();
Point2f {
x: self.x + rhs.x,
y: self.y + rhs.y,
}
}
}
impl Sub for Point2f {
type Output = Vector2f;
#[inline]
fn sub(self, rhs: Point2f) -> Vector2f {
Vector2f {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl Sub<(f32, f32)> for Point2f {
type Output = Vector2f;
#[inline]
fn sub(self, rhs: (f32, f32)) -> Vector2f {
Vector2f {
x: self.x - rhs.0,
y: self.y - rhs.1,
}
}
}
impl Sub<Point2f> for (f32, f32) {
type Output = Vector2f;
#[inline]
fn sub(self, rhs: Point2f) -> Vector2f {
Vector2f {
x: self.0 - rhs.x,
y: self.1 - rhs.y,
}
}
}
impl<V> Sub<V> for Point2f
where
V: Into<Vector2f>,
{
type Output = Point2f;
#[inline]
fn sub(self, rhs: V) -> Point2f {
let rhs = rhs.into();
Point2f {
x: self.x - rhs.x,
y: self.y - rhs.y,
}
}
}
impl From<(f32, f32)> for Point2f {
#[inline]
fn from((x, y): (f32, f32)) -> Point2f {
Point2f { x, y }
}
}
impl From<[f32; 2]> for Point2f {
#[inline]
fn from(p: [f32; 2]) -> Point2f {
Point2f { x: p[0], y: p[0] }
}
}
impl From<Point2f> for [f32; 2] {
#[inline]
fn from(p: Point2f) -> [f32; 2] {
[p.x, p.y]
}
}
#[cfg(all(windows, feature = "d2d"))]
impl From<Point2f> for D2D_POINT_2F {
#[inline]
fn from(point: Point2f) -> D2D_POINT_2F {
D2D_POINT_2F {
x: point.x,
y: point.y,
}
}
}
#[cfg(all(windows, feature = "d2d"))]
impl From<D2D_POINT_2F> for Point2f {
#[inline]
fn from(point: D2D_POINT_2F) -> Point2f {
Point2f {
x: point.x,
y: point.y,
}
}
}
#[cfg(feature = "mint")]
impl From<Point2f> for mint::Point2<f32> {
#[inline]
fn from(p: Point2f) -> mint::Point2<f32> {
mint::Point2 { x: p.x, y: p.y }
}
}
#[cfg(feature = "mint")]
impl From<mint::Point2<f32>> for Point2f {
#[inline]
fn from(p: mint::Point2<f32>) -> Point2f {
Point2f { x: p.x, y: p.y }
}
}
#[cfg(all(test, windows, feature = "d2d"))]
#[test]
fn pt2f_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 pt = Point2f::ORIGIN;
let d2d = unsafe { &*((&pt) as *const _ as *const D2D_POINT_2F) };
assert!(ptr_eq(&pt.x, &d2d.x));
assert!(ptr_eq(&pt.y, &d2d.y));
assert_eq!(size_of_val(&pt), size_of_val(d2d));
}