use crate::{ m3x3::M3x3, quats::{Quat, RadianQuat}, v2::V2, }; use std::ops::{Add, Div, Mul, Neg, Sub}; #[derive(Clone, Copy, Debug)] pub struct V3(pub f64, pub f64, pub f64); impl V3 { pub fn init(v: f64) -> Self { Self(v, v, v) } pub fn map f64>(&self, func: F) -> Self { Self(func(self.0), func(self.1), func(self.2)) } pub fn zip f64>(&self, rhs: V3, func: F) -> Self { Self( func(self.0, rhs.0), func(self.1, rhs.1), func(self.2, rhs.2), ) } pub fn iter(&self) -> impl Iterator { [self.0, self.1, self.2].into_iter() } pub fn reduce f64>(&self, initial: f64, func: F) -> f64 { let mut acc = initial; for v in self.iter() { acc = func(acc, v); } acc } pub fn cross(&self, rhs: V3) -> Self { let V3(ax, ay, az) = self; let V3(bx, by, bz) = rhs; V3(ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx) } pub fn rotate_by_v3(&self, rot: V3) -> Self { M3x3::new_rotate_z(rot.2) * (M3x3::new_rotate_y(rot.1) * (M3x3::new_rotate_x(rot.0) * *self)) } pub fn rotate_by_quat(&self, rot: RadianQuat) -> Self { let u = rot.vector_quat(); let theta = rot.rad; let q_real = theta.cos(); let q_vector = u * theta.sin(); let p = *self; let r = p + (u.cross(p)) * 2.0 * theta.cos() * theta.sin() + (u * 2.0 * theta.sin().powi(2)).cross(u.cross(p)); r } pub fn rotate_by_m3x3(&self, rot: M3x3) -> Self { rot * *self } /// See https://en.wikipedia.org/wiki/3D_projection#Mathematical_formula /// for details on the implementation. pub fn project_2d(&self, camera_pos: V3, camera_rot: M3x3, screen_rel_pos: V3) -> V2 { let a = *self; let c = camera_pos; let d = (a - c).rotate_by_m3x3(camera_rot); let e = screen_rel_pos - c; V2(e.2 / d.2 * d.0 + e.0, e.2 / d.2 * d.1 + e.1) } pub fn angle(&self, rhs: Self) -> f64 { (self.dot(rhs) / (self.len() * rhs.len())).acos() } pub fn dot(&self, rhs: Self) -> f64 { self.zip(rhs, |a, b| a * b).reduce(0.0, |acc, v| acc + v) } pub fn translate(&self, offset: Self) -> Self { *self + offset } pub fn scale(&self, scale: Self) -> Self { self.zip(scale, |a, b| a * b) } pub fn len(&self) -> f64 { self.map(|v| v.powi(2)).reduce(0.0, |acc, v| acc + v).sqrt() } pub fn unit(&self) -> V3 { *self / self.len() } } impl Add for V3 { type Output = V3; fn add(self, rhs: V3) -> Self::Output { self.zip(rhs, |a, b| a + b) } } impl Sub for V3 { type Output = V3; fn sub(self, rhs: V3) -> Self::Output { self.zip(rhs, |a, b| a - b) } } impl Mul for V3 { type Output = V3; fn mul(self, rhs: f64) -> Self::Output { self.map(|v| v * rhs) } } impl Div for V3 { type Output = V3; fn div(self, rhs: f64) -> Self::Output { self.map(|v| v / rhs) } } impl Neg for V3 { type Output = V3; fn neg(self) -> Self::Output { V3::init(0.0) - self } }