ranim_items/vitem/geometry/
anchor.rs

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