// 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. use std::cast; use core::{Vec2, Vec3, Quat}; /// A geometric point pub trait Point: Eq + Add + Sub + Mul + ApproxEq + ToStr { pub fn as_vec<'a>(&'a self) -> &'a Vec; pub fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec; pub fn translate(&self, offset: &Vec) -> Self; pub fn rotate(&self, rotation: &Rot) -> 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; } /// A two-dimensional point #[deriving(Clone, Eq)] pub struct Point2 { x: T, y: T } impl Point2 { #[inline] pub fn new(x: T, y: T) -> Point2 { Point2 { x: x, y: y } } #[inline] pub fn from_vec(vec: Vec2) -> Point2 { unsafe { cast::transmute(vec) } } } impl Point, T> for Point2 { #[inline] pub fn as_vec<'a>(&'a self) -> &'a Vec2 { unsafe { cast::transmute(self) } } #[inline] pub fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec2 { unsafe { cast::transmute(self) } } #[inline] pub fn translate(&self, offset: &Vec2) -> Point2 { (*self) + (*offset) } #[inline] pub fn rotate(&self, radians: &T) -> Point2 { Point2::new((*self).x.cos() * (*radians), (*self).y.sin() * (*radians)) } #[inline] pub fn scale(&self, factor: &Vec2) -> Point2 { (*self) * (*factor) } #[inline] pub fn distance2(&self, other: &Point2) -> T { ((*other) - (*self)).length2() } #[inline] pub fn distance(&self, other: &Point2) -> T { other.distance2(self).sqrt() } #[inline] pub fn direction(&self, other: &Point2) -> Vec2 { ((*other) - (*self)).normalize() } } 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> ApproxEq for Point2 { #[inline] pub fn approx_epsilon() -> T { ApproxEq::approx_epsilon::() } #[inline] pub fn approx_eq(&self, other: &Point2) -> bool { self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) } #[inline] pub fn approx_eq_eps(&self, other: &Point2, epsilon: &T) -> bool { self.x.approx_eq_eps(&other.x, epsilon) && self.y.approx_eq_eps(&other.y, epsilon) } } impl ToStr for Point2 { pub fn to_str(&self) -> ~str { fmt!("[%?, %?]", self.x, self.y) } } #[cfg(test)] mod test_point2 { use geom::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 Point3 { #[inline] pub fn new(x: T, y: T, z: T) -> Point3 { Point3 { x: x, y: y, z: z } } #[inline] pub fn from_vec(vec: Vec3) -> Point3 { unsafe { cast::transmute(vec) } } } impl Point, Quat> for Point3 { #[inline] pub fn as_vec<'a>(&'a self) -> &'a Vec3 { unsafe { cast::transmute(self) } } #[inline] pub fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec3 { unsafe { cast::transmute(self) } } #[inline] pub fn translate(&self, offset: &Vec3) -> Point3 { (*self) + (*offset) } #[inline] pub fn rotate(&self, rotation: &Quat) -> Point3 { Point3::from_vec(rotation.mul_v(self.as_vec())) } #[inline] pub fn scale(&self, factor: &Vec3) -> Point3 { (*self) * (*factor) } #[inline] pub fn distance2(&self, other: &Point3) -> T { ((*other) - (*self)).length2() } #[inline] pub fn distance(&self, other: &Point3) -> T { other.distance2(self).sqrt() } #[inline] pub fn direction(&self, other: &Point3) -> Vec3 { ((*other) - (*self)).normalize() } } 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> ApproxEq for Point3 { #[inline] pub fn approx_epsilon() -> T { ApproxEq::approx_epsilon::() } #[inline] pub fn approx_eq(&self, other: &Point3) -> bool { self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) } #[inline] pub fn approx_eq_eps(&self, other: &Point3, epsilon: &T) -> 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) } } impl ToStr for Point3 { pub fn to_str(&self) -> ~str { fmt!("[%?, %?, %?]", self.x, self.y, self.z) } } #[cfg(test)] mod test_point3 { use geom::point::*; #[test] fn test_to_str() { assert_eq!(Point3::new(1, 2, 3).to_str(), ~"[1, 2, 3]"); } }