1use std::ops::{Add, Sub};
2
3use rand::RngExt;
4use vek::{Aabb, Aabr, Mat3, Vec2, Vec3};
5
6#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
8pub enum Dir2 {
9 X,
10 Y,
11 NegX,
12 NegY,
13}
14
15impl Dir2 {
16 pub const ALL: [Dir2; 4] = [Dir2::X, Dir2::Y, Dir2::NegX, Dir2::NegY];
17
18 pub fn choose(rng: &mut impl RngExt) -> Dir2 {
19 match rng.random_range(0..4) {
20 0 => Dir2::X,
21 1 => Dir2::Y,
22 2 => Dir2::NegX,
23 _ => Dir2::NegY,
24 }
25 }
26
27 pub fn choose_orthogonal(self, rng: &mut impl rand::Rng) -> Dir2 {
28 if rng.random_bool(0.5) {
29 self.orthogonal()
30 } else {
31 -self.orthogonal()
32 }
33 }
34
35 pub fn from_vec2(vec: impl Into<Vec2<i32>>) -> Dir2 {
36 let vec = vec.into();
37 if vec.x.abs() > vec.y.abs() {
38 if vec.x > 0 { Dir2::X } else { Dir2::NegX }
39 } else if vec.y > 0 {
40 Dir2::Y
41 } else {
42 Dir2::NegY
43 }
44 }
45
46 pub fn to_dir3(self) -> Dir3 { Dir3::from_dir(self) }
47
48 #[must_use]
49 pub fn opposite(self) -> Dir2 {
50 match self {
51 Dir2::X => Dir2::NegX,
52 Dir2::NegX => Dir2::X,
53 Dir2::Y => Dir2::NegY,
54 Dir2::NegY => Dir2::Y,
55 }
56 }
57
58 #[must_use]
60 pub fn rotated_ccw(self) -> Dir2 {
61 match self {
62 Dir2::X => Dir2::Y,
63 Dir2::NegX => Dir2::NegY,
64 Dir2::Y => Dir2::NegX,
65 Dir2::NegY => Dir2::X,
66 }
67 }
68
69 #[must_use]
71 pub fn rotated_cw(self) -> Dir2 { self.rotated_ccw().opposite() }
72
73 #[must_use]
74 pub fn orthogonal(self) -> Dir2 {
75 match self {
76 Dir2::X | Dir2::NegX => Dir2::Y,
77 Dir2::Y | Dir2::NegY => Dir2::X,
78 }
79 }
80
81 #[must_use]
82 pub fn abs(self) -> Dir2 {
83 match self {
84 Dir2::X | Dir2::NegX => Dir2::X,
85 Dir2::Y | Dir2::NegY => Dir2::Y,
86 }
87 }
88
89 #[must_use]
90 pub fn signum(self) -> i32 {
91 match self {
92 Dir2::X | Dir2::Y => 1,
93 Dir2::NegX | Dir2::NegY => -1,
94 }
95 }
96
97 pub fn to_vec2(self) -> Vec2<i32> {
98 match self {
99 Dir2::X => Vec2::new(1, 0),
100 Dir2::NegX => Vec2::new(-1, 0),
101 Dir2::Y => Vec2::new(0, 1),
102 Dir2::NegY => Vec2::new(0, -1),
103 }
104 }
105
106 pub fn diagonal(self) -> Vec2<i32> { self.to_vec2() + self.rotated_ccw().to_vec2() }
109
110 pub fn to_vec3(self) -> Vec3<i32> {
111 match self {
112 Dir2::X => Vec3::new(1, 0, 0),
113 Dir2::NegX => Vec3::new(-1, 0, 0),
114 Dir2::Y => Vec3::new(0, 1, 0),
115 Dir2::NegY => Vec3::new(0, -1, 0),
116 }
117 }
118
119 pub fn vec2(self, x: i32, y: i32) -> Vec2<i32> {
122 match self {
123 Dir2::X => Vec2::new(x, y),
124 Dir2::NegX => Vec2::new(-x, -y),
125 Dir2::Y => Vec2::new(y, x),
126 Dir2::NegY => Vec2::new(-y, -x),
127 }
128 }
129
130 pub fn vec2_abs<T>(self, x: T, y: T) -> Vec2<T> {
133 match self {
134 Dir2::X => Vec2::new(x, y),
135 Dir2::NegX => Vec2::new(x, y),
136 Dir2::Y => Vec2::new(y, x),
137 Dir2::NegY => Vec2::new(y, x),
138 }
139 }
140
141 pub fn to_mat3(self) -> Mat3<i32> {
165 match self {
166 Dir2::X => Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, 1),
167 Dir2::NegX => Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1),
168 Dir2::Y => Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1),
169 Dir2::NegY => Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1),
170 }
171 }
172
173 pub fn from_z_mat3(self) -> Mat3<i32> {
176 match self {
177 Dir2::X => Mat3::new(0, 0, -1, 0, 1, 0, 1, 0, 0),
178 Dir2::NegX => Mat3::new(0, 0, 1, 0, 1, 0, -1, 0, 0),
179 Dir2::Y => Mat3::new(1, 0, 0, 0, 0, -1, 0, 1, 0),
180 Dir2::NegY => Mat3::new(1, 0, 0, 0, 0, 1, 0, -1, 0),
181 }
182 }
183
184 #[must_use]
187 pub fn relative_to(self, other: Dir2) -> Dir2 {
188 match other {
189 Dir2::X => self,
190 Dir2::NegX => self.opposite(),
191 Dir2::Y => self.rotated_cw(),
192 Dir2::NegY => self.rotated_ccw(),
193 }
194 }
195
196 pub fn is_x(self) -> bool { matches!(self, Dir2::X | Dir2::NegX) }
198
199 pub fn is_y(self) -> bool { matches!(self, Dir2::Y | Dir2::NegY) }
201
202 pub fn is_positive(self) -> bool { matches!(self, Dir2::X | Dir2::Y) }
203
204 pub fn is_negative(self) -> bool { !self.is_positive() }
205
206 pub fn select(self, vec: impl Into<Vec2<i32>>) -> i32 {
208 let vec = vec.into();
209 match self {
210 Dir2::X | Dir2::NegX => vec.x,
211 Dir2::Y | Dir2::NegY => vec.y,
212 }
213 }
214
215 pub fn select_with(self, vec: impl Into<Vec2<i32>>, other: impl Into<Vec2<i32>>) -> Vec2<i32> {
218 let vec = vec.into();
219 let other = other.into();
220 match self {
221 Dir2::X | Dir2::NegX => Vec2::new(vec.x, other.y),
222 Dir2::Y | Dir2::NegY => Vec2::new(other.x, vec.y),
223 }
224 }
225
226 pub fn select_aabr<T>(self, aabr: Aabr<T>) -> T {
228 match self {
229 Dir2::X => aabr.max.x,
230 Dir2::NegX => aabr.min.x,
231 Dir2::Y => aabr.max.y,
232 Dir2::NegY => aabr.min.y,
233 }
234 }
235
236 pub fn select_aabr_with<T>(self, aabr: Aabr<T>, other: impl Into<Vec2<T>>) -> Vec2<T> {
239 let other = other.into();
240 match self {
241 Dir2::X => Vec2::new(aabr.max.x, other.y),
242 Dir2::NegX => Vec2::new(aabr.min.x, other.y),
243 Dir2::Y => Vec2::new(other.x, aabr.max.y),
244 Dir2::NegY => Vec2::new(other.x, aabr.min.y),
245 }
246 }
247
248 pub fn sprite_ori(self) -> u8 {
250 match self {
251 Dir2::X => 0,
252 Dir2::Y => 2,
253 Dir2::NegX => 4,
254 Dir2::NegY => 6,
255 }
256 }
257
258 pub fn from_sprite_ori(ori: u8) -> Option<(Dir2, u8)> {
262 let dir = match ori / 2 {
263 0 => Dir2::X,
264 1 => Dir2::Y,
265 2 => Dir2::NegX,
266 3 => Dir2::NegY,
267 _ => return None,
268 };
269 let rest = ori % 2;
270
271 Some((dir, rest))
272 }
273
274 pub fn sprite_ori_legacy(self) -> u8 {
276 match self {
277 Dir2::X => 2,
278 Dir2::NegX => 6,
279 Dir2::Y => 4,
280 Dir2::NegY => 0,
281 }
282 }
283
284 pub fn split_aabr_offset<T>(self, aabr: Aabr<T>, offset: T) -> [Aabr<T>; 2]
285 where
286 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
287 {
288 match self {
289 Dir2::X => aabr.split_at_x(aabr.min.x + offset),
290 Dir2::Y => aabr.split_at_y(aabr.min.y + offset),
291 Dir2::NegX => {
292 let res = aabr.split_at_x(aabr.max.x - offset);
293 [res[1], res[0]]
294 },
295 Dir2::NegY => {
296 let res = aabr.split_at_y(aabr.max.y - offset);
297 [res[1], res[0]]
298 },
299 }
300 }
301
302 pub fn trim_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
303 (-self).extend_aabr(aabr, -amount)
304 }
305
306 pub fn extend_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
307 let offset = self.to_vec2() * amount;
308 match self {
309 _ if self.is_positive() => Aabr {
310 min: aabr.min,
311 max: aabr.max + offset,
312 },
313 _ => Aabr {
314 min: aabr.min + offset,
315 max: aabr.max,
316 },
317 }
318 }
319
320 pub fn translate_aabr(self, aabr: Aabr<i32>, amount: i32) -> Aabr<i32> {
321 let offset = self.scale(amount);
322 Aabr {
323 min: aabr.min + offset,
324 max: aabr.max + offset,
325 }
326 }
327
328 pub fn scale(self, vec: impl Into<Vec2<i32>>) -> Vec2<i32> { self.to_vec2() * vec }
329}
330
331impl std::ops::Neg for Dir2 {
332 type Output = Dir2;
333
334 fn neg(self) -> Self::Output { self.opposite() }
335}
336
337#[derive(Debug, enum_map::Enum, strum::EnumIter, enumset::EnumSetType)]
339pub enum Dir3 {
340 X,
341 Y,
342 Z,
343 NegX,
344 NegY,
345 NegZ,
346}
347
348impl Dir3 {
349 pub const ALL: [Dir2; 4] = [Dir2::X, Dir2::Y, Dir2::NegX, Dir2::NegY];
350
351 pub fn choose(rng: &mut impl RngExt) -> Dir3 {
352 match rng.random_range(0..6) {
353 0 => Dir3::X,
354 1 => Dir3::Y,
355 2 => Dir3::Z,
356 3 => Dir3::NegX,
357 4 => Dir3::NegY,
358 _ => Dir3::NegZ,
359 }
360 }
361
362 pub fn from_dir(dir: Dir2) -> Dir3 {
363 match dir {
364 Dir2::X => Dir3::X,
365 Dir2::Y => Dir3::Y,
366 Dir2::NegX => Dir3::NegX,
367 Dir2::NegY => Dir3::NegY,
368 }
369 }
370
371 pub fn to_dir(self) -> Option<Dir2> {
372 match self {
373 Dir3::X => Some(Dir2::X),
374 Dir3::Y => Some(Dir2::Y),
375 Dir3::NegX => Some(Dir2::NegX),
376 Dir3::NegY => Some(Dir2::NegY),
377 _ => None,
378 }
379 }
380
381 pub fn from_vec3(vec: Vec3<i32>) -> Dir3 {
382 if vec.x.abs() > vec.y.abs() && vec.x.abs() > vec.z.abs() {
383 if vec.x > 0 { Dir3::X } else { Dir3::NegX }
384 } else if vec.y.abs() > vec.z.abs() {
385 if vec.y > 0 { Dir3::Y } else { Dir3::NegY }
386 } else if vec.z > 0 {
387 Dir3::Z
388 } else {
389 Dir3::NegZ
390 }
391 }
392
393 #[must_use]
394 pub fn opposite(self) -> Dir3 {
395 match self {
396 Dir3::X => Dir3::NegX,
397 Dir3::NegX => Dir3::X,
398 Dir3::Y => Dir3::NegY,
399 Dir3::NegY => Dir3::Y,
400 Dir3::Z => Dir3::NegZ,
401 Dir3::NegZ => Dir3::Z,
402 }
403 }
404
405 pub fn rotate_axis_ccw(self, axis: Dir3) -> Dir3 {
407 match axis {
408 Dir3::X | Dir3::NegX => match self {
409 Dir3::Y => Dir3::Z,
410 Dir3::NegY => Dir3::NegZ,
411 Dir3::Z => Dir3::NegY,
412 Dir3::NegZ => Dir3::Y,
413 x => x,
414 },
415 Dir3::Y | Dir3::NegY => match self {
416 Dir3::X => Dir3::Z,
417 Dir3::NegX => Dir3::NegZ,
418 Dir3::Z => Dir3::NegX,
419 Dir3::NegZ => Dir3::X,
420 y => y,
421 },
422 Dir3::Z | Dir3::NegZ => match self {
423 Dir3::X => Dir3::Y,
424 Dir3::NegX => Dir3::NegY,
425 Dir3::Y => Dir3::NegX,
426 Dir3::NegY => Dir3::X,
427 z => z,
428 },
429 }
430 }
431
432 pub fn rotate_axis_cw(self, axis: Dir3) -> Dir3 { self.rotate_axis_ccw(axis).opposite() }
434
435 pub fn cross(self, other: Dir3) -> Dir3 {
438 match (self, other) {
439 (Dir3::X | Dir3::NegX, Dir3::Y | Dir3::NegY)
440 | (Dir3::Y | Dir3::NegY, Dir3::X | Dir3::NegX) => Dir3::Z,
441 (Dir3::X | Dir3::NegX, Dir3::Z | Dir3::NegZ)
442 | (Dir3::Z | Dir3::NegZ, Dir3::X | Dir3::NegX) => Dir3::Y,
443 (Dir3::Z | Dir3::NegZ, Dir3::Y | Dir3::NegY)
444 | (Dir3::Y | Dir3::NegY, Dir3::Z | Dir3::NegZ) => Dir3::X,
445 (Dir3::X | Dir3::NegX, Dir3::X | Dir3::NegX) => Dir3::Y,
446 (Dir3::Y | Dir3::NegY, Dir3::Y | Dir3::NegY) => Dir3::X,
447 (Dir3::Z | Dir3::NegZ, Dir3::Z | Dir3::NegZ) => Dir3::Y,
448 }
449 }
450
451 #[must_use]
452 pub fn abs(self) -> Dir3 {
453 match self {
454 Dir3::X | Dir3::NegX => Dir3::X,
455 Dir3::Y | Dir3::NegY => Dir3::Y,
456 Dir3::Z | Dir3::NegZ => Dir3::Z,
457 }
458 }
459
460 #[must_use]
461 pub fn signum(self) -> i32 {
462 match self {
463 Dir3::X | Dir3::Y | Dir3::Z => 1,
464 Dir3::NegX | Dir3::NegY | Dir3::NegZ => -1,
465 }
466 }
467
468 pub fn to_vec3(self) -> Vec3<i32> {
469 match self {
470 Dir3::X => Vec3::new(1, 0, 0),
471 Dir3::NegX => Vec3::new(-1, 0, 0),
472 Dir3::Y => Vec3::new(0, 1, 0),
473 Dir3::NegY => Vec3::new(0, -1, 0),
474 Dir3::Z => Vec3::new(0, 0, 1),
475 Dir3::NegZ => Vec3::new(0, 0, -1),
476 }
477 }
478
479 pub fn is_x(self) -> bool { matches!(self, Dir3::X | Dir3::NegX) }
481
482 pub fn is_y(self) -> bool { matches!(self, Dir3::Y | Dir3::NegY) }
484
485 pub fn is_z(self) -> bool { matches!(self, Dir3::Z | Dir3::NegZ) }
487
488 pub fn is_positive(self) -> bool { matches!(self, Dir3::X | Dir3::Y | Dir3::Z) }
489
490 pub fn is_negative(self) -> bool { !self.is_positive() }
491
492 pub fn select(self, vec: impl Into<Vec3<i32>>) -> i32 {
494 let vec = vec.into();
495 match self {
496 Dir3::X | Dir3::NegX => vec.x,
497 Dir3::Y | Dir3::NegY => vec.y,
498 Dir3::Z | Dir3::NegZ => vec.z,
499 }
500 }
501
502 pub fn select_with(self, vec: impl Into<Vec3<i32>>, other: impl Into<Vec3<i32>>) -> Vec3<i32> {
505 let vec = vec.into();
506 let other = other.into();
507 match self {
508 Dir3::X | Dir3::NegX => Vec3::new(vec.x, other.y, other.z),
509 Dir3::Y | Dir3::NegY => Vec3::new(other.x, vec.y, other.z),
510 Dir3::Z | Dir3::NegZ => Vec3::new(other.x, other.y, vec.z),
511 }
512 }
513
514 pub fn select_aabb<T>(self, aabb: Aabb<T>) -> T {
516 match self {
517 Dir3::X => aabb.max.x,
518 Dir3::NegX => aabb.min.x,
519 Dir3::Y => aabb.max.y,
520 Dir3::NegY => aabb.min.y,
521 Dir3::Z => aabb.max.z,
522 Dir3::NegZ => aabb.min.z,
523 }
524 }
525
526 pub fn select_aabb_with<T>(self, aabb: Aabb<T>, other: impl Into<Vec3<T>>) -> Vec3<T> {
529 let other = other.into();
530 match self {
531 Dir3::X => Vec3::new(aabb.max.x, other.y, other.z),
532 Dir3::NegX => Vec3::new(aabb.min.x, other.y, other.z),
533 Dir3::Y => Vec3::new(other.x, aabb.max.y, other.z),
534 Dir3::NegY => Vec3::new(other.x, aabb.min.y, other.z),
535 Dir3::Z => Vec3::new(other.x, other.y, aabb.max.z),
536 Dir3::NegZ => Vec3::new(other.x, other.y, aabb.min.z),
537 }
538 }
539
540 pub fn split_aabb_offset<T>(self, aabb: Aabb<T>, offset: T) -> [Aabb<T>; 2]
541 where
542 T: Copy + PartialOrd + Add<T, Output = T> + Sub<T, Output = T>,
543 {
544 match self {
545 Dir3::X => aabb.split_at_x(aabb.min.x + offset),
546 Dir3::NegX => {
547 let res = aabb.split_at_x(aabb.max.x - offset);
548 [res[1], res[0]]
549 },
550 Dir3::Y => aabb.split_at_y(aabb.min.y + offset),
551 Dir3::NegY => {
552 let res = aabb.split_at_y(aabb.max.y - offset);
553 [res[1], res[0]]
554 },
555 Dir3::Z => aabb.split_at_z(aabb.min.z + offset),
556 Dir3::NegZ => {
557 let res = aabb.split_at_z(aabb.max.z - offset);
558 [res[1], res[0]]
559 },
560 }
561 }
562
563 pub fn trim_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
564 (-self).extend_aabb(aabb, -amount)
565 }
566
567 pub fn extend_aabb(self, aabb: Aabb<i32>, amount: i32) -> Aabb<i32> {
568 let offset = self.to_vec3() * amount;
569 match self {
570 _ if self.is_positive() => Aabb {
571 min: aabb.min,
572 max: aabb.max + offset,
573 },
574 _ => Aabb {
575 min: aabb.min + offset,
576 max: aabb.max,
577 },
578 }
579 }
580}
581impl std::ops::Neg for Dir3 {
582 type Output = Dir3;
583
584 fn neg(self) -> Self::Output { self.opposite() }
585}