plotters_unstable/coord/ranged1d/
discrete.rs1use crate::coord::ranged1d::{
2 AsRangedCoord, KeyPointHint, NoDefaultFormatting, Ranged, ReversibleRanged, ValueFormatter,
3};
4use std::ops::Range;
5
6pub trait DiscreteRanged
12where
13 Self: Ranged,
14{
15 fn size(&self) -> usize;
20
21 fn index_of(&self, value: &Self::ValueType) -> Option<usize>;
30
31 fn from_index(&self, index: usize) -> Option<Self::ValueType>;
38
39 fn values(&self) -> DiscreteValueIter<'_, Self>
43 where
44 Self: Sized,
45 {
46 DiscreteValueIter(self, 0, self.size())
47 }
48
49 fn previous(&self, value: &Self::ValueType) -> Option<Self::ValueType> {
59 if let Some(idx) = self.index_of(value) {
60 if idx > 0 {
61 return self.from_index(idx - 1);
62 }
63 }
64 None
65 }
66
67 fn next(&self, value: &Self::ValueType) -> Option<Self::ValueType> {
77 if let Some(idx) = self.index_of(value) {
78 if idx + 1 < self.size() {
79 return self.from_index(idx + 1);
80 }
81 }
82 None
83 }
84}
85
86#[derive(Clone)]
95pub struct SegmentedCoord<D: DiscreteRanged>(D);
96
97pub trait IntoSegmentedCoord: AsRangedCoord
99where
100 Self::CoordDescType: DiscreteRanged,
101{
102 fn into_segmented(self) -> SegmentedCoord<Self::CoordDescType> {
104 SegmentedCoord(self.into())
105 }
106}
107
108impl<R: AsRangedCoord> IntoSegmentedCoord for R where R::CoordDescType: DiscreteRanged {}
109
110#[derive(Clone, Debug)]
112pub enum SegmentValue<T> {
113 Exact(T),
115 CenterOf(T),
117 Last,
119}
120
121impl<T, D: DiscreteRanged + Ranged<ValueType = T>> ValueFormatter<SegmentValue<T>>
122 for SegmentedCoord<D>
123where
124 D: ValueFormatter<T>,
125{
126 fn format(value: &SegmentValue<T>) -> String {
127 match value {
128 SegmentValue::Exact(ref value) => D::format(value),
129 SegmentValue::CenterOf(ref value) => D::format(value),
130 _ => "".to_string(),
131 }
132 }
133}
134
135impl<D: DiscreteRanged> Ranged for SegmentedCoord<D> {
136 type FormatOption = NoDefaultFormatting;
137 type ValueType = SegmentValue<D::ValueType>;
138
139 fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32 {
140 let margin = ((limit.1 - limit.0) as f32 / self.0.size() as f32).round() as i32;
141
142 match value {
143 SegmentValue::Exact(coord) => self.0.map(coord, (limit.0, limit.1 - margin)),
144 SegmentValue::CenterOf(coord) => {
145 let left = self.0.map(coord, (limit.0, limit.1 - margin));
146 if let Some(idx) = self.0.index_of(coord) {
147 if idx + 1 < self.0.size() {
148 let right = self.0.map(
149 &self.0.from_index(idx + 1).unwrap(),
150 (limit.0, limit.1 - margin),
151 );
152 return (left + right) / 2;
153 }
154 }
155 left + margin / 2
156 }
157 SegmentValue::Last => limit.1,
158 }
159 }
160
161 fn key_points<HintType: KeyPointHint>(&self, hint: HintType) -> Vec<Self::ValueType> {
162 self.0
163 .key_points(hint)
164 .into_iter()
165 .map(SegmentValue::CenterOf)
166 .collect()
167 }
168
169 fn range(&self) -> Range<Self::ValueType> {
170 let range = self.0.range();
171 SegmentValue::Exact(range.start)..SegmentValue::Exact(range.end)
172 }
173}
174
175impl<D: DiscreteRanged> DiscreteRanged for SegmentedCoord<D> {
176 fn size(&self) -> usize {
177 self.0.size() + 1
178 }
179
180 fn index_of(&self, value: &Self::ValueType) -> Option<usize> {
181 match value {
182 SegmentValue::Exact(value) => self.0.index_of(value),
183 SegmentValue::CenterOf(value) => self.0.index_of(value),
184 SegmentValue::Last => Some(self.0.size()),
185 }
186 }
187
188 fn from_index(&self, idx: usize) -> Option<Self::ValueType> {
189 match idx {
190 idx if idx < self.0.size() => self.0.from_index(idx).map(SegmentValue::Exact),
191 idx if idx == self.0.size() => Some(SegmentValue::Last),
192 _ => None,
193 }
194 }
195}
196
197impl<T> From<T> for SegmentValue<T> {
198 fn from(this: T) -> SegmentValue<T> {
199 SegmentValue::Exact(this)
200 }
201}
202
203impl<DC: DiscreteRanged> ReversibleRanged for DC {
204 fn unmap(&self, input: i32, limit: (i32, i32)) -> Option<Self::ValueType> {
205 let idx = (f64::from(input - limit.0) * (self.size() as f64) / f64::from(limit.1 - limit.0))
206 .floor() as usize;
207 self.from_index(idx)
208 }
209}
210
211pub struct DiscreteValueIter<'a, T: DiscreteRanged>(&'a T, usize, usize);
213
214impl<'a, T: DiscreteRanged> Iterator for DiscreteValueIter<'a, T> {
215 type Item = T::ValueType;
216 fn next(&mut self) -> Option<T::ValueType> {
217 if self.1 >= self.2 {
218 return None;
219 }
220 let idx = self.1;
221 self.1 += 1;
222 self.0.from_index(idx)
223 }
224}
225
226#[cfg(test)]
227mod test {
228 use super::*;
229 #[test]
230 fn test_value_iter() {
231 let range: crate::coord::ranged1d::types::RangedCoordi32 = (-10..10).into();
232
233 let values: Vec<_> = range.values().collect();
234
235 assert_eq!(21, values.len());
236
237 for (expected, value) in (-10..=10).zip(values) {
238 assert_eq!(expected, value);
239 }
240 assert_eq!(range.next(&5), Some(6));
241 assert_eq!(range.next(&10), None);
242 assert_eq!(range.previous(&-10), None);
243 assert_eq!(range.previous(&10), Some(9));
244 }
245
246 #[test]
247 fn test_centric_coord() {
248 let coord = (0..10).into_segmented();
249
250 assert_eq!(coord.size(), 12);
251 for i in 0..=11 {
252 match coord.from_index(i as usize) {
253 Some(SegmentValue::Exact(value)) => assert_eq!(i, value),
254 Some(SegmentValue::Last) => assert_eq!(i, 11),
255 _ => panic!(),
256 }
257 }
258
259 for (kps, idx) in coord.key_points(20).into_iter().zip(0..) {
260 match kps {
261 SegmentValue::CenterOf(value) if value <= 10 => assert_eq!(value, idx),
262 _ => panic!(),
263 }
264 }
265
266 assert_eq!(coord.map(&SegmentValue::CenterOf(0), (0, 24)), 1);
267 assert_eq!(coord.map(&SegmentValue::Exact(0), (0, 24)), 0);
268 assert_eq!(coord.map(&SegmentValue::Exact(1), (0, 24)), 2);
269 }
270}