Remove collision types and traits from the library

Closes #244
This commit is contained in:
Brendan Zabarauskas 2015-11-01 13:42:58 +11:00
parent 9e87f5507d
commit 943a92e691
22 changed files with 4 additions and 1245 deletions

View file

@ -17,14 +17,8 @@ The library provides:
- rotation matrices: `Basis2`, `Basis3` - rotation matrices: `Basis2`, `Basis3`
- angle units: `Rad`, `Deg` - angle units: `Rad`, `Deg`
- points: `Point2`, `Point3` - points: `Point2`, `Point3`
- a generic ray: `Ray`
- a plane type: `Plane`
- perspective projections: `Perspective`, `PerspectiveFov`, `Ortho` - perspective projections: `Perspective`, `PerspectiveFov`, `Ortho`
- a view frustum: `Frustum`
- spatial transformations: `AffineMatrix3`, `Transform3` - spatial transformations: `AffineMatrix3`, `Transform3`
- axis-aligned bounding boxes: `Aabb2`, `Aabb3`
- oriented bounding boxes: `Obb2`, `Obb3`
- collision primitives: `Sphere`, `Cylinder`
Not all of the functionality has been implemented yet, and the existing code Not all of the functionality has been implemented yet, and the existing code
is not fully covered by the testsuite. If you encounter any mistakes or is not fully covered by the testsuite. If you encounter any mistakes or

View file

@ -1,256 +0,0 @@
// 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.
//! Axis-aligned bounding boxes
//!
//! An AABB is a geometric object which encompasses a set of points and is not
//! rotated. It is either a rectangle or a rectangular prism (depending on the
//! dimension) where the slope of every line is either 0 or undefined. These
//! are useful for very cheap collision detection.
use std::fmt;
use rust_num::{Float, Zero, One};
use bound::*;
use point::{Point, Point2, Point3};
use vector::{Vector, Vector2, Vector3};
use ray::{Ray2};
use intersect::Intersect;
use num::{BaseNum, BaseFloat};
use plane::Plane;
pub trait Aabb<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
/// Create a new AABB using two points as opposing corners.
fn new(p1: P, p2: P) -> Self;
/// Return a shared reference to the point nearest to (-inf, -inf).
fn min<'a>(&'a self) -> &'a P;
/// Return a shared reference to the point nearest to (inf, inf).
fn max<'a>(&'a self) -> &'a P;
/// Return the dimensions of this AABB.
#[inline]
fn dim(&self) -> V { self.max().sub_p(self.min()) }
/// Return the volume this AABB encloses.
#[inline]
fn volume(&self) -> S { self.dim().product() }
/// Return the center point of this AABB.
#[inline]
fn center(&self) -> P {
let two = S::one() + S::one();
self.min().add_v(&self.dim().div_s(two))
}
/// Tests whether a point is cointained in the box, inclusive for min corner
/// and exclusive for the max corner.
#[inline]
fn contains(&self, p: &P) -> bool;
/// Returns a new AABB that is grown to include the given point.
fn grow(&self, p: &P) -> Self {
let min = self.min().min(p);
let max = self.max().max(p);
Aabb::new(min, max)
}
/// Add a vector to every point in the AABB, returning a new AABB.
fn add_v(&self, v: &V) -> Self {
Aabb::new(self.min().add_v(v), self.max().add_v(v))
}
/// Multiply every point in the AABB by a scalar, returning a new AABB.
fn mul_s(&self, s: S) -> Self {
Aabb::new(self.min().mul_s(s.clone()), self.max().mul_s(s.clone()))
}
/// Multiply every point in the AABB by a vector, returning a new AABB.
fn mul_v(&self, v: &V) -> Self {
let min = P::from_vec(&self.min().to_vec().mul_v(v));
let max = P::from_vec(&self.max().to_vec().mul_v(v));
Aabb::new(min, max)
}
}
/// A two-dimensional AABB, aka a rectangle.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Aabb2<S> {
pub min: Point2<S>,
pub max: Point2<S>,
}
impl<S: BaseNum> Aabb2<S> {
/// Construct a new axis-aligned bounding box from two points.
#[inline]
pub fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> {
Aabb2 {
min: Point2::new(p1.x.partial_min(p2.x),
p1.y.partial_min(p2.y)),
max: Point2::new(p1.x.partial_max(p2.x),
p1.y.partial_max(p2.y)),
}
}
/// Compute corners.
#[inline]
pub fn to_corners(&self) -> [Point2<S>; 4] {
[self.min,
Point2::new(self.max.x, self.min.y),
Point2::new(self.min.x, self.max.y),
self.max]
}
}
impl<S: BaseNum> Aabb<S, Vector2<S>, Point2<S>> for Aabb2<S> {
#[inline]
fn new(p1: Point2<S>, p2: Point2<S>) -> Aabb2<S> { Aabb2::new(p1, p2) }
#[inline]
fn min<'a>(&'a self) -> &'a Point2<S> { &self.min }
#[inline]
fn max<'a>(&'a self) -> &'a Point2<S> { &self.max }
#[inline]
fn contains(&self, p: &Point2<S>) -> bool {
let v_min = p.sub_p(self.min());
let v_max = self.max().sub_p(p);
v_min.x >= S::zero() && v_min.y >= S::zero() &&
v_max.x > S::zero() && v_max.y > S::zero()
}
}
impl<S: BaseNum> fmt::Debug for Aabb2<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{:?} - {:?}]", self.min, self.max)
}
}
/// A three-dimensional AABB, aka a rectangular prism.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Aabb3<S> {
pub min: Point3<S>,
pub max: Point3<S>,
}
impl<S: BaseNum> Aabb3<S> {
/// Construct a new axis-aligned bounding box from two points.
#[inline]
pub fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> {
Aabb3 {
min: Point3::new(p1.x.partial_min(p2.x),
p1.y.partial_min(p2.y),
p1.z.partial_min(p2.z)),
max: Point3::new(p1.x.partial_max(p2.x),
p1.y.partial_max(p2.y),
p1.z.partial_max(p2.z)),
}
}
/// Compute corners.
#[inline]
pub fn to_corners(&self) -> [Point3<S>; 8] {
[self.min,
Point3::new(self.max.x, self.min.y, self.min.z),
Point3::new(self.min.x, self.max.y, self.min.z),
Point3::new(self.max.x, self.max.y, self.min.z),
Point3::new(self.min.x, self.min.y, self.max.z),
Point3::new(self.max.x, self.min.y, self.max.z),
Point3::new(self.min.x, self.max.y, self.max.z),
self.max]
}
}
impl<S: BaseNum> Aabb<S, Vector3<S>, Point3<S>> for Aabb3<S> {
#[inline]
fn new(p1: Point3<S>, p2: Point3<S>) -> Aabb3<S> { Aabb3::new(p1, p2) }
#[inline]
fn min<'a>(&'a self) -> &'a Point3<S> { &self.min }
#[inline]
fn max<'a>(&'a self) -> &'a Point3<S> { &self.max }
#[inline]
fn contains(&self, p: &Point3<S>) -> bool {
let v_min = p.sub_p(self.min());
let v_max = self.max().sub_p(p);
v_min.x >= S::zero() && v_min.y >= S::zero() && v_min.z >= S::zero() &&
v_max.x > S::zero() && v_max.y > S::zero() && v_max.z > S::zero()
}
}
impl<S: BaseNum> fmt::Debug for Aabb3<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{:?} - {:?}]", self.min, self.max)
}
}
impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Aabb2<S>) {
fn intersection(&self) -> Option<Point2<S>> {
let (ref ray, ref aabb) = *self;
let mut tmin = S::neg_infinity();
let mut tmax = S::infinity();
if ray.direction.x != S::zero() {
let tx1 = (aabb.min.x - ray.origin.x) / ray.direction.x;
let tx2 = (aabb.max.x - ray.origin.x) / ray.direction.x;
tmin = tmin.max(tx1.min(tx2));
tmax = tmax.min(tx1.max(tx2));
}
if ray.direction.y != S::zero() {
let ty1 = (aabb.min.y - ray.origin.y) / ray.direction.y;
let ty2 = (aabb.max.y - ray.origin.y) / ray.direction.y;
tmin = tmin.max(ty1.min(ty2));
tmax = tmax.min(ty1.max(ty2));
}
if tmin < S::zero() && tmax < S::zero() {
None
}
else if tmax >= tmin {
if tmin >= S::zero() {
Some(Point2::new(ray.origin.x + ray.direction.x * tmin,
ray.origin.y + ray.direction.y * tmin))
}
else {
Some(Point2::new(ray.origin.x + ray.direction.x * tmax,
ray.origin.y + ray.direction.y * tmax))
}
}
else {
None
}
}
}
impl<S: BaseFloat + 'static> Bound<S> for Aabb3<S> {
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
let corners = self.to_corners();
let first = corners[0].relate_plane(plane);
for p in corners[1..].iter() {
if p.relate_plane(plane) != first {
return Relation::Cross;
}
}
first
}
}

