vox_geometry_rust/
plane3.rs

1/*
2 * // Copyright (c) 2021 Feng Yang
3 * //
4 * // I am making my contributions/submissions to this project solely in my
5 * // personal capacity and am not conveying any rights to any intellectual
6 * // property of any third parties.
7 */
8
9use crate::surface3::*;
10use crate::vector3::Vector3D;
11use crate::transform3::Transform3;
12use crate::bounding_box3::BoundingBox3D;
13use crate::ray3::Ray3D;
14use std::sync::{RwLock, Arc};
15
16///
17/// # 3-D plane geometry.
18///
19/// This class represents 3-D plane geometry which extends Surface3 by
20/// overriding surface-related queries.
21///
22pub struct Plane3 {
23    /// Plane normal.
24    pub normal: Vector3D,
25
26    /// Point that lies on the plane.
27    pub point: Vector3D,
28
29    /// data from surface3
30    pub surface_data: Surface3Data,
31}
32
33impl Plane3 {
34    /// Constructs a plane that crosses (0, 0) with surface normal (0, 1).
35    pub fn new_default(transform: Option<Transform3>,
36                       is_normal_flipped: Option<bool>) -> Plane3 {
37        return Plane3 {
38            normal: Vector3D::new(0.0, 1.0, 0.0),
39            point: Vector3D::new_default(),
40            surface_data: Surface3Data::new(transform, is_normal_flipped),
41        };
42    }
43
44    /// Constructs a plane that cross \p point with surface normal \p normal.
45    pub fn new(normal: Vector3D,
46               point: Vector3D,
47               transform: Option<Transform3>,
48               is_normal_flipped: Option<bool>) -> Plane3 {
49        return Plane3 {
50            normal,
51            point,
52            surface_data: Surface3Data::new(transform, is_normal_flipped),
53        };
54    }
55
56    /// Returns builder fox Plane3.
57    pub fn builder() -> Builder {
58        return Builder::new();
59    }
60}
61
62impl Surface3 for Plane3 {
63    fn closest_point_local(&self, other_point: &Vector3D) -> Vector3D {
64        let r = *other_point - self.point;
65        return r - self.normal * self.normal.dot(&r) + self.point;
66    }
67
68    fn bounding_box_local(&self) -> BoundingBox3D {
69        let eps = f64::EPSILON;
70        let dmax = f64::MAX;
71
72        return if f64::abs(self.normal.dot(&Vector3D::new(1.0, 0.0, 0.0)) - 1.0) < eps {
73            BoundingBox3D::new(self.point - Vector3D::new(0.0, dmax, dmax),
74                               self.point + Vector3D::new(0.0, dmax, dmax))
75        } else if f64::abs(self.normal.dot(&Vector3D::new(0.0, 1.0, 0.0)) - 1.0) < eps {
76            BoundingBox3D::new(self.point - Vector3D::new(dmax, 0.0, dmax),
77                               self.point + Vector3D::new(dmax, 0.0, dmax))
78        } else if f64::abs(self.normal.dot(&Vector3D::new(0.0, 0.0, 1.0)) - 1.0) < eps {
79            BoundingBox3D::new(self.point - Vector3D::new(dmax, dmax, 0.0),
80                               self.point + Vector3D::new(dmax, dmax, 0.0))
81        } else {
82            BoundingBox3D::new(Vector3D::new(dmax, dmax, dmax),
83                               Vector3D::new(dmax, dmax, dmax))
84        };
85    }
86
87    fn closest_intersection_local(&self, ray: &Ray3D) -> SurfaceRayIntersection3 {
88        let mut intersection = SurfaceRayIntersection3::new();
89        let d_dot_n = ray.direction.dot(&self.normal);
90
91        // Check if not parallel
92        if f64::abs(d_dot_n) > 0.0 {
93            let t = self.normal.dot(&(self.point - ray.origin)) / d_dot_n;
94            if t >= 0.0 {
95                intersection.is_intersecting = true;
96                intersection.distance = t;
97                intersection.point = ray.point_at(t);
98                intersection.normal = self.normal;
99            }
100        }
101
102        return intersection;
103    }
104
105    fn closest_normal_local(&self, _other_point: &Vector3D) -> Vector3D {
106        return self.normal;
107    }
108
109    fn intersects_local(&self, ray_local: &Ray3D) -> bool {
110        return f64::abs(ray_local.direction.dot(&self.normal)) > 0.0;
111    }
112
113    fn view(&self) -> &Surface3Data {
114        return &self.surface_data;
115    }
116}
117
118/// Shared pointer for the Plane3 type.
119pub type Plane3Ptr = Arc<RwLock<Plane3>>;
120
121///
122/// # Front-end to create Plane3 objects step by step.
123///
124pub struct Builder {
125    _normal: Vector3D,
126    _point: Vector3D,
127
128    _surface_data: Surface3Data,
129}
130
131impl Builder {
132    /// Returns builder with plane normal.
133    pub fn with_normal(&mut self, normal: Vector3D) -> &mut Self {
134        self._normal = normal;
135        return self;
136    }
137
138    /// Returns builder with point on the plane.
139    pub fn with_point(&mut self, point: Vector3D) -> &mut Self {
140        self._point = point;
141        return self;
142    }
143
144    /// Builds Plane3.
145    pub fn build(&mut self) -> Plane3 {
146        return Plane3::new(self._normal,
147                           self._point,
148                           Some(self._surface_data.transform.clone()),
149                           Some(self._surface_data.is_normal_flipped),
150        );
151    }
152
153    /// Builds shared pointer of Plane3 instance.
154    pub fn make_shared(&mut self) -> Plane3Ptr {
155        return Plane3Ptr::new(RwLock::new(self.build()));
156    }
157
158    /// constructor
159    pub fn new() -> Builder {
160        return Builder {
161            _normal: Vector3D::new(0.0, 1.0, 0.0),
162            _point: Vector3D::new_default(),
163            _surface_data: Surface3Data::new(None, None),
164        };
165    }
166}
167
168impl SurfaceBuilderBase3 for Builder {
169    fn view(&mut self) -> &mut Surface3Data {
170        return &mut self._surface_data;
171    }
172}