gpui_component/plot/scale/
point.rs1use itertools::Itertools;
4
5use super::Scale;
6
7#[derive(Clone)]
12pub struct ScalePoint<T> {
13 domain: Vec<T>,
14 range_start: f32,
15 range_tick: f32,
16}
17
18impl<T> ScalePoint<T>
19where
20 T: PartialEq,
21{
22 pub fn new(domain: Vec<T>, range: Vec<f32>) -> Self {
33 let len = domain.len();
34 let (range_start, range_tick) = if len == 0 {
35 (0., 0.)
36 } else {
37 let (min, max) = range
38 .iter()
39 .minmax()
40 .into_option()
41 .map_or((0., 0.), |(min, max)| (*min, *max));
42
43 let range_diff = max - min;
44
45 if len == 1 {
46 (min, range_diff)
47 } else {
48 (min, range_diff / (len - 1) as f32)
49 }
50 };
51
52 Self {
53 domain,
54 range_start,
55 range_tick,
56 }
57 }
58}
59
60impl<T> Scale<T> for ScalePoint<T>
61where
62 T: PartialEq,
63{
64 fn tick(&self, value: &T) -> Option<f32> {
65 let index = self.domain.iter().position(|v| v == value)?;
66
67 if self.domain.len() == 1 {
68 Some(self.range_start + self.range_tick / 2.)
69 } else {
70 Some(self.range_start + index as f32 * self.range_tick)
71 }
72 }
73
74 fn least_index(&self, tick: f32) -> usize {
75 if self.domain.is_empty() {
76 return 0;
77 }
78
79 if self.range_tick == 0. {
80 return 0;
81 }
82
83 let normalized_tick = tick - self.range_start;
84 let index = (normalized_tick / self.range_tick).round() as usize;
85 index.min(self.domain.len() - 1)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_scale_point() {
95 let scale = ScalePoint::new(vec![1, 2, 3], vec![0., 100.]);
96 assert_eq!(scale.tick(&1), Some(0.));
97 assert_eq!(scale.tick(&2), Some(50.));
98 assert_eq!(scale.tick(&3), Some(100.));
99 }
100
101 #[test]
102 fn test_scale_point_range() {
103 let scale = ScalePoint::new(vec![1, 2, 3], vec![40., 80.]);
104 assert_eq!(scale.tick(&1), Some(40.));
105 assert_eq!(scale.tick(&2), Some(60.));
106 assert_eq!(scale.tick(&3), Some(80.));
107 }
108
109 #[test]
110 fn test_scale_point_empty() {
111 let scale = ScalePoint::new(vec![], vec![0., 100.]);
112 assert_eq!(scale.tick(&1), None);
113 assert_eq!(scale.tick(&2), None);
114 assert_eq!(scale.tick(&3), None);
115
116 let scale = ScalePoint::new(vec![1, 2, 3], vec![]);
117 assert_eq!(scale.tick(&1), Some(0.));
118 assert_eq!(scale.tick(&2), Some(0.));
119 assert_eq!(scale.tick(&3), Some(0.));
120 }
121
122 #[test]
123 fn test_scale_point_single() {
124 let scale = ScalePoint::new(vec![1], vec![0., 100.]);
125 assert_eq!(scale.tick(&1), Some(50.));
126 }
127
128 #[test]
129 fn test_least_index_basic() {
130 let scale = ScalePoint::new(vec![1, 2, 3], vec![0., 100.]);
131
132 assert_eq!(scale.least_index(0.), 0);
134 assert_eq!(scale.least_index(50.), 1);
135 assert_eq!(scale.least_index(100.), 2);
136
137 assert_eq!(scale.least_index(24.), 0); assert_eq!(scale.least_index(25.), 1); assert_eq!(scale.least_index(26.), 1); assert_eq!(scale.least_index(74.), 1); assert_eq!(scale.least_index(75.), 2); assert_eq!(scale.least_index(76.), 2); assert_eq!(scale.least_index(-10.), 0); assert_eq!(scale.least_index(150.), 2); }
149
150 #[test]
151 fn test_least_index_with_offset() {
152 let scale = ScalePoint::new(vec![1, 2, 3], vec![40., 80.]);
153
154 assert_eq!(scale.least_index(40.), 0);
156 assert_eq!(scale.least_index(60.), 1);
157 assert_eq!(scale.least_index(80.), 2);
158
159 assert_eq!(scale.least_index(49.), 0); assert_eq!(scale.least_index(50.), 1); assert_eq!(scale.least_index(51.), 1); assert_eq!(scale.least_index(69.), 1); assert_eq!(scale.least_index(70.), 2); assert_eq!(scale.least_index(71.), 2); assert_eq!(scale.least_index(30.), 0); assert_eq!(scale.least_index(100.), 2); }
171
172 #[test]
173 fn test_least_index_empty() {
174 let scale = ScalePoint::new(Vec::<i32>::new(), vec![0., 100.]);
175 assert_eq!(scale.least_index(0.), 0);
176 assert_eq!(scale.least_index(50.), 0);
177 assert_eq!(scale.least_index(100.), 0);
178 }
179
180 #[test]
181 fn test_least_index_single() {
182 let scale = ScalePoint::new(vec![1], vec![0., 100.]);
183 assert_eq!(scale.least_index(0.), 0);
184 assert_eq!(scale.least_index(50.), 0);
185 assert_eq!(scale.least_index(100.), 0);
186 }
187
188 #[test]
189 fn test_least_index_empty_range() {
190 let scale = ScalePoint::new(vec![1, 2, 3], vec![]);
191 assert_eq!(scale.least_index(0.), 0);
192 assert_eq!(scale.least_index(50.), 0);
193 assert_eq!(scale.least_index(100.), 0);
194 }
195}