View file

@ -1,46 +0,0 @@
// Copyright 2013-2014 The CGMath 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.
//! Generic spatial bounds.
use matrix::Matrix4;
use num::BaseFloat;
use plane::Plane;
/// Spatial relation between two objects.
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
#[repr(u8)]
pub enum Relation {
/// Completely inside.
In,
/// Crosses the boundary.
Cross,
/// Completely outside.
Out,
}
/// Generic bound.
pub trait Bound<S: BaseFloat + 'static>: Sized {
/// Classify the spatial relation with a plane.
fn relate_plane(&self, &Plane<S>) -> Relation;
/// Classify the relation with a projection matrix.
fn relate_clip_space(&self, projection: &Matrix4<S>) -> Relation {
use frustum::Frustum;
match Frustum::from_matrix4(*projection) {
Some(f) => f.contains(self),
None => Relation::Cross,
}
}
}

View file

@ -1,26 +0,0 @@
// Copyright 2013 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.
//! Oriented bounding cylinder
use point::Point3;
use vector::Vector3;
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Cylinder<S> {
pub center: Point3<S>,
pub axis: Vector3<S>,
pub radius: S,
}

View file

@ -1,94 +0,0 @@
// 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.
//! View frustum for visibility determination
use array::Array2;
use bound::*;
use matrix::Matrix4;
use num::BaseFloat;
use plane::Plane;
use point::Point3;
use vector::{Vector, EuclideanVector};
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Frustum<S: BaseFloat> {
pub left: Plane<S>,
pub right: Plane<S>,
pub bottom: Plane<S>,
pub top: Plane<S>,
pub near: Plane<S>,
pub far: Plane<S>,
}
impl<S: BaseFloat + 'static>
Frustum<S> {
/// Construct a frustum.
pub fn new(left: Plane<S>, right: Plane<S>,
bottom: Plane<S>, top: Plane<S>,
near: Plane<S>, far: Plane<S>) -> Frustum<S> {
Frustum {
left: left,
right: right,
bottom: bottom,
top: top,
near: near,
far: far,
}
}
/// Extract frustum planes from a projection matrix.
pub fn from_matrix4(mat: Matrix4<S>) -> Option<Frustum<S>> {
Some(Frustum::new(
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(0))).normalize()
{ Some(p) => p, None => return None },
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(0))).normalize()
{ Some(p) => p, None => return None },
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(1))).normalize()
{ Some(p) => p, None => return None },
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(1))).normalize()
{ Some(p) => p, None => return None },
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(2))).normalize()
{ Some(p) => p, None => return None },
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(2))).normalize()
{ Some(p) => p, None => return None }
))
}
/// Find the spatial relation of a bound inside this frustum.
pub fn contains<B: Bound<S>>(&self, bound: &B) -> Relation {
[&self.left, &self.right, &self.top, &self.bottom, &self.near, &self.far]
.iter().fold(Relation::In, |cur, p| {
use std::cmp::max;
let r = bound.relate_plane(p);
// If any of the planes are `Out`, the bound is outside.
// Otherwise, if any are `Cross`, the bound is crossing.
// Otherwise, the bound is fully inside.
max(cur, r)
})
}
}
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct FrustumPoints<S> {
pub near_top_left: Point3<S>,
pub near_top_right: Point3<S>,
pub near_bottom_left: Point3<S>,
pub near_bottom_right: Point3<S>,
pub far_top_left: Point3<S>,
pub far_top_right: Point3<S>,
pub far_bottom_left: Point3<S>,
pub far_bottom_right: Point3<S>,
}

