commit
de2c03276d
12 changed files with 310 additions and 54 deletions
37
src/aabb.rs
37
src/aabb.rs
|
@ -20,11 +20,13 @@
|
||||||
//! dimension) where the slope of every line is either 0 or undefined. These
|
//! dimension) where the slope of every line is either 0 or undefined. These
|
||||||
//! are useful for very cheap collision detection.
|
//! are useful for very cheap collision detection.
|
||||||
|
|
||||||
|
use bound::*;
|
||||||
use point::{Point, Point2, Point3};
|
use point::{Point, Point2, Point3};
|
||||||
use vector::{Vector, Vector2, Vector3};
|
use vector::{Vector, Vector2, Vector3};
|
||||||
use ray::{Ray2};
|
use ray::{Ray2};
|
||||||
use intersect::Intersect;
|
use intersect::Intersect;
|
||||||
use num::{zero, one, BaseNum, BaseFloat};
|
use num::{zero, one, BaseNum, BaseFloat};
|
||||||
|
use plane::Plane;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::num::Float;
|
use std::num::Float;
|
||||||
|
|
||||||
|
@ -101,6 +103,15 @@ impl<S: BaseNum> Aabb2<S> {
|
||||||
p1.y.partial_max(p2.y)),
|
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> {
|
impl<S: BaseNum> Aabb<S, Vector2<S>, Point2<S>> for Aabb2<S> {
|
||||||
|
@ -148,6 +159,19 @@ impl<S: BaseNum> Aabb3<S> {
|
||||||
p1.z.partial_max(p2.z)),
|
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> {
|
impl<S: BaseNum> Aabb<S, Vector3<S>, Point3<S>> for Aabb3<S> {
|
||||||
|
@ -217,3 +241,16 @@ impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Aabb2<S>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
46
src/bound.rs
Normal file
46
src/bound.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,14 +16,15 @@
|
||||||
//! View frustum for visibility determination
|
//! View frustum for visibility determination
|
||||||
|
|
||||||
use array::Array2;
|
use array::Array2;
|
||||||
|
use bound::*;
|
||||||
use matrix::Matrix4;
|
use matrix::Matrix4;
|
||||||
use num::BaseFloat;
|
use num::BaseFloat;
|
||||||
use plane::Plane;
|
use plane::Plane;
|
||||||
use point::Point3;
|
use point::Point3;
|
||||||
use vector::{Vector, EuclideanVector};
|
use vector::{Vector, EuclideanVector};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Frustum<S> {
|
pub struct Frustum<S: BaseFloat> {
|
||||||
pub left: Plane<S>,
|
pub left: Plane<S>,
|
||||||
pub right: Plane<S>,
|
pub right: Plane<S>,
|
||||||
pub bottom: Plane<S>,
|
pub bottom: Plane<S>,
|
||||||
|
@ -34,7 +35,7 @@ pub struct Frustum<S> {
|
||||||
|
|
||||||
impl<S: BaseFloat + 'static>
|
impl<S: BaseFloat + 'static>
|
||||||
Frustum<S> {
|
Frustum<S> {
|
||||||
/// Constructs a frustum
|
/// Construct a frustum.
|
||||||
pub fn new(left: Plane<S>, right: Plane<S>,
|
pub fn new(left: Plane<S>, right: Plane<S>,
|
||||||
bottom: Plane<S>, top: Plane<S>,
|
bottom: Plane<S>, top: Plane<S>,
|
||||||
near: Plane<S>, far: Plane<S>) -> Frustum<S> {
|
near: Plane<S>, far: Plane<S>) -> Frustum<S> {
|
||||||
|
@ -48,14 +49,35 @@ Frustum<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts frustum planes from a projection matrix
|
/// Extract frustum planes from a projection matrix.
|
||||||
pub fn from_matrix4(mat: Matrix4<S>) -> Frustum<S> {
|
pub fn from_matrix4(mat: Matrix4<S>) -> Option<Frustum<S>> {
|
||||||
Frustum::new(Plane::from_vector4(mat.row(3).add_v(&mat.row(0)).normalize()),
|
Some(Frustum::new(
|
||||||
Plane::from_vector4(mat.row(3).sub_v(&mat.row(0)).normalize()),
|
match Plane::from_vector4_alt(mat.row(3).add_v(&mat.row(0))).normalize()
|
||||||
Plane::from_vector4(mat.row(3).add_v(&mat.row(1)).normalize()),
|
{ Some(p) => p, None => return None },
|
||||||
Plane::from_vector4(mat.row(3).sub_v(&mat.row(1)).normalize()),
|
match Plane::from_vector4_alt(mat.row(3).sub_v(&mat.row(0))).normalize()
|
||||||
Plane::from_vector4(mat.row(3).add_v(&mat.row(2)).normalize()),
|
{ Some(p) => p, None => return None },
|
||||||
Plane::from_vector4(mat.row(3).sub_v(&mat.row(2)).normalize()))
|
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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ pub use transform::*;
|
||||||
pub use projection::*;
|
pub use projection::*;
|
||||||
|
|
||||||
pub use aabb::*;
|
pub use aabb::*;
|
||||||
|
pub use bound::*;
|
||||||
pub use cylinder::Cylinder;
|
pub use cylinder::Cylinder;
|
||||||
pub use frustum::{Frustum, FrustumPoints};
|
pub use frustum::{Frustum, FrustumPoints};
|
||||||
pub use intersect::Intersect;
|
pub use intersect::Intersect;
|
||||||
|
@ -80,6 +81,7 @@ mod transform;
|
||||||
mod projection;
|
mod projection;
|
||||||
|
|
||||||
mod aabb;
|
mod aabb;
|
||||||
|
mod bound;
|
||||||
mod cylinder;
|
mod cylinder;
|
||||||
mod frustum;
|
mod frustum;
|
||||||
mod intersect;
|
mod intersect;
|
21
src/plane.rs
21
src/plane.rs
|
@ -17,7 +17,7 @@ use std::fmt;
|
||||||
|
|
||||||
use approx::ApproxEq;
|
use approx::ApproxEq;
|
||||||
use intersect::Intersect;
|
use intersect::Intersect;
|
||||||
use num::{BaseFloat, Zero, zero};
|
use num::{BaseFloat, one, Zero, zero};
|
||||||
use point::{Point, Point3};
|
use point::{Point, Point3};
|
||||||
use ray::Ray3;
|
use ray::Ray3;
|
||||||
use vector::{Vector3, Vector4};
|
use vector::{Vector3, Vector4};
|
||||||
|
@ -65,9 +65,13 @@ impl<S: BaseFloat> Plane<S> {
|
||||||
|
|
||||||
/// Construct a plane from the components of a four-dimensional vector
|
/// Construct a plane from the components of a four-dimensional vector
|
||||||
pub fn from_vector4(v: Vector4<S>) -> Plane<S> {
|
pub fn from_vector4(v: Vector4<S>) -> Plane<S> {
|
||||||
match v {
|
Plane { n: Vector3::new(v.x, v.y, v.z), d: v.w }
|
||||||
Vector4 { x, y, z, w } => Plane { n: Vector3::new(x, y, z), d: 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`
|
/// Constructs a plane that passes through the the three points `a`, `b` and `c`
|
||||||
|
@ -94,6 +98,15 @@ impl<S: BaseFloat> Plane<S> {
|
||||||
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
|
pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> {
|
||||||
Plane { n: n, d: p.dot(&n) }
|
Plane { n: n, d: p.dot(&n) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize a plane.
|
||||||
|
pub fn normalize(&self) -> Option<Plane<S>> {
|
||||||
|
if self.n.approx_eq(&zero()) { None }
|
||||||
|
else {
|
||||||
|
let denom = one::<S>() / 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>) {
|
impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) {
|
||||||
|
|
26
src/point.rs
26
src/point.rs
|
@ -23,7 +23,10 @@ use std::ops::*;
|
||||||
|
|
||||||
use approx::ApproxEq;
|
use approx::ApproxEq;
|
||||||
use array::{Array1, FixedArray};
|
use array::{Array1, FixedArray};
|
||||||
|
use bound::*;
|
||||||
|
use matrix::{Matrix, Matrix4};
|
||||||
use num::{BaseNum, BaseFloat, one, zero};
|
use num::{BaseNum, BaseFloat, one, zero};
|
||||||
|
use plane::Plane;
|
||||||
use vector::*;
|
use vector::*;
|
||||||
|
|
||||||
/// A point in 2-dimensional space.
|
/// A point in 2-dimensional space.
|
||||||
|
@ -445,3 +448,26 @@ impl<S: BaseNum> fmt::Debug for Point3<S> {
|
||||||
write!(f, "[{:?}, {:?}, {:?}]", self.x, self.y, self.z)
|
write!(f, "[{:?}, {:?}, {:?}]", self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ impl<S: BaseFloat, A: Angle<S>> PerspectiveFov<S, A> {
|
||||||
impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
|
impl<S: BaseFloat + 'static, A: Angle<S>> Projection<S> for PerspectiveFov<S, A> {
|
||||||
fn to_frustum(&self) -> Frustum<S> {
|
fn to_frustum(&self) -> Frustum<S> {
|
||||||
// TODO: Could this be faster?
|
// TODO: Could this be faster?
|
||||||
Frustum::from_matrix4(self.to_matrix4())
|
Frustum::from_matrix4(self.to_matrix4()).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ pub struct Perspective<S> {
|
||||||
impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
|
impl<S: BaseFloat + 'static> Projection<S> for Perspective<S> {
|
||||||
fn to_frustum(&self) -> Frustum<S> {
|
fn to_frustum(&self) -> Frustum<S> {
|
||||||
// TODO: Could this be faster?
|
// TODO: Could this be faster?
|
||||||
Frustum::from_matrix4(self.to_matrix4())
|
Frustum::from_matrix4(self.to_matrix4()).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
|
|
||||||
//! Bounding sphere
|
//! Bounding sphere
|
||||||
|
|
||||||
|
use bound::*;
|
||||||
use intersect::Intersect;
|
use intersect::Intersect;
|
||||||
use num::{BaseFloat, zero};
|
use num::{BaseFloat, zero};
|
||||||
use point::{Point, Point3};
|
use point::{Point, Point3};
|
||||||
|
use plane::Plane;
|
||||||
use ray::Ray3;
|
use ray::Ray3;
|
||||||
use vector::Vector;
|
use vector::Vector;
|
||||||
|
|
||||||
|
@ -42,3 +44,16 @@ impl<S: BaseFloat> Intersect<Option<Point3<S>>> for (Sphere<S>, Ray3<S>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,53 +19,54 @@ use cgmath::{Aabb, Aabb2, Aabb3};
|
||||||
use cgmath::{Point2, Point3};
|
use cgmath::{Point2, Point3};
|
||||||
use cgmath::{Vector2, Vector3};
|
use cgmath::{Vector2, Vector3};
|
||||||
use cgmath::{Ray, Intersect};
|
use cgmath::{Ray, Intersect};
|
||||||
|
use cgmath::{Plane, Bound, Relation};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_aabb() {
|
fn test_general() {
|
||||||
let aabb = Aabb2::new(Point2::new(-20is, 30is), Point2::new(10is, -10is));
|
let aabb = Aabb2::new(Point2::new(-20isize, 30isize), Point2::new(10isize, -10isize));
|
||||||
assert_eq!(aabb.min(), &Point2::new(-20is, -10is));
|
assert_eq!(aabb.min(), &Point2::new(-20isize, -10isize));
|
||||||
assert_eq!(aabb.max(), &Point2::new(10is, 30is));
|
assert_eq!(aabb.max(), &Point2::new(10isize, 30isize));
|
||||||
assert_eq!(aabb.dim(), Vector2::new(30is, 40is));
|
assert_eq!(aabb.dim(), Vector2::new(30isize, 40isize));
|
||||||
assert_eq!(aabb.volume(), 30is * 40is);
|
assert_eq!(aabb.volume(), 30isize * 40isize);
|
||||||
assert_eq!(aabb.center(), Point2::new(-5is, 10is));
|
assert_eq!(aabb.center(), Point2::new(-5isize, 10isize));
|
||||||
|
|
||||||
assert!(aabb.contains(&Point2::new(0is, 0is)));
|
assert!(aabb.contains(&Point2::new(0isize, 0isize)));
|
||||||
assert!(!aabb.contains(&Point2::new(-50is, -50is)));
|
assert!(!aabb.contains(&Point2::new(-50isize, -50isize)));
|
||||||
assert!(!aabb.contains(&Point2::new(50is, 50is)));
|
assert!(!aabb.contains(&Point2::new(50isize, 50isize)));
|
||||||
|
|
||||||
assert_eq!(aabb.grow(&Point2::new(0is, 0is)), aabb);
|
assert_eq!(aabb.grow(&Point2::new(0isize, 0isize)), aabb);
|
||||||
assert_eq!(aabb.grow(&Point2::new(100is, 100is)),
|
assert_eq!(aabb.grow(&Point2::new(100isize, 100isize)),
|
||||||
Aabb2::new(Point2::new(-20is, -10is), Point2::new(100is, 100is)));
|
Aabb2::new(Point2::new(-20isize, -10isize), Point2::new(100isize, 100isize)));
|
||||||
assert_eq!(aabb.grow(&Point2::new(-100is, -100is)),
|
assert_eq!(aabb.grow(&Point2::new(-100isize, -100isize)),
|
||||||
Aabb2::new(Point2::new(-100is, -100is), Point2::new(10is, 30is)));
|
Aabb2::new(Point2::new(-100isize, -100isize), Point2::new(10isize, 30isize)));
|
||||||
|
|
||||||
let aabb = Aabb3::new(Point3::new(-20is, 30is, 5is), Point3::new(10is, -10is, -5is));
|
let aabb = Aabb3::new(Point3::new(-20isize, 30isize, 5isize), Point3::new(10isize, -10isize, -5isize));
|
||||||
assert_eq!(aabb.min(), &Point3::new(-20is, -10is, -5is));
|
assert_eq!(aabb.min(), &Point3::new(-20isize, -10isize, -5isize));
|
||||||
assert_eq!(aabb.max(), &Point3::new(10is, 30is, 5is));
|
assert_eq!(aabb.max(), &Point3::new(10isize, 30isize, 5isize));
|
||||||
assert_eq!(aabb.dim(), Vector3::new(30is, 40is, 10is));
|
assert_eq!(aabb.dim(), Vector3::new(30isize, 40isize, 10isize));
|
||||||
assert_eq!(aabb.volume(), 30is * 40is * 10is);
|
assert_eq!(aabb.volume(), 30isize * 40isize * 10isize);
|
||||||
assert_eq!(aabb.center(), Point3::new(-5is, 10is, 0is));
|
assert_eq!(aabb.center(), Point3::new(-5isize, 10isize, 0isize));
|
||||||
|
|
||||||
assert!(aabb.contains(&Point3::new(0is, 0is, 0is)));
|
assert!(aabb.contains(&Point3::new(0isize, 0isize, 0isize)));
|
||||||
assert!(!aabb.contains(&Point3::new(-100is, 0is, 0is)));
|
assert!(!aabb.contains(&Point3::new(-100isize, 0isize, 0isize)));
|
||||||
assert!(!aabb.contains(&Point3::new(100is, 0is, 0is)));
|
assert!(!aabb.contains(&Point3::new(100isize, 0isize, 0isize)));
|
||||||
assert!(aabb.contains(&Point3::new(9is, 29is, -1is)));
|
assert!(aabb.contains(&Point3::new(9isize, 29isize, -1isize)));
|
||||||
assert!(!aabb.contains(&Point3::new(10is, 30is, 5is)));
|
assert!(!aabb.contains(&Point3::new(10isize, 30isize, 5isize)));
|
||||||
assert!(aabb.contains(&Point3::new(-20is, -10is, -5is)));
|
assert!(aabb.contains(&Point3::new(-20isize, -10isize, -5isize)));
|
||||||
assert!(!aabb.contains(&Point3::new(-21is, -11is, -6is)));
|
assert!(!aabb.contains(&Point3::new(-21isize, -11isize, -6isize)));
|
||||||
|
|
||||||
assert_eq!(aabb.add_v(&Vector3::new(1is, 2is, 3is)),
|
assert_eq!(aabb.add_v(&Vector3::new(1isize, 2isize, 3isize)),
|
||||||
Aabb3::new(Point3::new(-19is, 32is, 8is), Point3::new(11is, -8is, -2is)));
|
Aabb3::new(Point3::new(-19isize, 32isize, 8isize), Point3::new(11isize, -8isize, -2isize)));
|
||||||
|
|
||||||
assert_eq!(aabb.mul_s(2is),
|
assert_eq!(aabb.mul_s(2isize),
|
||||||
Aabb3::new(Point3::new(-40is, -20is, -10is), Point3::new(20is, 60is, 10is)));
|
Aabb3::new(Point3::new(-40isize, -20isize, -10isize), Point3::new(20isize, 60isize, 10isize)));
|
||||||
|
|
||||||
assert_eq!(aabb.mul_v(&Vector3::new(1is, 2is, 3is)),
|
assert_eq!(aabb.mul_v(&Vector3::new(1isize, 2isize, 3isize)),
|
||||||
Aabb3::new(Point3::new(-20is, -20is, -15is), Point3::new(10is, 60is, 15is)));
|
Aabb3::new(Point3::new(-20isize, -20isize, -15isize), Point3::new(10isize, 60isize, 15isize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_aabb_ray_intersect() {
|
fn test_ray_intersect() {
|
||||||
let aabb = Aabb2::new(Point2::new(-5.0f32, 5.0), Point2::new(5.0, 10.0));
|
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 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 ray2 = Ray::new(Point2::new(-10.0f32, 0.0), Vector2::new(2.5, 1.0));
|
||||||
|
@ -77,3 +78,28 @@ fn test_aabb_ray_intersect() {
|
||||||
assert_eq!((ray3, aabb).intersection(), None);
|
assert_eq!((ray3, aabb).intersection(), None);
|
||||||
assert_eq!((ray4, aabb).intersection(), Some(Point2::new(5.0, 9.0)));
|
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);
|
||||||
|
}
|
||||||
|
|
40
tests/frustum.rs
Normal file
40
tests/frustum.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// 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);
|
||||||
|
}
|
|
@ -16,11 +16,23 @@
|
||||||
|
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
|
|
||||||
use cgmath::Point3;
|
use cgmath::{Point, Point3, Vector, Vector3};
|
||||||
use cgmath::ApproxEq;
|
use cgmath::{Bound, Relation, Plane};
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -31,3 +31,20 @@ fn test_intersection() {
|
||||||
assert_eq!((sphere,r2).intersection(), Some(Point3::new(1f64, 0f64, 0f64)));
|
assert_eq!((sphere,r2).intersection(), Some(Point3::new(1f64, 0f64, 0f64)));
|
||||||
assert_eq!((sphere,r3).intersection(), None);
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue