use super::{CoordTranslate, ReverseCoordTranslate};
use crate::drawing::backend::{BackendCoord, DrawingBackend, DrawingErrorKind};
use crate::style::ShapeStyle;
use std::ops::Range;
pub trait Ranged {
type ValueType;
fn map(&self, value: &Self::ValueType, limit: (i32, i32)) -> i32;
fn key_points(&self, max_points: usize) -> Vec<Self::ValueType>;
fn range(&self) -> Range<Self::ValueType>;
}
pub trait ReversableRanged: Ranged {
fn unmap(&self, input: i32, limit: (i32, i32)) -> Option<Self::ValueType>;
}
pub struct RangedCoord<X: Ranged, Y: Ranged> {
logic_x: X,
logic_y: Y,
back_x: (i32, i32),
back_y: (i32, i32),
}
impl<X: Ranged, Y: Ranged> RangedCoord<X, Y> {
pub fn new<IntoX: Into<X>, IntoY: Into<Y>>(
logic_x: IntoX,
logic_y: IntoY,
actual: (Range<i32>, Range<i32>),
) -> Self {
Self {
logic_x: logic_x.into(),
logic_y: logic_y.into(),
back_x: (actual.0.start, actual.0.end),
back_y: (actual.1.start, actual.1.end),
}
}
pub fn draw_mesh<E, DrawMesh: FnMut(MeshLine<X, Y>) -> Result<(), E>>(
&self,
h_limit: usize,
v_limit: usize,
mut draw_mesh: DrawMesh,
) -> Result<(), E> {
let (xkp, ykp) = (
self.logic_x.key_points(v_limit),
self.logic_y.key_points(h_limit),
);
for logic_x in xkp {
let x = self.logic_x.map(&logic_x, self.back_x);
draw_mesh(MeshLine::XMesh(
(x, self.back_y.0),
(x, self.back_y.1),
&logic_x,
))?;
}
for logic_y in ykp {
let y = self.logic_y.map(&logic_y, self.back_y);
draw_mesh(MeshLine::YMesh(
(self.back_x.0, y),
(self.back_x.1, y),
&logic_y,
))?;
}
Ok(())
}
pub fn get_x_range(&self) -> Range<X::ValueType> {
self.logic_x.range()
}
pub fn get_y_range(&self) -> Range<Y::ValueType> {
self.logic_y.range()
}
}
impl<X: Ranged, Y: Ranged> CoordTranslate for RangedCoord<X, Y> {
type From = (X::ValueType, Y::ValueType);
fn translate(&self, from: &Self::From) -> BackendCoord {
(
self.logic_x.map(&from.0, self.back_x),
self.logic_y.map(&from.1, self.back_y),
)
}
}
impl<X: ReversableRanged, Y: ReversableRanged> ReverseCoordTranslate for RangedCoord<X, Y> {
fn reverse_translate(&self, input: BackendCoord) -> Option<Self::From> {
Some((
self.logic_x.unmap(input.0, self.back_x)?,
self.logic_y.unmap(input.1, self.back_y)?,
))
}
}
pub enum MeshLine<'a, X: Ranged, Y: Ranged> {
XMesh(BackendCoord, BackendCoord, &'a X::ValueType),
YMesh(BackendCoord, BackendCoord, &'a Y::ValueType),
}
impl<'a, X: Ranged, Y: Ranged> MeshLine<'a, X, Y> {
pub fn draw<DB: DrawingBackend>(
&self,
backend: &mut DB,
style: &ShapeStyle,
) -> Result<(), DrawingErrorKind<DB::ErrorType>> {
let (&left, &right) = match self {
MeshLine::XMesh(a, b, _) => (a, b),
MeshLine::YMesh(a, b, _) => (a, b),
};
backend.draw_line(left, right, &style.color)
}
}
pub trait DescreteRanged
where
Self: Ranged,
Self::ValueType: Eq,
{
fn next_value(this: &Self::ValueType) -> Self::ValueType;
}
pub trait AsRangedCoord: Sized {
type CoordDescType: Ranged + From<Self>;
type Value;
}
impl<T> AsRangedCoord for T
where
T: Ranged,
Range<T::ValueType>: Into<T>,
{
type CoordDescType = T;
type Value = T::ValueType;
}