1use std::{f32::consts::FRAC_1_SQRT_2, fmt};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Vec2(pub f32, pub f32);
8
9#[derive(Debug, Clone, Copy, PartialEq)]
14pub struct Rotation3 {
15 xyzw: [f32; 4],
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
20pub struct Vec3(pub f32, pub f32, pub f32);
21
22impl Vec3 {
23 #[must_use]
25 pub fn cross(self, other: Self) -> Self {
26 Self(
27 self.1.mul_add(other.2, -(self.2 * other.1)),
28 self.2.mul_add(other.0, -(self.0 * other.2)),
29 self.0.mul_add(other.1, -(self.1 * other.0)),
30 )
31 }
32
33 fn add(self, other: Self) -> Self {
34 Self(self.0 + other.0, self.1 + other.1, self.2 + other.2)
35 }
36
37 fn scale(self, factor: f32) -> Self {
38 Self(self.0 * factor, self.1 * factor, self.2 * factor)
39 }
40
41 const fn abs(self) -> Self {
42 Self(self.0.abs(), self.1.abs(), self.2.abs())
43 }
44}
45
46impl Rotation3 {
47 pub const IDENTITY: Self = Self::from_xyzw([0.0, 0.0, 0.0, 1.0]);
49
50 pub const HABITAT_MP3D: Self = Self::from_xyzw([-FRAC_1_SQRT_2, 0.0, 0.0, FRAC_1_SQRT_2]);
52
53 #[must_use]
55 pub const fn from_xyzw(xyzw: [f32; 4]) -> Self {
56 Self { xyzw }
57 }
58
59 #[must_use]
61 pub const fn xyzw(self) -> [f32; 4] {
62 self.xyzw
63 }
64
65 #[must_use]
67 pub fn is_identity(self) -> bool {
68 self == Self::IDENTITY
69 }
70
71 #[must_use]
73 pub fn transform_vector(self, vector: Vec3) -> Vec3 {
74 if self.is_identity() {
75 return vector;
76 }
77
78 let [quat_x, quat_y, quat_z, quat_w] = self.xyzw;
79 let quaternion_vector = Vec3(quat_x, quat_y, quat_z);
80 let uv = quaternion_vector.cross(vector);
81 let uuv = quaternion_vector.cross(uv);
82 vector.add(uv.scale(2.0 * quat_w)).add(uuv.scale(2.0))
83 }
84}
85
86impl Default for Rotation3 {
87 fn default() -> Self {
88 Self::HABITAT_MP3D
89 }
90}
91
92impl fmt::Display for Vec2 {
93 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(formatter, "({:.2}, {:.2})", self.0, self.1)
95 }
96}
97
98impl fmt::Display for Vec3 {
99 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(formatter, "({:.2}, {:.2}, {:.2})", self.0, self.1, self.2)
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq)]
106pub struct Aabb {
107 pub min: Vec3,
109 pub max: Vec3,
111}
112
113impl Aabb {
114 #[must_use]
116 pub fn contains(self, point: Vec3) -> bool {
117 point.0 >= self.min.0
118 && point.0 <= self.max.0
119 && point.1 >= self.min.1
120 && point.1 <= self.max.1
121 && point.2 >= self.min.2
122 && point.2 <= self.max.2
123 }
124
125 #[must_use]
127 pub const fn center(self) -> Vec3 {
128 Vec3(
129 self.min.0.midpoint(self.max.0),
130 self.min.1.midpoint(self.max.1),
131 self.min.2.midpoint(self.max.2),
132 )
133 }
134
135 #[must_use]
137 pub fn size(self) -> Vec3 {
138 Vec3(
139 self.max.0 - self.min.0,
140 self.max.1 - self.min.1,
141 self.max.2 - self.min.2,
142 )
143 }
144
145 #[must_use]
147 pub fn rotated(self, rotation: Rotation3) -> Self {
148 if rotation.is_identity() {
149 return self;
150 }
151
152 let center = rotation.transform_vector(self.center());
153 let half_sizes = rotation.transform_vector(self.size()).abs().scale(0.5);
154 Self {
155 min: Vec3(
156 center.0 - half_sizes.0,
157 center.1 - half_sizes.1,
158 center.2 - half_sizes.2,
159 ),
160 max: Vec3(
161 center.0 + half_sizes.0,
162 center.1 + half_sizes.1,
163 center.2 + half_sizes.2,
164 ),
165 }
166 }
167}
168
169impl fmt::Display for Aabb {
170 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
171 write!(formatter, "min={}, max={}", self.min, self.max)
172 }
173}
174
175#[derive(Debug, Clone, Copy, PartialEq)]
177pub struct Obb {
178 pub center: Vec3,
180 pub axis0: Vec3,
182 pub axis1: Vec3,
184 pub axis2: Vec3,
186 pub half_extents: Vec3,
188}
189
190impl Obb {
191 #[must_use]
193 pub fn to_aabb(self) -> Aabb {
194 let ex = extent(self.axis0.0, self.axis1.0, self.axis2.0, self.half_extents);
195 let ey = extent(self.axis0.1, self.axis1.1, self.axis2.1, self.half_extents);
196 let ez = extent(self.axis0.2, self.axis1.2, self.axis2.2, self.half_extents);
197
198 Aabb {
199 min: Vec3(self.center.0 - ex, self.center.1 - ey, self.center.2 - ez),
200 max: Vec3(self.center.0 + ex, self.center.1 + ey, self.center.2 + ez),
201 }
202 }
203
204 #[must_use]
206 pub fn rotated(self, rotation: Rotation3) -> Self {
207 if rotation.is_identity() {
208 return self;
209 }
210
211 let axis0 = rotation.transform_vector(self.axis0);
212 let axis1 = rotation.transform_vector(self.axis1);
213 Self {
214 center: rotation.transform_vector(self.center),
215 axis0,
216 axis1,
217 axis2: axis0.cross(axis1),
218 half_extents: self.half_extents,
219 }
220 }
221}
222
223impl fmt::Display for Obb {
224 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
225 write!(
226 formatter,
227 "center={}, half_extents={}",
228 self.center, self.half_extents
229 )
230 }
231}
232
233fn extent(axis0: f32, axis1: f32, axis2: f32, half_extents: Vec3) -> f32 {
234 axis2.abs().mul_add(
235 half_extents.2,
236 axis0
237 .abs()
238 .mul_add(half_extents.0, axis1.abs() * half_extents.1),
239 )
240}