pub trait Convert<T> {
fn convert(self) -> T;
}
pub trait ApproximateConvert<T> {
fn approximate_convert(self) -> T;
}
pub trait BatchConvertExact<T, U> {
fn convert_batch_exact(self) -> U;
}
pub trait BatchConvertApproximate<T, U> {
fn convert_batch_approximate(self) -> U;
}
use crate::coordinates::square::{ Coordinate as SquareCoord, FourConnected as SquareFour, EightConnected as SquareEight };
use crate::coordinates::isometric::{ Coordinate as IsoCoord, Diamond };
impl Convert<IsoCoord<Diamond>> for SquareCoord<SquareFour> {
fn convert(self) -> IsoCoord<Diamond> {
IsoCoord::<Diamond>::new(self.x, self.y)
}
}
impl Convert<IsoCoord<Diamond>> for SquareCoord<SquareEight> {
fn convert(self) -> IsoCoord<Diamond> {
IsoCoord::<Diamond>::new(self.x, self.y)
}
}
impl Convert<SquareCoord<SquareFour>> for IsoCoord<Diamond> {
fn convert(self) -> SquareCoord<SquareFour> {
SquareCoord::<SquareFour>::new(self.x, self.y)
}
}
impl Convert<SquareCoord<SquareEight>> for IsoCoord<Diamond> {
fn convert(self) -> SquareCoord<SquareEight> {
SquareCoord::<SquareEight>::new(self.x, self.y)
}
}
use crate::coordinates::hexagonal::{ Coordinate as HexCoord, Axial, Pointy };
impl<Orientation> ApproximateConvert<SquareCoord<SquareFour>> for HexCoord<Axial, Orientation> {
fn approximate_convert(self) -> SquareCoord<SquareFour> {
let x = self.q + (self.r / 2);
let y = self.r;
SquareCoord::<SquareFour>::new(x, y)
}
}
impl<Orientation> ApproximateConvert<SquareCoord<SquareEight>> for HexCoord<Axial, Orientation> {
fn approximate_convert(self) -> SquareCoord<SquareEight> {
let x = self.q + (self.r / 2);
let y = self.r;
SquareCoord::<SquareEight>::new(x, y)
}
}
impl<Connectivity> ApproximateConvert<HexCoord<Axial, Pointy>> for SquareCoord<Connectivity> {
fn approximate_convert(self) -> HexCoord<Axial, Pointy> {
let q = self.x - (self.y / 2);
let r = self.y;
HexCoord::<Axial, Pointy>::new(q, r)
}
}
impl<Orientation> ApproximateConvert<IsoCoord<Diamond>> for HexCoord<Axial, Orientation> {
fn approximate_convert(self) -> IsoCoord<Diamond> {
let square: SquareCoord<SquareFour> = self.approximate_convert();
square.convert()
}
}
impl ApproximateConvert<HexCoord<Axial, Pointy>> for IsoCoord<Diamond> {
fn approximate_convert(self) -> HexCoord<Axial, Pointy> {
let square: SquareCoord<SquareFour> = self.convert();
square.approximate_convert()
}
}
use crate::coordinates::triangular::{ Coordinate as TriCoord, TwelveConnected };
impl ApproximateConvert<SquareCoord<SquareFour>> for TriCoord<TwelveConnected> {
fn approximate_convert(self) -> SquareCoord<SquareFour> {
let x = self.x;
let y = self.y / 2; SquareCoord::<SquareFour>::new(x, y)
}
}
impl ApproximateConvert<SquareCoord<SquareEight>> for TriCoord<TwelveConnected> {
fn approximate_convert(self) -> SquareCoord<SquareEight> {
let x = self.x;
let y = self.y / 2;
SquareCoord::<SquareEight>::new(x, y)
}
}
impl<Connectivity> ApproximateConvert<TriCoord<TwelveConnected>> for SquareCoord<Connectivity> {
fn approximate_convert(self) -> TriCoord<TwelveConnected> {
let x = self.x;
let y = self.y * 2;
TriCoord::<TwelveConnected>::new(x, y)
}
}
impl ApproximateConvert<IsoCoord<Diamond>> for TriCoord<TwelveConnected> {
fn approximate_convert(self) -> IsoCoord<Diamond> {
let square: SquareCoord<SquareFour> = self.approximate_convert();
square.convert()
}
}
impl ApproximateConvert<TriCoord<TwelveConnected>> for IsoCoord<Diamond> {
fn approximate_convert(self) -> TriCoord<TwelveConnected> {
let square: SquareCoord<SquareFour> = self.convert();
square.approximate_convert()
}
}
impl ApproximateConvert<HexCoord<Axial, Pointy>> for TriCoord<TwelveConnected> {
fn approximate_convert(self) -> HexCoord<Axial, Pointy> {
let square: SquareCoord<SquareFour> = self.approximate_convert();
square.approximate_convert()
}
}
impl<Orientation> ApproximateConvert<TriCoord<TwelveConnected>> for HexCoord<Axial, Orientation> {
fn approximate_convert(self) -> TriCoord<TwelveConnected> {
let square: SquareCoord<SquareFour> = self.approximate_convert();
square.approximate_convert()
}
}
impl<T, U> BatchConvertExact<Vec<T>, Vec<U>> for Vec<T>
where
T: Convert<U>,
{
fn convert_batch_exact(self) -> Vec<U> {
self.into_iter().map(|coord| coord.convert()).collect()
}
}
impl<T, U> BatchConvertApproximate<Vec<T>, Vec<U>> for Vec<T>
where
T: ApproximateConvert<U>,
{
fn convert_batch_approximate(self) -> Vec<U> {
self.into_iter().map(|coord| coord.approximate_convert()).collect()
}
}
pub fn convert_batch_exact<T, U>(coords: Vec<T>) -> Vec<U>
where
T: Convert<U>,
{
coords.into_iter().map(|coord| coord.convert()).collect()
}
pub fn convert_batch_approximate<T, U>(coords: Vec<T>) -> Vec<U>
where
T: ApproximateConvert<U>,
{
coords.into_iter().map(|coord| coord.approximate_convert()).collect()
}
pub fn test_roundtrip_conversion<T, U, V>(original: T) -> bool
where
T: Convert<U> + PartialEq + Clone,
U: Convert<V>,
V: PartialEq<T>,
{
let converted: U = original.clone().convert();
let roundtrip: V = converted.convert();
roundtrip == original
}
pub fn measure_approximate_conversion_error<T, U>(original: T) -> f64
where
T: ApproximateConvert<U> + Clone,
U: ApproximateConvert<T>,
T: Into<(i32, i32)>,
{
let converted: U = original.clone().approximate_convert();
let roundtrip: T = converted.approximate_convert();
let (x1, y1) = original.into();
let (x2, y2) = roundtrip.into();
let dx = (x2 - x1) as f64;
let dy = (y2 - y1) as f64;
(dx * dx + dy * dy).sqrt()
}