Add Plane::from_points constructor and impl ApproxEq for Plane

This commit is contained in:
Brendan Zabarauskas 2013-09-18 11:36:41 +10:00
parent d2dcd51428
commit 8519e0fb8e
2 changed files with 85 additions and 17 deletions

View file

@ -14,25 +14,67 @@
// limitations under the License. // limitations under the License.
use intersect::Intersect; use intersect::Intersect;
use point::Point3; use point::{Point, Point3};
use ray::Ray3; use ray::Ray3;
use vector::Vec3; use vector::{Vector, EuclideanVector, Vec3};
use std::fmt; use std::fmt;
/// A 3-dimendional plane formed from the equation: `Ax + Bx + Cx + D = 0` /// A 3-dimendional plane formed from the equation: `a*x + b*y + c*z - d = 0`.
/// ///
/// # Fields /// # Fields
/// ///
/// - `normal`: the normal of the plane where: /// - `n`: a unit vector representing the normal of the plane where:
/// - `normal.x`: corresponds to `A` in the plane equation /// - `n.x`: corresponds to `A` in the plane equation
/// - `normal.y`: corresponds to `B` in the plane equation /// - `n.y`: corresponds to `B` in the plane equation
/// - `normal.z`: corresponds to `C` in the plane equation /// - `n.z`: corresponds to `C` in the plane equation
/// - `distance`: the distance value, corresponding to `D` 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).
#[deriving(Clone, Eq)] #[deriving(Clone, Eq)]
pub struct Plane<S> { pub struct Plane<S> {
normal: Vec3<S>, n: Vec3<S>,
distance: S, d: S,
}
impl<S: Float> Plane<S> {
/// Construct a plane from a normal vector and a scalar distance
pub fn new(n: Vec3<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: Vec3::new(a, b, c), d: d }
}
/// 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(&Vec3::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))
}
}
} }
impl<S: Float> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) { impl<S: Float> Intersect<Option<Point3<S>>> for (Plane<S>, Ray3<S>) {
@ -53,12 +95,32 @@ impl<S: Float> Intersect<Option<Point3<S>>> for (Plane<S>, Plane<S>, Plane<S>) {
} }
} }
impl<S: Clone + fmt::Float> ToStr for Plane<S> { impl<S: Float> ApproxEq<S> for Plane<S> {
fn to_str(&self) -> ~str { #[inline]
format!("{:f}x + {:f}y + {:f}z + {:f} = 0", fn approx_epsilon() -> S {
self.normal.x, // TODO: fix this after static methods are fixed in rustc
self.normal.y, fail!(~"Doesn't work!");
self.normal.z, }
self.distance)
#[inline]
fn approx_eq(&self, other: &Plane<S>) -> bool {
self.n.approx_eq(&other.n) &&
self.d.approx_eq(&other.d)
}
#[inline]
fn approx_eq_eps(&self, other: &Plane<S>, approx_epsilon: &S) -> bool {
self.n.approx_eq_eps(&other.n, approx_epsilon) &&
self.d.approx_eq_eps(&other.d, approx_epsilon)
}
}
impl<S: Clone + fmt::Float> ToStr for Plane<S> {
fn to_str(&self) -> ~str {
format!("{:f}x + {:f}y + {:f}z - {:f} = 0",
self.n.x,
self.n.y,
self.n.z,
self.d)
} }
} }

View file

@ -74,6 +74,12 @@ pub trait Point
#[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) } #[inline] fn rem_self_s(&mut self, s: S) { self.each_mut(|_, x| *x = x.rem(&s)) }
#[inline] fn add_self_v(&mut self, other: &V) { self.each_mut(|i, x| *x = x.add(other.i(i))) } #[inline] fn add_self_v(&mut self, other: &V) { self.each_mut(|i, x| *x = x.add(other.i(i))) }
/// This is a weird one, but its useful for plane calculations
#[inline]
fn dot(&self, v: &V) -> S {
build::<S, Slice, V>(|i| self.i(i).mul(v.i(i))).comp_add()
}
} }
array!(impl<S> Point2<S> -> [S, ..2] _2) array!(impl<S> Point2<S> -> [S, ..2] _2)