1use super::{CoordTranslate, ReverseCoordTranslate};
2use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
3use crate::style::ShapeStyle;
4
5use std::ops::Range;
6
7pub trait Ranged {
10 type ValueType;
12
13 fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32;
15
16 fn key_points(&self, max_points: usize) -> Vec<Self::ValueType>;
18
19 fn range(&self) -> Range<Self::ValueType>;
21}
22
23pub trait ReversableRanged: Ranged {
27 fn unmap(&self, input: i32, limit: (i32, i32)) -> Option<Self::ValueType>;
28}
29
30pub struct RangedCoord<X: Ranged, Y: Ranged> {
32 logic_x: X,
33 logic_y: Y,
34 back_x: (i32, i32),
35 back_y: (i32, i32),
36}
37
38impl<X: Ranged, Y: Ranged> RangedCoord<X, Y> {
39 pub fn new<IntoX: Into<X>, IntoY: Into<Y>>(
41 logic_x: IntoX,
42 logic_y: IntoY,
43 actual: (Range<i32>, Range<i32>),
44 ) -> Self {
45 Self {
46 logic_x: logic_x.into(),
47 logic_y: logic_y.into(),
48 back_x: (actual.0.start, actual.0.end),
49 back_y: (actual.1.start, actual.1.end),
50 }
51 }
52
53 pub fn draw_mesh<E, DrawMesh: FnMut(MeshLine<X, Y>) -> Result<(), E>>(
55 &self,
56 h_limit: usize,
57 v_limit: usize,
58 mut draw_mesh: DrawMesh,
59 ) -> Result<(), E> {
60 let (xkp, ykp) = (
61 self.logic_x.key_points(v_limit),
62 self.logic_y.key_points(h_limit),
63 );
64
65 for logic_x in xkp {
66 let x = self.logic_x.map(&logic_x, self.back_x);
67 draw_mesh(MeshLine::XMesh(
68 (x, self.back_y.0),
69 (x, self.back_y.1),
70 &logic_x,
71 ))?;
72 }
73
74 for logic_y in ykp {
75 let y = self.logic_y.map(&logic_y, self.back_y);
76 draw_mesh(MeshLine::YMesh(
77 (self.back_x.0, y),
78 (self.back_x.1, y),
79 &logic_y,
80 ))?;
81 }
82
83 Ok(())
84 }
85
86 pub fn get_x_range(&self) -> Range<X::ValueType> {
88 self.logic_x.range()
89 }
90
91 pub fn get_y_range(&self) -> Range<Y::ValueType> {
93 self.logic_y.range()
94 }
95}
96
97impl<X: Ranged, Y: Ranged> CoordTranslate for RangedCoord<X, Y> {
98 type From = (X::ValueType, Y::ValueType);
99
100 fn translate(&self, from: &Self::From) -> BackendCoord {
101 (
102 self.logic_x.map(&from.0, self.back_x),
103 self.logic_y.map(&from.1, self.back_y),
104 )
105 }
106}
107
108impl<X: ReversableRanged, Y: ReversableRanged> ReverseCoordTranslate for RangedCoord<X, Y> {
109 fn reverse_translate(&self, input: BackendCoord) -> Option<Self::From> {
110 Some((
111 self.logic_x.unmap(input.0, self.back_x)?,
112 self.logic_y.unmap(input.1, self.back_y)?,
113 ))
114 }
115}
116
117pub enum MeshLine<'a, X: Ranged, Y: Ranged> {
119 XMesh(BackendCoord, BackendCoord, &'a X::ValueType),
120 YMesh(BackendCoord, BackendCoord, &'a Y::ValueType),
121}
122
123impl<'a, X: Ranged, Y: Ranged> MeshLine<'a, X, Y> {
124 pub fn draw<DB: DrawingBackend>(
126 &self,
127 backend: &mut DB,
128 style: &ShapeStyle,
129 ) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
130 let (&left, &right) = match self {
131 MeshLine::XMesh(a, b, _) => (a, b),
132 MeshLine::YMesh(a, b, _) => (a, b),
133 };
134 backend.draw_line(left, right, &Box::new(style.color))
135 }
136}
137
138pub trait DescreteRanged
140where
141 Self: Ranged,
142 Self::ValueType: Eq,
143{
144 fn next_value(this: &Self::ValueType) -> Self::ValueType;
146}
147
148pub trait AsRangedCoord: Sized {
150 type CoordDescType: Ranged + From<Self>;
151 type Value;
152}
153
154impl<T> AsRangedCoord for T
155where
156 T: Ranged,
157 Range<T::ValueType>: Into<T>,
158{
159 type CoordDescType = T;
160 type Value = T::ValueType;
161}