Skip to main content

ranim_core/
anchor.rs

1//! Anchor
2//!
3//! Ranim has an anchor system based on generics, an anchor can be any type `T`,
4//! and types that implement [`crate::anchor::Locate<T>`] can use
5//! [`crate::anchor::Locate::locate`] to convert the anchor to a [`glam::DVec3`] point.
6//!
7//! Ranim provides some built-in anchors and related [`crate::anchor::Locate`] implementations:
8//! - [`glam::DVec3`]: The point itself in 3d space.
9//! - [`crate::anchor::Centroid`]: The avg point of all points.
10//!   Note that sometime the center of Aabb is not the centroid.
11//!   (0, 0, 0) is the center point.
12//! - [`crate::anchor::AabbPoint`]: A point based on [`crate::anchor::Aabb`]'s size,
13//!   the number in each axis means the fraction of the size of the [`crate::anchor::Aabb`].
14
15use glam::DVec3;
16use tracing::warn;
17
18/// Locate a point.
19pub trait Locate<T: ?Sized> {
20    /// Locate self on the target
21    fn locate(&self, target: &T) -> DVec3;
22}
23
24impl<T: ?Sized> Locate<T> for DVec3 {
25    fn locate(&self, _target: &T) -> DVec3 {
26        *self
27    }
28}
29
30/// The centroid.
31///
32/// Avg of all points.
33pub struct Centroid;
34
35impl Locate<DVec3> for Centroid {
36    fn locate(&self, target: &DVec3) -> DVec3 {
37        *target
38    }
39}
40
41impl<T> Locate<[T]> for Centroid
42where
43    Centroid: Locate<T>,
44{
45    fn locate(&self, target: &[T]) -> DVec3 {
46        target.iter().map(|x| self.locate(x)).sum::<DVec3>() / target.len() as f64
47    }
48}
49
50/// A point based on [`Aabb`], the number in each axis means the fraction of the size of the [`Aabb`].
51/// (0, 0, 0) is the center point.
52/// ```text
53///      +Y
54///      |
55///      |
56///      +----- +X
57///    /
58/// +Z
59/// ```
60#[derive(Debug, Clone, Copy, PartialEq)]
61pub struct AabbPoint(pub DVec3);
62
63impl AabbPoint {
64    /// Center point, shorthand of `Anchor(DVec3::ZERO)`.
65    pub const CENTER: Self = Self(DVec3::ZERO);
66    // /// Left point (-X)
67    // pub const LEFT: Self = Self(DVec3::NEG_X);
68    // /// Right point (+X)
69    // pub const RIGHT: Self = Self(DVec3::X);
70    // /// Top point (+Y)
71    // pub const TOP: Self = Self(DVec3::Y);
72    // /// Bottom point (-Y)
73    // pub const BOTTOM: Self = Self(DVec3::NEG_Y);
74    // /// Top Right point (+X, +Y)
75    // pub const TOP_RIGHT: Self = Self(dvec3(1.0, 1.0, 0.0));
76    // /// Top Left point (-X, +Y)
77    // pub const TOP_LEFT: Self = Self(dvec3(-1.0, 1.0, 0.0));
78    // /// Bottom Right point (+X, -Y)
79    // pub const BOTTOM_RIGHT: Self = Self(dvec3(1.0, -1.0, 0.0));
80    // /// Bottom Left point (-X, -Y)
81    // pub const BOTTOM_LEFT: Self = Self(dvec3(-1.0, -1.0, 0.0));
82}
83
84impl<T: Aabb + ?Sized> Locate<T> for AabbPoint {
85    fn locate(&self, target: &T) -> DVec3 {
86        let center = target.aabb_center();
87        let half_size = target.aabb_size() / 2.0;
88        center + self.0 * half_size
89    }
90}
91
92/// Axis-Aligned Bounding Box
93///
94/// This is the basic trait for an item.
95pub trait Aabb {
96    /// Get the Axis-aligned bounding box represent in `[<min>, <max>]`.
97    fn aabb(&self) -> [DVec3; 2];
98    /// Get the size of the Aabb.
99    fn aabb_size(&self) -> DVec3 {
100        let [min, max] = self.aabb();
101        max - min
102    }
103    /// Get the center of the Aabb.
104    fn aabb_center(&self) -> DVec3 {
105        let [min, max] = self.aabb();
106        (max + min) / 2.0
107    }
108}
109
110impl Aabb for DVec3 {
111    fn aabb(&self) -> [DVec3; 2] {
112        [*self; 2]
113    }
114}
115
116impl<T: Aabb> Aabb for [T] {
117    fn aabb(&self) -> [DVec3; 2] {
118        let [min, max] = self
119            .iter()
120            .map(|x| x.aabb())
121            .reduce(|[acc_min, acc_max], [min, max]| [acc_min.min(min), acc_max.max(max)])
122            .unwrap_or([DVec3::ZERO, DVec3::ZERO]);
123        if min == max {
124            warn!("Empty bounding box, is the slice empty?")
125        }
126        [min, max]
127    }
128}
129
130impl<T: Aabb> Aabb for Vec<T> {
131    fn aabb(&self) -> [DVec3; 2] {
132        self.as_slice().aabb()
133    }
134}