Added Bound::relate_clip_space with default implementation

This commit is contained in:
Dzmitry Malyshau 2015-03-14 23:41:15 +03:00
parent fa3aacafcf
commit 6691dce420
8 changed files with 47 additions and 26 deletions

View file

@ -242,12 +242,12 @@ impl<S: BaseFloat> Intersect<Option<Point2<S>>> for (Ray2<S>, Aabb2<S>) {
}
}
impl<S: BaseNum> Bound<S> for Aabb3<S> {
fn relate(&self, plane: &Plane<S>) -> Relation {
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);
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;
}
}

View file

@ -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<S> {
/// Classify the spatial relation with a plane
fn relate(&self, &Plane<S>) -> Relation;
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

@ -71,7 +71,7 @@ Frustum<S> {
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| {
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

View file

@ -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<S: BaseNum> fmt::Debug for Point3<S> {
}
}
impl<S: BaseNum> Bound<S> for Point3<S> {
fn relate(&self, plane: &Plane<S>) -> Relation {
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
@ -459,4 +460,14 @@ impl<S: BaseNum> Bound<S> for Point3<S> {
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,
}
}
}

View file

@ -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<S: BaseFloat> Intersect<Option<Point3<S>>> for (Sphere<S>, Ray3<S>) {
}
}
impl<S: BaseNum> Bound<S> for Sphere<S> {
fn relate(&self, plane: &Plane<S>) -> Relation {
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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}