View file

@ -1,18 +0,0 @@
// Copyright 2013 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.
pub trait Intersect<Result> {
fn intersection(&self) -> Result;
}

View file

@ -42,23 +42,12 @@ pub use quaternion::*;
pub use vector::*; pub use vector::*;
pub use angle::*; pub use angle::*;
pub use plane::Plane;
pub use point::*; pub use point::*;
pub use line::*;
pub use ray::*;
pub use rotation::*; pub use rotation::*;
pub use transform::*; pub use transform::*;
pub use projection::*; pub use projection::*;
pub use aabb::*;
pub use bound::*;
pub use cylinder::Cylinder;
pub use frustum::{Frustum, FrustumPoints};
pub use intersect::Intersect;
pub use obb::*;
pub use sphere::Sphere;
pub use approx::ApproxEq; pub use approx::ApproxEq;
pub use num::*; pub use num::*;
@ -73,22 +62,11 @@ mod quaternion;
mod vector; mod vector;
mod angle; mod angle;
mod plane;
mod point; mod point;
mod line;
mod ray;
mod rotation; mod rotation;
mod transform; mod transform;
mod projection; mod projection;
mod aabb;
mod bound;
mod cylinder;
mod frustum;
mod intersect;
mod obb;
mod sphere;
mod approx; mod approx;
mod num; mod num;

View file

@ -1,100 +0,0 @@
// 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.
//! Line segments
use std::marker::PhantomData;
use rust_num::{Zero, One};
use num::{BaseNum, BaseFloat};
use point::{Point, Point2, Point3};
use vector::{Vector, Vector2, Vector3};
use ray::{Ray2};
use intersect::Intersect;
/// A generic directed line segment from `origin` to `dest`.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Line<S, V, P> {
pub origin: P,
pub dest: P,
phantom_s: PhantomData<S>,
phantom_v: PhantomData<V>
}
impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Line<S, V, P> {
pub fn new(origin: P, dest: P) -> Line<S, V, P> {
Line {
origin: origin,
dest: dest,
phantom_v: PhantomData,
phantom_s: PhantomData
}
}
}
pub type Line2<S> = Line<S, Vector2<S>, Point2<S>>;
pub type Line3<S> = Line<S, Vector3<S>, Point3<S>>;
/// Determines if an intersection between a ray and a line segment is found.
impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Line2<S>) {
fn intersection(&self) -> Option<Point2<S>> {
let (ref ray, ref line) = *self;
let p = ray.origin;
let q = line.origin;
let r = ray.direction;
let s = Vector2::new(line.dest.x - line.origin.x, line.dest.y - line.origin.y);
let cross_1 = r.perp_dot(&s);
let qmp = Vector2::new(q.x - p.x, q.y - p.y);
let cross_2 = qmp.perp_dot(&r);
if cross_1 == S::zero() {
if cross_2 != S::zero() {
// parallel
return None;
}
// collinear
let q2mp = Vector2::new(line.dest.x - p.x, line.dest.y - p.y);
let dot_1 = qmp.dot(&r);
let dot_2 = q2mp.dot(&r);
if (dot_1 <= S::zero() && dot_2 >= S::zero()) || (dot_1 >= S::zero() && dot_2 <= S::zero()) {
return Some(p);
}
else if dot_1 >= S::zero() && dot_2 >= S::zero() {
if dot_1 <= dot_2 {
return Some(q);
}
else {
return Some(line.dest);
}
}
// no overlap exists
return None;
}
let t = qmp.perp_dot(&s) / cross_1;
let u = cross_2 / cross_1;
if S::zero() <= t && u >= S::zero() && u <= S::one() {
return Some(Point2::new(p.x + t*r.x, p.y + t*r.y));
}
return None;
}
}

View file

@ -1,33 +0,0 @@
// Copyright 2013 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.
//! Oriented bounding boxes
use point::{Point2, Point3};
use vector::{Vector2, Vector3};
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Obb2<S> {
pub center: Point2<S>,
pub axis: Vector2<S>,
pub extents: Vector2<S>,
}
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Obb3<S> {
pub center: Point3<S>,
pub axis: Vector3<S>,
pub extents: Vector3<S>,
}

View file

@ -1,150 +0,0 @@
// 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.
use std::fmt;
use rust_num::{One, Zero};
use approx::ApproxEq;
use intersect::Intersect;
use num::{BaseFloat};
use point::{Point, Point3};
use ray::Ray3;
use vector::{Vector3, Vector4};
use vector::{Vector, EuclideanVector};
/// A 3-dimensional plane formed from the equation: `A*x + B*y + C*z - D = 0`.
///
/// # Fields
///
/// - `n`: a unit vector representing 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
///
/// # Notes
///
/// The `A*x + B*y + C*z - D = 0` form is preferred over the other common
/// alternative, `A*x + B*y + C*z + D = 0`, because it tends to avoid
/// superfluous negations (see _Real Time Collision Detection_, p. 55).
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Plane<S> {
pub n: Vector3<S>,
pub d: S,
}
impl<S: BaseFloat> Plane<S> {
/// Construct a plane from a normal vector and a scalar distance. The
/// plane will be perpendicular to `n`, and `d` units offset from the
/// origin.
pub fn new(n: Vector3<S>, d: S) -> Plane<S> {
Plane { n: n, d: d }
}
/// # 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: S, b: S, c: S, d: S) -> Plane<S> {
Plane { n: Vector3::new(a, b, c), d: d }
}
/// Construct a plane from the components of a four-dimensional vector
pub fn from_vector4(v: Vector4<S>) -> Plane<S> {
Plane { n: Vector3::new(v.x, v.y, v.z), d: v.w }
}
/// Construct a plane from the components of a four-dimensional vector
/// Assuming alternative representation: `A*x + B*y + C*z + D = 0`
pub fn from_vector4_alt(v: Vector4<S>) -> Plane<S> {
Plane { n: Vector3::new(v.x, v.y, v.z), d: -v.w }
}
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
pub fn from_points(a: Point3<S>, b: Point3<S>, c: Point3<S>) -> Option<Plane<S>> {
// create two vectors that run parallel to the plane
let v0 = b.sub_p(&a);
let v1 = c.sub_p(&a);
// find the normal vector that is perpendicular to v1 and v2
let mut n = v0.cross(&v1);
if n.approx_eq(&Vector3::zero()) { None }
else {
// compute the normal and the distance to the plane
n.normalize_self();
let d = -a.dot(&n);
Some(Plane::new(n, d))
}
}
/// Construct a plane from a point and a normal vector.
/// The plane will contain the point `p` and be perpendicular to `n`.
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
Plane { n: n, d: p.dot(&n) }
}
/// Normalize a plane.
pub fn normalize(&self) -> Option<Plane<S>> {
if self.n.approx_eq(&Vector3::zero()) { None }
else {
let denom = S::one() / self.n.length();
Some(Plane::new(self.n.mul_s(denom), self.d*denom))
}
}
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) {
fn intersection(&self) -> Option<Point3<S>> {
let (ref p, ref r) = *self;
let t = -(p.d + r.origin.dot(&p.n)) / r.direction.dot(&p.n);
if t < Zero::zero() { None }
else { Some(r.origin.add_v(&r.direction.mul_s(t))) }
}
}
impl<S: BaseFloat> Intersect<Option<Ray3<S>>> for (Plane<S>, Plane<S>) {
fn intersection(&self) -> Option<Ray3<S>> {
panic!("Not yet implemented");
}
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Plane<S>, Plane<S>) {
fn intersection(&self) -> Option<Point3<S>> {
panic!("Not yet implemented");
}
}
impl<S: BaseFloat + ApproxEq<S>>
ApproxEq<S> for Plane<S> {
#[inline]
fn approx_eq_eps(&self, other: &Plane<S>, epsilon: &S) -> bool {
self.n.approx_eq_eps(&other.n, epsilon) &&
self.d.approx_eq_eps(&other.d, epsilon)
}
}
impl<S: BaseFloat> fmt::Debug for Plane<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}x + {:?}y + {:?}z - {:?} = 0",
self.n.x, self.n.y, self.n.z, self.d)
}
}

View file

