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::core_item::vitem::Basis2d;
17use ranim_core::traits::{FillColor, Opacity, StrokeColor, With};
18
19use crate::vitem::VItem;
20
21use super::Arc;
22
23#[derive(Clone, Debug, ranim_macros::Interpolatable)]
26pub struct Circle {
27 pub basis: Basis2d,
29 pub center: DVec3,
31 pub radius: f64,
33
34 pub stroke_rgba: AlphaColor<Srgb>,
36 pub stroke_width: f32,
38 pub fill_rgba: AlphaColor<Srgb>,
40}
41
42impl Circle {
43 pub fn new(radius: f64) -> Self {
45 Self {
46 basis: Basis2d::default(),
47 center: DVec3::ZERO,
48 radius,
49
50 stroke_rgba: AlphaColor::WHITE,
51 stroke_width: DEFAULT_STROKE_WIDTH,
52 fill_rgba: AlphaColor::TRANSPARENT,
53 }
54 }
55 pub fn scale(&mut self, scale: f64) -> &mut Self {
60 self.scale_by_anchor(scale, AabbPoint::CENTER)
61 }
62 pub fn scale_by_anchor<T>(&mut self, scale: f64, anchor: T) -> &mut Self
67 where
68 T: Locate<Self>,
69 {
70 let point = anchor.locate(self);
71 self.radius *= scale;
72 self.center
73 .shift(-point)
74 .scale(DVec3::splat(scale))
75 .shift(point);
76 self
77 }
78}
79
80impl Aabb for Circle {
82 fn aabb(&self) -> [DVec3; 2] {
83 let (u, v) = self.basis.uv();
84 let r = self.radius * (u + v);
85 [self.center + r, self.center - r].aabb()
86 }
87}
88
89impl ShiftTransform for Circle {
90 fn shift(&mut self, shift: DVec3) -> &mut Self {
91 self.center.shift(shift);
92 self
93 }
94}
95
96impl RotateTransform for Circle {
97 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
98 self.center.rotate_on_axis(axis, angle);
99 self.basis.rotate_on_axis(axis, angle);
100 self
101 }
102}
103
104impl Opacity for Circle {
105 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
106 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
107 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
108 self
109 }
110}
111
112impl StrokeColor for Circle {
113 fn stroke_color(&self) -> AlphaColor<Srgb> {
114 self.stroke_rgba
115 }
116 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
117 self.stroke_rgba = color;
118 self
119 }
120 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
121 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
122 self
123 }
124}
125
126impl FillColor for Circle {
127 fn fill_color(&self) -> AlphaColor<Srgb> {
128 self.fill_rgba
129 }
130 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
131 self.fill_rgba = color;
132 self
133 }
134 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
135 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
136 self
137 }
138}
139
140impl From<Circle> for Arc {
142 fn from(value: Circle) -> Self {
143 let Circle {
144 basis,
145 center,
146 radius,
147 stroke_rgba,
148 stroke_width,
149 ..
150 } = value;
151 Self {
152 basis,
153 center,
154 radius,
155 angle: 2.0 * PI,
156 stroke_rgba,
157 stroke_width,
158 }
159 }
160}
161
162impl From<Circle> for VItem {
163 fn from(value: Circle) -> Self {
164 let fill_rgba = value.fill_rgba;
165 VItem::from(Arc::from(value)).with(|item| {
166 item.set_fill_color(fill_rgba);
167 })
168 }
169}
170
171impl Extract for Circle {
172 type Target = CoreItem;
173 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
174 VItem::from(self.clone()).extract_into(buf);
175 }
176}