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.
|
||||
|
||||
use intersect::Intersect;
|
||||
use point::Point3;
|
||||
use point::{Point, Point3};
|
||||
use ray::Ray3;
|
||||
use vector::Vec3;
|
||||
use vector::{Vector, EuclideanVector, Vec3};
|
||||
|
||||
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
|
||||
///
|
||||
/// - `normal`: the normal of the plane where:
|
||||
/// - `normal.x`: corresponds to `A` in the plane equation
|
||||
/// - `normal.y`: corresponds to `B` in the plane equation
|
||||
/// - `normal.z`: corresponds to `C` in the plane equation
|
||||
/// - `distance`: the distance value, corresponding to `D` in the plane equation
|
||||
/// - `n`: a unit vector representing the normal of the plane where:
|
||||
/// - `n.x`: corresponds to `A` in the plane equation
|
||||
/// - `n.y`: corresponds to `B` in the plane equation
|
||||
/// - `n.z`: corresponds to `C` 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)]
|
||||
pub struct Plane<S> {
|
||||
normal: Vec3<S>,
|
||||
distance: S,
|
||||
n: Vec3<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>) {
|
||||
|
@ -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> {
|
||||
fn to_str(&self) -> ~str {
|
||||
format!("{:f}x + {:f}y + {:f}z + {:f} = 0",
|
||||
self.normal.x,
|
||||
self.normal.y,
|
||||
self.normal.z,
|
||||
self.distance)
|
||||
impl<S: Float> ApproxEq<S> for Plane<S> {
|
||||
#[inline]
|
||||
fn approx_epsilon() -> S {
|
||||
// TODO: fix this after static methods are fixed in rustc
|
||||
fail!(~"Doesn't work!");
|
||||
}
|
||||
|
||||
#[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 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)
|
||||
|
|
Loading…
Reference in a new issue