ranim_items/vitem/geometry/
ellipse.rs

1use ranim_core::{
2    Extract,
3    color::{AlphaColor, Srgb},
4    core_item::{CoreItem, vitem::DEFAULT_STROKE_WIDTH},
5    glam::{DVec2, DVec3},
6    traits::{
7        Aabb, Discard, FillColor, Opacity, RotateTransform, ShiftTransform, StrokeColor, With,
8    },
9};
10
11use crate::vitem::{
12    VItem,
13    geometry::{Circle, EllipticArc},
14};
15
16/// An ellipse.
17#[derive(Clone, Debug, ranim_macros::Interpolatable)]
18pub struct Ellipse {
19    /// Axes
20    pub axes: (DVec3, DVec3),
21    /// Center
22    pub center: DVec3,
23    /// Semi-axes in x and y directions
24    pub radius: DVec2,
25
26    /// Stroke rgba
27    pub stroke_rgba: AlphaColor<Srgb>,
28    /// Stroke width
29    pub stroke_width: f32,
30    /// Fill rgba
31    pub fill_rgba: AlphaColor<Srgb>,
32}
33
34impl Ellipse {
35    /// Creates a new ellipse.
36    pub fn new(radius: DVec2) -> Self {
37        Self {
38            axes: (DVec3::X, DVec3::Y),
39            center: DVec3::ZERO,
40            radius,
41            stroke_rgba: AlphaColor::WHITE,
42            stroke_width: DEFAULT_STROKE_WIDTH,
43            fill_rgba: AlphaColor::TRANSPARENT,
44        }
45    }
46}
47
48impl From<Circle> for Ellipse {
49    fn from(value: Circle) -> Self {
50        let Circle {
51            axes,
52            center,
53            radius,
54            stroke_rgba,
55            stroke_width,
56            fill_rgba,
57        } = value;
58        Self {
59            axes,
60            center,
61            radius: DVec2::splat(radius),
62            stroke_rgba,
63            stroke_width,
64            fill_rgba,
65        }
66    }
67}
68
69impl From<Ellipse> for VItem {
70    fn from(value: Ellipse) -> Self {
71        let fill_rgba = value.fill_rgba;
72        VItem::from(EllipticArc::from(value)).with(|item| item.set_fill_color(fill_rgba).discard())
73    }
74}
75
76impl Aabb for Ellipse {
77    fn aabb(&self) -> [DVec3; 2] {
78        let center = self.center;
79        let (u, v) = (self.axes.0.normalize(), self.axes.1.normalize());
80        let DVec2 { x: rx, y: ry } = self.radius;
81        let r = u * rx + v * ry;
82        [center - r, center + r].aabb()
83    }
84}
85
86impl ShiftTransform for Ellipse {
87    fn shift(&mut self, offset: DVec3) -> &mut Self {
88        self.center += offset;
89        self
90    }
91}
92
93impl RotateTransform for Ellipse {
94    fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
95        self.axes.0.rotate_on_axis(axis, angle);
96        self.axes.0 = self.axes.0.normalize();
97        self.axes.1.rotate_on_axis(axis, angle);
98        self.axes.1 = self.axes.1.normalize();
99        self.center.rotate_on_axis(axis, angle);
100        self
101    }
102}
103
104impl StrokeColor for Ellipse {
105    fn stroke_color(&self) -> AlphaColor<Srgb> {
106        self.stroke_rgba
107    }
108
109    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
110        self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
111        self
112    }
113
114    fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
115        self.stroke_rgba = color;
116        self
117    }
118}
119
120impl FillColor for Ellipse {
121    fn fill_color(&self) -> AlphaColor<Srgb> {
122        self.fill_rgba
123    }
124
125    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
126        self.fill_rgba = self.fill_rgba.with_alpha(opacity);
127        self
128    }
129
130    fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
131        self.fill_rgba = color;
132        self
133    }
134}
135
136impl Opacity for Ellipse {
137    fn set_opacity(&mut self, opacity: f32) -> &mut Self {
138        self.set_fill_opacity(opacity).set_stroke_opacity(opacity);
139        self
140    }
141}
142
143impl Extract for Ellipse {
144    type Target = CoreItem;
145
146    fn extract_into(&self, buf: &mut Vec<Self::Target>) {
147        VItem::from(self.clone()).extract_into(buf);
148    }
149}