session_rust/
plane.rs

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    /// Translate (move) a plane along its normal direction by a specified distance
426    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;