1use crate::{Point, Vector, Xform};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(tag = "type", rename = "Plane")]
7pub struct Plane {
8 pub guid: String,
9 pub name: String,
10 #[serde(rename = "origin")]
11 _origin: Point,
12 #[serde(rename = "x_axis")]
13 _x_axis: Vector,
14 #[serde(rename = "y_axis")]
15 _y_axis: Vector,
16 #[serde(rename = "z_axis")]
17 _z_axis: Vector,
18 #[serde(rename = "a")]
19 _a: f32,
20 #[serde(rename = "b")]
21 _b: f32,
22 #[serde(rename = "c")]
23 _c: f32,
24 #[serde(rename = "d")]
25 _d: f32,
26 #[serde(default = "Xform::identity")]
27 pub xform: Xform,
28}
29
30impl Default for Plane {
31 fn default() -> Self {
32 Self {
33 guid: Uuid::new_v4().to_string(),
34 name: "my_plane".to_string(),
35 _origin: Point::default(),
36 _x_axis: Vector::x_axis(),
37 _y_axis: Vector::y_axis(),
38 _z_axis: Vector::z_axis(),
39 _a: 0.0,
40 _b: 0.0,
41 _c: 1.0,
42 _d: 0.0,
43 xform: Xform::identity(),
44 }
45 }
46}
47
48impl Plane {
49 pub fn new(point: Point, mut x_axis: Vector, mut y_axis: Vector) -> Self {
50 x_axis.normalize_self();
51 let dot_product = y_axis.dot(&x_axis);
52 y_axis -= x_axis.clone() * dot_product;
53 y_axis.normalize_self();
54 let mut z_axis = x_axis.cross(&y_axis);
55 z_axis.normalize_self();
56
57 let a = z_axis.x();
58 let b = z_axis.y();
59 let c = z_axis.z();
60 let d = -(a * point.x() + b * point.y() + c * point.z());
61
62 Self {
63 guid: Uuid::new_v4().to_string(),
64 name: "my_plane".to_string(),
65 _origin: point,
66 _x_axis: x_axis,
67 _y_axis: y_axis,
68 _z_axis: z_axis,
69 _a: a,
70 _b: b,
71 _c: c,
72 _d: d,
73 xform: Xform::identity(),
74 }
75 }
76
77 pub fn with_name(point: Point, mut x_axis: Vector, mut y_axis: Vector, name: String) -> Self {
78 x_axis.normalize_self();
79 let dot_product = y_axis.dot(&x_axis);
80 y_axis -= x_axis.clone() * dot_product;
81 y_axis.normalize_self();
82 let mut z_axis = x_axis.cross(&y_axis);
83 z_axis.normalize_self();
84
85 let a = z_axis.x();
86 let b = z_axis.y();
87 let c = z_axis.z();
88 let d = -(a * point.x() + b * point.y() + c * point.z());
89
90 Self {
91 guid: Uuid::new_v4().to_string(),
92 name,
93 _origin: point,
94 _x_axis: x_axis,
95 _y_axis: y_axis,
96 _z_axis: z_axis,
97 _a: a,
98 _b: b,
99 _c: c,
100 _d: d,
101 xform: Xform::identity(),
102 }
103 }
104
105 pub fn from_point_normal(point: Point, normal: Vector) -> Self {
106 let origin = point.clone();
107 let mut z_axis = normal;
108 z_axis.normalize_self();
109 let mut x_axis = Vector::default();
110 x_axis.perpendicular_to(&z_axis);
111 x_axis.normalize_self();
112 let mut y_axis = z_axis.cross(&x_axis);
113 y_axis.normalize_self();
114
115 let a = z_axis.x();
116 let b = z_axis.y();
117 let c = z_axis.z();
118 let d = -(a * origin.x() + b * origin.y() + c * origin.z());
119
120 Self {
121 guid: Uuid::new_v4().to_string(),
122 name: "my_plane".to_string(),
123 _origin: origin,
124 _x_axis: x_axis,
125 _y_axis: y_axis,
126 _z_axis: z_axis,
127 _a: a,
128 _b: b,
129 _c: c,
130 _d: d,
131 xform: Xform::identity(),
132 }
133 }
134
135 pub fn from_points(points: Vec<Point>) -> Self {
136 if points.len() < 3 {
137 return Self::default();
138 }
139
140 let point1 = &points[0];
141 let point2 = &points[1];
142 let point3 = &points[2];
143 let v1 = point2.clone() - point1.clone();
144 let v2 = point3.clone() - point1.clone();
145 let mut z_axis = v1.cross(&v2);
146 z_axis.normalize_self();
147 let mut x_axis = Vector::default();
148 x_axis.perpendicular_to(&z_axis);
149 x_axis.normalize_self();
150 let mut y_axis = z_axis.cross(&x_axis);
151 y_axis.normalize_self();
152 let origin = point1.clone();
153
154 let a = z_axis.x();
155 let b = z_axis.y();
156 let c = z_axis.z();
157 let d = -(a * origin.x() + b * origin.y() + c * origin.z());
158
159 Self {
160 guid: Uuid::new_v4().to_string(),
161 name: "my_plane".to_string(),
162 _origin: origin,
163 _x_axis: x_axis,
164 _y_axis: y_axis,
165 _z_axis: z_axis,
166 _a: a,
167 _b: b,
168 _c: c,
169 _d: d,
170 xform: Xform::identity(),
171 }
172 }
173
174 pub fn from_two_points(point1: Point, point2: Point) -> Self {
175 let origin = point1.clone();
176
177 let mut direction = point2.clone() - point1.clone();
178 direction.normalize_self();
179 let mut z_axis = Vector::default();
180 z_axis.perpendicular_to(&direction);
181 z_axis.normalize_self();
182
183 let x_axis = direction;
184 let mut y_axis = z_axis.cross(&x_axis);
185 y_axis.normalize_self();
186
187 let a = z_axis.x();
188 let b = z_axis.y();
189 let c = z_axis.z();
190 let d = -(a * origin.x() + b * origin.y() + c * origin.z());
191
192 Self {
193 guid: Uuid::new_v4().to_string(),
194 name: "my_plane".to_string(),
195 _origin: origin,
196 _x_axis: x_axis,
197 _y_axis: y_axis,
198 _z_axis: z_axis,
199 _a: a,
200 _b: b,
201 _c: c,
202 _d: d,
203 xform: Xform::identity(),
204 }
205 }
206
207 pub fn xy_plane() -> Self {
208 Self {
209 guid: Uuid::new_v4().to_string(),
210 name: "xy_plane".to_string(),
211 _origin: Point::new(0.0, 0.0, 0.0),
212 _x_axis: Vector::x_axis(),
213 _y_axis: Vector::y_axis(),
214 _z_axis: Vector::z_axis(),
215 _a: 0.0,
216 _b: 0.0,
217 _c: 1.0,
218 _d: 0.0,
219 xform: Xform::identity(),
220 }
221 }
222
223 pub fn yz_plane() -> Self {
224 Self {
225 guid: Uuid::new_v4().to_string(),
226 name: "yz_plane".to_string(),
227 _origin: Point::new(0.0, 0.0, 0.0),
228 _x_axis: Vector::y_axis(),
229 _y_axis: Vector::z_axis(),
230 _z_axis: Vector::x_axis(),
231 _a: 1.0,
232 _b: 0.0,
233 _c: 0.0,
234 _d: 0.0,
235 xform: Xform::identity(),
236 }
237 }
238
239 pub fn xz_plane() -> Self {
240 Self {
241 guid: Uuid::new_v4().to_string(),
242 name: "xz_plane".to_string(),
243 _origin: Point::new(0.0, 0.0, 0.0),
244 _x_axis: Vector::x_axis(),
245 _y_axis: Vector::new(0.0, 0.0, -1.0),
246 _z_axis: Vector::new(0.0, 1.0, 0.0),
247 _a: 0.0,
248 _b: 1.0,
249 _c: 0.0,
250 _d: 0.0,
251 xform: Xform::identity(),
252 }
253 }
254
255 pub fn origin(&self) -> Point {
256 self._origin.clone()
257 }
258
259 pub fn x_axis(&self) -> Vector {
260 self._x_axis.clone()
261 }
262
263 pub fn y_axis(&self) -> Vector {
264 self._y_axis.clone()
265 }
266
267 pub fn z_axis(&self) -> Vector {
268 self._z_axis.clone()
269 }
270
271 pub fn a(&self) -> f32 {
272 self._a
273 }
274
275 pub fn b(&self) -> f32 {
276 self._b
277 }
278
279 pub fn c(&self) -> f32 {
280 self._c
281 }
282
283 pub fn d(&self) -> f32 {
284 self._d
285 }
286
287 pub fn reverse(&mut self) {
288 std::mem::swap(&mut self._x_axis, &mut self._y_axis);
289 self._z_axis.reverse();
290
291 self._a = self._z_axis.x();
292 self._b = self._z_axis.y();
293 self._c = self._z_axis.z();
294 self._d =
295 -(self._a * self._origin.x() + self._b * self._origin.y() + self._c * self._origin.z());
296 }
297
298 pub fn rotate(&mut self, angles_in_radians: f32) {
299 let cos_angle = angles_in_radians.cos();
300 let sin_angle = angles_in_radians.sin();
301
302 let new_x = self._x_axis.clone() * cos_angle + self._y_axis.clone() * sin_angle;
303 let new_y = self._y_axis.clone() * cos_angle - self._x_axis.clone() * sin_angle;
304
305 self._x_axis = new_x;
306 self._y_axis = new_y;
307
308 self._a = self._z_axis.x();
309 self._b = self._z_axis.y();
310 self._c = self._z_axis.z();
311 self._d =
312 -(self._a * self._origin.x() + self._b * self._origin.y() + self._c * self._origin.z());
313 }
314
315 pub fn is_right_hand(&self) -> bool {
316 let x_copy = self._x_axis.clone();
317 let y_copy = self._y_axis.clone();
318 let z_copy = self._z_axis.clone();
319 let cross = x_copy.cross(&y_copy);
320 let dot_product = cross.dot(&z_copy);
321 dot_product > 0.999
322 }
323
324 pub fn is_same_direction(plane0: &Plane, plane1: &Plane, can_be_flipped: bool) -> bool {
325 let n0 = plane0._z_axis.clone();
326 let n1 = plane1._z_axis.clone();
327
328 let parallel = n0.is_parallel_to(&n1);
329
330 if can_be_flipped {
331 parallel != 0
332 } else {
333 parallel == 1
334 }
335 }
336
337 pub fn is_same_position(plane0: &Plane, plane1: &Plane) -> bool {
338 let dist0 = (plane0._a * plane1._origin.x()
339 + plane0._b * plane1._origin.y()
340 + plane0._c * plane1._origin.z()
341 + plane0._d)
342 .abs();
343
344 let dist1 = (plane1._a * plane0._origin.x()
345 + plane1._b * plane0._origin.y()
346 + plane1._c * plane0._origin.z()
347 + plane1._d)
348 .abs();
349
350 let tolerance = crate::tolerance::Tolerance::ZERO_TOLERANCE as f32;
351 dist0 < tolerance && dist1 < tolerance
352 }
353
354 pub fn is_coplanar(plane0: &Plane, plane1: &Plane, can_be_flipped: bool) -> bool {
355 Self::is_same_direction(plane0, plane1, can_be_flipped)
356 && Self::is_same_position(plane0, plane1)
357 }
358}
359
360impl std::ops::Index<usize> for Plane {
361 type Output = Vector;
362
363 fn index(&self, index: usize) -> &Self::Output {
364 match index {
365 0 => &self._x_axis,
366 1 => &self._y_axis,
367 _ => &self._z_axis,
368 }
369 }
370}
371
372impl std::ops::IndexMut<usize> for Plane {
373 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
374 match index {
375 0 => &mut self._x_axis,
376 1 => &mut self._y_axis,
377 _ => &mut self._z_axis,
378 }
379 }
380}
381
382impl std::ops::AddAssign<Vector> for Plane {
383 fn add_assign(&mut self, other: Vector) {
384 self._origin += other;
385 self._d =
386 -(self._a * self._origin.x() + self._b * self._origin.y() + self._c * self._origin.z());
387 }
388}
389
390impl std::ops::SubAssign<Vector> for Plane {
391 fn sub_assign(&mut self, other: Vector) {
392 self._origin -= other;
393 self._d =
394 -(self._a * self._origin.x() + self._b * self._origin.y() + self._c * self._origin.z());
395 }
396}
397
398impl std::ops::Add<Vector> for Plane {
399 type Output = Plane;
400
401 fn add(self, other: Vector) -> Plane {
402 let mut result = self.clone();
403 result += other;
404 result
405 }
406}
407
408impl std::ops::Sub<Vector> for Plane {
409 type Output = Plane;
410
411 fn sub(self, other: Vector) -> Plane {
412 let mut result = self.clone();
413 result -= other;
414 result
415 }
416}
417
418impl PartialEq<Point> for Plane {
419 fn eq(&self, other: &Point) -> bool {
420 self._origin == *other
421 }
422}
423
424impl Plane {
425 pub fn translate_by_normal(&self, distance: f64) -> Plane {
427 let mut normal = self._z_axis.clone();
428 normal.normalize_self();
429
430 let new_origin = self._origin.clone() + (normal * distance as f32);
431
432 Plane::new(new_origin, self._x_axis.clone(), self._y_axis.clone())
433 }
434}
435
436impl std::fmt::Display for Plane {
437 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
438 write!(
439 f,
440 "Plane(origin={}, x_axis={}, y_axis={}, z_axis={}, guid={}, name={})",
441 self._origin, self._x_axis, self._y_axis, self._z_axis, self.guid, self.name
442 )
443 }
444}
445
446impl Plane {
447 pub fn jsondump(&self) -> Result<String, Box<dyn std::error::Error>> {
448 Ok(serde_json::to_string_pretty(self)?)
449 }
450
451 pub fn jsonload(json_data: &str) -> Result<Self, Box<dyn std::error::Error>> {
452 Ok(serde_json::from_str(json_data)?)
453 }
454}
455
456#[cfg(test)]
457#[path = "plane_test.rs"]
458mod plane_test;