egml_core/operations/
surface.rs

1use crate::model::geometry::DirectPosition;
2use crate::operations::geometry::Geometry;
3use crate::util::plane::Plane;
4use nalgebra::Vector3;
5
6pub trait Surface: Geometry {
7    fn outer_boundary_points(&self) -> Vec<&DirectPosition>;
8
9    fn outer_boundary_lower_corner(&self) -> DirectPosition {
10        let x_min = self
11            .outer_boundary_points()
12            .iter()
13            .min_by(|a, b| a.x().partial_cmp(&b.x()).unwrap())
14            .unwrap()
15            .x();
16        let y_min = self
17            .outer_boundary_points()
18            .iter()
19            .min_by(|a, b| a.y().partial_cmp(&b.y()).unwrap())
20            .unwrap()
21            .y();
22        let z_min = self
23            .outer_boundary_points()
24            .iter()
25            .min_by(|a, b| a.z().partial_cmp(&b.z()).unwrap())
26            .unwrap()
27            .z();
28
29        DirectPosition::new(x_min, y_min, z_min).unwrap()
30    }
31
32    ///
33    /// See also <https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal#Newell.27s_Method>
34    fn normal(&self) -> Vector3<f64> {
35        let mut enclosed_boundary_points = self.outer_boundary_points();
36        enclosed_boundary_points.extend(self.outer_boundary_points().first());
37
38        let mut normal = Vector3::new(0.0, 0.0, 0.0);
39        for current_point_pair in enclosed_boundary_points.windows(2) {
40            let current_first_point: Vector3<f64> = current_point_pair[0].into();
41            let current_second_point: Vector3<f64> = current_point_pair[1].into();
42
43            normal += (current_first_point - current_second_point)
44                .cross(&(current_first_point + current_second_point));
45        }
46
47        normal.normalize()
48    }
49
50    fn plane_equation(&self) -> Plane {
51        Plane::new(self.outer_boundary_lower_corner(), self.normal()).unwrap()
52    }
53}