use std::f64::consts::{ PI };
use std::ops::{ Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Neg };
use std::fmt::{ Display, Result as DRes };
use super::{ cylindrical::Cylindrical, spherical::Spherical };
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Cartesian {
pub x: f64,
pub y: f64,
pub z: f64
}
impl Display for Cartesian {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> DRes {
write!(f, "x={} :: y={} :: z={}", self.x, self.y, self.z)?;
Ok(())
}
}
impl Cartesian {
pub const fn origin() -> Self {
Self {
x: 0.0,
y: 0.0,
z: 0.0
}
}
pub fn from<T, U, V>(x: T, y: U, z: V) -> Self
where T: Into<f64>, U: Into<f64>, V: Into<f64> {
Self {
x: x.into(),
y: y.into(),
z: z.into()
}
}
pub fn from_coord<T>(c: T) -> Self
where T: Into<Self> {
c.into()
}
pub fn norm(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt()
}
pub fn distance_square(self, rhs: Self) -> f64 {
(rhs.x - self.x).powi(2) + (rhs.y - self.y).powi(2) + (rhs.z - self.z).powi(2)
}
pub fn distance(self, rhs: Self) -> f64 {
self.distance_square(rhs).sqrt()
}
pub fn rotate(&self, yaw: f64, pitch: f64, roll: f64) -> Self {
let (y_sin, y_cos): (f64, f64) = yaw.sin_cos();
let (p_sin, p_cos): (f64, f64) = pitch.sin_cos();
let (r_sin, r_cos): (f64, f64) = roll.sin_cos();
let a11: f64 = y_cos * p_cos;
let a12: f64 = y_cos * p_sin * r_sin - y_sin * r_cos;
let a13: f64 = y_cos * p_sin * r_cos + y_sin * r_sin;
let a21: f64 = y_sin * p_cos;
let a22: f64 = y_sin * p_sin * r_sin + y_cos * r_cos;
let a23: f64 = y_sin * p_sin * r_cos - y_cos * r_sin;
let a31: f64 = -p_sin;
let a32: f64 = p_cos * r_sin;
let a33: f64 = p_cos * r_cos;
Self {
x: a11 * self.x + a12 * self.y + a13 * self.z,
y: a21 * self.x + a22 * self.y + a23 * self.z,
z: a31 * self.x + a32 * self.y + a33 * self.z
}
}
}
impl Into<Spherical> for Cartesian {
fn into(self) -> Spherical {
let rho: f64 = self.norm();
let mut nt: f64 = (self.y / self.x).atan();
if self.x.is_sign_negative() {
nt += PI;
}
Spherical {
r: rho,
theta: nt,
phi: (self.z / rho).acos()
}
}
}
impl Into<Cylindrical> for Cartesian {
fn into(self) -> Cylindrical {
let rho: f64 = (self.x.powi(2) + self.y.powi(2)).sqrt();
let mut nt: f64 = (self.y / self.x).atan();
if self.x.is_sign_negative() {
nt += PI;
}
Cylindrical {
r: rho,
theta: nt,
z: self.z
}
}
}
impl<T: Into<Self>> Add<T> for Cartesian {
type Output = Self;
fn add(self, rhs: T) -> Self::Output {
let rhs: Self = rhs.into();
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z
}
}
}
impl Add<&Self> for Cartesian {
type Output = Self;
fn add(self, rhs: &Self) -> Self::Output {
Self {
x: self.x + rhs.x,
y: self.y + rhs.y,
z: self.z + rhs.z
}
}
}
impl<T: Into<Self>> AddAssign<T> for Cartesian {
fn add_assign(&mut self, rhs: T) {
let rhs: Self = rhs.into();
self.x += rhs.x;
self.y += rhs.y;
self.z += rhs.z;
}
}
impl AddAssign<&Self> for Cartesian {
fn add_assign(&mut self, rhs: &Self) {
self.x += rhs.x;
self.y += rhs.y;
self.z += rhs.z;
}
}
impl<T: Into<Self>> Sub<T> for Cartesian {
type Output = Self;
fn sub(self, rhs: T) -> Self::Output {
let rhs: Self = rhs.into();
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z
}
}
}
impl Sub<&Self> for Cartesian {
type Output = Self;
fn sub(self, rhs: &Self) -> Self::Output {
Self {
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z
}
}
}
impl<T: Into<Self>> SubAssign<T> for Cartesian {
fn sub_assign(&mut self, rhs: T) {
let rhs: Self = rhs.into();
self.x -= rhs.x;
self.y -= rhs.y;
self.z -= rhs.z;
}
}
impl SubAssign<&Self> for Cartesian {
fn sub_assign(&mut self, rhs: &Self) {
self.x -= rhs.x;
self.y -= rhs.y;
self.z -= rhs.z;
}
}
impl<T: Into<f64>> Mul<T> for Cartesian {
type Output = Self;
fn mul(self, rhs: T) -> Self::Output {
let f: f64 = rhs.into();
Self {
x: self.x * f,
y: self.y * f,
z: self.z * f
}
}
}
impl<T: Into<f64>> MulAssign<T> for Cartesian {
fn mul_assign(&mut self, rhs: T) {
let f: f64 = rhs.into();
self.x *= f;
self.y *= f;
self.z *= f;
}
}
impl<T: Into<f64>> Div<T> for Cartesian {
type Output = Self;
fn div(self, rhs: T) -> Self::Output {
let f: f64 = 1.0 / rhs.into();
Self {
x: self.x * f,
y: self.y * f,
z: self.z * f,
}
}
}
impl<T: Into<f64>> DivAssign<T> for Cartesian {
fn div_assign(&mut self, rhs: T) {
let f: f64 = 1.0 / rhs.into();
self.x *= f;
self.y *= f;
self.z *= f;
}
}
impl Neg for Cartesian {
type Output = Self;
fn neg(self) -> Self::Output {
self * -1
}
}