@ -25,10 +25,8 @@ use rust_num::{One, Zero};
use approx::ApproxEq; use approx::ApproxEq;
use array::Array1; use array::Array1;
use bound::*; use matrix::Matrix;
use matrix::{Matrix, Matrix4};
use num::{BaseNum, BaseFloat}; use num::{BaseNum, BaseFloat};
use plane::Plane;
use vector::*; use vector::*;
/// A point in 2-dimensional space. /// A point in 2-dimensional space.
@ -470,29 +468,6 @@ impl<S: BaseNum> fmt::Debug for Point3<S> {
} }
} }
impl<S: BaseFloat + 'static> Bound<S> for Point3<S> {
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
let dist = self.dot(&plane.n);
if dist > plane.d {
Relation::In
}else if dist < plane.d {
Relation::Out
}else {
Relation::Cross
}
}
fn relate_clip_space(&self, projection: &Matrix4<S>) -> Relation {
use std::cmp::Ordering::*;
let p = projection.mul_v(&self.to_homogeneous());
match (p.x.abs().partial_cmp(&p.w), p.y.abs().partial_cmp(&p.w), p.z.abs().partial_cmp(&p.w)) {
(Some(Less), Some(Less), Some(Less)) => Relation::In,
(Some(Greater), _, _) | (_, Some(Greater), _) | (_, _, Some(Greater)) => Relation::Out,
_ => Relation::Cross,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
mod point2 { mod point2 {

View file

@ -17,10 +17,8 @@ use rust_num::{Zero, One};
use rust_num::traits::cast; use rust_num::traits::cast;
use angle::{Angle, Rad, tan, cot}; use angle::{Angle, Rad, tan, cot};
use frustum::Frustum;
use matrix::Matrix4; use matrix::Matrix4;
use num::BaseFloat; use num::BaseFloat;
use plane::Plane;
/// Create a perspective projection matrix. /// Create a perspective projection matrix.
/// ///
@ -65,10 +63,6 @@ pub fn ortho<S: BaseFloat + 'static>(left: S, right: S, bottom: S, top: S, near:
}.into() }.into()
} }
pub trait Projection<S: BaseFloat>: Into<Matrix4<S>> {
fn to_frustum(&self) -> Frustum<S>;
}
/// A perspective projection based on a vertical field-of-view angle. /// A perspective projection based on a vertical field-of-view angle.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct PerspectiveFov<S, A> { pub struct PerspectiveFov<S, A> {
@ -96,13 +90,6 @@ impl<S: BaseFloat, A: Angle<S>> PerspectiveFov<S, A> {
} }
} }
impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
fn to_frustum(&self) -> Frustum<S> {
// TODO: Could this be faster?
Frustum::from_matrix4(self.clone().into()).unwrap()
}
}
impl<S: BaseFloat, A: Angle<S>> From<PerspectiveFov<S, A>> for Matrix4<S> { impl<S: BaseFloat, A: Angle<S>> From<PerspectiveFov<S, A>> for Matrix4<S> {
fn from(persp: PerspectiveFov<S, A>) -> Matrix4<S> { fn from(persp: PerspectiveFov<S, A>) -> Matrix4<S> {
let half_turn: A = Angle::turn_div_2(); let half_turn: A = Angle::turn_div_2();
@ -156,13 +143,6 @@ pub struct Perspective<S> {
pub far: S, pub far: S,
} }
impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
fn to_frustum(&self) -> Frustum<S> {
// TODO: Could this be faster?
Frustum::from_matrix4(self.clone().into()).unwrap()
}
}
impl<S: BaseFloat + 'static> From<Perspective<S>> for Matrix4<S> { impl<S: BaseFloat + 'static> From<Perspective<S>> for Matrix4<S> {
fn from(persp: Perspective<S>) -> Matrix4<S> { fn from(persp: Perspective<S>) -> Matrix4<S> {
assert!(persp.left <= persp.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", persp.left, persp.right); assert!(persp.left <= persp.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", persp.left, persp.right);
@ -209,19 +189,6 @@ pub struct Ortho<S> {
pub far: S, pub far: S,
} }
impl<S: BaseFloat> Projection<S> for Ortho<S> {
fn to_frustum(&self) -> Frustum<S> {
Frustum {
left: Plane::from_abcd( S::one(), S::zero(), S::zero(), self.left.clone()),
right: Plane::from_abcd(-S::one(), S::zero(), S::zero(), self.right.clone()),
bottom: Plane::from_abcd(S::zero(), S::one(), S::zero(), self.bottom.clone()),
top: Plane::from_abcd(S::zero(), -S::one(), S::zero(), self.top.clone()),
near: Plane::from_abcd(S::zero(), S::zero(), -S::one(), self.near.clone()),
far: Plane::from_abcd(S::zero(), S::zero(), S::one(), self.far.clone()),
}
}
}
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> { impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
fn from(ortho: Ortho<S>) -> Matrix4<S> { fn from(ortho: Ortho<S>) -> Matrix4<S> {
let two: S = cast(2i8).unwrap(); let two: S = cast(2i8).unwrap();

View file

@ -1,41 +0,0 @@
// 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.
use std::marker::PhantomData;
use num::BaseNum;
use point::{Point, Point2, Point3};
use vector::{Vector, Vector2, Vector3};
/// A generic ray starting at `origin` and extending infinitely in
/// `direction`.
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Ray<S, P, V> {
pub origin: P,
pub direction: V,
phantom_s: PhantomData<S>
}
impl<S: BaseNum, V: Vector<S>, P: Point<S, V>> Ray<S, P, V> {
pub fn new(origin: P, direction: V) -> Ray<S, P, V> {
Ray {
origin: origin,
direction: direction,
phantom_s: PhantomData
}
}
}
pub type Ray2<S> = Ray<S, Point2<S>, Vector2<S>>;
pub type Ray3<S> = Ray<S, Point3<S>, Vector3<S>>;

View file

@ -21,7 +21,6 @@ use matrix::Matrix3;
use num::BaseFloat; use num::BaseFloat;
use point::{Point, Point2, Point3}; use point::{Point, Point2, Point3};
use quaternion::Quaternion; use quaternion::Quaternion;
use ray::Ray;
use vector::{Vector, Vector2, Vector3}; use vector::{Vector, Vector2, Vector3};
/// A trait for a generic rotation. A rotation is a transformation that /// A trait for a generic rotation. A rotation is a transformation that
@ -47,12 +46,6 @@ pub trait Rotation<S: BaseFloat, V: Vector<S>, P: Point<S, V>>: PartialEq + Appr
P::from_vec(&self.rotate_vector(&point.to_vec())) P::from_vec(&self.rotate_vector(&point.to_vec()))
} }
/// Rotate a ray using this rotation.
#[inline]
fn rotate_ray(&self, ray: &Ray<S, P, V>) -> Ray<S, P,V> {
Ray::new(ray.origin.clone(), self.rotate_vector(&ray.direction))
}
/// Create a new rotation which combines both this rotation, and another. /// Create a new rotation which combines both this rotation, and another.
fn concat(&self, other: &Self) -> Self; fn concat(&self, other: &Self) -> Self;

View file

@ -1,59 +0,0 @@
// 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.
//! Bounding sphere
use rust_num::Zero;
use bound::*;
use intersect::Intersect;
use num::BaseFloat;
use point::{Point, Point3};
use plane::Plane;
use ray::Ray3;
use vector::Vector;
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Sphere<S> {
pub center: Point3<S>,
pub radius: S,
}
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Sphere<S>, Ray3<S>) {
fn intersection(&self) -> Option<Point3<S>> {
let (ref s, ref r) = *self;
let l = s.center.sub_p(&r.origin);
let tca = l.dot(&r.direction);
if tca < S::zero() { return None; }
let d2 = l.dot(&l) - tca*tca;
if d2 > s.radius*s.radius { return None; }
let thc = (s.radius*s.radius - d2).sqrt();
Some(r.origin.add_v(&r.direction.mul_s(tca - thc)))
}
}
impl<S: BaseFloat + 'static> Bound<S> for Sphere<S> {
fn relate_plane(&self, plane: &Plane<S>) -> Relation {
let dist = self.center.dot(&plane.n) - plane.d;
if dist > self.radius {
Relation::In
}else if dist < - self.radius {
Relation::Out
}else {
Relation::Cross
}
}
}

View file

@ -21,7 +21,6 @@ use approx::ApproxEq;
use matrix::*; use matrix::*;
use num::*; use num::*;
use point::*; use point::*;
use ray::Ray;
use rotation::*; use rotation::*;
use vector::*; use vector::*;
@ -43,12 +42,6 @@ pub trait Transform<S: BaseNum, V: Vector<S>, P: Point<S, V>>: Sized {
/// Transform a point using this transform. /// Transform a point using this transform.
fn transform_point(&self, point: &P) -> P; fn transform_point(&self, point: &P) -> P;
/// Transform a ray using this transform.
#[inline]
fn transform_ray(&self, ray: &Ray<S, P,V>) -> Ray<S, P, V> {
Ray::new(self.transform_point(&ray.origin), self.transform_vector(&ray.direction))
}
/// Transform a vector as a point using this transform. /// Transform a vector as a point using this transform.
#[inline] #[inline]
fn transform_as_point(&self, vec: &V) -> V { fn transform_as_point(&self, vec: &V) -> V {

View file

@ -1,105 +0,0 @@
// Copyright 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.
extern crate cgmath;
use cgmath::{Aabb, Aabb2, Aabb3};
use cgmath::{Point2, Point3};
use cgmath::{Vector2, Vector3};
use cgmath::{Ray, Intersect};
use cgmath::{Plane, Bound, Relation};
#[test]
fn test_general() {
let aabb = Aabb2::new(Point2::new(-20isize, 30isize), Point2::new(10isize, -10isize));
assert_eq!(aabb.min(), &Point2::new(-20isize, -10isize));
assert_eq!(aabb.max(), &Point2::new(10isize, 30isize));
assert_eq!(aabb.dim(), Vector2::new(30isize, 40isize));
assert_eq!(aabb.volume(), 30isize * 40isize);
assert_eq!(aabb.center(), Point2::new(-5isize, 10isize));
assert!(aabb.contains(&Point2::new(0isize, 0isize)));
assert!(!aabb.contains(&Point2::new(-50isize, -50isize)));
assert!(!aabb.contains(&Point2::new(50isize, 50isize)));
assert_eq!(aabb.grow(&Point2::new(0isize, 0isize)), aabb);
assert_eq!(aabb.grow(&Point2::new(100isize, 100isize)),
Aabb2::new(Point2::new(-20isize, -10isize), Point2::new(100isize, 100isize)));
assert_eq!(aabb.grow(&Point2::new(-100isize, -100isize)),
Aabb2::new(Point2::new(-100isize, -100isize), Point2::new(10isize, 30isize)));
let aabb = Aabb3::new(Point3::new(-20isize, 30isize, 5isize), Point3::new(10isize, -10isize, -5isize));
assert_eq!(aabb.min(), &Point3::new(-20isize, -10isize, -5isize));
assert_eq!(aabb.max(), &Point3::new(10isize, 30isize, 5isize));
assert_eq!(aabb.dim(), Vector3::new(30isize, 40isize, 10isize));
assert_eq!(aabb.volume(), 30isize * 40isize * 10isize);
assert_eq!(aabb.center(), Point3::new(-5isize, 10isize, 0isize));
assert!(aabb.contains(&Point3::new(0isize, 0isize, 0isize)));
assert!(!aabb.contains(&Point3::new(-100isize, 0isize, 0isize)));
assert!(!aabb.contains(&Point3::new(100isize, 0isize, 0isize)));
assert!(aabb.contains(&Point3::new(9isize, 29isize, -1isize)));
assert!(!aabb.contains(&Point3::new(10isize, 30isize, 5isize)));
assert!(aabb.contains(&Point3::new(-20isize, -10isize, -5isize)));
assert!(!aabb.contains(&Point3::new(-21isize, -11isize, -6isize)));
assert_eq!(aabb.add_v(&Vector3::new(1isize, 2isize, 3isize)),
Aabb3::new(Point3::new(-19isize, 32isize, 8isize), Point3::new(11isize, -8isize, -2isize)));
assert_eq!(aabb.mul_s(2isize),
Aabb3::new(Point3::new(-40isize, -20isize, -10isize), Point3::new(20isize, 60isize, 10isize)));
assert_eq!(aabb.mul_v(&Vector3::new(1isize, 2isize, 3isize)),
Aabb3::new(Point3::new(-20isize, -20isize, -15isize), Point3::new(10isize, 60isize, 15isize)));
}
#[test]
fn test_ray_intersect() {
let aabb = Aabb2::new(Point2::new(-5.0f32, 5.0), Point2::new(5.0, 10.0));
let ray1 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(0.0, 1.0));
let ray2 = Ray::new(Point2::new(-10.0f32, 0.0), Vector2::new(2.5, 1.0));
let ray3 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(-1.0, -1.0));
let ray4 = Ray::new(Point2::new(3.0f32, 7.0), Vector2::new(1.0, 1.0));
assert_eq!((ray1, aabb).intersection(), Some(Point2::new(0.0, 5.0)));
assert_eq!((ray2, aabb).intersection(), Some(Point2::new(2.5, 5.0)));
assert_eq!((ray3, aabb).intersection(), None);
assert_eq!((ray4, aabb).intersection(), Some(Point2::new(5.0, 9.0)));
}
#[test]
fn test_corners() {
let corners = Aabb2::new(Point2::new(-5.0f32, 5.0), Point2::new(5.0, 10.0))
.to_corners();
assert!(corners.contains(&Point2::new(-5f32, 10.0)));
assert!(corners.contains(&Point2::new(5f32, 5.0)));
let corners = Aabb3::new(Point3::new(-20isize, 30isize, 5isize), Point3::new(10isize, -10isize, -5isize))
.to_corners();
assert!(corners.contains(&Point3::new(-20isize, 30isize, -5isize)));
assert!(corners.contains(&Point3::new(10isize, 30isize, 5isize)));
assert!(corners.contains(&Point3::new(10isize, -10isize, 5isize)));
}
#[test]
fn test_bound() {
let aabb = Aabb3::new(Point3::new(-5.0f32, 5.0, 0.0), Point3::new(5.0, 10.0, 1.0));
let plane1 = Plane::from_point_normal(Point3::new(0f32, 0.0, 0.0), Vector3::new(0f32, 0.0, 1.0));
let plane2 = Plane::from_point_normal(Point3::new(-5.0f32, 4.0, 0.0), Vector3::new(0f32, 1.0, 0.0));
let plane3 = Plane::from_point_normal(Point3::new(6.0f32, 0.0, 0.0), Vector3::new(1f32, 0.0, 0.0));
assert_eq!(aabb.relate_plane(&plane1), Relation::Cross);
assert_eq!(aabb.relate_plane(&plane2), Relation::In);
assert_eq!(aabb.relate_plane(&plane3), Relation::Out);
}

View file

@ -1,40 +0,0 @@
// Copyright 2015 The CGMath 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.
extern crate cgmath;
use cgmath::{PerspectiveFov, Point3, Projection, Relation, Sphere, rad};
#[test]
fn test_contains() {
let frustum = PerspectiveFov {
fovy: rad(1f32),
aspect: 1f32,
near: 1f32,
far: 10f32,
}.to_frustum();
assert_eq!(frustum.contains(&Sphere {
center: Point3::new(0f32, 0f32, -5f32),
radius: 1f32,
}), Relation::In);
assert_eq!(frustum.contains(&Sphere {
center: Point3::new(0f32, 3f32, -5f32),
radius: 1f32,
}), Relation::Cross);
assert_eq!(frustum.contains(&Sphere {
center: Point3::new(0f32, 0f32, 5f32),
radius: 1f32,
}), Relation::Out);
}

View file

@ -1,67 +0,0 @@
// 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.
extern crate cgmath;
use cgmath::*;
#[test]
fn test_line_intersection() {
// collinear, intersection is line dest
let r1 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(0.25, 0.0));
let l1 = Line::new(Point2::new(1.5f32, 0.0), Point2::new(0.5, 0.0));
assert_eq!((r1, l1).intersection(), Some(Point2::new(0.5, 0.0)));
// collinear, intersection is at ray origin
let r2 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(5.0, 0.0));
let l2 = Line::new(Point2::new(-11.0f32, 0.0), Point2::new(1.0, 0.0));
assert_eq!((r2, l2).intersection(), Some(Point2::new(0.0, 0.0)));
// collinear, intersection is line origin
let r3 = Ray::new(Point2::new(0.0f32, 1.0), Vector2::new(0.0, -0.25));
let l3 = Line::new(Point2::new(0.0f32, 0.5), Point2::new(0.0, -0.5));
assert_eq!((r3, l3).intersection(), Some(Point2::new(0.0, 0.5)));
// collinear, no overlap
let r4 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(3.0, 0.0));
let l4 = Line::new(Point2::new(-10.0f32, 0.0), Point2::new(-5.0, 0.0));
assert_eq!((r4, l4).intersection(), None);
// no intersection
let r5 = Ray::new(Point2::new(5.0f32, 5.0), Vector2::new(40.0, 8.0));
let l5 = Line::new(Point2::new(5.0f32, 4.8), Point2::new(10.0, 4.1));
assert_eq!((r5, l5).intersection(), None); // no intersection
// non-collinear intersection
let r6 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(10.0, 10.0));
let l6 = Line::new(Point2::new(0.0f32, 10.0), Point2::new(10.0, 0.0));
assert_eq!((r6, l6).intersection(), Some(Point2::new(5.0, 5.0)));
// line is a point that does not intersect
let r7 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 1.0));
let l7 = Line::new(Point2::new(1.0f32, 0.0), Point2::new(1.0, 0.0));
assert_eq!((r7, l7).intersection(), None);
// line is a point that does intersect
let r8 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 0.0));
let l8 = Line::new(Point2::new(3.0f32, 0.0), Point2::new(3.0, 0.0));
assert_eq!((r8, l8).intersection(), Some(Point2::new(3.0, 0.0)));
// line is a collinear point but no intersection
let r9 = Ray::new(Point2::new(0.0f32, 0.0), Vector2::new(1.0, 0.0));
let l9 = Line::new(Point2::new(-1.0f32, 0.0), Point2::new(-1.0, 0.0));
assert_eq!((r9, l9).intersection(), None);
}

