1use nalgebra::Vector3;
22
23#[derive(Copy, Clone, Debug, PartialEq)]
24pub struct Plane {
25 pub normal: Vector3<f32>,
26 pub d: f32,
27}
28
29impl Default for Plane {
30 #[inline]
31 fn default() -> Self {
32 Plane {
33 normal: Vector3::new(0.0, 1.0, 0.0),
34 d: 0.0,
35 }
36 }
37}
38
39impl Plane {
40 #[inline]
43 pub fn from_normal_and_point(normal: &Vector3<f32>, point: &Vector3<f32>) -> Option<Self> {
44 normal
45 .try_normalize(f32::EPSILON)
46 .map(|normalized_normal| Self {
47 normal: normalized_normal,
48 d: -point.dot(&normalized_normal),
49 })
50 }
51
52 #[inline]
55 pub fn from_triangle(a: &Vector3<f32>, b: &Vector3<f32>, c: &Vector3<f32>) -> Option<Self> {
56 let normal = (b - a).cross(&(c - a));
57 Self::from_normal_and_point(&normal, a)
58 }
59
60 #[inline]
63 pub fn from_abcd(a: f32, b: f32, c: f32, d: f32) -> Option<Self> {
64 let normal = Vector3::new(a, b, c);
65 let len = normal.norm();
66 if len == 0.0 {
67 None
68 } else {
69 let coeff = 1.0 / len;
70 Some(Self {
71 normal: normal.scale(coeff),
72 d: d * coeff,
73 })
74 }
75 }
76
77 #[inline]
78 pub fn dot(&self, point: &Vector3<f32>) -> f32 {
79 self.normal.dot(point) + self.d
80 }
81
82 #[inline]
83 pub fn distance(&self, point: &Vector3<f32>) -> f32 {
84 self.dot(point).abs()
85 }
86
87 #[inline]
89 pub fn project(&self, point: &Vector3<f32>) -> Vector3<f32> {
90 point - self.normal.scale(self.normal.dot(point) + self.d)
91 }
92
93 pub fn intersection_point(&self, b: &Plane, c: &Plane) -> Vector3<f32> {
95 let f = -1.0 / self.normal.dot(&b.normal.cross(&c.normal));
96
97 let v1 = b.normal.cross(&c.normal).scale(self.d);
98 let v2 = c.normal.cross(&self.normal).scale(b.d);
99 let v3 = self.normal.cross(&b.normal).scale(c.d);
100
101 (v1 + v2 + v3).scale(f)
102 }
103}
104
105#[cfg(test)]
106mod test {
107 use crate::plane::Plane;
108 use nalgebra::Vector3;
109
110 #[test]
111 fn plane_sanity_tests() {
112 let plane = Plane::from_normal_and_point(
114 &Vector3::new(0.0, 10.0, 0.0),
115 &Vector3::new(0.0, 3.0, 0.0),
116 );
117 assert!(plane.is_some());
118 let plane = plane.unwrap();
119 assert_eq!(plane.normal.x, 0.0);
120 assert_eq!(plane.normal.y, 1.0);
121 assert_eq!(plane.normal.z, 0.0);
122 assert_eq!(plane.d, -3.0);
123
124 let plane = Plane::from_normal_and_point(
126 &Vector3::new(0.0, 0.0, 0.0),
127 &Vector3::new(0.0, 0.0, 0.0),
128 );
129 assert!(plane.is_none());
130
131 let plane = Plane::from_abcd(0.0, 0.0, 0.0, 0.0);
132 assert!(plane.is_none())
133 }
134
135 #[test]
136 fn test_default_for_plane() {
137 assert_eq!(
138 Plane::default(),
139 Plane {
140 normal: Vector3::new(0.0, 1.0, 0.0),
141 d: 0.0,
142 }
143 );
144 }
145
146 #[test]
147 fn test_plane_from_abcd() {
148 assert_eq!(Plane::from_abcd(0.0, 0.0, 0.0, 0.0), None);
149 assert_eq!(
150 Plane::from_abcd(1.0, 1.0, 1.0, 0.0),
151 Some(Plane {
152 normal: Vector3::new(0.57735026, 0.57735026, 0.57735026),
153 d: 0.0
154 })
155 );
156 }
157
158 #[test]
159 fn test_plane_dot() {
160 let plane = Plane::from_normal_and_point(
161 &Vector3::new(0.0, 0.0, 1.0),
162 &Vector3::new(0.0, 0.0, 0.0),
163 );
164 assert!(plane.is_some());
165 assert_eq!(plane.unwrap().dot(&Vector3::new(1.0, 1.0, 1.0)), 1.0);
166 }
167
168 #[test]
169 fn test_plane_distance() {
170 let plane = Plane::from_normal_and_point(
171 &Vector3::new(0.0, 0.0, 1.0),
172 &Vector3::new(0.0, 0.0, 0.0),
173 );
174 assert!(plane.is_some());
175 assert_eq!(plane.unwrap().distance(&Vector3::new(0.0, 0.0, 0.0)), 0.0);
176 assert_eq!(plane.unwrap().distance(&Vector3::new(1.0, 0.0, 0.0)), 0.0);
177 assert_eq!(plane.unwrap().distance(&Vector3::new(0.0, 1.0, 0.0)), 0.0);
178 assert_eq!(plane.unwrap().distance(&Vector3::new(0.0, 0.0, 1.0)), 1.0);
179 }
180
181 #[test]
182 fn test_plane_intersection_point() {
183 let plane = Plane::from_normal_and_point(
184 &Vector3::new(0.0, 0.0, 1.0),
185 &Vector3::new(0.0, 0.0, 0.0),
186 );
187 let plane2 = Plane::from_normal_and_point(
188 &Vector3::new(0.0, 1.0, 0.0),
189 &Vector3::new(0.0, 0.0, 0.0),
190 );
191 let plane3 = Plane::from_normal_and_point(
192 &Vector3::new(1.0, 0.0, 0.0),
193 &Vector3::new(0.0, 0.0, 0.0),
194 );
195 assert!(plane.is_some());
196 assert!(plane2.is_some());
197 assert!(plane3.is_some());
198
199 assert_eq!(
200 plane
201 .unwrap()
202 .intersection_point(&plane2.unwrap(), &plane3.unwrap()),
203 Vector3::new(0.0, 0.0, 0.0)
204 );
205 }
206}