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