ranim_items/vitem/geometry/
circle.rs1use std::f64::consts::PI;
2
3use color::{AlphaColor, Srgb};
4use glam::DVec3;
5use ranim_core::{
6 Extract,
7 anchor::{Aabb, Locate},
8 color,
9 core_item::CoreItem,
10 glam,
11 traits::{RotateTransform, ScaleTransform, ShiftTransform},
12};
13
14use crate::vitem::DEFAULT_STROKE_WIDTH;
15use ranim_core::anchor::AabbPoint;
16use ranim_core::traits::{FillColor, Opacity, StrokeColor, With};
17
18use crate::vitem::VItem;
19
20use super::Arc;
21
22#[derive(Clone, Debug, ranim_macros::Interpolatable)]
25pub struct Circle {
26 pub axes: (DVec3, DVec3),
28 pub center: DVec3,
30 pub radius: f64,
32
33 pub stroke_rgba: AlphaColor<Srgb>,
35 pub stroke_width: f32,
37 pub fill_rgba: AlphaColor<Srgb>,
39}
40
41impl Circle {
42 pub fn new(radius: f64) -> Self {
44 Self {
45 axes: (DVec3::X, DVec3::Y),
46 center: DVec3::ZERO,
47 radius,
48
49 stroke_rgba: AlphaColor::WHITE,
50 stroke_width: DEFAULT_STROKE_WIDTH,
51 fill_rgba: AlphaColor::TRANSPARENT,
52 }
53 }
54 pub fn scale(&mut self, scale: f64) -> &mut Self {
59 self.scale_by_anchor(scale, AabbPoint::CENTER)
60 }
61 pub fn scale_by_anchor<T>(&mut self, scale: f64, anchor: T) -> &mut Self
66 where
67 T: Locate<Self>,
68 {
69 let point = anchor.locate(self);
70 self.radius *= scale;
71 self.center
72 .shift(-point)
73 .scale(DVec3::splat(scale))
74 .shift(point);
75 self
76 }
77}
78
79impl Aabb for Circle {
81 fn aabb(&self) -> [DVec3; 2] {
82 let (u, v) = (self.axes.0.normalize(), self.axes.1.normalize());
83 let r = self.radius * (u + v);
84 [self.center + r, self.center - r].aabb()
85 }
86}
87
88impl ShiftTransform for Circle {
89 fn shift(&mut self, shift: DVec3) -> &mut Self {
90 self.center.shift(shift);
91 self
92 }
93}
94
95impl RotateTransform for Circle {
96 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
97 self.center.rotate_on_axis(axis, angle);
98 self.axes.0.rotate_on_axis(axis, angle);
99 self.axes.0 = self.axes.0.normalize();
100 self.axes.1.rotate_on_axis(axis, angle);
101 self.axes.1 = self.axes.1.normalize();
102 self
103 }
104}
105
106impl Opacity for Circle {
107 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
108 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
109 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
110 self
111 }
112}
113
114impl StrokeColor for Circle {
115 fn stroke_color(&self) -> AlphaColor<Srgb> {
116 self.stroke_rgba
117 }
118 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
119 self.stroke_rgba = color;
120 self
121 }
122 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
123 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
124 self
125 }
126}
127
128impl FillColor for Circle {
129 fn fill_color(&self) -> AlphaColor<Srgb> {
130 self.fill_rgba
131 }
132 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
133 self.fill_rgba = color;
134 self
135 }
136 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
137 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
138 self
139 }
140}
141
142impl From<Circle> for Arc {
144 fn from(value: Circle) -> Self {
145 let Circle {
146 axes,
147 center,
148 radius,
149 stroke_rgba,
150 stroke_width,
151 ..
152 } = value;
153 Self {
154 axes,
155 center,
156 radius,
157 angle: 2.0 * PI,
158 stroke_rgba,
159 stroke_width,
160 }
161 }
162}
163
164impl From<Circle> for VItem {
165 fn from(value: Circle) -> Self {
166 let fill_rgba = value.fill_rgba;
167 VItem::from(Arc::from(value)).with(|item| {
168 item.set_fill_color(fill_rgba);
169 })
170 }
171}
172
173impl Extract for Circle {
174 type Target = CoreItem;
175 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
176 VItem::from(self.clone()).extract_into(buf);
177 }
178}