Add Plane::from_points constructor and impl ApproxEq for Plane
This commit is contained in:
parent
d2dcd51428
commit
8519e0fb8e
2 changed files with 85 additions and 17 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue