use num::One; use std::fmt; use std::cmp::Ordering; use approx::ApproxEq; #[cfg(feature = "serde-serialize")] use serde::{Serialize, Serializer, Deserialize, Deserializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; use core::{Scalar, ColumnVector, OwnedColumnVector}; use core::iter::{MatrixIter, MatrixIterMut}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::storage::{Storage, StorageMut, MulStorage}; use core::allocator::{Allocator, SameShapeR}; // XXX Bad name: we can't even add points… /// The type of the result of the sum of a point with a vector. pub type PointSum = PointBase, <>::Alloc as Allocator, U1>>::Buffer>; /// The type of the result of the multiplication of a point by a matrix. pub type PointMul = PointBase>; /// A point with an owned storage. pub type OwnedPoint = PointBase>::Buffer>; /// A point in a n-dimensional euclidean space. #[repr(C)] #[derive(Hash, Debug)] pub struct PointBase> { /// The coordinates of this point, i.e., the shift from the origin. pub coords: ColumnVector } impl Copy for PointBase where N: Scalar, D: DimName, S: Storage + Copy { } impl Clone for PointBase where N: Scalar, D: DimName, S: Storage + Clone { #[inline] fn clone(&self) -> Self { PointBase::from_coordinates(self.coords.clone()) } } #[cfg(feature = "serde-serialize")] impl Serialize for PointBase where N: Scalar, D: DimName, S: Storage, ColumnVector: Serialize, { fn serialize(&self, serializer: T) -> Result where T: Serializer { self.coords.serialize(serializer) } } #[cfg(feature = "serde-serialize")] impl<'de, N, D, S> Deserialize<'de> for PointBase where N: Scalar, D: DimName, S: Storage, ColumnVector: Deserialize<'de>, { fn deserialize(deserializer: T) -> Result where T: Deserializer<'de> { ColumnVector::deserialize(deserializer).map(|x| PointBase { coords: x }) } } #[cfg(feature = "abomonation-serialize")] impl Abomonation for PointBase where N: Scalar, D: DimName, S: Storage, ColumnVector: Abomonation { unsafe fn entomb(&self, writer: &mut Vec) { self.coords.entomb(writer) } unsafe fn embalm(&mut self) { self.coords.embalm() } unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { self.coords.exhume(bytes) } } impl> PointBase { /// Creates a new point with the given coordinates. #[inline] pub fn from_coordinates(coords: ColumnVector) -> PointBase { PointBase { coords: coords } } } impl> PointBase { /// Moves this point into one that owns its data. #[inline] pub fn into_owned(self) -> OwnedPoint { PointBase::from_coordinates(self.coords.into_owned()) } /// Clones this point into one that owns its data. #[inline] pub fn clone_owned(&self) -> OwnedPoint { PointBase::from_coordinates(self.coords.clone_owned()) } /// The dimension of this point. #[inline] pub fn len(&self) -> usize { self.coords.len() } /// The stride of this point. This is the number of buffer element separating each component of /// this point. #[inline] pub fn stride(&self) -> usize { self.coords.strides().0 } /// Iterates through this point coordinates. #[inline] pub fn iter(&self) -> MatrixIter { self.coords.iter() } /// Gets a reference to i-th element of this point without bound-checking. #[inline] pub unsafe fn get_unchecked(&self, i: usize) -> &N { self.coords.get_unchecked(i, 0) } /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the /// end of it. #[inline] pub fn to_homogeneous(&self) -> OwnedColumnVector, S::Alloc> where N: One, D: DimNameAdd, S::Alloc: Allocator, U1> { let mut res = unsafe { OwnedColumnVector::::new_uninitialized() }; res.fixed_slice_mut::(0, 0).copy_from(&self.coords); res[(D::dim(), 0)] = N::one(); res } } impl> PointBase { /// Mutably iterates through this point coordinates. #[inline] pub fn iter_mut(&mut self) -> MatrixIterMut { self.coords.iter_mut() } /// Gets a mutable reference to i-th element of this point without bound-checking. #[inline] pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> &mut N { self.coords.get_unchecked_mut(i, 0) } /// Swaps two entries without bound-checking. #[inline] pub unsafe fn swap_unchecked(&mut self, i1: usize, i2: usize) { self.coords.swap_unchecked((i1, 0), (i2, 0)) } } impl ApproxEq for PointBase where N: Scalar + ApproxEq, S: Storage, N::Epsilon: Copy { type Epsilon = N::Epsilon; #[inline] fn default_epsilon() -> Self::Epsilon { N::default_epsilon() } #[inline] fn default_max_relative() -> Self::Epsilon { N::default_max_relative() } #[inline] fn default_max_ulps() -> u32 { N::default_max_ulps() } #[inline] fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool { self.coords.relative_eq(&other.coords, epsilon, max_relative) } #[inline] fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool { self.coords.ulps_eq(&other.coords, epsilon, max_ulps) } } impl Eq for PointBase where N: Scalar + Eq, S: Storage { } impl PartialEq for PointBase where N: Scalar, S: Storage { #[inline] fn eq(&self, right: &Self) -> bool { self.coords == right.coords } } impl PartialOrd for PointBase where N: Scalar + PartialOrd, S: Storage { #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.coords.partial_cmp(&other.coords) } #[inline] fn lt(&self, right: &Self) -> bool { self.coords.lt(&right.coords) } #[inline] fn le(&self, right: &Self) -> bool { self.coords.le(&right.coords) } #[inline] fn gt(&self, right: &Self) -> bool { self.coords.gt(&right.coords) } #[inline] fn ge(&self, right: &Self) -> bool { self.coords.ge(&right.coords) } } /* * * Display * */ impl fmt::Display for PointBase where N: Scalar + fmt::Display, S: Storage { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); let mut it = self.coords.iter(); try!(write!(f, "{}", *it.next().unwrap())); for comp in it { try!(write!(f, ", {}", *comp)); } write!(f, "}}") } }