// Copyright 2013 The Lmath Developers. For a full listing of the authors, // refer to the AUTHORS 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. //! Coordinate vectors for positional data //! //! These types differ from the vector types implemented in `core::vec` because //! they describe coordinates in geometric space and not a magnitude and a //! direction. All positional data throughout the library uses these point //! types, which allows for a clear, self-documenting API. use std::cast; use math::{Dimensional, Swap}; use math::{Mat2, Mat3, Quat}; use math::{Ray2, Ray3}; use math::{Vec2, ToVec2, AsVec2}; use math::{Vec3, ToVec3, AsVec3}; use math::{Vec4, ToVec4}; /// A geometric point pub trait Point: Eq + Add + Sub + Mul + ApproxEq + ToStr { pub fn translate(&self, offset: &Vec) -> Self; pub fn scale(&self, factor: &Vec) -> Self; pub fn distance2(&self, other: &Self) -> T; pub fn distance(&self, other: &Self) -> T; pub fn direction(&self, other: &Self) -> Vec; pub fn ray_to(&self, other: &Self) -> Ray; } /// A two-dimensional point #[deriving(Clone, Eq)] pub struct Point2 { x: T, y: T } impl_dimensional!(Point2, T, 2) impl_to_vec!(Point2, 2) impl_as_vec!(Point2, 2) impl_swap!(Point2) impl_approx!(Point2 { x, y }) pub trait AsPoint2 { pub fn as_point2<'a>(&'a self) -> &'a Point2; pub fn as_mut_point2<'a>(&'a mut self) -> &'a mut Point2; } impl AsPoint2 for Vec2 { #[inline] pub fn as_point2<'a>(&'a self) -> &'a Point2 { unsafe { cast::transmute(self) } } #[inline] pub fn as_mut_point2<'a>(&'a mut self) -> &'a mut Point2 { unsafe { cast::transmute(self) } } } impl Point2 { #[inline] pub fn new(x: T, y: T) -> Point2 { Point2 { x: x, y: y } } #[inline] pub fn from_vec2(vec: Vec2) -> Point2 { unsafe { cast::transmute(vec) } } #[inline] pub fn origin() -> Point2 { Point2::new(zero!(T), zero!(T)) } } impl ToVec3 for Point2 { /// Converts the point to a three-dimensional homogeneous vector: /// `[x, y] -> [x, y, 1]` #[inline] pub fn to_vec3(&self) -> Vec3 { Vec3::new(self.x.clone(), self.y.clone(), one!(T)) } } impl Point2 { #[inline] pub fn rotate_t(&self, radians: &T) -> Point2 { Point2::new(self.x.cos() * (*radians), self.y.sin() * (*radians)) } #[inline] pub fn rotate_m(&self, mat: &Mat2) -> Point2 { Point2::from_vec2(mat.mul_v(self.as_vec2())) } } impl Point, Ray2> for Point2 { #[inline] pub fn translate(&self, offset: &Vec2) -> Point2 { (*self) + (*offset) } #[inline] pub fn scale(&self, factor: &Vec2) -> Point2 { (*self) * (*factor) } #[inline] pub fn distance2(&self, other: &Point2) -> T { ((*other) - (*self)).magnitude2() } /// Returns the scalar distance to the other point #[inline] pub fn distance(&self, other: &Point2) -> T { other.distance2(self).sqrt() } /// Returns a normalized direction vector pointing to the other point #[inline] pub fn direction(&self, other: &Point2) -> Vec2 { ((*other) - (*self)).normalize() } /// Projects a normalized ray towards the other point #[inline] pub fn ray_to(&self, other: &Point2) -> Ray2 { Ray2::new(self.clone(), self.direction(other)) } } impl Add, Point2> for Point2 { fn add(&self, other: &Vec2) -> Point2 { Point2::new(self.x + other.x, self.y + other.y) } } impl Sub, Vec2> for Point2 { fn sub(&self, other: &Point2) -> Vec2 { Vec2::new(self.x - other.x, self.y - other.y) } } impl Mul, Point2> for Point2 { fn mul(&self, scale: &Vec2) -> Point2 { Point2::new(self.x * scale.x, self.y * scale.y) } } impl ToStr for Point2 { pub fn to_str(&self) -> ~str { fmt!("[%?, %?]", self.x, self.y) } } #[cfg(test)] mod test_point2 { use math::point::*; #[test] fn test_to_str() { assert_eq!(Point2::new(1, 2).to_str(), ~"[1, 2]"); } } /// A three-dimensional point #[deriving(Clone, Eq)] pub struct Point3 { x: T, y: T, z: T } impl_dimensional!(Point3, T, 3) impl_to_vec!(Point3, 3) impl_as_vec!(Point3, 3) impl_swap!(Point3) impl_approx!(Point3 { x, y, z }) pub trait AsPoint3 { pub fn as_point3<'a>(&'a self) -> &'a Point3; pub fn as_mut_point3<'a>(&'a mut self) -> &'a mut Point3; } impl AsPoint3 for Vec3 { #[inline] pub fn as_point3<'a>(&'a self) -> &'a Point3 { unsafe { cast::transmute(self) } } #[inline] pub fn as_mut_point3<'a>(&'a mut self) -> &'a mut Point3 { unsafe { cast::transmute(self) } } } impl Point3 { #[inline] pub fn new(x: T, y: T, z: T) -> Point3 { Point3 { x: x, y: y, z: z } } #[inline] pub fn from_vec3(vec: Vec3) -> Point3 { unsafe { cast::transmute(vec) } } #[inline] pub fn origin() -> Point3 { Point3::new(zero!(T), zero!(T), zero!(T)) } } impl ToVec4 for Point3 { /// Converts the point to a four-dimensional homogeneous vector: /// `[x, y, z] -> [x, y, z, 1]` #[inline] pub fn to_vec4(&self) -> Vec4 { Vec4::new(self.x.clone(), self.y.clone(), self.z.clone(), one!(T)) } } impl Point3 { #[inline] pub fn rotate_q(&self, quat: &Quat) -> Point3 { Point3::from_vec3(quat.mul_v(self.as_vec3())) } #[inline] pub fn rotate_m(&self, mat: &Mat3) -> Point3 { Point3::from_vec3(mat.mul_v(self.as_vec3())) } } impl Point, Ray3> for Point3 { #[inline] pub fn translate(&self, offset: &Vec3) -> Point3 { (*self) + (*offset) } #[inline] pub fn scale(&self, factor: &Vec3) -> Point3 { (*self) * (*factor) } #[inline] pub fn distance2(&self, other: &Point3) -> T { ((*other) - (*self)).magnitude2() } /// Returns the scalar distance to the other point #[inline] pub fn distance(&self, other: &Point3) -> T { other.distance2(self).sqrt() } /// Returns a normalized direction vector pointing to the other point #[inline] pub fn direction(&self, other: &Point3) -> Vec3 { ((*other) - (*self)).normalize() } /// Projects a normalized ray towards the other point #[inline] pub fn ray_to(&self, other: &Point3) -> Ray3 { Ray3::new(self.clone(), self.direction(other)) } } impl Add, Point3> for Point3 { fn add(&self, other: &Vec3) -> Point3 { Point3::new(self.x + other.x, self.y + other.y, self.z + other.z) } } impl Sub, Vec3> for Point3 { fn sub(&self, other: &Point3) -> Vec3 { Vec3::new(self.x - other.x, self.y - other.y, self.z - other.z) } } impl Mul, Point3> for Point3 { fn mul(&self, scale: &Vec3) -> Point3 { Point3::new(self.x * scale.x, self.y * scale.y, self.z * scale.z) } } impl ToStr for Point3 { pub fn to_str(&self) -> ~str { fmt!("[%?, %?, %?]", self.x, self.y, self.z) } } #[cfg(test)] mod test_point3 { use math::point::*; #[test] fn test_to_str() { assert_eq!(Point3::new(1, 2, 3).to_str(), ~"[1, 2, 3]"); } }