1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors, // refer to the Cargo.toml file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // 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" 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. use std::fmt; use cgmath::{ApproxEq, BaseFloat}; use cgmath::{Point3}; use cgmath::{Vector3, Vector4}; use cgmath::{EuclideanSpace, InnerSpace}; use cgmath::{Zero}; /// A 3-dimensional plane formed from the equation: `A*x + B*y + C*z - D = 0`. /// /// # Fields /// /// - `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). #[derive(Copy, Clone, PartialEq)] pub struct Plane<S> { pub n: Vector3<S>, pub d: S, } impl<S: BaseFloat> Plane<S> { /// Construct a plane from a normal vector and a scalar distance. The /// plane will be perpendicular to `n`, and `d` units offset from the /// origin. pub fn new(n: Vector3<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: Vector3::new(a, b, c), d: d } } /// Construct a plane from the components of a four-dimensional vector pub fn from_vector4(v: Vector4<S>) -> Plane<S> { Plane { n: Vector3::new(v.x, v.y, v.z), d: v.w } } /// Construct a plane from the components of a four-dimensional vector /// Assuming alternative representation: `A*x + B*y + C*z + D = 0` pub fn from_vector4_alt(v: Vector4<S>) -> Plane<S> { Plane { n: Vector3::new(v.x, v.y, v.z), d: -v.w } } /// 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 - a; let v1 = c - a; // find the normal vector that is perpendicular to v1 and v2 let n = v0.cross(v1); if n.approx_eq(&Vector3::zero()) { None } else { // compute the normal and the distance to the plane let n = n.normalize(); let d = -a.dot(n); Some(Plane::new(n, d)) } } /// Construct a plane from a point and a normal vector. /// The plane will contain the point `p` and be perpendicular to `n`. pub fn from_point_normal(p: Point3<S>, n: Vector3<S>) -> Plane<S> { Plane { n: n, d: p.dot(n) } } /// Normalize a plane. pub fn normalize(&self) -> Option<Plane<S>> { if self.n.approx_eq(&Vector3::zero()) { None } else { let denom = S::one() / self.n.magnitude(); Some(Plane::new(self.n * denom, self.d*denom)) } } } impl<S> ApproxEq for Plane<S> where S: BaseFloat + ApproxEq<Epsilon=S> { type Epsilon = S; #[inline] fn approx_eq_eps(&self, other: &Plane<S>, epsilon: &S) -> bool { self.n.approx_eq_eps(&other.n, epsilon) && self.d.approx_eq_eps(&other.d, epsilon) } } impl<S: BaseFloat> fmt::Debug for Plane<S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}x + {:?}y + {:?}z - {:?} = 0", self.n.x, self.n.y, self.n.z, self.d) } }