Add types from cgmath

This commit is contained in:
Brendan Zabarauskas 2013-06-16 17:34:09 +10:00
parent 11e1623dad
commit 9d99347bbf
6 changed files with 693 additions and 1 deletions

120
src/frustum.rs Normal file
View file

@ -0,0 +1,120 @@
// 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 mat::Mat4;
use plane::Plane;
use point::Point3;
mod num_macros;
#[deriving(Eq)]
pub struct Frustum<T> {
left: Plane<T>,
right: Plane<T>,
bottom: Plane<T>,
top: Plane<T>,
near: Plane<T>,
far: Plane<T>,
}
#[deriving(Eq)]
pub struct FrustumPoints<T> {
near_top_left: Point3<T>,
near_top_right: Point3<T>,
near_bottom_left: Point3<T>,
near_bottom_right: Point3<T>,
far_top_left: Point3<T>,
far_top_right: Point3<T>,
far_bottom_left: Point3<T>,
far_bottom_right: Point3<T>,
}
impl<T:Copy + Real> Frustum<T> {
/// Constructs a frustum
pub fn from_planes(left: Plane<T>, right: Plane<T>,
bottom: Plane<T>, top: Plane<T>,
near: Plane<T>, far: Plane<T>) -> Frustum<T> {
Frustum {
left: left,
right: right,
bottom: bottom,
top: top,
near: near,
far: far,
}
}
/// Extracts frustum planes from a projection matrix
pub fn from_matrix(mat: Mat4<T>) -> Frustum<T> {
Frustum {
left: Plane::from_vec4(mat.row(3).add_v(&mat.row(0)).normalize()),
right: Plane::from_vec4(mat.row(3).sub_v(&mat.row(0)).normalize()),
bottom: Plane::from_vec4(mat.row(3).add_v(&mat.row(1)).normalize()),
top: Plane::from_vec4(mat.row(3).sub_v(&mat.row(1)).normalize()),
near: Plane::from_vec4(mat.row(3).add_v(&mat.row(2)).normalize()),
far: Plane::from_vec4(mat.row(3).sub_v(&mat.row(2)).normalize()),
}
}
pub fn base() -> Frustum<T> {
Frustum {
left: Plane::from_abcd( one!(T), zero!(T), zero!(T), one!(T)),
right: Plane::from_abcd(-one!(T), zero!(T), zero!(T), one!(T)),
bottom: Plane::from_abcd( zero!(T), one!(T), zero!(T), one!(T)),
top: Plane::from_abcd( zero!(T), -one!(T), zero!(T), one!(T)),
near: Plane::from_abcd( zero!(T), zero!(T), -one!(T), one!(T)),
far: Plane::from_abcd( zero!(T), zero!(T), one!(T), one!(T)),
}
}
}
impl<T:Copy + Real + ApproxEq<T>> Frustum<T> {
/// Computes where the frustum planes intersect to form corners and returns
/// a struct containing the eight resulting position vectors.
pub fn to_points(&self) -> FrustumPoints<T> {
FrustumPoints {
near_top_left: self.near.intersection_3pl(&self.top, &self.left).unwrap(),
near_top_right: self.near.intersection_3pl(&self.top, &self.right).unwrap(),
near_bottom_left: self.near.intersection_3pl(&self.bottom, &self.left).unwrap(),
near_bottom_right: self.near.intersection_3pl(&self.bottom, &self.right).unwrap(),
far_top_left: self.far.intersection_3pl(&self.top, &self.left).unwrap(),
far_top_right: self.far.intersection_3pl(&self.top, &self.right).unwrap(),
far_bottom_left: self.far.intersection_3pl(&self.bottom, &self.left).unwrap(),
far_bottom_right: self.far.intersection_3pl(&self.bottom, &self.right).unwrap(),
}
}
}
impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for Frustum<T> {
#[inline]
pub fn approx_epsilon() -> T {
ApproxEq::approx_epsilon::<T,T>()
}
#[inline]
pub fn approx_eq(&self, other: &Frustum<T>) -> bool {
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
}
#[inline]
pub fn approx_eq_eps(&self, other: &Frustum<T>, epsilon: &T) -> bool {
self.left.approx_eq_eps(&other.left, epsilon) &&
self.right.approx_eq_eps(&other.right, epsilon) &&
self.bottom.approx_eq_eps(&other.bottom, epsilon) &&
self.top.approx_eq_eps(&other.top, epsilon) &&
self.near.approx_eq_eps(&other.near, epsilon) &&
self.far.approx_eq_eps(&other.far, epsilon)
}
}

View file

@ -19,7 +19,7 @@
author = "Brendan Zabarauskas",
url = "https://github.com/bjz/lmath-rs")];
#[comment = "A generic linear algebra library."];
#[comment = "A mathematics library for computer graphics."];
#[license = "ASL2"];
#[crate_type = "lib"];
@ -29,4 +29,8 @@ pub mod mat;
pub mod quat;
pub mod vec;
pub mod frustum;
pub mod plane;
pub mod point;
pub mod projection;
pub mod ray;

187
src/plane.rs Normal file
View file

@ -0,0 +1,187 @@
// 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.
pub use dim::Dimensional;
use mat::Mat3;
use point::Point3;
use ray::Ray3;
use vec::{Vec3, Vec4};
mod num_macros;
mod dim_macros;
/// A plane formed from the equation: `Ax + Bx + Cx + D = 0`
///
/// # Fields
///
/// - `n`: the normal of the plane where:
/// - `n.x`: corresponds to `A` in the plane equation
/// - `n.y`: corresponds to `B` in the plane equation
/// - `n.z`: corresponds to `C` in the plane equation
/// - `d`: the distance value, corresponding to `D` in the plane equation
#[deriving(Eq)]
pub struct Plane<T> {
norm: Vec3<T>,
dist: T,
}
impl_dimensional!(Plane, T, 4)
impl_dimensional_fns!(Plane, T, 4)
impl_swap!(Plane)
impl_approx!(Plane)
impl<T:Copy + Real> Plane<T> {
/// # Arguments
///
/// - `a`: the `x` component of the normal
/// - `b`: the `y` component of the normal
/// - `c`: the `z` component of the normal
/// - `d`: the plane's distance value
pub fn from_abcd(a: T, b: T, c: T, d: T) -> Plane<T> {
Plane {
norm: Vec3::new(a, b, c),
dist: d,
}
}
/// Construct a plane from a normal vector `n` and a distance `d`
pub fn from_nd(norm: Vec3<T>, dist: T) -> Plane<T> {
Plane { norm: norm, dist: dist }
}
/// Construct a plane from the components of a four-dimensional vector
pub fn from_vec4(vec: Vec4<T>) -> Plane<T> {
Plane::from_abcd(vec.x, vec.y, vec.z, vec.w)
}
/// Compute the distance from the plane to the point
pub fn distance(&self, pos: &Point3<T>) -> T {
self.norm.dot(&**pos) + self.dist
}
/// Computes the point at which `ray` intersects the plane
pub fn intersection_r(&self, _ray: &Ray3<T>) -> Point3<T> {
fail!(~"not yet implemented")
}
/// Returns `true` if the ray intersects the plane
pub fn intersects(&self, _ray: &Ray3<T>) -> bool {
fail!(~"not yet implemented")
}
/// Returns `true` if `pos` is located behind the plane - otherwise it returns `false`
pub fn contains(&self, pos: &Point3<T>) -> bool {
self.distance(pos) < zero!(T)
}
}
impl<T:Copy + Real + ApproxEq<T>> Plane<T> {
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
pub fn from_3p(a: Point3<T>,
b: Point3<T>,
c: Point3<T>) -> Option<Plane<T>> {
// create two vectors that run parallel to the plane
let v0 = (*b).sub_v(&*a);
let v1 = (*c).sub_v(&*a);
// find the vector that is perpendicular to v1 and v2
let mut norm = v0.cross(&v1);
if norm.approx_eq(&Vec3::zero()) {
None
} else {
// compute the normal and the distance to the plane
norm.normalize_self();
let dist = -a.dot(&norm);
Some(Plane::from_nd(norm, dist))
}
}
/// Computes the ray created from the two-plane intersection of `self` and `other`
///
/// # Return value
///
/// - `Some(r)`: The ray `r` where the planes intersect.
/// - `None`: No valid intersection was found. The planes are probably parallel.
pub fn intersection_2pl(&self, other: &Plane<T>) -> Option<Ray3<T>> {
let ray_dir = self.norm.cross(&other.norm);
if ray_dir.approx_eq(&Vec3::zero::<T>()) {
None // the planes are parallel
} else {
// The end-point of the ray is at the three-plane intersection between
// `self`, `other`, and a tempory plane positioned at the origin
do Plane::from_nd(ray_dir, zero!(T)).intersection_3pl(self, other).map |ray_pos| {
Ray3 {
pos: *ray_pos,
dir: ray_dir,
}
}
}
}
/// Computes the three-plane intersection between `self`, `other_a` and `other_b`.
///
/// # Return value
///
/// - `Some(p)`: The position vector `p` where the planes intersect.
/// - `None`: No valid intersection was found. The normals of the three
/// planes are probably coplanar.
pub fn intersection_3pl(&self, other_a: &Plane<T>, other_b: &Plane<T>) -> Option<Point3<T>> {
let mx = Mat3::new(self.norm.x, other_a.norm.x, other_b.norm.x,
self.norm.y, other_a.norm.y, other_b.norm.y,
self.norm.z, other_a.norm.z, other_b.norm.z);
do mx.inverse().map |m| {
Point3(m.mul_v(&Vec3::new(self.dist, other_a.dist, other_b.dist)))
}
}
}
impl<T> ToStr for Plane<T> {
pub fn to_str(&self) -> ~str {
fmt!("%?x + %?y + %?z + %? = 0", self.norm.x, self.norm.y, self.norm.z, self.dist)
}
}
#[cfg(test)]
mod tests {
use plane::*;
use point::*;
#[test]
fn test_from_3p() {
assert_eq!(Plane::from_3p(Point3::new(5f, 0f, 5f),
Point3::new(5f, 5f, 5f),
Point3::new(5f, 0f, -1f)), Some(Plane::from_abcd(-1f, 0f, 0f, 5f)));
assert_eq!(Plane::from_3p(Point3::new(0f, 5f, -5f),
Point3::new(0f, 5f, 0f),
Point3::new(0f, 5f, 5f)), None); // The points are parallel
}
#[test]
fn test_plane_intersection_3pl() {
let p0 = Plane::from_abcd(1.0, 0.0, 0.0, 1.0);
let p1 = Plane::from_abcd(0.0, -1.0, 0.0, 2.0);
let p2 = Plane::from_abcd(0.0, 0.0, 1.0, 1.0);
assert_eq!(p0.intersection_3pl(&p1, &p2).unwrap(), Point3::new(1.0, -2.0, 1.0));
}
#[test]
fn test_to_str() {
assert_eq!(Plane::from_abcd(1.0, 2.0, 3.0, 4.0).to_str(), ~"1x + 2y + 3z + 4 = 0");
}
}

