gpui_component/plot/shape/
pie.rs1use std::f32::consts::TAU;
4
5use super::arc::ArcData;
6
7#[allow(clippy::type_complexity)]
8pub struct Pie<T> {
9 value: Box<dyn Fn(&T) -> Option<f32>>,
10 start_angle: f32,
11 end_angle: f32,
12 pad_angle: f32,
13}
14
15impl<T> Default for Pie<T> {
16 fn default() -> Self {
17 Self {
18 value: Box::new(|_| None),
19 start_angle: 0.,
20 end_angle: TAU,
21 pad_angle: 0.,
22 }
23 }
24}
25
26impl<T> Pie<T> {
27 pub fn new() -> Self {
28 Self::default()
29 }
30
31 pub fn value<F>(mut self, value: F) -> Self
33 where
34 F: 'static + Fn(&T) -> Option<f32>,
35 {
36 self.value = Box::new(value);
37 self
38 }
39
40 pub fn start_angle(mut self, start_angle: f32) -> Self {
42 self.start_angle = start_angle;
43 self
44 }
45
46 pub fn end_angle(mut self, end_angle: f32) -> Self {
48 self.end_angle = end_angle;
49 self
50 }
51
52 pub fn pad_angle(mut self, pad_angle: f32) -> Self {
54 self.pad_angle = pad_angle;
55 self
56 }
57
58 pub fn arcs<'a>(&self, data: &'a [T]) -> Vec<ArcData<'a, T>> {
60 let mut values = Vec::new();
61 let mut sum = 0.;
62
63 for (idx, v) in data.iter().enumerate() {
64 if let Some(value) = (self.value)(v) {
65 if value > 0. {
66 sum += value;
67 values.push((idx, v, value));
68 }
69 }
70 }
71
72 let mut arcs = Vec::with_capacity(values.len());
73 let mut k = self.start_angle;
74
75 for (index, v, value) in values {
76 let start_angle = k;
77 let angle_delta = if sum > 0. {
78 (value / sum) * (self.end_angle - self.start_angle)
79 } else {
80 0.
81 };
82 k += angle_delta;
83 let end_angle = k;
84
85 arcs.push(ArcData {
86 data: v,
87 index,
88 value,
89 start_angle,
90 end_angle,
91 pad_angle: self.pad_angle,
92 });
93 }
94
95 arcs
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_pie() {
105 let pie = Pie::new().value(|v| Some(*v));
106
107 let data = vec![1., 1., 1.];
108 let arcs = pie.arcs(&data);
109
110 assert_eq!(arcs.len(), 3);
111
112 assert_eq!(arcs[0].value, 1.);
113 assert_eq!(arcs[1].value, 1.);
114 assert_eq!(arcs[2].value, 1.);
115
116 assert_eq!(arcs[0].start_angle, 0.);
117 assert_eq!(arcs[0].end_angle, arcs[1].start_angle);
118 assert_eq!(arcs[1].end_angle, arcs[2].start_angle);
119 assert_eq!(arcs[2].end_angle, TAU);
120 }
121
122 #[test]
123 fn test_pie_zero_values() {
124 let pie = Pie::new().value(|v| Some(*v));
125 let data = vec![0., 1., 0., 2.];
126 let arcs = pie.arcs(&data);
127
128 assert_eq!(arcs.len(), 2);
129 assert_eq!(arcs[0].value, 1.);
130 assert_eq!(arcs[1].value, 2.);
131 assert_eq!(arcs[0].index, 1);
132 assert_eq!(arcs[1].index, 3);
133 }
134}