use crate::coord::Coord64;
use crate::point::Point3;
use crate::transforms;
#[derive(Debug, Clone, Copy)]
pub struct RotationMatrix(
pub [[f64; 3]; 3]
);
impl RotationMatrix {
#[must_use]
pub const fn identity() -> Self {
Self([
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
])
}
#[must_use]
pub fn from_euler(rx: f64, ry: f64, rz: f64) -> Self {
let (sx, cx) = rx.sin_cos();
let (sy, cy) = ry.sin_cos();
let (sz, cz) = rz.sin_cos();
Self([
[cy*cz, cz.mul_add(-sx, -(sy*cx*cz)), cx.mul_add(cz, -(sy*sx*cz))],
[cy*sz, sx.mul_add(sy*sz, cx*cz), cx.mul_add(sy*sz, -(sx*cz))],
[-sy, cy*sx, cy*cx ],
])
}
#[must_use]
pub fn from_quat(qx: f64, qy: f64, qz: f64, qw: f64) -> Self {
let len = qw.mul_add(qw, qx.mul_add(qx, qy.mul_add(qy, qz * qz))).sqrt();
let (qx, qy, qz, qw) = (qx/len, qy/len, qz/len, qw/len);
let (x2, y2, z2) = (qx+qx, qy+qy, qz+qz);
let (xx, yy, zz) = (qx*x2, qy*y2, qz*z2);
let (xy, xz, yz) = (qx*y2, qx*z2, qy*z2);
let (wx, wy, wz) = (qw*x2, qw*y2, qw*z2);
Self([
[1.0 - (yy + zz), xy - wz, xz + wy ],
[xy + wz, 1.0 - (xx + zz), yz - wx ],
[xz - wy, yz + wx, 1.0 - (xx + yy)],
])
}
}
#[derive(Debug, Clone, Copy)]
pub struct Transform {
pub translate_x: f64,
pub translate_y: f64,
pub translate_z: f64,
pub scale_x: f64,
pub scale_y: f64,
pub scale_z: f64,
pub rotation: RotationMatrix,
}
impl Transform {
#[must_use]
pub const fn identity() -> Self {
Self {
translate_x: 0.0, translate_y: 0.0, translate_z: 0.0,
scale_x: 1.0, scale_y: 1.0, scale_z: 1.0,
rotation: RotationMatrix::identity(),
}
}
}
#[must_use]
pub struct Points(Vec<Point3<i64>>);
impl Points {
#[inline]
#[must_use]
pub fn as_slice(&self) -> &[Point3<i64>] {
&self.0
}
#[must_use]
pub fn into_vec(self) -> Vec<Point3<i64>> {
self.0
}
#[inline]
#[must_use]
pub fn to_f32(&self) -> Vec<[f32; 3]> {
self.0.iter().map(|p| [
p.x.to_f32(),
p.y.to_f32(),
p.z.to_f32(),
]).collect()
}
#[inline]
#[must_use]
pub fn to_i64(&self) -> Vec<[i64; 3]> {
self.0.iter().map(|p| [
p.x.raw(),
p.y.raw(),
p.z.raw(),
]).collect()
}
#[must_use]
pub const fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
#[must_use]
pub struct Mesh {
original: Vec<Point3<i64>>,
transform: Transform,
}
impl Mesh {
pub fn from_floats(verts: &[[f32; 3]]) -> Self {
Self {
original: verts.iter().map(|v| Point3 {
x: Coord64::from_f32(v[0]),
y: Coord64::from_f32(v[1]),
z: Coord64::from_f32(v[2]),
}).collect(),
transform: Transform::identity(),
}
}
pub fn translate(mut self, x: f32, y: f32, z: f32) -> Self {
self.transform.translate_x = f64::from(x);
self.transform.translate_y = f64::from(y);
self.transform.translate_z = f64::from(z);
self
}
pub fn scale(mut self, x: f32, y: f32, z: f32) -> Self {
self.transform.scale_x = f64::from(x);
self.transform.scale_y = f64::from(y);
self.transform.scale_z = f64::from(z);
self
}
pub fn rotate(mut self, x: f32, y: f32, z: f32) -> Self {
self.transform.rotation = RotationMatrix::from_euler(
f64::from(x), f64::from(y), f64::from(z),
);
self
}
pub fn rotate_quat(mut self, qx: f32, qy: f32, qz: f32, qw: f32) -> Self {
self.transform.rotation = RotationMatrix::from_quat(
f64::from(qx), f64::from(qy), f64::from(qz), f64::from(qw),
);
self
}
pub fn compute(&self) -> Points {
Points(transforms::apply_transform(&self.original, &self.transform))
}
#[must_use]
pub fn original_points(&self) -> &[Point3<i64>] {
&self.original
}
#[must_use]
pub const fn len(&self) -> usize {
self.original.len()
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.original.is_empty()
}
}
impl Point3<i64> {
#[must_use]
pub fn from_f32(x: f32, y: f32, z: f32) -> Self {
Self {
x: Coord64::from_f32(x),
y: Coord64::from_f32(y),
z: Coord64::from_f32(z),
}
}
#[must_use]
pub fn to_f32(&self) -> (f32, f32, f32) {
(self.x.to_f32(), self.y.to_f32(), self.z.to_f32())
}
#[must_use]
pub const fn to_i64(&self) -> (i64, i64, i64) {
(self.x.raw(), self.y.raw(), self.z.raw())
}
}