hyperbolic_drawing 1.0.0

Manipulate and display elements of 2D hyperbolic space (ℍ²)
Documentation
//! Interface with the [`plotters`] crate.
//! 
//! Somewhat incomplete.

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 fn draw_frame(&self) {
		todo!()
	}
	*/
	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};