gpui_base/plot/scale/
linear.rs1use itertools::Itertools;
4
5use super::{PlotValue, Scale};
6
7#[derive(Clone)]
8pub struct ScaleLinear<T> {
9 domain_start: T,
10 domain_diff: T,
11 range_start: f32,
12 range_diff: f32,
13}
14
15impl<T: PlotValue> ScaleLinear<T> {
16 pub fn new(domain: impl IntoIterator<Item = T>, range: [f32; 2]) -> Self {
20 let (domain_start, domain_end) = domain
21 .into_iter()
22 .minmax_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
23 .into_option()
24 .unwrap_or((T::zero(), T::zero()));
25
26 Self {
27 domain_start,
28 domain_diff: domain_end - domain_start,
29 range_start: range[0],
30 range_diff: range[1] - range[0],
31 }
32 }
33}
34
35impl<T: PlotValue> Scale<T> for ScaleLinear<T> {
36 fn tick(&self, value: &T) -> Option<f32> {
37 if self.domain_diff.is_zero() {
38 return None;
39 }
40
41 let ratio = ((*value - self.domain_start) / self.domain_diff).to_f32()?;
42
43 Some(ratio * self.range_diff + self.range_start)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn test_scale_linear() {
53 let scale = ScaleLinear::new(vec![1., 2., 3.], [0., 100.]);
54 assert_eq!(scale.tick(&1.), Some(0.));
55 assert_eq!(scale.tick(&2.), Some(50.));
56 assert_eq!(scale.tick(&3.), Some(100.));
57
58 let scale = ScaleLinear::new(vec![1., 2., 3.], [100., 0.]);
59 assert_eq!(scale.tick(&1.), Some(100.));
60 assert_eq!(scale.tick(&2.), Some(50.));
61 assert_eq!(scale.tick(&3.), Some(0.));
62 }
63
64 #[test]
65 fn test_scale_linear_unordered_domain() {
66 let scale = ScaleLinear::new([3., 1., 2.], [0., 100.]);
67 assert_eq!(scale.tick(&1.), Some(0.));
68 assert_eq!(scale.tick(&3.), Some(100.));
69 }
70
71 #[test]
72 fn test_scale_linear_f32() {
73 let scale = ScaleLinear::new([0f32, 4.], [0., 100.]);
74 assert_eq!(scale.tick(&1f32), Some(25.));
75 assert_eq!(scale.tick(&4f32), Some(100.));
76 }
77
78 #[test]
79 fn test_scale_linear_empty() {
80 let scale = ScaleLinear::<f64>::new(vec![], [0., 100.]);
81 assert_eq!(scale.tick(&1.), None);
82 assert_eq!(scale.tick(&2.), None);
83 assert_eq!(scale.tick(&3.), None);
84
85 let scale = ScaleLinear::new(vec![1., 2., 3.], [0., 0.]);
86 assert_eq!(scale.tick(&1.), Some(0.));
87 assert_eq!(scale.tick(&2.), Some(0.));
88 assert_eq!(scale.tick(&3.), Some(0.));
89 }
90}