1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use cgmath::{EuclideanSpace, Point3};
use cgmath::BaseFloat;
use cgmath::Matrix4;
use std::{cmp, fmt};
use frustum::Frustum;
use plane::Plane;
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialOrd, PartialEq)]
#[repr(u8)]
pub enum Relation {
In,
Cross,
Out,
}
pub trait PlaneBound<S: BaseFloat>: fmt::Debug {
fn relate_plane(&self, Plane<S>) -> Relation;
fn relate_clip_space(&self, projection: Matrix4<S>) -> Relation {
let frustum = match Frustum::from_matrix4(projection) {
Some(f) => f,
None => return Relation::Cross,
};
[
frustum.left,
frustum.right,
frustum.top,
frustum.bottom,
frustum.near,
frustum.far,
].iter()
.fold(Relation::In, |cur, p| {
let r = self.relate_plane(*p);
cmp::max(cur, r)
})
}
}
impl<S: BaseFloat> PlaneBound<S> for Point3<S> {
fn relate_plane(&self, plane: Plane<S>) -> Relation {
let dist = self.dot(plane.n);
if dist > plane.d {
Relation::In
} else if dist < plane.d {
Relation::Out
} else {
Relation::Cross
}
}
fn relate_clip_space(&self, projection: Matrix4<S>) -> Relation {
use std::cmp::Ordering::*;
let p = projection * self.to_homogeneous();
match (
p.x.abs().partial_cmp(&p.w),
p.y.abs().partial_cmp(&p.w),
p.z.abs().partial_cmp(&p.w),
) {
(Some(Less), Some(Less), Some(Less)) => Relation::In,
(Some(Greater), _, _) | (_, Some(Greater), _) | (_, _, Some(Greater)) => Relation::Out,
_ => Relation::Cross,
}
}
}