use glam::Vec3;
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) struct Cplx {
pub re: f32,
pub im: f32,
}
impl Cplx {
pub(crate) const ZERO: Self = Self { re: 0.0, im: 0.0 };
#[inline]
pub(crate) const fn re(re: f32) -> Self {
Self { re, im: 0.0 }
}
#[inline]
pub(crate) const fn add(self, o: Self) -> Self {
Self {
re: self.re + o.re,
im: self.im + o.im,
}
}
#[inline]
pub(crate) const fn sub(self, o: Self) -> Self {
Self {
re: self.re - o.re,
im: self.im - o.im,
}
}
#[inline]
pub(crate) const fn mul(self, o: Self) -> Self {
Self {
re: self.re * o.re - self.im * o.im,
im: self.re * o.im + self.im * o.re,
}
}
#[inline]
pub(crate) const fn scale(self, s: f32) -> Self {
Self {
re: self.re * s,
im: self.im * s,
}
}
#[inline]
pub(crate) const fn conj(self) -> Self {
Self {
re: self.re,
im: -self.im,
}
}
#[inline]
pub(crate) fn norm_sqr(self) -> f32 {
self.im.mul_add(self.im, self.re * self.re)
}
#[inline]
pub(crate) fn div(self, o: Self) -> Self {
let denom = o.im.mul_add(o.im, o.re * o.re).max(1e-20);
Self {
re: self.im.mul_add(o.im, self.re * o.re) / denom,
im: self.re.mul_add(-o.im, self.im * o.re) / denom,
}
}
#[inline]
pub(crate) fn sqrt_forward_branch(self) -> Self {
if self.im == 0.0 && self.re < 0.0 {
return Self {
re: 0.0,
im: (-self.re).sqrt(),
};
}
let r = self.norm_sqr().sqrt().sqrt();
let theta = self.im.atan2(self.re) * 0.5;
let mut out = Self {
re: r * theta.cos(),
im: r * theta.sin(),
};
if out.re < 0.0 {
out = Self {
re: -out.re,
im: -out.im,
};
}
if out.re.abs() < 1e-9 && out.im < 0.0 {
out = Self {
re: -out.re,
im: -out.im,
};
}
out
}
}
impl std::ops::Add for Cplx {
type Output = Self;
#[inline]
fn add(self, o: Self) -> Self {
Self::add(self, o)
}
}
impl std::ops::Sub for Cplx {
type Output = Self;
#[inline]
fn sub(self, o: Self) -> Self {
Self::sub(self, o)
}
}
impl std::ops::Mul for Cplx {
type Output = Self;
#[inline]
fn mul(self, o: Self) -> Self {
Self::mul(self, o)
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct CVec3 {
pub re: Vec3,
pub im: Vec3,
}
impl CVec3 {
#[inline]
pub(crate) const fn from_real(v: Vec3) -> Self {
Self {
re: v,
im: Vec3::ZERO,
}
}
#[inline]
pub(crate) fn wavevector(that: Vec3, zhat: Vec3, tangential: f32, q: Cplx) -> Self {
Self {
re: that * tangential + zhat * q.re,
im: zhat * q.im,
}
}
#[inline]
pub(crate) fn add(self, o: Self) -> Self {
Self {
re: self.re + o.re,
im: self.im + o.im,
}
}
#[inline]
pub(crate) fn scale_real(self, s: f32) -> Self {
Self {
re: self.re * s,
im: self.im * s,
}
}
#[inline]
pub(crate) fn scale_complex(self, s: Cplx) -> Self {
Self {
re: self.re * s.re - self.im * s.im,
im: self.re * s.im + self.im * s.re,
}
}
#[inline]
pub(crate) fn cross_real(self, r: Vec3) -> Self {
Self {
re: self.re.cross(r),
im: self.im.cross(r),
}
}
#[inline]
pub(crate) fn cross(self, o: Self) -> Self {
Self {
re: self.re.cross(o.re) - self.im.cross(o.im),
im: self.re.cross(o.im) + self.im.cross(o.re),
}
}
#[inline]
pub(crate) fn dot_real(self, r: Vec3) -> Cplx {
Cplx {
re: self.re.dot(r),
im: self.im.dot(r),
}
}
#[inline]
pub(crate) fn conj(self) -> Self {
Self {
re: self.re,
im: -self.im,
}
}
}
impl std::ops::Add for CVec3 {
type Output = Self;
#[inline]
fn add(self, o: Self) -> Self {
Self::add(self, o)
}
}