From 6691dce4209a6c769f5a9ac53aab9f1481430f47 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 14 Mar 2015 23:41:15 +0300 Subject: [PATCH] Added Bound::relate_clip_space with default implementation --- src/aabb.rs | 8 ++++---- src/bound.rs | 22 ++++++++++++++++------ src/frustum.rs | 2 +- src/point.rs | 15 +++++++++++++-- src/sphere.rs | 6 +++--- tests/aabb.rs | 8 ++++---- tests/point.rs | 6 +++--- tests/sphere.rs | 6 +++--- 8 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/aabb.rs b/src/aabb.rs index cf47d80..b0d1846 100644 --- a/src/aabb.rs +++ b/src/aabb.rs @@ -242,12 +242,12 @@ impl Intersect>> for (Ray2, Aabb2) { } } -impl Bound for Aabb3 { - fn relate(&self, plane: &Plane) -> Relation { +impl Bound for Aabb3 { + fn relate_plane(&self, plane: &Plane) -> Relation { let corners = self.to_corners(); - let first = corners[0].relate(plane); + let first = corners[0].relate_plane(plane); for p in corners[1..].iter() { - if p.relate(plane) != first { + if p.relate_plane(plane) != first { return Relation::Cross; } } diff --git a/src/bound.rs b/src/bound.rs index cc5ff56..4154ebf 100644 --- a/src/bound.rs +++ b/src/bound.rs @@ -15,22 +15,32 @@ //! 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 + /// Completely inside. In, - /// Crosses the boundary + /// Crosses the boundary. Cross, - /// Completely outside + /// Completely outside. Out, } /// Generic bound. -pub trait Bound { - /// Classify the spatial relation with a plane - fn relate(&self, &Plane) -> Relation; +pub trait Bound: Sized { + /// Classify the spatial relation with a plane. + fn relate_plane(&self, &Plane) -> Relation; + /// Classify the relation with a projection matrix. + fn relate_clip_space(&self, projection: &Matrix4) -> Relation { + use frustum::Frustum; + match Frustum::from_matrix4(*projection) { + Some(f) => f.contains(self), + None => Relation::Cross, + } + } } diff --git a/src/frustum.rs b/src/frustum.rs index 9cefe1a..2dc6c1d 100644 --- a/src/frustum.rs +++ b/src/frustum.rs @@ -71,7 +71,7 @@ Frustum { pub fn contains>(&self, bound: &B) -> Relation { [&self.left, &self.right, &self.top, &self.bottom, &self.near, &self.far] .iter().fold(Relation::In, |cur, p| { - let r = bound.relate(p); + let r = bound.relate_plane(p); // if we see Cross, then the result is Cross // if we see In, then we keep the old result // otherwise, take the current result diff --git a/src/point.rs b/src/point.rs index 6e2bf0d..ab854dd 100644 --- a/src/point.rs +++ b/src/point.rs @@ -24,6 +24,7 @@ use std::ops::*; use approx::ApproxEq; use array::{Array1, FixedArray}; use bound::*; +use matrix::{Matrix, Matrix4}; use num::{BaseNum, BaseFloat, one, zero}; use plane::Plane; use vector::*; @@ -448,8 +449,8 @@ impl fmt::Debug for Point3 { } } -impl Bound for Point3 { - fn relate(&self, plane: &Plane) -> Relation { +impl Bound for Point3 { + fn relate_plane(&self, plane: &Plane) -> Relation { let dist = self.dot(&plane.n); if dist > plane.d { Relation::In @@ -459,4 +460,14 @@ impl Bound for Point3 { Relation::Cross } } + + fn relate_clip_space(&self, projection: &Matrix4) -> 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, + } + } } diff --git a/src/sphere.rs b/src/sphere.rs index 519be4f..61565ac 100644 --- a/src/sphere.rs +++ b/src/sphere.rs @@ -17,7 +17,7 @@ use bound::*; use intersect::Intersect; -use num::{BaseNum, BaseFloat, zero}; +use num::{BaseFloat, zero}; use point::{Point, Point3}; use plane::Plane; use ray::Ray3; @@ -45,8 +45,8 @@ impl Intersect>> for (Sphere, Ray3) { } } -impl Bound for Sphere { - fn relate(&self, plane: &Plane) -> Relation { +impl Bound for Sphere { + fn relate_plane(&self, plane: &Plane) -> Relation { let dist = self.center.dot(&plane.n) - plane.d; if dist > self.radius { Relation::In diff --git a/tests/aabb.rs b/tests/aabb.rs index b21d238..41cf0db 100644 --- a/tests/aabb.rs +++ b/tests/aabb.rs @@ -8,7 +8,7 @@ // 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" BASisize, +// 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. @@ -99,7 +99,7 @@ fn test_bound() { 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(&plane1), Relation::Cross); - assert_eq!(aabb.relate(&plane2), Relation::In); - assert_eq!(aabb.relate(&plane3), Relation::Out); + assert_eq!(aabb.relate_plane(&plane1), Relation::Cross); + assert_eq!(aabb.relate_plane(&plane2), Relation::In); + assert_eq!(aabb.relate_plane(&plane3), Relation::Out); } diff --git a/tests/point.rs b/tests/point.rs index f67a5c0..5f65f3c 100644 --- a/tests/point.rs +++ b/tests/point.rs @@ -32,7 +32,7 @@ fn test_bound() { let normal = Vector3::new(0f32, -0.8, -0.36); let plane = Plane::from_point_normal(point, normal); - assert_eq!(point.relate(&plane), Relation::Cross); - assert_eq!(point.add_v(&normal).relate(&plane), Relation::In); - assert_eq!(point.add_v(&normal.mul_s(-1.0)).relate(&plane), Relation::Out); + 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); } diff --git a/tests/sphere.rs b/tests/sphere.rs index 4ab9af0..a3f61eb 100644 --- a/tests/sphere.rs +++ b/tests/sphere.rs @@ -38,13 +38,13 @@ fn test_bound() { let sphere = Sphere { center: point, radius: 1.0 }; let normal = vec3(0f32, 0.0, 1.0); - assert_eq!(sphere.relate( + assert_eq!(sphere.relate_plane( &Plane::from_point_normal(point, normal) ), Relation::Cross); - assert_eq!(sphere.relate( + assert_eq!(sphere.relate_plane( &Plane::from_point_normal(point.add_v(&normal.mul_s(-3.0)), normal), ), Relation::In); - assert_eq!(sphere.relate( + assert_eq!(sphere.relate_plane( &Plane::from_point_normal(point.add_v(&normal.mul_s(3.0)), normal), ), Relation::Out); }