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::{HasTransformedView, TransformMut, Transformation, TranslateMut};
#[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 TranslateMut for Point {
fn translate_mut(&mut self, p: Point) {
self.x += p.x;
self.y += p.y;
}
}
impl TransformMut for Point {
fn transform_mut(&mut self, trans: Transformation) {
let xf = self.x as f64;
let yf = self.y as f64;
let x = trans.a[0][0] * xf + trans.a[0][1] * yf + trans.b[0];
let y = trans.a[1][0] * xf + trans.a[1][1] * yf + trans.b[1];
self.x = x.round() as i64;
self.y = y.round() as i64;
}
}
impl HasTransformedView for Point {
type TransformedView = Point;
fn transformed_view(&self, trans: Transformation) -> Self::TransformedView {
self.transform(trans)
}
}
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 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())
}
}