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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use crate::{Line, Point, Scalar, Vector};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
#[repr(C)]
pub struct Plane {
origin: Point<3>,
u: Vector<3>,
v: Vector<3>,
}
impl Plane {
pub fn from_parametric(
origin: impl Into<Point<3>>,
u: impl Into<Vector<3>>,
v: impl Into<Vector<3>>,
) -> Self {
let origin = origin.into();
let u = u.into();
let v = v.into();
Self { origin, u, v }
}
pub fn origin(&self) -> Point<3> {
self.origin
}
pub fn u(&self) -> Vector<3> {
self.u
}
pub fn v(&self) -> Vector<3> {
self.v
}
pub fn normal(&self) -> Vector<3> {
self.u().cross(&self.v()).normalize()
}
pub fn three_point_form(&self) -> [Point<3>; 3] {
let a = self.origin();
let b = self.origin() + self.u();
let c = self.origin() + self.v();
[a, b, c]
}
pub fn constant_normal_form(&self) -> (Scalar, Vector<3>) {
let normal = self.normal();
let distance = normal.dot(&self.origin().coords);
(distance, normal)
}
pub fn is_parallel_to_vector(&self, vector: &Vector<3>) -> bool {
self.normal().dot(vector) == Scalar::ZERO
}
pub fn project_point(&self, point: impl Into<Point<3>>) -> Point<2> {
let origin_to_point = point.into() - self.origin();
let coords = self.project_vector(origin_to_point);
Point { coords }
}
pub fn project_vector(&self, vector: impl Into<Vector<3>>) -> Vector<2> {
let m =
nalgebra::Matrix::<_, _, nalgebra::Const<3>, _>::from_columns(&[
self.u().to_na(),
self.v().to_na(),
self.normal().to_na(),
]);
let b = vector.into();
let x = m
.lu()
.solve(&b.to_na())
.expect("Expected matrix to be invertible");
Vector::from([x.x, x.y])
}
pub fn project_line(&self, line: &Line<3>) -> Line<2> {
let line_origin_in_plane = self.project_point(line.origin());
let line_direction_in_plane = self.project_vector(line.direction());
Line::from_origin_and_direction(
line_origin_in_plane,
line_direction_in_plane,
)
}
}
#[cfg(test)]
mod tests {
use crate::{Plane, Point, Vector};
#[test]
fn project_point() {
let plane =
Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [0., 1., 0.]);
assert_eq!(plane.project_point([2., 1., 2.]), Point::from([1., 0.]));
assert_eq!(plane.project_point([1., 2., 2.]), Point::from([0., 1.]));
}
#[test]
fn project_vector() {
let plane =
Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [0., 1., 0.]);
assert_eq!(plane.project_vector([1., 0., 1.]), Vector::from([1., 0.]));
assert_eq!(plane.project_vector([0., 1., 1.]), Vector::from([0., 1.]));
let plane =
Plane::from_parametric([1., 1., 1.], [1., 0., 0.], [1., 1., 0.]);
assert_eq!(plane.project_vector([0., 1., 0.]), Vector::from([-1., 1.]));
}
}