Use full 4x4 matrix for affine transformation
This commit is contained in:
parent
ae4dc2c21a
commit
c48790f32f
2 changed files with 172 additions and 49 deletions
|
|
@ -2,14 +2,40 @@ use std::ops::{Mul, MulAssign};
|
|||
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AffineTransform {
|
||||
mat: [[Float; 4]; 3],
|
||||
inv: [[Float; 3]; 3],
|
||||
mat: [[Float; 4]; 4],
|
||||
inv: [[Float; 4]; 4],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AffineTransform {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
struct MatDebug([[Float; 4]; 4]);
|
||||
struct RowDebug([Float; 4]);
|
||||
|
||||
impl std::fmt::Debug for RowDebug {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{:.5?}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for MatDebug {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_list()
|
||||
.entries(self.0.into_iter().map(RowDebug))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
f.debug_struct("AffineTransform")
|
||||
.field("mat", &MatDebug(self.mat))
|
||||
.field("inv", &MatDebug(self.inv))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AffineTransform {
|
||||
pub fn new(mat: [[Float; 4]; 3]) -> Option<Self> {
|
||||
pub fn new(mat: [[Float; 4]; 4]) -> Option<Self> {
|
||||
let inv = Self::invert(mat)?;
|
||||
Some(Self { mat, inv })
|
||||
}
|
||||
|
|
@ -20,8 +46,14 @@ impl AffineTransform {
|
|||
[1.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 1.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
inv: [
|
||||
[1.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 1.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0, 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
inv: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,8 +63,14 @@ impl AffineTransform {
|
|||
[1.0, 0.0, 0.0, pos.x()],
|
||||
[0.0, 1.0, 0.0, pos.y()],
|
||||
[0.0, 0.0, 1.0, pos.z()],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
inv: [
|
||||
[1.0, 0.0, 0.0, -pos.x()],
|
||||
[0.0, 1.0, 0.0, -pos.y()],
|
||||
[0.0, 0.0, 1.0, -pos.z()],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
inv: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +80,13 @@ impl AffineTransform {
|
|||
[sx, 0.0, 0.0, 0.0],
|
||||
[0.0, sy, 0.0, 0.0],
|
||||
[0.0, 0.0, sz, 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
inv: [
|
||||
[1.0 / sx, 0.0, 0.0],
|
||||
[0.0, 1.0 / sy, 0.0],
|
||||
[0.0, 0.0, 1.0 / sz],
|
||||
[1.0 / sx, 0.0, 0.0, 0.0],
|
||||
[0.0, 1.0 / sy, 0.0, 0.0],
|
||||
[0.0, 0.0, 1.0 / sz, 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -71,13 +111,15 @@ impl AffineTransform {
|
|||
dir.z() * dir.z() * (1.0 - angle.cos()) + angle.cos(),
|
||||
0.0,
|
||||
],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
];
|
||||
Self {
|
||||
mat,
|
||||
inv: [
|
||||
[mat[0][0], mat[1][0], mat[2][0]],
|
||||
[mat[0][1], mat[1][1], mat[2][1]],
|
||||
[mat[0][2], mat[1][2], mat[2][2]],
|
||||
[mat[0][0], mat[1][0], mat[2][0], 0.0],
|
||||
[mat[0][1], mat[1][1], mat[2][1], 0.0],
|
||||
[mat[0][2], mat[1][2], mat[2][2], 0.0],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -91,33 +133,46 @@ impl AffineTransform {
|
|||
[right.x(), new_up.x(), dir.x(), pos.x()],
|
||||
[right.y(), new_up.y(), dir.y(), pos.y()],
|
||||
[right.z(), new_up.z(), dir.z(), pos.z()],
|
||||
[0.0, 0.0, 0.0, 1.0],
|
||||
];
|
||||
|
||||
Self::new(mat)
|
||||
}
|
||||
|
||||
fn invert(mat: [[Float; 4]; 3]) -> Option<[[Float; 3]; 3]> {
|
||||
fn invert(mat: [[Float; 4]; 4]) -> Option<[[Float; 4]; 4]> {
|
||||
// using cramers rule
|
||||
let cofactor_indices = |p| match p {
|
||||
0 => (1, 2, 3),
|
||||
1 => (0, 2, 3),
|
||||
2 => (0, 1, 3),
|
||||
3 => (0, 1, 2),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let adj = |y, x| {
|
||||
let cofactor_indices = |p| match p {
|
||||
0 => (1, 2),
|
||||
1 => (0, 2),
|
||||
2 => (0, 1),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let (y1, y2) = cofactor_indices(y);
|
||||
let (x1, x2) = cofactor_indices(x);
|
||||
let (y0, y1, y2) = cofactor_indices(y);
|
||||
let (x0, x1, x2) = cofactor_indices(x);
|
||||
|
||||
(if (x + y) % 2 == 0 { 1.0 } else { -1.0 })
|
||||
* (mat[y1][x1] * mat[y2][x2] - mat[y1][x2] * mat[y2][x1])
|
||||
* (mat[y0][x0] * mat[y1][x1] * mat[y2][x2]
|
||||
+ mat[y0][x1] * mat[y1][x2] * mat[y2][x0]
|
||||
+ mat[y0][x2] * mat[y1][x0] * mat[y2][x1]
|
||||
- mat[y0][x2] * mat[y1][x1] * mat[y2][x0]
|
||||
- mat[y0][x1] * mat[y1][x0] * mat[y2][x2]
|
||||
- mat[y0][x0] * mat[y1][x2] * mat[y2][x1])
|
||||
};
|
||||
|
||||
let det = mat[0][0] * mat[1][1] * mat[2][2]
|
||||
+ mat[0][1] * mat[1][2] * mat[2][0]
|
||||
+ mat[0][2] * mat[1][0] * mat[2][1]
|
||||
- mat[0][2] * mat[1][1] * mat[2][0]
|
||||
- mat[0][1] * mat[1][0] * mat[2][2]
|
||||
- mat[0][0] * mat[1][2] * mat[2][1];
|
||||
let mut det = 0.0;
|
||||
for i in 0..=3 {
|
||||
let (x0, x1, x2) = cofactor_indices(i);
|
||||
det = if i % 2 == 0 { -1.0 } else { 1.0 }
|
||||
* mat[3][i]
|
||||
* (mat[0][x0] * mat[1][x1] * mat[2][x2]
|
||||
+ mat[0][x1] * mat[1][x2] * mat[2][x0]
|
||||
+ mat[0][x2] * mat[1][x0] * mat[2][x1]
|
||||
- mat[0][x2] * mat[1][x1] * mat[2][x0]
|
||||
- mat[0][x1] * mat[1][x0] * mat[2][x2]
|
||||
- mat[0][x0] * mat[1][x2] * mat[2][x1]);
|
||||
}
|
||||
|
||||
if det != 0.0 {
|
||||
let det_frac = 1.0 / det;
|
||||
|
|
@ -127,16 +182,25 @@ impl AffineTransform {
|
|||
adj(0, 0) * det_frac,
|
||||
adj(1, 0) * det_frac,
|
||||
adj(2, 0) * det_frac,
|
||||
adj(3, 0) * det_frac,
|
||||
],
|
||||
[
|
||||
adj(0, 1) * det_frac,
|
||||
adj(1, 1) * det_frac,
|
||||
adj(2, 1) * det_frac,
|
||||
adj(3, 1) * det_frac,
|
||||
],
|
||||
[
|
||||
adj(0, 2) * det_frac,
|
||||
adj(1, 2) * det_frac,
|
||||
adj(2, 2) * det_frac,
|
||||
adj(3, 2) * det_frac,
|
||||
],
|
||||
[
|
||||
adj(0, 3) * det_frac,
|
||||
adj(1, 3) * det_frac,
|
||||
adj(2, 3) * det_frac,
|
||||
adj(3, 3) * det_frac,
|
||||
],
|
||||
])
|
||||
} else {
|
||||
|
|
@ -194,90 +258,147 @@ impl Mul<AffineTransform> for AffineTransform {
|
|||
self.mat[0][0] * rhs.mat[0][0]
|
||||
+ self.mat[0][1] * rhs.mat[1][0]
|
||||
+ self.mat[0][2] * rhs.mat[2][0]
|
||||
+ self.mat[0][3],
|
||||
+ self.mat[0][3] * rhs.mat[3][0],
|
||||
self.mat[0][0] * rhs.mat[0][1]
|
||||
+ self.mat[0][1] * rhs.mat[1][1]
|
||||
+ self.mat[0][2] * rhs.mat[2][1]
|
||||
+ self.mat[0][3],
|
||||
+ self.mat[0][3] * rhs.mat[3][1],
|
||||
self.mat[0][0] * rhs.mat[0][2]
|
||||
+ self.mat[0][1] * rhs.mat[1][2]
|
||||
+ self.mat[0][2] * rhs.mat[2][2]
|
||||
+ self.mat[0][3],
|
||||
+ self.mat[0][3] * rhs.mat[3][2],
|
||||
self.mat[0][0] * rhs.mat[0][3]
|
||||
+ self.mat[0][1] * rhs.mat[1][3]
|
||||
+ self.mat[0][2] * rhs.mat[2][3]
|
||||
+ self.mat[0][3],
|
||||
+ self.mat[0][3] * rhs.mat[3][3],
|
||||
],
|
||||
[
|
||||
self.mat[1][0] * rhs.mat[0][0]
|
||||
+ self.mat[1][1] * rhs.mat[1][0]
|
||||
+ self.mat[1][2] * rhs.mat[2][0]
|
||||
+ self.mat[1][3],
|
||||
+ self.mat[1][3] * rhs.mat[3][0],
|
||||
self.mat[1][0] * rhs.mat[0][1]
|
||||
+ self.mat[1][1] * rhs.mat[1][1]
|
||||
+ self.mat[1][2] * rhs.mat[2][1]
|
||||
+ self.mat[1][3],
|
||||
+ self.mat[1][3] * rhs.mat[3][1],
|
||||
self.mat[1][0] * rhs.mat[0][2]
|
||||
+ self.mat[1][1] * rhs.mat[1][2]
|
||||
+ self.mat[1][2] * rhs.mat[2][2]
|
||||
+ self.mat[1][3],
|
||||
+ self.mat[1][3] * rhs.mat[3][2],
|
||||
self.mat[1][0] * rhs.mat[0][3]
|
||||
+ self.mat[1][1] * rhs.mat[1][3]
|
||||
+ self.mat[1][2] * rhs.mat[2][3]
|
||||
+ self.mat[1][3],
|
||||
+ self.mat[1][3] * rhs.mat[3][3],
|
||||
],
|
||||
[
|
||||
self.mat[2][0] * rhs.mat[0][0]
|
||||
+ self.mat[2][1] * rhs.mat[1][0]
|
||||
+ self.mat[2][2] * rhs.mat[2][0]
|
||||
+ self.mat[2][3],
|
||||
+ self.mat[2][3] * rhs.mat[3][0],
|
||||
self.mat[2][0] * rhs.mat[0][1]
|
||||
+ self.mat[2][1] * rhs.mat[1][1]
|
||||
+ self.mat[2][2] * rhs.mat[2][1]
|
||||
+ self.mat[2][3],
|
||||
+ self.mat[2][3] * rhs.mat[3][1],
|
||||
self.mat[2][0] * rhs.mat[0][2]
|
||||
+ self.mat[2][1] * rhs.mat[1][2]
|
||||
+ self.mat[2][2] * rhs.mat[2][2]
|
||||
+ self.mat[2][3],
|
||||
+ self.mat[2][3] * rhs.mat[3][3],
|
||||
self.mat[2][0] * rhs.mat[0][3]
|
||||
+ self.mat[2][1] * rhs.mat[1][3]
|
||||
+ self.mat[2][2] * rhs.mat[2][3]
|
||||
+ self.mat[2][3],
|
||||
+ self.mat[2][3] * rhs.mat[3][3],
|
||||
],
|
||||
[
|
||||
self.mat[3][0] * rhs.mat[0][0]
|
||||
+ self.mat[3][1] * rhs.mat[1][0]
|
||||
+ self.mat[3][2] * rhs.mat[2][0]
|
||||
+ self.mat[3][3] * rhs.mat[3][0],
|
||||
self.mat[3][0] * rhs.mat[0][1]
|
||||
+ self.mat[3][1] * rhs.mat[1][1]
|
||||
+ self.mat[3][2] * rhs.mat[2][1]
|
||||
+ self.mat[3][3] * rhs.mat[3][1],
|
||||
self.mat[3][0] * rhs.mat[0][2]
|
||||
+ self.mat[3][1] * rhs.mat[1][2]
|
||||
+ self.mat[3][2] * rhs.mat[2][2]
|
||||
+ self.mat[3][3] * rhs.mat[3][2],
|
||||
self.mat[3][0] * rhs.mat[0][3]
|
||||
+ self.mat[3][1] * rhs.mat[1][3]
|
||||
+ self.mat[3][2] * rhs.mat[2][3]
|
||||
+ self.mat[3][3] * rhs.mat[3][3],
|
||||
],
|
||||
],
|
||||
inv: [
|
||||
[
|
||||
rhs.inv[0][0] * self.inv[0][0]
|
||||
+ rhs.inv[0][1] * self.inv[1][0]
|
||||
+ rhs.inv[0][2] * self.inv[2][0],
|
||||
+ rhs.inv[0][2] * self.inv[2][0]
|
||||
+ rhs.inv[0][3] * self.inv[3][0],
|
||||
rhs.inv[0][0] * self.inv[0][1]
|
||||
+ rhs.inv[0][1] * self.inv[1][1]
|
||||
+ rhs.inv[0][2] * self.inv[2][1],
|
||||
+ rhs.inv[0][2] * self.inv[2][1]
|
||||
+ rhs.inv[0][3] * self.inv[3][1],
|
||||
rhs.inv[0][0] * self.inv[0][2]
|
||||
+ rhs.inv[0][1] * self.inv[1][2]
|
||||
+ rhs.inv[0][2] * self.inv[2][2],
|
||||
+ rhs.inv[0][2] * self.inv[2][2]
|
||||
+ rhs.inv[0][3] * self.inv[3][2],
|
||||
rhs.inv[0][0] * self.inv[0][3]
|
||||
+ rhs.inv[0][1] * self.inv[1][3]
|
||||
+ rhs.inv[0][2] * self.inv[2][3]
|
||||
+ rhs.inv[0][3] * self.inv[3][3],
|
||||
],
|
||||
[
|
||||
rhs.inv[1][0] * self.inv[0][0]
|
||||
+ rhs.inv[1][1] * self.inv[1][0]
|
||||
+ rhs.inv[1][2] * self.inv[2][0],
|
||||
+ rhs.inv[1][2] * self.inv[2][0]
|
||||
+ rhs.inv[1][3] * self.inv[3][0],
|
||||
rhs.inv[1][0] * self.inv[0][1]
|
||||
+ rhs.inv[1][1] * self.inv[1][1]
|
||||
+ rhs.inv[1][2] * self.inv[2][1],
|
||||
+ rhs.inv[1][2] * self.inv[2][1]
|
||||
+ rhs.inv[1][3] * self.inv[3][1],
|
||||
rhs.inv[1][0] * self.inv[0][2]
|
||||
+ rhs.inv[1][1] * self.inv[1][2]
|
||||
+ rhs.inv[1][2] * self.inv[2][2],
|
||||
+ rhs.inv[1][2] * self.inv[2][2]
|
||||
+ rhs.inv[1][3] * self.inv[3][2],
|
||||
rhs.inv[1][0] * self.inv[0][3]
|
||||
+ rhs.inv[1][1] * self.inv[1][3]
|
||||
+ rhs.inv[1][2] * self.inv[2][3]
|
||||
+ rhs.inv[1][3] * self.inv[3][3],
|
||||
],
|
||||
[
|
||||
rhs.inv[2][0] * self.inv[0][0]
|
||||
+ rhs.inv[2][1] * self.inv[1][0]
|
||||
+ rhs.inv[2][2] * self.inv[2][0],
|
||||
+ rhs.inv[2][2] * self.inv[2][0]
|
||||
+ rhs.inv[2][3] * self.inv[3][0],
|
||||
rhs.inv[2][0] * self.inv[0][1]
|
||||
+ rhs.inv[2][1] * self.inv[1][1]
|
||||
+ rhs.inv[2][2] * self.inv[2][1],
|
||||
+ rhs.inv[2][2] * self.inv[2][1]
|
||||
+ rhs.inv[2][3] * self.inv[3][1],
|
||||
rhs.inv[2][0] * self.inv[0][2]
|
||||
+ rhs.inv[2][1] * self.inv[1][2]
|
||||
+ rhs.inv[2][2] * self.inv[2][2],
|
||||
+ rhs.inv[2][2] * self.inv[2][2]
|
||||
+ rhs.inv[2][3] * self.inv[3][3],
|
||||
rhs.inv[2][0] * self.inv[0][3]
|
||||
+ rhs.inv[2][1] * self.inv[1][3]
|
||||
+ rhs.inv[2][2] * self.inv[2][3]
|
||||
+ rhs.inv[2][3] * self.inv[3][3],
|
||||
],
|
||||
[
|
||||
rhs.inv[3][0] * self.inv[0][0]
|
||||
+ rhs.inv[3][1] * self.inv[1][0]
|
||||
+ rhs.inv[3][2] * self.inv[2][0]
|
||||
+ rhs.inv[3][3] * self.inv[3][0],
|
||||
rhs.inv[3][0] * self.inv[0][1]
|
||||
+ rhs.inv[3][1] * self.inv[1][1]
|
||||
+ rhs.inv[3][2] * self.inv[2][1]
|
||||
+ rhs.inv[3][3] * self.inv[3][1],
|
||||
rhs.inv[3][0] * self.inv[0][2]
|
||||
+ rhs.inv[3][1] * self.inv[1][2]
|
||||
+ rhs.inv[3][2] * self.inv[2][2]
|
||||
+ rhs.inv[3][3] * self.inv[3][2],
|
||||
rhs.inv[3][0] * self.inv[0][3]
|
||||
+ rhs.inv[3][1] * self.inv[1][3]
|
||||
+ rhs.inv[3][2] * self.inv[2][3]
|
||||
+ rhs.inv[3][3] * self.inv[3][3],
|
||||
],
|
||||
],
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue