use std::{marker::PhantomData, ops::Range};
pub trait HasUnitFormatter {
type Formatter: Ranged<ValueType = Self> + ReversibleRanged;
fn unit_formatter() -> Self::Formatter;
fn reverse_unit_formatter() -> Self::Formatter;
}
impl HasUnitFormatter for f32 {
type Formatter = RangedCoordf32;
fn unit_formatter() -> Self::Formatter {
Self::Formatter::from(-1.0..1.0)
}
fn reverse_unit_formatter() -> Self::Formatter {
Self::Formatter::from(1.0..-1.0)
}
}
impl HasUnitFormatter for f64 {
type Formatter = RangedCoordf64;
fn unit_formatter() -> Self::Formatter {
Self::Formatter::from(-1.0..1.0)
}
fn reverse_unit_formatter() -> Self::Formatter {
Self::Formatter::from(1.0..-1.0)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Poincaré2D<K: Scalar + HasUnitFormatter = f64> {
_marker: PhantomData<fn (K)>,
back_x: (i32, i32),
back_y: (i32, i32),
}
impl<K: Scalar + HasUnitFormatter> Poincaré2D<K> {
pub const fn new(actual: (Range<i32>, Range<i32>)) -> Self {
Self {
_marker: PhantomData,
back_x: (actual.0.start, actual.0.end),
back_y: (actual.1.start, actual.1.end),
}
}
pub const fn get_x_axis_pixel_range(&self) -> Range<i32> {
self.back_x.0..self.back_x.1
}
pub const fn get_y_axis_pixel_range(&self) -> Range<i32> {
self.back_y.0..self.back_y.1
}
}
impl<K: Scalar + HasUnitFormatter> CoordTranslate for Poincaré2D<K> {
type From = WeightedPoint<K>;
fn translate(&self, from: &Self::From) -> (i32, i32) {
let (ux, uy) = from.poincaré();
(
K::unit_formatter().map(&ux, self.back_x),
K::reverse_unit_formatter().map(&uy, self.back_y),
)
}
}
impl<K: Scalar + HasUnitFormatter> ReverseCoordTranslate for Poincaré2D<K> {
fn reverse_translate(&self, input: (i32, i32)) -> Option<Self::From> {
let x = K::unit_formatter().unmap(input.0, self.back_x)?;
let y = K::reverse_unit_formatter().unmap(input.1, self.back_y)?;
(x * x + y * y < K::ONE).then_some(WeightedPoint { t: K::ONE, x, y })
}
}
use plotters::{coord::{ranged1d::ReversibleRanged, types::{RangedCoordf32, RangedCoordf64}, CoordTranslate, ReverseCoordTranslate}, prelude::Ranged};
pub use Poincaré2D as Poincare2D;
use crate::{Scalar, WeightedPoint};