use std::ops::{Add, Sub};
use crate::{Zero, linear_algebra::{
matrix3::Matrix3,
matrix4::Matrix4,
vector3::Vector3
}, rotation::{Rotation, quaternion::Quaternion}};
#[derive(Debug, Clone, Copy)]
pub struct Space {
pub center: Vector3<f32>,
pub rotation: Quaternion<f32>,
pub scale_factor: Matrix3<f32>
}
impl Space {
#[allow(clippy::redundant_closure)] pub fn new(
center: Option<Vector3<f32>>,
rotation: Option<Quaternion<f32>>,
scale_factor: Option<Vector3<f32>>) -> Space {
let vec = scale_factor.unwrap_or_else(|| Vector3::new(1.0, 1.0, 1.0));
Space{
rotation: rotation.unwrap_or_else(|| Quaternion::f32_identity()),
center: center.unwrap_or(Vector3::ZERO),
scale_factor: Matrix3::new(
[vec.0, 0.0, 0.0],
[0.0, vec.1, 0.0],
[0.0, 0.0, vec.2],
)
}
}
pub fn identity() -> Space {
Space{
rotation: Quaternion::f32_identity(),
center: Vector3::ZERO,
scale_factor: Matrix3::identity()
}
}
pub fn join(&self, other: Space) -> Space {
let sf = self.scale_factor.transpose().m;
let left = other.rotation * Quaternion::new_vector_real(Vector3::from(sf[0]), 0.0) * other.rotation.reciprocal();
let up = other.rotation * Quaternion::new_vector_real(Vector3::from(sf[1]), 0.0) * other.rotation.reciprocal();
let frd = other.rotation * Quaternion::new_vector_real(Vector3::from(sf[2]), 0.0) * other.rotation.reciprocal();
let scl_mat = Matrix3::new(
[left.0, up.0, frd.0],
[left.1, up.1, frd.1],
[left.2, up.2, frd.2]
);
let rotated_center = other.rotation * Quaternion::new_vector_real(self.center, 0.0) * other.rotation.reciprocal();
Space{
rotation: other.rotation * self.rotation,
center: other.center + Vector3(rotated_center.0, rotated_center.1, rotated_center.2),
scale_factor: Matrix3::from(other.rotation).transpose() * (scl_mat * other.scale_factor)
}
}
pub fn join_reverse(&self, other: Space) -> Space {
let sf = other.scale_factor.transpose().m;
let left = self.rotation.reciprocal() * Quaternion::new_vector_real(Vector3::from(sf[0]), 0.0) * self.rotation;
let up = self.rotation.reciprocal() * Quaternion::new_vector_real(Vector3::from(sf[1]), 0.0) * self.rotation;
let frd = self.rotation.reciprocal() * Quaternion::new_vector_real(Vector3::from(sf[2]), 0.0) * self.rotation;
let scl_mat = Matrix3::new(
[left.0, up.0, frd.0],
[left.1, up.1, frd.1],
[left.2, up.2, frd.2]
);
let rotated_center = self.rotation.reciprocal() * Quaternion::new_vector_real(other.center - self.center, 0.0) * self.rotation;
Space{
rotation: self.rotation.reciprocal() * other.rotation,
center: Vector3(rotated_center.0, rotated_center.1, rotated_center.2),
scale_factor: Matrix3::from(self.rotation) * (scl_mat * self.scale_factor.inverse())
}
}
pub fn build(&self) -> Matrix4<f32>{
let res: Matrix4<f32> = Matrix4::from(Matrix3::from(self.rotation));
let scale_mat = Matrix4::from(self.scale_factor);
let translation_mat = Matrix4::new(
[1.0, 0.0, 0.0, self.center.0],
[0.0, 1.0, 0.0, self.center.1],
[0.0, 0.0, 1.0, self.center.2],
[0.0, 0.0, 0.0, 1.0],
);
translation_mat * res * scale_mat
}
pub fn translate(&mut self, vector: Vector3<f32>){
self.center = self.center + vector;
}
pub fn rotate(&mut self, quaternion: Quaternion<f32>){ self.rotation = quaternion.unit_quaternion() * self.rotation.unit_quaternion();
}
pub fn look_at(&mut self, look_at: Vector3<f32>){
self.rotation = Quaternion::camera_look_at_xy(self.center, look_at);
}
}
impl Add for Space {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
self.join(rhs)
}
}
impl Sub for Space {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self.join_reverse(rhs)
}
}