ranim_items/vitem/geometry/
ellipse.rs1use 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#[derive(Clone, Debug, ranim_macros::Interpolatable)]
18pub struct Ellipse {
19 pub axes: (DVec3, DVec3),
21 pub center: DVec3,
23 pub radius: DVec2,
25
26 pub stroke_rgba: AlphaColor<Srgb>,
28 pub stroke_width: f32,
30 pub fill_rgba: AlphaColor<Srgb>,
32}
33
34impl Ellipse {
35 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}