use fixed::traits::{Fixed, ToFixed};
use fixed::types::extra::*;
use crate::num_traits as num;
use crate::traits::*;
use crate::types::*;
use crate::types::coordinate::*;
macro_rules! impl_dimension {
(
$point:ident, $vector:ident, $matrix:ident, $position:ident, $displacement:ident,
$transform:ident, $fixed_point:ident, $fixed_vector:ident, $fixed_matrix:ident,
$dimension:expr, $mat_dims:expr, [$($component:ident),+]
) => {
#[doc = "Convert to fixed precision"]
#[doc = $dimension]
#[doc = "vector"]
pub trait $fixed_vector <S> {
fn from_num <N : ToFixed> (num : $vector <N>) -> Self;
fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self;
}
impl <S> $fixed_vector <S> for $vector <S> where S : Fixed {
fn from_num <N : ToFixed> (num : $vector <N>) -> Self {
$vector::new ($(num.$component.to_fixed()),+)
}
fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self {
$vector::new ($(num.$component.wrapping_to_fixed()),+)
}
}
impl <S, U> $fixed_vector <S> for $displacement <S, U> where S : Fixed {
fn from_num <N : ToFixed> (num : $vector <N>) -> Self {
$vector::from_num (num).into()
}
fn wrapping_from_num <N : ToFixed> (num : $vector <N>) -> Self {
$vector::wrapping_from_num (num).into()
}
}
#[doc = "Convert to fixed precision"]
#[doc = $dimension]
#[doc = "point"]
pub trait $fixed_point <S> {
fn from_num <N : ToFixed> (num : $point <N>) -> Self;
fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self;
}
impl <S> $fixed_point <S> for $point <S> where S : Fixed {
fn from_num <N : ToFixed> (num : $point <N>) -> Self {
$vector::from_num (num.0).into()
}
fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self {
$vector::wrapping_from_num (num.0).into()
}
}
impl <S, U> $fixed_point <S> for $position <S, U> where S : Fixed {
fn from_num <N : ToFixed> (num : $point <N>) -> Self {
$point::from_num (num).into()
}
fn wrapping_from_num <N : ToFixed> (num : $point <N>) -> Self {
$point::wrapping_from_num (num).into()
}
}
#[doc = "Convert to fixed precision"]
#[doc = $mat_dims]
#[doc = "matrix"]
pub trait $fixed_matrix <S> {
fn from_num <N : ToFixed> (num : $matrix <N>) -> Self;
fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self;
}
impl <S> $fixed_matrix <S> for $matrix <S> where S : Fixed {
fn from_num <N : ToFixed> (num : $matrix <N>) -> Self {
$matrix {
cols: [
$($vector::from_num (num.cols.$component)),+
].into()
}
}
fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self {
$matrix {
cols: [
$($vector::wrapping_from_num (num.cols.$component)),+
].into()
}
}
}
impl <S, U, V> $fixed_matrix <S> for $transform <S, U, V> where
S : Fixed + num::Zero + num::One
{
fn from_num <N : ToFixed> (num : $matrix <N>) -> Self {
$matrix::from_num (num).into()
}
fn wrapping_from_num <N : ToFixed> (num : $matrix <N>) -> Self {
$matrix::wrapping_from_num (num).into()
}
}
}
}
impl_dimension!(
Point2, Vector2, Matrix2,
Position2, Displacement2, Transform2,
FixedPoint2, FixedVector2, FixedMatrix2, "2D",
"2x2", [x, y]);
impl_dimension!(
Point3, Vector3, Matrix3,
Position3, Displacement3, Transform3,
FixedPoint3, FixedVector3, FixedMatrix3, "3D",
"3x3", [x, y, z]);
impl_dimension!(
Point4, Vector4, Matrix4,
Position4, Displacement4, Transform4,
FixedPoint4, FixedVector4, FixedMatrix4, "4D",
"4x4", [x, y, z, w]);
macro impl_real_fixed ($fixed:ident,
$cordic_bound_1:ident, $cordic_bound_2:ident, $cordic_bound_3:ident,
$fixed_sqrt_bound:path
) {
impl <U> VectorSpace <Self> for fixed::$fixed <U> where
U : Unsigned +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True> +
$fixed_sqrt_bound
{
fn map <F> (self, mut f : F) -> Self where F : FnMut (Self) -> Self {
f (self)
}
}
impl <U> Module <Self> for fixed::$fixed <U> where
U : Unsigned +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True> +
$fixed_sqrt_bound
{
type LinearEndo = Self;
}
impl <U> LinearMap <Self, Self, Self> for fixed::$fixed <U> where
U : Unsigned +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True> +
$fixed_sqrt_bound
{
fn determinant (self) -> Self {
self
}
fn transpose (self) -> Self {
self
}
}
impl <U> Real for fixed::$fixed <U> where
U : Unsigned +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True> +
$fixed_sqrt_bound
{
fn pi() -> Self {
Self::from_num (fixed::consts::PI)
}
fn frac_pi_3() -> Self {
Self::from_num (fixed::consts::FRAC_PI_3)
}
fn sqrt_3() -> Self {
Self::from_num (fixed::consts::SQRT_3)
}
fn frac_1_sqrt_3() -> Self {
Self::from_num (fixed::consts::FRAC_1_SQRT_3)
}
fn floor (self) -> Self {
self.floor()
}
fn ceil (self) -> Self {
self.ceil()
}
fn trunc (self) -> Self {
self.int()
}
fn fract (self) -> Self {
self.frac()
}
}
impl <U> MinMax for fixed::$fixed <U> where U : Unsigned + $fixed_sqrt_bound {
fn min (self, other : Self) -> Self {
Ord::min (self, other)
}
fn max (self, other : Self) -> Self {
Ord::max (self, other)
}
fn clamp (self, min : Self, max : Self) -> Self {
Ord::clamp (self, min, max)
}
}
impl <U> Sqrt for fixed::$fixed <U> where U : $fixed_sqrt_bound {
fn sqrt (self) -> Self {
fixed_sqrt::FastSqrt::fast_sqrt (self)
}
}
impl <U> Exp for fixed::$fixed <U> where
U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True>
{
fn exp (self) -> Self {
cordic::exp (self)
}
}
impl <U> Powi for fixed::$fixed <U> where
U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
{
fn powi (self, _n : i32) -> Self {
unimplemented!("TODO: fixed integer powers")
}
}
impl <U> Powf for fixed::$fixed <U> where
U : Unsigned + IsLessOrEqual<$cordic_bound_2, Output = True> + $fixed_sqrt_bound
{
fn powf (self, _n : Self) -> Self {
unimplemented!("TODO: fixed fractional powers")
}
}
impl <U> Trig for fixed::$fixed <U> where
U : 'static + Unsigned + IsLessOrEqual<$cordic_bound_3, Output = True> +
IsLessOrEqual<$cordic_bound_2, Output = True> +
IsLessOrEqual<$cordic_bound_1, Output = True>
{
fn sin (self) -> Self {
cordic::sin (self)
}
fn sin_cos (self) -> (Self, Self) {
cordic::sin_cos (self)
}
fn cos (self) -> Self {
cordic::cos (self)
}
fn tan (self) -> Self {
cordic::tan (self)
}
fn asin (self) -> Self {
cordic::asin (self)
}
fn acos (self) -> Self {
cordic::acos (self)
}
fn atan (self) -> Self {
cordic::atan (self)
}
fn atan2 (self, other : Self) -> Self {
cordic::atan2 (self, other)
}
}
}
impl_real_fixed!(FixedI8, U5, U6, U8, fixed_sqrt::traits::LtU8);
impl_real_fixed!(FixedI16, U13, U14, U16, fixed_sqrt::traits::LtU16);
impl_real_fixed!(FixedI32, U29, U30, U32, fixed_sqrt::traits::LtU32);
impl_real_fixed!(FixedI64, U61, U62, U64, fixed_sqrt::traits::LtU64);