1use glam::{Vec3, Vec4, Vec4Swizzles};
2
3use crate::{
4 brush::{Face, FaceIntersect},
5 util::TOLERANCE,
6};
7
8#[derive(Debug, Copy, Clone)]
9pub struct Plane {
10 pub normal: Vec3,
11 pub distance: f32,
12}
13
14impl Plane {
15 pub fn new(normal: Vec3, distance: f32) -> Self {
16 Self { normal, distance }
17 }
18
19 pub fn from_face(face: Face) -> Self {
20 let normal = face.normal();
21 assert!(normal.is_finite());
22 let distance = face.p1.dot(normal);
23
24 Self { normal, distance }
25 }
26
27 pub fn distance_to_point(&self, point: Vec3) -> f32 {
28 point.dot(self.normal) - self.distance
29 }
30
31 pub fn intersect_ray(&self, ray_origin: Vec3, ray_direction: Vec3) -> Option<f32> {
32 let denom = self.normal.dot(ray_direction);
33 if denom.abs() > f32::EPSILON {
34 let t = (self.normal * self.distance - ray_origin).dot(self.normal) / denom;
35 if t >= 0.0 {
36 return Some(t);
37 }
38 }
39
40 None
41 }
42
43 pub fn classify_face(&self, face: Face) -> FaceIntersect {
44 let d1 = self.distance_to_point(face.p1);
45 let d2 = self.distance_to_point(face.p2);
46 let d3 = self.distance_to_point(face.p3);
47
48 if d1.abs() <= TOLERANCE && d2.abs() <= TOLERANCE && d3.abs() <= TOLERANCE {
49 if face.normal().dot(self.normal) > 0.0 {
50 return FaceIntersect::CoplanarFront;
51 } else {
52 return FaceIntersect::CoplanarBack;
53 }
54 }
55
56 if d1 >= -TOLERANCE && d2 >= -TOLERANCE && d3 >= -TOLERANCE {
57 FaceIntersect::Front
58 } else if d1 <= TOLERANCE && d2 <= TOLERANCE && d3 <= TOLERANCE {
59 FaceIntersect::Back
60 } else {
61 FaceIntersect::Intersect
62 }
63 }
64
65 pub fn split_face(
66 &self,
67 face: Face,
68 front_result: &mut Vec<Face>,
69 back_result: &mut Vec<Face>,
70 ) {
71 let mut front_count = 0;
72 let mut back_count = 0;
73 let mut coplanar_count = 0;
74
75 let mut front = [Vec4::NAN; 3];
76 let mut back = [Vec4::NAN; 3];
77 let mut coplanar = [Vec3::NAN; 3];
78
79 for p in face.points() {
80 let distance = self.distance_to_point(p);
81 if distance >= TOLERANCE {
82 front[front_count] = p.extend(distance);
83 front_count += 1;
84 } else if distance <= -TOLERANCE {
85 back[back_count] = p.extend(distance);
86 back_count += 1;
87 } else {
88 coplanar[coplanar_count] = p;
89 coplanar_count += 1;
90 }
91 }
92
93 let normal = face.normal();
94 let orient = |face: Face| {
95 if face.normal().dot(normal) < 0.0 {
96 Face::new(face.p3, face.p2, face.p1)
97 } else {
98 face
99 }
100 };
101
102 if coplanar_count == 1 {
103 assert_eq!(back_count, 1);
104 assert_eq!(front_count, 1);
105 let back = back[0];
106 let front = front[0];
107 let coplanar = coplanar[0];
108
109 let i1 = back.xyz().lerp(front.xyz(), back.w / (back.w - front.w));
110
111 front_result.push(orient(Face::new(coplanar, front.xyz(), i1)));
112 back_result.push(orient(Face::new(coplanar, i1, back.xyz())));
113 } else if front_count == 1 && back_count == 2 {
114 let f = front[0].xyz();
116
117 let back1 = back[0].xyz();
118 let back2 = back[1].xyz();
119
120 let i1 = f.lerp(back1, front[0].w / (front[0].w - back[0].w));
121 let i2 = f.lerp(back2, front[0].w / (front[0].w - back[1].w));
122
123 front_result.push(orient(Face::new(f, i1, i2)));
124 back_result.push(orient(Face::new(back1, back2, i1)));
125 back_result.push(orient(Face::new(i1, back2, i2)));
126 } else if front_count == 2 && back_count == 1 {
127 let b = back[0].xyz();
128 let front1 = front[0].xyz();
129 let front2 = front[1].xyz();
130
131 let t1 = back[0].w / (back[0].w - front[0].w);
133 let t2 = back[0].w / (back[0].w - front[1].w);
134
135 let i1 = b.lerp(front1, t1);
136 let i2 = b.lerp(front2, t2);
137
138 back_result.push(orient(Face::new(b, i1, i2)));
139 front_result.push(orient(Face::new(front1, front2, i1)));
140 front_result.push(orient(Face::new(i1, front2, i2)));
141 }
142 }
143
144 pub(crate) fn invert(&self) -> Self {
145 Self {
146 normal: -self.normal,
147 distance: -self.distance,
148 }
149 }
150}