// 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 //! disinguishes them from vectors, which have a length and direction, but do //! not have a fixed position. use std::fmt; use std::mem; use std::ops::*; use rust_num::{One, Zero}; use approx::ApproxEq; use array::Array1; use matrix::Matrix; use num::{BaseNum, BaseFloat}; use vector::*; /// A point in 2-dimensional space. #[derive(PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable)] pub struct Point2 { pub x: S, pub y: S } /// A point in 3-dimensional space. #[derive(PartialEq, Eq, Copy, Clone, Hash, RustcEncodable, RustcDecodable)] pub struct Point3 { pub x: S, pub y: S, pub z: S } impl Point2 { #[inline] pub fn new(x: S, y: S) -> Point2 { Point2 { x: x, y: y } } } impl Point3 { #[inline] pub fn new(x: S, y: S, z: S) -> Point3 { Point3 { x: x, y: y, z: z } } } impl Point3 { #[inline] pub fn from_homogeneous(v: &Vector4) -> Point3 { let e = v.truncate().mul_s(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()) } } /// Specifies the numeric operations for point types. pub trait Point: Clone where // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 Self: Array1::Scalar>, // FIXME: blocked by rust-lang/rust#20671 // // for<'a, 'b> &'a Self: Add<&'b V, Output = Self>, // for<'a, 'b> &'a Self: Sub<&'b Self, Output = V>, // // for<'a> &'a Self: Mul, // for<'a> &'a Self: Div, // for<'a> &'a Self: Rem, { /// The associated scalar. /// /// Due to the equality constraints demanded by `Self::Vector`, this is effectively just an /// alias to `Self::Vector::Scalar`. type Scalar: BaseNum; /// The associated displacement vector. type Vector: Vector; /// Create a point at the origin. fn origin() -> Self; /// Create a point from a vector. fn from_vec(v: &Self::Vector) -> Self; /// Convert a point to a vector. fn to_vec(&self) -> Self::Vector; /// Multiply each component by a scalar, returning the new point. #[must_use] fn mul_s(&self, scalar: Self::Scalar) -> Self; /// Divide each component by a scalar, returning the new point. #[must_use] fn div_s(&self, scalar: Self::Scalar) -> Self; /// Subtract a scalar from each component, returning the new point. #[must_use] fn rem_s(&self, scalar: Self::Scalar) -> Self; /// Add a vector to this point, returning the new point. #[must_use] fn add_v(&self, v: &Self::Vector) -> Self; /// Subtract another point from this one, returning a new vector. fn sub_p(&self, p: &Self) -> Self::Vector; /// Multiply each component by a scalar, in-place. fn mul_self_s(&mut self, scalar: Self::Scalar); /// Divide each component by a scalar, in-place. fn div_self_s(&mut self, scalar: Self::Scalar); /// Take the remainder of each component by a scalar, in-place. fn rem_self_s(&mut self, scalar: Self::Scalar); /// Add a vector to this point, in-place. fn add_self_v(&mut self, v: &Self::Vector); /// This is a weird one, but its useful for plane calculations. fn dot(&self, v: &Self::Vector) -> Self::Scalar; #[must_use] fn min(&self, p: &Self) -> Self; #[must_use] fn max(&self, p: &Self) -> Self; } impl Array1 for Point2 { type Element = S; } impl Point for Point2 { type Scalar = S; type Vector = Vector2; #[inline] fn origin() -> Point2 { Point2::new(S::zero(), S::zero()) } #[inline] fn from_vec(v: &Vector2) -> Point2 { Point2::new(v.x, v.y) } #[inline] fn to_vec(&self) -> Vector2 { Vector2::new(self.x, self.y) } #[inline] fn mul_s(&self, scalar: S) -> Point2 { self * scalar } #[inline] fn div_s(&self, scalar: S) -> Point2 { self / scalar } #[inline] fn rem_s(&self, scalar: S) -> Point2 { self % scalar } #[inline] fn add_v(&self, v: &Vector2) -> Point2 { self + v } #[inline] fn sub_p(&self, p: &Point2) -> Vector2 { self - p } #[inline] fn mul_self_s(&mut self, scalar: S) { self.x = self.x * scalar; self.y = self.y * scalar; } #[inline] fn div_self_s(&mut self, scalar: S) { self.x = self.x / scalar; self.y = self.y / scalar; } #[inline] fn rem_self_s(&mut self, scalar: S) { self.x = self.x % scalar; self.y = self.y % scalar; } #[inline] fn add_self_v(&mut self, v: &Vector2) { self.x = self.x + v.x; self.y = self.y + v.y; } #[inline] fn dot(&self, v: &Vector2) -> S { self.x * v.x + self.y * v.y } #[inline] fn min(&self, p: &Point2) -> Point2 { Point2::new(self.x.partial_min(p.x), self.y.partial_min(p.y)) } #[inline] fn max(&self, p: &Point2) -> Point2 { Point2::new(self.x.partial_max(p.x), self.y.partial_max(p.y)) } } impl ApproxEq for Point2 { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Point2, epsilon: &S) -> bool { self.x.approx_eq_eps(&other.x, epsilon) && self.y.approx_eq_eps(&other.y, epsilon) } } impl Array1 for Point3 { type Element = S; } impl Point for Point3 { type Scalar = S; type Vector = Vector3; #[inline] fn origin() -> Point3 { Point3::new(S::zero(), S::zero(), S::zero()) } #[inline] fn from_vec(v: &Vector3) -> Point3 { Point3::new(v.x, v.y, v.z) } #[inline] fn to_vec(&self) -> Vector3 { Vector3::new(self.x, self.y, self.z) } #[inline] fn mul_s(&self, scalar: S) -> Point3 { self * scalar } #[inline] fn div_s(&self, scalar: S) -> Point3 { self / scalar } #[inline] fn rem_s(&self, scalar: S) -> Point3 { self % scalar } #[inline] fn add_v(&self, v: &Vector3) -> Point3 { self + v } #[inline] fn sub_p(&self, p: &Point3) -> Vector3 { self - p } #[inline] fn mul_self_s(&mut self, scalar: S) { self.x = self.x * scalar; self.y = self.y * scalar; self.z = self.z * scalar; } #[inline] fn div_self_s(&mut self, scalar: S) { self.x = self.x / scalar; self.y = self.y / scalar; self.z = self.z / scalar; } #[inline] fn rem_self_s(&mut self, scalar: S) { self.x = self.x % scalar; self.y = self.y % scalar; self.z = self.z % scalar; } #[inline] fn add_self_v(&mut self, v: &Vector3) { self.x = self.x + v.x; self.y = self.y + v.y; self.z = self.z + v.z; } #[inline] fn dot(&self, v: &Vector3) -> S { self.x * v.x + self.y * v.y + self.z * v.z } #[inline] fn min(&self, p: &Point3) -> Point3 { Point3::new(self.x.partial_min(p.x), self.y.partial_min(p.y), self.z.partial_min(p.z)) } #[inline] fn max(&self, p: &Point3) -> Point3 { Point3::new(self.x.partial_max(p.x), self.y.partial_max(p.y), self.z.partial_max(p.z)) } } impl ApproxEq for Point3 { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Point3, epsilon: &S) -> bool { self.x.approx_eq_eps(&other.x, epsilon) && self.y.approx_eq_eps(&other.y, epsilon) && self.z.approx_eq_eps(&other.z, epsilon) } } macro_rules! impl_operators { ($PointN:ident { $($field:ident),+ }, $VectorN:ident) => { impl<'a, S: BaseNum> Mul for &'a $PointN { type Output = $PointN; #[inline] fn mul(self, scalar: S) -> $PointN { $PointN::new($(self.$field * scalar),+) } } impl<'a, S: BaseNum> Div for &'a $PointN { type Output = $PointN; #[inline] fn div(self, scalar: S) -> $PointN { $PointN::new($(self.$field / scalar),+) } } impl<'a, S: BaseNum> Rem for &'a $PointN { type Output = $PointN; #[inline] fn rem(self, scalar: S) -> $PointN { $PointN::new($(self.$field % scalar),+) } } impl<'a, 'b, S: BaseNum> Add<&'a $VectorN> for &'b $PointN { type Output = $PointN; #[inline] fn add(self, v: &'a $VectorN) -> $PointN { $PointN::new($(self.$field + v.$field),+) } } impl<'a, 'b, S: BaseNum> Sub<&'a $PointN> for &'b $PointN { type Output = $VectorN; #[inline] fn sub(self, p: &'a $PointN) -> $VectorN { $VectorN::new($(self.$field - p.$field),+) } } } } impl_operators!(Point2 { x, y }, Vector2); impl_operators!(Point3 { x, y, z }, Vector3); macro_rules! fixed_array_conversions { ($PointN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => { impl<$S> Into<[$S; $n]> for $PointN<$S> { #[inline] fn into(self) -> [$S; $n] { match self { $PointN { $($field),+ } => [$($field),+] } } } impl<$S> AsRef<[$S; $n]> for $PointN<$S> { #[inline] fn as_ref(&self) -> &[$S; $n] { unsafe { mem::transmute(self) } } } impl<$S> AsMut<[$S; $n]> for $PointN<$S> { #[inline] fn as_mut(&mut self) -> &mut [$S; $n] { unsafe { mem::transmute(self) } } } impl<$S: Clone> From<[$S; $n]> for $PointN<$S> { #[inline] fn from(v: [$S; $n]) -> $PointN<$S> { // We need to use a clone here because we can't pattern match on arrays yet $PointN { $($field: v[$index].clone()),+ } } } impl<'a, $S> From<&'a [$S; $n]> for &'a $PointN<$S> { #[inline] fn from(v: &'a [$S; $n]) -> &'a $PointN<$S> { unsafe { mem::transmute(v) } } } impl<'a, $S> From<&'a mut [$S; $n]> for &'a mut $PointN<$S> { #[inline] fn from(v: &'a mut [$S; $n]) -> &'a mut $PointN<$S> { unsafe { mem::transmute(v) } } } } } fixed_array_conversions!(Point2 { x:0, y:1 }, 2); fixed_array_conversions!(Point3 { x:0, y:1, z:2 }, 3); macro_rules! tuple_conversions { ($PointN:ident <$S:ident> { $($field:ident),+ }, $Tuple:ty) => { impl<$S> Into<$Tuple> for $PointN<$S> { #[inline] fn into(self) -> $Tuple { match self { $PointN { $($field),+ } => ($($field),+) } } } impl<$S> AsRef<$Tuple> for $PointN<$S> { #[inline] fn as_ref(&self) -> &$Tuple { unsafe { mem::transmute(self) } } } impl<$S> AsMut<$Tuple> for $PointN<$S> { #[inline] fn as_mut(&mut self) -> &mut $Tuple { unsafe { mem::transmute(self) } } } impl<$S> From<$Tuple> for $PointN<$S> { #[inline] fn from(v: $Tuple) -> $PointN<$S> { // We need to use a clone here because we can't pattern match on arrays yet match v { ($($field),+) => $PointN { $($field: $field),+ } } } } impl<'a, $S> From<&'a $Tuple> for &'a $PointN<$S> { #[inline] fn from(v: &'a $Tuple) -> &'a $PointN<$S> { unsafe { mem::transmute(v) } } } impl<'a, $S> From<&'a mut $Tuple> for &'a mut $PointN<$S> { #[inline] fn from(v: &'a mut $Tuple) -> &'a mut $PointN<$S> { unsafe { mem::transmute(v) } } } } } tuple_conversions!(Point2 { x, y }, (S, S)); tuple_conversions!(Point3 { x, y, z }, (S, S, S)); macro_rules! index_operators { ($PointN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => { impl<$S> Index<$I> for $PointN<$S> { type Output = $Output; #[inline] fn index<'a>(&'a self, i: $I) -> &'a $Output { let v: &[$S; $n] = self.as_ref(); &v[i] } } impl<$S> IndexMut<$I> for $PointN<$S> { #[inline] fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { let v: &mut [$S; $n] = self.as_mut(); &mut v[i] } } } } index_operators!(Point2, 2, S, usize); index_operators!(Point3, 3, S, usize); index_operators!(Point2, 2, [S], Range); index_operators!(Point3, 3, [S], Range); index_operators!(Point2, 2, [S], RangeTo); index_operators!(Point3, 3, [S], RangeTo); index_operators!(Point2, 2, [S], RangeFrom); index_operators!(Point3, 3, [S], RangeFrom); index_operators!(Point2, 2, [S], RangeFull); index_operators!(Point3, 3, [S], RangeFull); impl fmt::Debug for Point2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{:?}, {:?}]", self.x, self.y) } } impl fmt::Debug for Point3 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[{:?}, {:?}, {:?}]", self.x, self.y, self.z) } } #[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); } } } 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); } } } }