View file

@ -1,45 +0,0 @@
// 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.
extern crate cgmath;
use cgmath::*;
#[test]
fn test_from_points() {
assert_eq!(Plane::from_points(Point3::new(5.0f64, 0.0f64, 5.0f64),
Point3::new(5.0f64, 5.0f64, 5.0f64),
Point3::new(5.0f64, 0.0f64, -1.0f64)),
Some(Plane::from_abcd(-1.0f64, 0.0f64, 0.0f64, 5.0f64)));
assert_eq!(Plane::from_points(Point3::new(0.0f64, 5.0f64, -5.0f64),
Point3::new(0.0f64, 5.0f64, 0.0f64),
Point3::new(0.0f64, 5.0f64, 5.0f64)),
None); // The points are parallel
}
#[test]
fn test_ray_intersection() {
let p0 = Plane::from_abcd(1f64, 0f64, 0f64, -7f64);
let r0: Ray3<f64> = Ray::new(Point3::new(2f64, 3f64, 4f64), Vector3::new(1f64, 1f64, 1f64).normalize());
assert_eq!((p0, r0).intersection(), Some(Point3::new(7f64, 8f64, 9f64)));
let p1 = Plane::from_points(Point3::new(5f64, 0f64, 5f64),
Point3::new(5f64, 5f64, 5f64),
Point3::new(5f64, 0f64, -1f64)).unwrap();
let r1: Ray3<f64> = Ray::new(Point3::new(0f64, 0f64, 0f64), Vector3::new(-1f64, 0f64, 0f64).normalize());
assert_eq!((p1, r1).intersection(), None); // r1 points away from p1
}

View file

@ -16,23 +16,11 @@
extern crate cgmath; extern crate cgmath;
use cgmath::{Point, Point3, Vector, Vector3}; use cgmath::Point3;
use cgmath::{Bound, Relation, Plane}; use cgmath::ApproxEq;
use cgmath::{ApproxEq};
#[test] #[test]
fn test_homogeneous() { fn test_homogeneous() {
let p = Point3::new(1.0f64, 2.0f64, 3.0f64); let p = Point3::new(1.0f64, 2.0f64, 3.0f64);
assert!(p.approx_eq(&Point3::from_homogeneous(&p.to_homogeneous()))); assert!(p.approx_eq(&Point3::from_homogeneous(&p.to_homogeneous())));
} }
#[test]
fn test_bound() {
let point = Point3::new(1f32, 2.0, 3.0);
let normal = Vector3::new(0f32, -0.8, -0.36);
let plane = Plane::from_point_normal(point, normal);
assert_eq!(point.relate_plane(&plane), Relation::Cross);
assert_eq!(point.add_v(&normal).relate_plane(&plane), Relation::In);
assert_eq!(point.add_v(&normal.mul_s(-1.0)).relate_plane(&plane), Relation::Out);
}

View file

@ -1,49 +0,0 @@
// Copyright 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.
extern crate cgmath;
use cgmath::*;
#[test]
fn test_intersection() {
let sphere = Sphere {center: Point3::new(0f64,0f64,0f64), radius: 1f64};
let r0 = Ray::new(Point3::new(0f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
let r1 = Ray::new(Point3::new(1f64.cos(), 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
let r2 = Ray::new(Point3::new(1f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
let r3 = Ray::new(Point3::new(2f64, 0f64, 5f64), Vector3::new(0f64, 0f64, -5f64).normalize());
assert_eq!((sphere,r0).intersection(), Some(Point3::new(0f64, 0f64, 1f64)));
assert!((sphere,r1).intersection().unwrap().approx_eq( &Point3::new(1f64.cos(), 0f64, 1f64.sin()) ));
assert_eq!((sphere,r2).intersection(), Some(Point3::new(1f64, 0f64, 0f64)));
assert_eq!((sphere,r3).intersection(), None);
}
#[test]
fn test_bound() {
let point = Point3::new(1f32, 2.0, 3.0);
let sphere = Sphere { center: point, radius: 1.0 };
let normal = vec3(0f32, 0.0, 1.0);
assert_eq!(sphere.relate_plane(
&Plane::from_point_normal(point, normal)
), Relation::Cross);
assert_eq!(sphere.relate_plane(
&Plane::from_point_normal(point.add_v(&normal.mul_s(-3.0)), normal),
), Relation::In);
assert_eq!(sphere.relate_plane(
&Plane::from_point_normal(point.add_v(&normal.mul_s(3.0)), normal),
), Relation::Out);
}