qvec: add 3x3 matrix inverse, row major factory method

This commit is contained in:
Eric Wasylishen 2022-11-02 00:32:06 -06:00
parent 388cd39821
commit c39ee38454
3 changed files with 74 additions and 0 deletions

View File

@ -137,6 +137,27 @@ qmat4x4f qv::inverse(const qmat4x4f &input)
return qmat4x4f(qv::inverse(qmat4x4d(input)));
}
qmat3x3f qv::inverse(const qmat3x3f &m)
{
qmat4x4d temp {};
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < 3; ++c) {
temp.at(r,c) = m.at(r,c);
}
}
temp = qv::inverse(temp);
// return the upper-left 3x3 matrix
qmat3x3f result;
for (int r = 0; r < 3; ++r) {
for (int c = 0; c < 3; ++c) {
result.at(r,c) = temp.at(r,c);
}
}
return result;
}
qmat2x2f qv::inverse(const qmat2x2f &m)
{
// http://www.mathwords.com/i/inverse_of_a_matrix.htm

View File

@ -909,6 +909,19 @@ public:
std::copy(list.begin(), list.end(), m_values.begin());
}
// static factory, row-major order
static qmat row_major(std::initializer_list<T> list) {
assert(list.size() == NRow * NCol);
qmat result;
for (size_t i = 0; i < NRow; i++) { // for each row
for (size_t j = 0; j < NCol; j++) { // for each col
result.at(i, j) = *(list.begin() + (i*NCol + j));
}
}
return result;
}
// Sort support
[[nodiscard]] constexpr bool operator<(const qmat &other) const { return m_values < other.m_values; }
[[nodiscard]] constexpr bool operator<=(const qmat &other) const { return m_values <= other.m_values; }
@ -1043,6 +1056,7 @@ namespace qv
[[nodiscard]] qmat4x4d inverse(const qmat4x4d &input);
[[nodiscard]] qmat2x2f inverse(const qmat2x2f &input);
[[nodiscard]] qmat3x3f inverse(const qmat3x3f &input);
}; // namespace qv
// returns the normalized direction from `start` to `stop` in the `dir` param

View File

@ -871,6 +871,32 @@ TEST_CASE("matrix2x2inv")
REQUIRE(std::isnan(nanMat.at(0, 0)));
}
TEST_CASE("matrix3x3inv")
{
std::mt19937 engine(0);
std::uniform_real_distribution<float> dis(-4096, 4096);
qmat3x3f randMat;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
randMat.at(i, j) = dis(engine);
qmat3x3f randInv = qv::inverse(randMat);
REQUIRE_FALSE(std::isnan(randInv.at(0, 0)));
qmat3x3f prod = randMat * randInv;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
float exp = (i == j) ? 1.0f : 0.0f;
REQUIRE(fabs(exp - prod.at(i, j)) < 0.001);
}
}
// check non-invertible gives nan
qmat3x3f nanMat = qv::inverse(qmat3x3f(0));
REQUIRE(std::isnan(nanMat.at(0, 0)));
}
TEST_CASE("matrix4x4inv")
{
std::mt19937 engine(0);
@ -897,6 +923,19 @@ TEST_CASE("matrix4x4inv")
REQUIRE(std::isnan(nanMat.at(0, 0)));
}
TEST_CASE("qmat_construct_initialize") {
const qmat2x2f test{1,2,3,4}; // column major
CHECK(qvec2f{1,3} == test.row(0));
CHECK(qvec2f{2,4} == test.row(1));
}
TEST_CASE("qmat_construct_row_major") {
const qmat2x2f test = qmat2x2f::row_major({1, 2, 3, 4});
CHECK(qvec2f{1,2} == test.row(0));
CHECK(qvec2f{3,4} == test.row(1));
}
}
TEST_SUITE("trace") {