ranim_items/vitem/geometry/
anchor.rs

1use ranim_core::{
2    core_item::vitem::Basis2d,
3    glam::{DVec2, DVec3},
4    traits::Locate,
5};
6
7use crate::vitem::geometry::{Arc, ArcBetweenPoints, Circle, Ellipse, EllipticArc};
8
9/// `Origin` anchor for shapes with an origin point.
10#[derive(Debug, Clone, Copy)]
11pub struct Origin;
12
13/// Focus of an ellipse.
14#[derive(Debug, Clone, Copy)]
15pub struct Focus {
16    pos: bool,
17}
18
19impl Focus {
20    /// Focus on the positive semi-major axis.
21    pub const POS: Self = Focus { pos: true };
22    /// Focus on the negative semi-major axis.
23    pub const NEG: Self = Focus { pos: false };
24}
25
26impl Locate<Arc> for Origin {
27    fn locate(&self, target: &Arc) -> DVec3 {
28        target.center
29    }
30}
31
32impl Locate<Arc> for Focus {
33    fn locate(&self, target: &Arc) -> DVec3 {
34        target.center
35    }
36}
37
38impl Locate<ArcBetweenPoints> for Origin {
39    fn locate(&self, target: &ArcBetweenPoints) -> DVec3 {
40        // TODO: make this better
41        Arc::from(target.clone()).center
42    }
43}
44
45impl Locate<ArcBetweenPoints> for Focus {
46    fn locate(&self, target: &ArcBetweenPoints) -> DVec3 {
47        // TODO: make this better
48        Arc::from(target.clone()).center
49    }
50}
51
52impl Locate<Circle> for Origin {
53    fn locate(&self, target: &Circle) -> DVec3 {
54        target.center
55    }
56}
57
58impl Locate<Circle> for Focus {
59    fn locate(&self, target: &Circle) -> DVec3 {
60        target.center
61    }
62}
63
64fn ellipse_focus(basis: Basis2d, radius: DVec2) -> DVec3 {
65    let DVec2 { x: rx, y: ry } = radius;
66    let c = (rx * rx - ry * ry).abs().sqrt();
67    (if rx > ry { basis.u() } else { basis.v() }) * c
68}
69
70impl Locate<EllipticArc> for Origin {
71    fn locate(&self, target: &EllipticArc) -> DVec3 {
72        target.center
73    }
74}
75
76impl Locate<EllipticArc> for Focus {
77    fn locate(&self, target: &EllipticArc) -> DVec3 {
78        let &EllipticArc {
79            basis,
80            center,
81            radius,
82            ..
83        } = target;
84        let focus = ellipse_focus(basis, radius);
85        if self.pos {
86            center + focus
87        } else {
88            center - focus
89        }
90    }
91}
92
93impl Locate<Ellipse> for Origin {
94    fn locate(&self, target: &Ellipse) -> DVec3 {
95        target.center
96    }
97}
98
99impl Locate<Ellipse> for Focus {
100    fn locate(&self, target: &Ellipse) -> DVec3 {
101        let &Ellipse {
102            basis,
103            center,
104            radius,
105            ..
106        } = target;
107        let focus = ellipse_focus(basis, radius);
108        if self.pos {
109            center + focus
110        } else {
111            center - focus
112        }
113    }
114}