plotters_unsable/coord/
logarithmic.rs1use super::{AsRangedCoord, Ranged, RangedCoordf64};
2use std::marker::PhantomData;
3use std::ops::Range;
4
5pub trait LogScalable: Clone {
7 fn as_f64(&self) -> f64;
9 fn from_f64(f: f64) -> Self;
11}
12
13macro_rules! impl_log_scalable {
14 (i, $t:ty) => {
15 impl LogScalable for $t {
16 fn as_f64(&self) -> f64 {
17 if *self != 0 {
18 return *self as f64;
19 }
20 return 0.5;
25 }
26 fn from_f64(f: f64) -> $t {
27 f.round() as $t
28 }
29 }
30 };
31 (f, $t:ty) => {
32 impl LogScalable for $t {
33 fn as_f64(&self) -> f64 {
34 *self as f64
35 }
36 fn from_f64(f: f64) -> $t {
37 f as $t
38 }
39 }
40 };
41}
42
43impl_log_scalable!(i, u8);
44impl_log_scalable!(i, u16);
45impl_log_scalable!(i, u32);
46impl_log_scalable!(i, u64);
47impl_log_scalable!(f, f32);
48impl_log_scalable!(f, f64);
49
50pub struct LogRange<V: LogScalable>(pub Range<V>);
52
53impl<V: LogScalable> From<LogRange<V>> for LogCoord<V> {
54 fn from(range: LogRange<V>) -> LogCoord<V> {
55 LogCoord {
56 linear: (range.0.start.as_f64().ln()..range.0.end.as_f64().ln()).into(),
57 logic: range.0,
58 marker: PhantomData,
59 }
60 }
61}
62
63impl<V: LogScalable> AsRangedCoord for LogRange<V> {
64 type CoordDescType = LogCoord<V>;
65 type Value = V;
66}
67
68pub struct LogCoord<V: LogScalable> {
70 linear: RangedCoordf64,
71 logic: Range<V>,
72 marker: PhantomData<V>,
73}
74
75impl<V: LogScalable> Ranged for LogCoord<V> {
76 type ValueType = V;
77
78 fn map(&self, value: &V, limit: (i32, i32)) -> i32 {
79 let value = value.as_f64();
80 let value = value.max(self.logic.start.as_f64()).ln();
81 self.linear.map(&value, limit)
82 }
83
84 fn key_points(&self, max_points: usize) -> Vec<Self::ValueType> {
85 let tier_1 = (self.logic.end.as_f64() / self.logic.start.as_f64())
86 .log10()
87 .abs()
88 .floor() as usize;
89 let tier_2_density = if max_points < tier_1 {
90 0
91 } else {
92 let density = 1 + (max_points - tier_1) / tier_1;
93 let mut exp = 1;
94 while exp * 10 <= density {
95 exp *= 10;
96 }
97 exp - 1
98 };
99
100 let mut multiplier = 10.0;
101 let mut cnt = 1;
102 while max_points < tier_1 / cnt {
103 multiplier *= 10.0;
104 cnt += 1;
105 }
106
107 let mut ret = vec![];
108 let mut val = (10f64).powf(self.logic.start.as_f64().log10().ceil());
109
110 while val <= self.logic.end.as_f64() {
111 ret.push(V::from_f64(val));
112 for i in 1..=tier_2_density {
113 let v = val
114 * (1.0
115 + multiplier / f64::from(tier_2_density as u32 + 1) * f64::from(i as u32));
116 if v > self.logic.end.as_f64() {
117 break;
118 }
119 ret.push(V::from_f64(v));
120 }
121 val *= multiplier;
122 }
123
124 ret
125 }
126
127 fn range(&self) -> Range<V> {
128 self.logic.clone()
129 }
130}