105
src/point.rs Normal file
View file

@ -0,0 +1,105 @@
// 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 dim::Dimensional;
use vec::{Vec2, Vec3};
mod dim_macros;
/// A geometric point
pub trait Point<T,V>: Eq + ApproxEq<T> + ToStr {
pub fn translate(&self, offset: &V) -> Self;
pub fn distance(&self, other: &Self) -> T;
}
/// A two-dimensional point
#[deriving(Eq)]
pub struct Point2<T>(Vec2<T>);
impl_dimensional!(Point2, T, 2)
impl_dimensional_fns!(Point2, T, 2)
impl_approx!(Point2)
impl<T> Point2<T> {
pub fn new(x: T, y: T) -> Point2<T> {
Point2(Vec2::new(x, y))
}
}
impl<T:Copy + Real> Point<T,Vec2<T>> for Point2<T> {
pub fn translate(&self, offset: &Vec2<T>) -> Point2<T> {
Point2(self.add_v(offset))
}
pub fn distance(&self, other: &Point2<T>) -> T {
(**self).distance(&**other)
}
}
impl<T> ToStr for Point2<T> {
pub fn to_str(&self) -> ~str {
fmt!("[%?, %?]", self.x, self.y)
}
}
/// A three-dimensional point
#[deriving(Eq)]
pub struct Point3<T>(Vec3<T>);
impl_dimensional!(Point3, T, 3)
impl_dimensional_fns!(Point3, T, 3)
impl_approx!(Point3)
impl<T> Point3<T> {
pub fn new(x: T, y: T, z: T) -> Point3<T> {
Point3(Vec3::new(x, y, z))
}
}
impl<T:Copy + Real> Point<T,Vec3<T>> for Point3<T> {
pub fn translate(&self, offset: &Vec3<T>) -> Point3<T> {
Point3(self.add_v(offset))
}
pub fn distance(&self, other: &Point3<T>) -> T {
(**self).distance(&**other)
}
}
impl<T> ToStr for Point3<T> {
pub fn to_str(&self) -> ~str {
fmt!("[%?, %?, %?]", self.x, self.y, self.z)
}
}
#[cfg(test)]
mod test_point2 {
use point::*;
#[test]
fn test_to_str() {
assert_eq!(Point2::new(1, 2).to_str(), ~"[1, 2]");
}
}
#[cfg(test)]
mod test_point3 {
use point::*;
#[test]
fn test_to_str() {
assert_eq!(Point3::new(1, 2, 3).to_str(), ~"[1, 2, 3]");
}
}

