use serde::{Deserialize, Serialize};
use std::ops::Mul;
use crate::dims::Dims;
use crate::dir::Dir;
use crate::prelude::Transform;
use crate::snap::snap_to_grid;
use crate::transform::{
TransformMut, TransformRef, Transformation, Translate, TranslateMut, TranslateRef,
};
#[derive(
Debug, Copy, Clone, Default, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord,
)]
pub struct Point {
pub x: i64,
pub y: i64,
}
impl Point {
pub const fn new(x: i64, y: i64) -> Self {
Self { x, y }
}
pub const fn from_dir_coords(dir: Dir, a: i64, b: i64) -> Self {
match dir {
Dir::Horiz => Self::new(a, b),
Dir::Vert => Self::new(b, a),
}
}
#[inline]
pub const fn zero() -> Self {
Self { x: 0, y: 0 }
}
pub const fn coord(&self, dir: Dir) -> i64 {
match dir {
Dir::Horiz => self.x,
Dir::Vert => self.y,
}
}
#[inline]
pub fn snap_to_grid(&self, grid: i64) -> Self {
self.snap_x_to_grid(grid).snap_y_to_grid(grid)
}
#[inline]
pub fn snap_x_to_grid(&self, grid: i64) -> Self {
let x = snap_to_grid(self.x, grid);
Self { x, y: self.y }
}
#[inline]
pub fn snap_y_to_grid(&self, grid: i64) -> Self {
let y = snap_to_grid(self.y, grid);
Self { x: self.x, y }
}
}
impl TranslateRef for Point {
fn translate_ref(&self, p: Point) -> Self {
self.translate(p)
}
}
impl TranslateMut for Point {
fn translate_mut(&mut self, p: Point) {
self.x += p.x;
self.y += p.y;
}
}
impl TransformRef for Point {
fn transform_ref(&self, trans: Transformation) -> Self {
self.transform(trans)
}
}
impl TransformMut for Point {
fn transform_mut(&mut self, trans: Transformation) {
*self = trans.mat * *self + trans.b;
}
}
impl std::ops::Add<Point> for Point {
type Output = Self;
fn add(self, rhs: Point) -> Self::Output {
Self::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl std::ops::Add<Dims> for Point {
type Output = Self;
fn add(self, rhs: Dims) -> Self::Output {
Self::new(self.x + rhs.width(), self.y + rhs.height())
}
}
impl std::ops::AddAssign<Point> for Point {
fn add_assign(&mut self, rhs: Point) {
self.x += rhs.x;
self.y += rhs.y;
}
}
impl std::ops::AddAssign<Dims> for Point {
fn add_assign(&mut self, rhs: Dims) {
self.x += rhs.width();
self.y += rhs.height();
}
}
impl std::ops::Sub<Point> for Point {
type Output = Self;
fn sub(self, rhs: Point) -> Self::Output {
Self::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl std::ops::SubAssign<Point> for Point {
fn sub_assign(&mut self, rhs: Point) {
self.x -= rhs.x;
self.y -= rhs.y;
}
}
impl std::ops::Neg for Point {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
x: -self.x,
y: -self.y,
}
}
}
impl From<(i64, i64)> for Point {
fn from(value: (i64, i64)) -> Self {
Self {
x: value.0,
y: value.1,
}
}
}
impl Mul<Point> for Point {
type Output = Self;
fn mul(self, rhs: Point) -> Self::Output {
Self::new(self.x * rhs.x, self.y * rhs.y)
}
}
impl Mul<Dims> for Point {
type Output = Self;
fn mul(self, rhs: Dims) -> Self::Output {
Self::new(self.x * rhs.w(), self.y * rhs.h())
}
}