use core::ops;
use serde::{Deserialize, Serialize};
use crate::util::{fuzzy_compare, fuzzy_is_zero};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct Point {
x: i32,
y: i32,
}
impl Point {
#[must_use]
pub const fn new() -> Self {
Self::from(0, 0)
}
#[must_use]
pub const fn from(x: i32, y: i32) -> Self {
Self { x, y }
}
pub fn set_x(&mut self, x: i32) {
self.x = x;
}
#[must_use]
pub const fn x(&self) -> i32 {
self.x
}
pub fn x_mut(&mut self) -> &mut i32 {
&mut self.x
}
pub fn set_y(&mut self, y: i32) {
self.y = y;
}
#[must_use]
pub const fn y(&self) -> i32 {
self.y
}
pub fn y_mut(&mut self) -> &mut i32 {
&mut self.y
}
pub fn set(&mut self, x: i32, y: i32) {
self.x = x;
self.y = y;
}
#[must_use]
pub const fn dot_product(&self, other: Self) -> i32 {
self.x * other.x + self.y * other.y
}
#[must_use]
pub const fn is_null(&self) -> bool {
self.x == 0 && self.y == 0
}
#[must_use]
pub const fn manhattan_length(&self) -> i32 {
self.x.abs() + self.y.abs()
}
#[must_use]
pub const fn transposed(&self) -> Self {
Self {
x: self.y,
y: self.x,
}
}
}
impl ops::Add for Point {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl ops::Sub for Point {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl ops::AddAssign for Point {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
}
}
impl ops::SubAssign for Point {
fn sub_assign(&mut self, other: Self) {
self.x -= other.x;
self.y -= other.y;
}
}
impl ops::MulAssign<i32> for Point {
fn mul_assign(&mut self, factor: i32) {
self.x *= factor;
self.y *= factor;
}
}
impl ops::MulAssign<f32> for Point {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
fn mul_assign(&mut self, factor: f32) {
self.x = (self.x as f32 * factor).round() as i32;
self.y = (self.y as f32 * factor).round() as i32;
}
}
impl ops::MulAssign<f64> for Point {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
fn mul_assign(&mut self, factor: f64) {
self.x = (f64::from(self.x) * factor).round() as i32;
self.y = (f64::from(self.y) * factor).round() as i32;
}
}
impl ops::DivAssign<f64> for Point {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
fn div_assign(&mut self, factor: f64) {
assert!(factor != 0.0);
self.x = (f64::from(self.x) / factor).round() as i32;
self.y = (f64::from(self.y) / factor).round() as i32;
}
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
pub struct PointF {
x: f64,
y: f64,
}
impl PartialEq for PointF {
fn eq(&self, other: &Self) -> bool {
fuzzy_compare(self.x, other.x) && fuzzy_compare(self.y, other.y)
}
}
impl PointF {
#[must_use]
pub const fn new() -> Self {
Self::from(0.0, 0.0)
}
#[must_use]
pub const fn from(x: f64, y: f64) -> Self {
Self { x, y }
}
pub fn set_x(&mut self, x: f64) {
self.x = x;
}
#[must_use]
pub const fn x(&self) -> f64 {
self.x
}
pub fn x_mut(&mut self) -> &mut f64 {
&mut self.x
}
pub fn set_y(&mut self, y: f64) {
self.y = y;
}
#[must_use]
pub const fn y(&self) -> f64 {
self.y
}
pub fn y_mut(&mut self) -> &mut f64 {
&mut self.y
}
pub fn set(&mut self, x: f64, y: f64) {
self.x = x;
self.y = y;
}
#[must_use]
pub fn dot_product(&self, other: Self) -> f64 {
self.x.mul_add(other.x, self.y * other.y)
}
#[must_use]
pub fn is_null(&self) -> bool {
self.x == 0.0 && self.y == 0.0
}
#[must_use]
pub fn manhattan_length(&self) -> f64 {
self.x.abs() + self.y.abs()
}
#[must_use]
pub fn to_point(&self) -> Point {
#[allow(clippy::cast_possible_truncation)]
Point::from(self.x.round() as i32, self.y.round() as i32)
}
#[must_use]
pub const fn transposed(&self) -> Self {
Self {
x: self.y,
y: self.x,
}
}
}
impl ops::Add for PointF {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl ops::Sub for PointF {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
impl ops::AddAssign for PointF {
fn add_assign(&mut self, other: Self) {
self.x += other.x;
self.y += other.y;
}
}
impl ops::SubAssign for PointF {
fn sub_assign(&mut self, other: Self) {
self.x -= other.x;
self.y -= other.y;
}
}
impl ops::Mul<f64> for PointF {
type Output = Self;
fn mul(self, factor: f64) -> Self {
Self::from(self.x * factor, self.y * factor)
}
}
impl ops::MulAssign<f64> for PointF {
fn mul_assign(&mut self, factor: f64) {
self.x *= factor;
self.y *= factor;
}
}
impl ops::DivAssign<f64> for PointF {
fn div_assign(&mut self, factor: f64) {
assert!(!fuzzy_is_zero(factor));
self.x /= factor;
self.y /= factor;
}
}
impl ops::Div<f64> for PointF {
type Output = Self;
fn div(self, factor: f64) -> Self {
assert!(!fuzzy_is_zero(factor));
Self::from(self.x / factor, self.y / factor)
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "skia")] {
impl From<skia_safe::Point> for PointF {
fn from(p: skia_safe::Point) -> Self {
Self::from(f64::from(p.x), f64::from(p.y))
}
}
impl From<PointF> for skia_safe::Point {
fn from(p: PointF) -> Self {
Self::new(p.x() as f32, p.y() as f32)
}
}
}
}