View file

@ -13,7 +13,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use frustum::Frustum;
use mat::Mat4;
use plane::Plane;
mod num_macros;
@ -97,3 +99,230 @@ pub fn ortho<T:Copy + Real>(left: T, right: T, bottom: T, top: T, near: T, far:
c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3)
}
pub trait Projection<T> {
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str>;
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str>;
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str>;
}
/// A symmetrical perspective projection based on a field-of-view angle
#[deriving(Eq)]
pub struct PerspectiveFOV<T> {
fovy: T, //radians
aspect: T,
near: T,
far: T,
}
impl<T:Copy + Real> PerspectiveFOV<T> {
pub fn to_perspective(&self) -> Result<Perspective<T>, ~str> {
do self.if_valid {
let angle = self.fovy / two!(T);
let ymax = self.near * angle.tan();
let xmax = ymax * self.aspect;
Perspective {
left: -xmax,
right: xmax,
bottom: -ymax,
top: ymax,
near: self.near,
far: self.far,
}
}
}
}
impl<T:Copy + Real> Projection<T> for PerspectiveFOV<T> {
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
let frac_pi_2: T = Real::frac_pi_2();
cond! (
(self.fovy < zero!(T)) { Err(fmt!("The vertical field of view cannot be below zero, found: %?", self.fovy)) }
(self.fovy > frac_pi_2) { Err(fmt!("The vertical field of view cannot be greater than a half turn, found: %?", self.fovy)) }
(self.aspect < zero!(T)) { Err(fmt!("The aspect ratio cannot be below zero, found: %?", self.aspect)) }
(self.near < zero!(T)) { Err(fmt!("The near plane distance cannot be below zero, found: %?", self.near)) }
(self.far < zero!(T)) { Err(fmt!("The far plane distance cannot be below zero, found: %?", self.far)) }
(self.far < self.near) { Err(fmt!("The far plane cannot be closer than the near plane, found: far: %?, near: %?", self.far, self.near)) }
_ { Ok(f()) }
)
}
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
do self.to_perspective().chain |proj| { proj.to_mat4() }
}
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
do self.to_perspective().chain |proj| { proj.to_frustum() }
}
}
/// A perspective projection with arbitrary left/right/bottom/top distances
#[deriving(Eq)]
pub struct Perspective<T> {
left: T,
right: T,
bottom: T,
top: T,
near: T,
far: T,
}
impl<T:Copy + Real> Projection<T> for Perspective<T> {
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
cond! (
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
_ { Ok(f()) }
)
}
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
do self.if_valid {
let c0r0 = (two!(T) * self.near) / (self.right - self.left);
let c0r1 = zero!(T);
let c0r2 = zero!(T);
let c0r3 = zero!(T);
let c1r0 = zero!(T);
let c1r1 = (two!(T) * self.near) / (self.top - self.bottom);
let c1r2 = zero!(T);
let c1r3 = zero!(T);
let c2r0 = (self.right + self.left) / (self.right - self.left);
let c2r1 = (self.top + self.bottom) / (self.top - self.bottom);
let c2r2 = -(self.far + self.near) / (self.far - self.near);
let c2r3 = -one!(T);
let c3r0 = zero!(T);
let c3r1 = zero!(T);
let c3r2 = -(two!(T) * self.far * self.near) / (self.far - self.near);
let c3r3 = zero!(T);
Mat4::new(c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3)
}
}
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
do self.if_valid {
/*
<---- l --->|<--- r ----->
+-----------+-----------+ ^
\ | / |
\ | / |
\ + | + / |
\ / Nl | Nr \ / |
\/ | \/ |
left \ | / right f
plane \ | / plane |
Nl,Dl \ | / Nr,Dr |
\θl|θr/ |
\ | / |
\|/ |
+ v
θl = tan¹(l/f)
+
/ Nl
/
/
\ | /
\θl| /
\ | /
\|/ θl
+- - - -
\
Nl = cos(θl), 0, sin(θl)
left plane = Nl, 0
= cos(θl), 0, sin(θl), 0
*/
let theta_l = (self.left / self.far).atan();
let theta_r = (self.right / self.far).atan();
let theta_b = (self.bottom / self.far).atan();
let theta_t = (self.top / self.far).atan();
Frustum {
left: Plane::from_abcd(theta_l.cos(), zero!(T), theta_l.sin(), zero!(T)),
right: Plane::from_abcd(theta_r.cos(), zero!(T), theta_r.sin(), zero!(T)),
bottom: Plane::from_abcd(zero!(T), theta_b.cos(), theta_b.sin(), zero!(T)),
top: Plane::from_abcd(zero!(T), theta_t.cos(), theta_t.sin(), zero!(T)),
near: Plane::from_abcd(zero!(T), zero!(T), -one!(T), -self.near),
far: Plane::from_abcd(zero!(T), zero!(T), one!(T), self.far),
}
}
}
}
/// An orthographic projection with arbitrary left/right/bottom/top distances
#[deriving(Eq)]
pub struct Ortho<T> {
left: T,
right: T,
bottom: T,
top: T,
near: T,
far: T,
}
impl<T:Copy + Real> Projection<T> for Ortho<T> {
pub fn if_valid<U:Copy>(&self, f: &fn() -> U) -> Result<U, ~str> {
cond! (
(self.left > self.right) { Err(fmt!("`left` cannot be greater than `right`, found: left: %? right: %?", self.left, self.right)) }
(self.bottom > self.top) { Err(fmt!("`bottom` cannot be greater than `top`, found: bottom: %? top: %?", self.bottom, self.top)) }
(self.near > self.far) { Err(fmt!("`near` cannot be greater than `far`, found: near: %? far: %?", self.near, self.far)) }
_ { Ok(f()) }
)
}
pub fn to_mat4(&self) -> Result<Mat4<T>, ~str> {
do self.if_valid {
let c0r0 = two!(T) / (self.right - self.left);
let c0r1 = zero!(T);
let c0r2 = zero!(T);
let c0r3 = zero!(T);
let c1r0 = zero!(T);
let c1r1 = two!(T) / (self.top - self.bottom);
let c1r2 = zero!(T);
let c1r3 = zero!(T);
let c2r0 = zero!(T);
let c2r1 = zero!(T);
let c2r2 = -two!(T) / (self.far - self.near);
let c2r3 = -one!(T);
let c3r0 = -(self.right + self.left) / (self.right - self.left);
let c3r1 = -(self.top + self.bottom) / (self.top - self.bottom);
let c3r2 = -(self.far + self.near) / (self.far - self.near);
let c3r3 = one!(T);
Mat4::new(c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3)
}
}
pub fn to_frustum(&self) -> Result<Frustum<T>, ~str> {
do self.if_valid {
Frustum {
left: Plane::from_abcd(one!(T), zero!(T), zero!(T), self.left),
right: Plane::from_abcd(-one!(T), zero!(T), zero!(T), self.right),
bottom: Plane::from_abcd(zero!(T), one!(T), zero!(T), self.bottom),
top: Plane::from_abcd(zero!(T), -one!(T), zero!(T), self.top),
near: Plane::from_abcd(zero!(T), zero!(T), -one!(T), self.near),
far: Plane::from_abcd(zero!(T), zero!(T), one!(T), self.far),
}
}
}
}

47
src/ray.rs Normal file
View file

@ -0,0 +1,47 @@
// 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 vec::Vec3;
use point::Point3;
/// A three-dimensional ray
///
/// # Fields
///
/// - `pos`: the endpoint of the ray
/// - `dir`: the direction vector
#[deriving(Eq)]
pub struct Ray3<T> {
pos: Point3<T>,
dir: Vec3<T>,
}
impl<T:Copy + Eq + ApproxEq<T>> ApproxEq<T> for Ray3<T> {
#[inline]
pub fn approx_epsilon() -> T {
ApproxEq::approx_epsilon::<T,T>()
}
#[inline]
pub fn approx_eq(&self, other: &Ray3<T>) -> bool {
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
}
#[inline]
pub fn approx_eq_eps(&self, other: &Ray3<T>, epsilon: &T) -> bool {
self.pos.approx_eq_eps(&other.pos, epsilon) &&
self.dir.approx_eq_eps(&other.dir, epsilon)
}
}