use crate::traits::{BoundingBox, MapPointwise, TryBoundingBox, TryCastCoord};
use crate::vector::Vector;
use std::cmp::{Ord, Ordering};
use std::fmt;
use crate::prelude::{Orientation2D, Rect};
pub use num_traits::Zero;
use num_traits::{Float, NumCast};
pub use std::ops::Deref;
use std::ops::{Add, AddAssign, DerefMut, Div, Mul, MulAssign, Neg, Sub, SubAssign};
#[macro_export]
macro_rules! point {
($x:expr, $y:expr) => {
Point::new($x, $y)
};
}
#[derive(Copy, Clone, Default, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Point<T> {
location: Vector<T>,
}
impl<T> Deref for Point<T> {
type Target = Vector<T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.location
}
}
impl<T> DerefMut for Point<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.location
}
}
impl<T> From<Vector<T>> for Point<T> {
#[inline]
fn from(v: Vector<T>) -> Self {
Point { location: v }
}
}
impl<T: Copy> From<&Vector<T>> for Point<T> {
#[inline]
fn from(v: &Vector<T>) -> Self {
Self::from(*v)
}
}
impl<T> From<Point<T>> for Vector<T> {
#[inline]
fn from(p: Point<T>) -> Self {
p.location
}
}
impl<T: Copy> From<&Point<T>> for Vector<T> {
#[inline]
fn from(p: &Point<T>) -> Self {
p.location
}
}
impl<T> Point<T> {
#[inline]
pub fn new(x: T, y: T) -> Self {
Point {
location: Vector::new(x, y),
}
}
}
impl<T: Copy> Point<T> {
#[inline]
pub fn v(&self) -> Vector<T> {
self.location
}
#[inline]
pub fn get(&self, coord: Orientation2D) -> T {
match coord {
Orientation2D::Horizontal => self.x,
Orientation2D::Vertical => self.y,
}
}
#[inline]
pub fn set(&mut self, coord: Orientation2D, value: T) {
match coord {
Orientation2D::Horizontal => self.x = value,
Orientation2D::Vertical => self.y = value,
}
}
}
impl<T: Zero> Point<T> {
#[inline]
pub fn zero() -> Self {
Vector::zero().into()
}
#[inline]
pub fn is_zero(&self) -> bool {
self.x.is_zero() && self.y.is_zero()
}
}
impl<T: Copy + Mul<Output = T> + Add<Output = T> + Sub<Output = T>> Point<T> {
#[inline]
pub fn distance_sq(self, other: &Point<T>) -> T {
let diff = self - *other;
diff.norm2_squared()
}
#[inline]
pub fn cross_prod3(&self, b: Point<T>, c: Point<T>) -> T {
(b.x - self.x) * (c.y - b.y) - (b.y - self.y) * (c.x - b.x)
}
}
impl<T: Copy + Sub<Output = T> + NumCast> Point<T> {
#[inline]
pub fn distance<F: Float>(self, other: &Point<T>) -> F {
let diff = self - *other;
diff.length()
}
}
impl<T: PartialOrd> PartialOrd for Point<T> {
#[inline]
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
match self.x.partial_cmp(&rhs.x) {
Some(Ordering::Equal) => self.y.partial_cmp(&rhs.y),
maybe_ordering => maybe_ordering,
}
}
}
impl<T: Ord> Ord for Point<T> {
#[inline]
fn cmp(&self, rhs: &Self) -> Ordering {
match self.x.cmp(&rhs.x) {
Ordering::Equal => self.y.cmp(&rhs.y),
ordering => ordering,
}
}
}
impl<T: Copy> MapPointwise<T> for Point<T> {
#[inline]
fn transform<F>(&self, transformation: F) -> Self
where
F: Fn(Point<T>) -> Point<T>,
{
transformation(*self)
}
}
impl<T: Copy> From<Point<T>> for (T, T) {
#[inline]
fn from(p: Point<T>) -> Self {
(p.x, p.y)
}
}
impl<T: Copy> From<&Point<T>> for (T, T) {
#[inline]
fn from(p: &Point<T>) -> Self {
(p.x, p.y)
}
}
impl<T: Copy> From<(T, T)> for Point<T> {
#[inline]
fn from(coords: (T, T)) -> Self {
Point::new(coords.0, coords.1)
}
}
impl<'a, T: Copy> From<&'a (T, T)> for Point<T> {
#[inline]
fn from(coords: &'a (T, T)) -> Self {
Point::new(coords.0, coords.1)
}
}
impl<'a, T: Copy> From<&'a Point<T>> for Point<T> {
#[inline]
fn from(v: &'a Point<T>) -> Self {
Point::new(v.x, v.y)
}
}
impl<T: Copy> From<[T; 2]> for Point<T> {
#[inline]
fn from(coords: [T; 2]) -> Self {
Point::new(coords[0], coords[1])
}
}
impl<T: Copy> From<Point<T>> for [T; 2] {
#[inline]
fn from(p: Point<T>) -> Self {
[p.x, p.y]
}
}
impl<T> fmt::Debug for Point<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Point({:?}, {:?})", self.x, self.y)
}
}
impl<T> fmt::Display for Point<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
impl<T: Copy + NumCast> Point<T> {
#[inline]
pub fn cast_to_float<F: Float + NumCast>(&self) -> Point<F> {
Point::new(F::from(self.x).unwrap(), F::from(self.y).unwrap())
}
}
impl<T: Copy + NumCast, Dst: Copy + NumCast> TryCastCoord<T, Dst> for Point<T> {
type Output = Point<Dst>;
#[inline]
fn try_cast(&self) -> Option<Self::Output> {
match (Dst::from(self.x), Dst::from(self.y)) {
(Some(x), Some(y)) => Some(Point::new(x, y)),
_ => None,
}
}
}
impl<T, V> Add<V> for Point<T>
where
T: Copy + Add<Output = T>,
V: Into<Point<T>>,
{
type Output = Self;
#[inline]
fn add(self, rhs: V) -> Self {
let rhs = rhs.into();
Point::new(self.x + rhs.x, self.y + rhs.y)
}
}
impl<T, V> AddAssign<V> for Point<T>
where
T: Copy + AddAssign<T>,
V: Into<Vector<T>>,
{
#[inline]
fn add_assign(&mut self, rhs: V) {
let rhs = rhs.into();
self.location += rhs;
}
}
impl<T> Sub<Point<T>> for Point<T>
where
T: Copy + Sub<Output = T>,
{
type Output = Vector<T>;
#[inline]
fn sub(self, rhs: Point<T>) -> Self::Output {
Vector::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl<T> Sub<Vector<T>> for Point<T>
where
T: Copy + Sub<Output = T>,
{
type Output = Point<T>;
#[inline]
fn sub(self, rhs: Vector<T>) -> Self::Output {
Point::new(self.x - rhs.x, self.y - rhs.y)
}
}
impl<T, V> SubAssign<V> for Point<T>
where
T: Copy + SubAssign<T>,
V: Into<Vector<T>>,
{
#[inline]
fn sub_assign(&mut self, rhs: V) {
let rhs = rhs.into();
self.location -= rhs;
}
}
impl<T> Neg for Point<T>
where
T: Copy + Neg<Output = T>,
{
type Output = Self;
#[inline]
fn neg(self) -> Self {
Point::new(-self.x, -self.y)
}
}
impl<T> Mul<T> for Point<T>
where
T: Copy + Mul<Output = T>,
{
type Output = Self;
#[inline]
fn mul(self, rhs: T) -> Self {
Point::new(self.x * rhs, self.y * rhs)
}
}
impl<T> MulAssign<T> for Point<T>
where
T: Copy + MulAssign<T>,
{
#[inline]
fn mul_assign(&mut self, rhs: T) {
self.location *= rhs;
}
}
impl<T> Div<T> for Point<T>
where
T: Copy + Div<Output = T>,
{
type Output = Self;
#[inline]
fn div(self, rhs: T) -> Self {
Point::new(self.x / rhs, self.y / rhs)
}
}
impl<T: Copy + Zero + Add<Output = T>> std::iter::Sum for Point<T> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::zero(), |acc, p| acc + p)
}
}
impl<T: Copy> BoundingBox<T> for Point<T> {
fn bounding_box(&self) -> Rect<T> {
Rect {
lower_left: *self,
upper_right: *self,
}
}
}
impl<T: Copy> TryBoundingBox<T> for Point<T> {
fn try_bounding_box(&self) -> Option<Rect<T>> {
Some(self.bounding_box())
}
}