ranim_items/vitem/geometry/
ellipse.rs

1use ranim_core::{
2    Extract,
3    color::{AlphaColor, Srgb},
4    core_item::{
5        CoreItem,
6        vitem::{Basis2d, DEFAULT_STROKE_WIDTH},
7    },
8    glam::{DVec2, DVec3},
9    traits::{
10        Aabb, Discard, FillColor, Opacity, RotateTransform, ShiftTransform, StrokeColor, With,
11    },
12};
13
14use crate::vitem::{
15    VItem,
16    geometry::{Circle, EllipticArc},
17};
18
19/// An ellipse.
20#[derive(Clone, Debug, ranim_macros::Interpolatable)]
21pub struct Ellipse {
22    /// Basis
23    pub basis: Basis2d,
24    /// Center
25    pub center: DVec3,
26    /// Semi-axes in x and y directions
27    pub radius: DVec2,
28
29    /// Stroke rgba
30    pub stroke_rgba: AlphaColor<Srgb>,
31    /// Stroke width
32    pub stroke_width: f32,
33    /// Fill rgba
34    pub fill_rgba: AlphaColor<Srgb>,
35}
36
37impl Ellipse {
38    /// Creates a new ellipse.
39    pub fn new(radius: DVec2) -> Self {
40        Self {
41            basis: Basis2d::default(),
42            center: DVec3::ZERO,
43            radius,
44            stroke_rgba: AlphaColor::WHITE,
45            stroke_width: DEFAULT_STROKE_WIDTH,
46            fill_rgba: AlphaColor::TRANSPARENT,
47        }
48    }
49}
50
51impl From<Circle> for Ellipse {
52    fn from(value: Circle) -> Self {
53        let Circle {
54            basis,
55            center,
56            radius,
57            stroke_rgba,
58            stroke_width,
59            fill_rgba,
60        } = value;
61        Self {
62            basis,
63            center,
64            radius: DVec2::splat(radius),
65            stroke_rgba,
66            stroke_width,
67            fill_rgba,
68        }
69    }
70}
71
72impl From<Ellipse> for VItem {
73    fn from(value: Ellipse) -> Self {
74        let fill_rgba = value.fill_rgba;
75        VItem::from(EllipticArc::from(value)).with(|item| item.set_fill_color(fill_rgba).discard())
76    }
77}
78
79impl Aabb for Ellipse {
80    fn aabb(&self) -> [DVec3; 2] {
81        let center = self.center;
82        let (u, v) = self.basis.uv();
83        let DVec2 { x: rx, y: ry } = self.radius;
84        let r = u * rx + v * ry;
85        [center - r, center + r].aabb()
86    }
87}
88
89impl ShiftTransform for Ellipse {
90    fn shift(&mut self, offset: DVec3) -> &mut Self {
91        self.center += offset;
92        self
93    }
94}
95
96impl RotateTransform for Ellipse {
97    fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
98        self.basis.rotate_on_axis(axis, angle);
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}