// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, // refer to the Cargo.toml file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Points are fixed positions in affine space with no length or direction. This //! distinguishes them from vectors, which have a length and direction, but do //! not have a fixed position. use num_traits::{Bounded, NumCast}; use std::fmt; use std::mem; use std::ops::*; use structure::*; use approx; use num::{BaseFloat, BaseNum}; use vector::{Vector1, Vector2, Vector3, Vector4}; #[cfg(feature = "mint")] use mint; /// A point in 1-dimensional space. /// /// This type is marked as `#[repr(C)]`. #[repr(C)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Point1 { pub x: S, } /// A point in 2-dimensional space. /// /// This type is marked as `#[repr(C)]`. #[repr(C)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Point2 { pub x: S, pub y: S, } /// A point in 3-dimensional space. /// /// This type is marked as `#[repr(C)]`. #[repr(C)] #[derive(PartialEq, Eq, Copy, Clone, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Point3 { pub x: S, pub y: S, pub z: S, } impl Point3 { #[inline] pub fn from_homogeneous(v: Vector4) -> Point3 { let e = v.truncate() * (S::one() / v.w); Point3::new(e.x, e.y, e.z) //FIXME } #[inline] pub fn to_homogeneous(self) -> Vector4 { Vector4::new(self.x, self.y, self.z, S::one()) } } macro_rules! impl_point { ($PointN:ident { $($field:ident),+ }, $VectorN:ident, $n:expr, $constructor:ident) => { impl $PointN { /// Construct a new point, using the provided values. #[inline] pub const fn new($($field: S),+) -> $PointN { $PointN { $($field: $field),+ } } /// Perform the given operation on each field in the point, returning a new point /// constructed from the operations. #[inline] pub fn map(self, mut f: F) -> $PointN where F: FnMut(S) -> U { $PointN { $($field: f(self.$field)),+ } } /// Construct a new point where each component is the result of /// applying the given operation to each pair of components of the /// given points. #[inline] pub fn zip(self, p2: $PointN, mut f: F) -> $PointN where F: FnMut(S, S2) -> S3 { $PointN { $($field: f(self.$field, p2.$field)),+ } } } /// The short constructor. #[inline] pub const fn $constructor($($field: S),+) -> $PointN { $PointN::new($($field),+) } impl Array for $PointN { type Element = S; #[inline] fn len() -> usize { $n } #[inline] fn from_value(scalar: S) -> $PointN { $PointN { $($field: scalar),+ } } #[inline] fn sum(self) -> S where S: Add { fold_array!(add, { $(self.$field),+ }) } #[inline] fn product(self) -> S where S: Mul { fold_array!(mul, { $(self.$field),+ }) } fn is_finite(&self) -> bool where S: BaseFloat { $(self.$field.is_finite())&&+ } } impl $PointN { /// Component-wise casting to another type #[inline] pub fn cast(&self) -> Option<$PointN> { $( let $field = match NumCast::from(self.$field) { Some(field) => field, None => return None }; )+ Some($PointN { $($field),+ }) } } impl MetricSpace for $PointN { type Metric = S; #[inline] fn distance2(self, other: Self) -> S { (other - self).magnitude2() } } impl EuclideanSpace for $PointN { type Scalar = S; type Diff = $VectorN; #[inline] fn origin() -> $PointN { $PointN { $($field: S::zero()),+ } } #[inline] fn from_vec(v: $VectorN) -> $PointN { $PointN::new($(v.$field),+) } #[inline] fn to_vec(self) -> $VectorN { $VectorN::new($(self.$field),+) } #[inline] fn dot(self, v: $VectorN) -> S { $VectorN::new($(self.$field * v.$field),+).sum() } } impl approx::AbsDiffEq for $PointN { type Epsilon = S::Epsilon; #[inline] fn default_epsilon() -> S::Epsilon { S::default_epsilon() } #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool { $(S::abs_diff_eq(&self.$field, &other.$field, epsilon))&&+ } } impl approx::RelativeEq for $PointN { #[inline] fn default_max_relative() -> S::Epsilon { S::default_max_relative() } #[inline] fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { $(S::relative_eq(&self.$field, &other.$field, epsilon, max_relative))&&+ } } impl approx::UlpsEq for $PointN { #[inline] fn default_max_ulps() -> u32 { S::default_max_ulps() } #[inline] fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { $(S::ulps_eq(&self.$field, &other.$field, epsilon, max_ulps))&&+ } } impl Bounded for $PointN { #[inline] fn min_value() -> $PointN { $PointN { $($field: S::min_value()),+ } } #[inline] fn max_value() -> $PointN { $PointN { $($field: S::max_value()),+ } } } impl_operator!( Add<$VectorN > for $PointN { fn add(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field + rhs.$field),+) } }); impl_operator!( Sub<$VectorN> for $PointN { fn sub(lhs, rhs) -> $PointN { $PointN::new($(lhs.$field - rhs.$field),+) } }); impl_assignment_operator!( AddAssign<$VectorN > for $PointN { fn add_assign(&mut self, vector) { $(self.$field += vector.$field);+ } }); impl_assignment_operator!( SubAssign<$VectorN> for $PointN { fn sub_assign(&mut self, vector) { $(self.$field -= vector.$field);+ } }); impl_operator!( Sub<$PointN > for $PointN { fn sub(lhs, rhs) -> $VectorN { $VectorN::new($(lhs.$field - rhs.$field),+) } }); impl_operator!( Mul for $PointN { fn mul(point, scalar) -> $PointN { $PointN::new($(point.$field * scalar),+) } }); impl_operator!( Div for $PointN { fn div(point, scalar) -> $PointN { $PointN::new($(point.$field / scalar),+) } }); impl_operator!( Rem for $PointN { fn rem(point, scalar) -> $PointN { $PointN::new($(point.$field % scalar),+) } }); impl_assignment_operator!( MulAssign for $PointN { fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ } }); impl_assignment_operator!( DivAssign for $PointN { fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ } }); impl_assignment_operator!( RemAssign for $PointN { fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ } }); impl ElementWise for $PointN { #[inline] fn add_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field + rhs.$field),+) } #[inline] fn sub_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field - rhs.$field),+) } #[inline] fn mul_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field * rhs.$field),+) } #[inline] fn div_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field / rhs.$field),+) } #[inline] fn rem_element_wise(self, rhs: $PointN) -> $PointN { $PointN::new($(self.$field % rhs.$field),+) } #[inline] fn add_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field += rhs.$field);+ } #[inline] fn sub_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field -= rhs.$field);+ } #[inline] fn mul_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field *= rhs.$field);+ } #[inline] fn div_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field /= rhs.$field);+ } #[inline] fn rem_assign_element_wise(&mut self, rhs: $PointN) { $(self.$field %= rhs.$field);+ } } impl ElementWise for $PointN { #[inline] fn add_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field + rhs),+) } #[inline] fn sub_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field - rhs),+) } #[inline] fn mul_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field * rhs),+) } #[inline] fn div_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field / rhs),+) } #[inline] fn rem_element_wise(self, rhs: S) -> $PointN { $PointN::new($(self.$field % rhs),+) } #[inline] fn add_assign_element_wise(&mut self, rhs: S) { $(self.$field += rhs);+ } #[inline] fn sub_assign_element_wise(&mut self, rhs: S) { $(self.$field -= rhs);+ } #[inline] fn mul_assign_element_wise(&mut self, rhs: S) { $(self.$field *= rhs);+ } #[inline] fn div_assign_element_wise(&mut self, rhs: S) { $(self.$field /= rhs);+ } #[inline] fn rem_assign_element_wise(&mut self, rhs: S) { $(self.$field %= rhs);+ } } impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_scalar_ops!($PointN { $($field),+ }); impl_index_operators!($PointN, $n, S, usize); impl_index_operators!($PointN, $n, [S], Range); impl_index_operators!($PointN, $n, [S], RangeTo); impl_index_operators!($PointN, $n, [S], RangeFrom); impl_index_operators!($PointN, $n, [S], RangeFull); } } macro_rules! impl_scalar_ops { ($PointN:ident<$S:ident> { $($field:ident),+ }) => { impl_operator!(Mul<$PointN<$S>> for $S { fn mul(scalar, point) -> $PointN<$S> { $PointN::new($(scalar * point.$field),+) } }); impl_operator!(Div<$PointN<$S>> for $S { fn div(scalar, point) -> $PointN<$S> { $PointN::new($(scalar / point.$field),+) } }); impl_operator!(Rem<$PointN<$S>> for $S { fn rem(scalar, point) -> $PointN<$S> { $PointN::new($(scalar % point.$field),+) } }); }; } impl_point!(Point1 { x }, Vector1, 1, point1); impl_point!(Point2 { x, y }, Vector2, 2, point2); impl_point!(Point3 { x, y, z }, Vector3, 3, point3); impl Point1 { impl_swizzle_functions!(Point1, Point2, Point3, S, x); } impl Point2 { impl_swizzle_functions!(Point1, Point2, Point3, S, xy); } impl Point3 { impl_swizzle_functions!(Point1, Point2, Point3, S, xyz); } impl_fixed_array_conversions!(Point1 { x: 0 }, 1); impl_fixed_array_conversions!(Point2 { x: 0, y: 1 }, 2); impl_fixed_array_conversions!(Point3 { x: 0, y: 1, z: 2 }, 3); impl_tuple_conversions!(Point1 { x }, (S,)); impl_tuple_conversions!(Point2 { x, y }, (S, S)); impl_tuple_conversions!(Point3 { x, y, z }, (S, S, S)); #[cfg(feature = "mint")] impl_mint_conversions!(Point2 { x, y }, Point2); #[cfg(feature = "mint")] impl_mint_conversions!(Point3 { x, y, z }, Point3); impl fmt::Debug for Point1 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Point1 ")?; <[S; 1] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Point2 ")?; <[S; 2] as fmt::Debug>::fmt(self.as_ref(), f) } } impl fmt::Debug for Point3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Point3 ")?; <[S; 3] as fmt::Debug>::fmt(self.as_ref(), f) } } #[cfg(test)] mod tests { mod point2 { use point::*; const POINT2: Point2 = Point2 { x: 1, y: 2 }; #[test] fn test_index() { assert_eq!(POINT2[0], POINT2.x); assert_eq!(POINT2[1], POINT2.y); } #[test] fn test_index_mut() { let mut p = POINT2; *&mut p[0] = 0; assert_eq!(p, [0, 2].into()); } #[test] #[should_panic] fn test_index_out_of_bounds() { POINT2[2]; } #[test] fn test_index_range() { assert_eq!(&POINT2[..0], &[]); assert_eq!(&POINT2[..1], &[1]); assert_eq!(POINT2[..0].len(), 0); assert_eq!(POINT2[..1].len(), 1); assert_eq!(&POINT2[2..], &[]); assert_eq!(&POINT2[1..], &[2]); assert_eq!(POINT2[2..].len(), 0); assert_eq!(POINT2[1..].len(), 1); assert_eq!(&POINT2[..], &[1, 2]); assert_eq!(POINT2[..].len(), 2); } #[test] fn test_into() { let p = POINT2; { let p: [i32; 2] = p.into(); assert_eq!(p, [1, 2]); } { let p: (i32, i32) = p.into(); assert_eq!(p, (1, 2)); } } #[test] fn test_as_ref() { let p = POINT2; { let p: &[i32; 2] = p.as_ref(); assert_eq!(p, &[1, 2]); } { let p: &(i32, i32) = p.as_ref(); assert_eq!(p, &(1, 2)); } } #[test] fn test_as_mut() { let mut p = POINT2; { let p: &mut [i32; 2] = p.as_mut(); assert_eq!(p, &mut [1, 2]); } { let p: &mut (i32, i32) = p.as_mut(); assert_eq!(p, &mut (1, 2)); } } #[test] fn test_from() { assert_eq!(Point2::from([1, 2]), POINT2); { let p = &[1, 2]; let p: &Point2<_> = From::from(p); assert_eq!(p, &POINT2); } { let p = &mut [1, 2]; let p: &mut Point2<_> = From::from(p); assert_eq!(p, &POINT2); } assert_eq!(Point2::from((1, 2)), POINT2); { let p = &(1, 2); let p: &Point2<_> = From::from(p); assert_eq!(p, &POINT2); } { let p = &mut (1, 2); let p: &mut Point2<_> = From::from(p); assert_eq!(p, &POINT2); } } #[test] fn test_zip() { assert_eq!( Point2::new(true, false), Point2::new(-2, 1).zip(Point2::new(-1, -1), |a, b| a < b) ); } } mod point3 { use point::*; const POINT3: Point3 = Point3 { x: 1, y: 2, z: 3 }; #[test] fn test_index() { assert_eq!(POINT3[0], POINT3.x); assert_eq!(POINT3[1], POINT3.y); assert_eq!(POINT3[2], POINT3.z); } #[test] fn test_index_mut() { let mut p = POINT3; *&mut p[1] = 0; assert_eq!(p, [1, 0, 3].into()); } #[test] #[should_panic] fn test_index_out_of_bounds() { POINT3[3]; } #[test] fn test_index_range() { assert_eq!(&POINT3[..1], &[1]); assert_eq!(&POINT3[..2], &[1, 2]); assert_eq!(POINT3[..1].len(), 1); assert_eq!(POINT3[..2].len(), 2); assert_eq!(&POINT3[2..], &[3]); assert_eq!(&POINT3[1..], &[2, 3]); assert_eq!(POINT3[2..].len(), 1); assert_eq!(POINT3[1..].len(), 2); assert_eq!(&POINT3[..], &[1, 2, 3]); assert_eq!(POINT3[..].len(), 3); } #[test] fn test_into() { let p = POINT3; { let p: [i32; 3] = p.into(); assert_eq!(p, [1, 2, 3]); } { let p: (i32, i32, i32) = p.into(); assert_eq!(p, (1, 2, 3)); } } #[test] fn test_as_ref() { let p = POINT3; { let p: &[i32; 3] = p.as_ref(); assert_eq!(p, &[1, 2, 3]); } { let p: &(i32, i32, i32) = p.as_ref(); assert_eq!(p, &(1, 2, 3)); } } #[test] fn test_as_mut() { let mut p = POINT3; { let p: &mut [i32; 3] = p.as_mut(); assert_eq!(p, &mut [1, 2, 3]); } { let p: &mut (i32, i32, i32) = p.as_mut(); assert_eq!(p, &mut (1, 2, 3)); } } #[test] fn test_from() { assert_eq!(Point3::from([1, 2, 3]), POINT3); { let p = &[1, 2, 3]; let p: &Point3<_> = From::from(p); assert_eq!(p, &POINT3); } { let p = &mut [1, 2, 3]; let p: &mut Point3<_> = From::from(p); assert_eq!(p, &POINT3); } assert_eq!(Point3::from((1, 2, 3)), POINT3); { let p = &(1, 2, 3); let p: &Point3<_> = From::from(p); assert_eq!(p, &POINT3); } { let p = &mut (1, 2, 3); let p: &mut Point3<_> = From::from(p); assert_eq!(p, &POINT3); } } #[test] fn test_zip() { assert_eq!( Point3::new(true, false, false), Point3::new(-2, 1, 0).zip(Point3::new(-1, -1, -1), |a, b| a < b) ); } } }