hcomplex/transform/moebius/
base.rs

1use core::ops::{Neg, Add, Sub, Mul, Div};
2use num_traits::{Zero, One, NumCast};
3use crate::{*, transform::*};
4
5
6#[derive(Copy, Clone, Debug, PartialEq)]
7pub struct Moebius<U> {
8    data: [U; 4],
9}
10
11impl<U> From<[U; 4]> for Moebius<U> {
12    fn from(array: [U; 4]) -> Self {
13        Self { data: array }
14    }
15}
16impl<U> Into<[U; 4]> for Moebius<U> {
17    fn into(self) -> [U; 4] {
18        self.data
19    }
20}
21
22impl<U> Moebius<U> {
23    pub fn new(a: U, b: U, c: U, d: U) -> Self {
24        Self::from([a, b, c, d])
25    }
26
27    pub fn a_ref(&self) -> &U { &self.data[0] }
28    pub fn b_ref(&self) -> &U { &self.data[1] }
29    pub fn c_ref(&self) -> &U { &self.data[2] }
30    pub fn d_ref(&self) -> &U { &self.data[3] }
31
32    pub fn a_mut(&mut self) -> &mut U { &mut self.data[0] }
33    pub fn b_mut(&mut self) -> &mut U { &mut self.data[1] }
34    pub fn c_mut(&mut self) -> &mut U { &mut self.data[2] }
35    pub fn d_mut(&mut self) -> &mut U { &mut self.data[3] }
36}
37
38impl<U: Clone> Moebius<U> {
39    pub fn a(&self) -> U { self.data[0].clone() }
40    pub fn b(&self) -> U { self.data[1].clone() }
41    pub fn c(&self) -> U { self.data[2].clone() }
42    pub fn d(&self) -> U { self.data[3].clone() }
43}
44
45impl<U: Zero + One> Identity for Moebius<U> {
46    fn identity() -> Self {
47        Self::new(U::one(), U::zero(), U::zero(), U::one())
48    }
49}
50
51impl<U> Chain<U> for Moebius<U> where U: Add<Output=U> + Mul<Output=U> + Div<Output=U> + Clone {
52    fn chain(self, other: Self) -> Self {
53        Self::new(
54            self.a()*other.a() + self.b()*other.c(),
55            self.a()*other.b() + self.b()*other.d(),
56            self.c()*other.a() + self.d()*other.c(),
57            self.c()*other.b() + self.d()*other.d(),
58        )
59    }
60}
61
62impl<U> Transform<U> for Moebius<U> where U: Add<Output=U> + Mul<Output=U> + Div<Output=U> + Clone {
63    fn apply(&self, x: U) -> U {
64        (self.a()*x.clone() + self.b())/(self.c()*x + self.d())
65    }
66}
67impl<T: Algebra + Clone, U: Algebra<T> + Clone> Transform<Construct<T, Construct<T, U>>> for Moebius<Construct<T, U>> {
68    fn apply(&self, x: Construct<T, Construct<T, U>>) -> Construct<T, Construct<T, U>> {
69        (self.a()*x.clone() + self.b())/(self.c()*x + self.d())
70    }
71}
72
73impl<U: Neg<Output=U> + Mul<Output=U> + Div<Output=U> + Sub<Output=U> + Clone> Moebius<U> {
74    pub fn det(&self) -> U {
75        self.a()*self.d() - self.b()*self.c()
76    }
77    pub fn normalize(mut self) -> Self {
78        let det = self.det();
79        self.data.iter_mut().for_each(|x| *x = x.clone() / det.clone());
80        self
81    }
82}
83
84impl<T: Algebra + Clone> Deriv<Complex<T>> for Moebius<Complex<T>> {
85    fn deriv(&self, p: Complex<T>) -> Complex<T> {
86        let u: Complex<T> = self.a() * p.clone() + self.b();
87        let d: Complex<T> = self.c() * p + self.d();
88        return (self.a() * d.clone() - u * self.c()) / (d.clone() * d);
89    }
90}
91
92impl<T: NumCast + Algebra + Dot<Output=T> + Clone> DerivDir<Quaternion<T>> for Moebius<Complex<T>> {
93    fn deriv_dir(&self, p: Quaternion<T>, v: Quaternion<T>) -> Quaternion<T> {
94        let u = self.a() * p.clone() + self.b();
95        let d = self.c() * p + self.d();
96        let d2 = d.clone().abs_sqr();
97        let g1 = (self.a() * v.clone()) / d.clone();
98        let g21 = (self.c() * v.clone()).conj();
99        let g22 = d.clone().conj() * (d.dot(self.c() * v) * T::from(2).unwrap() / d2.clone());
100        let g2 = u * ((g21 - g22) / d2);
101        return g1 + g2;
102    }
103}