/*
* This file is part of libgim.
*
* libgim is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* libgim is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with libgim. If not, see .
*
* Copyright 2011-2014 Danny Robson
*/
#include "matrix.hpp"
#include "debug.hpp"
#include
using namespace util;
//-----------------------------------------------------------------------------
template
void
matrix::scale (T x, T y, T z) {
CHECK_HARD (is_affine ());
values[0][0] *= x;
values[1][1] *= y;
values[2][2] *= z;
}
//-----------------------------------------------------------------------------
template
void
matrix::translate (T x, T y, T z) {
CHECK_HARD (is_affine ());
values[0][3] += x;
values[1][3] += y;
values[2][3] += z;
}
//-----------------------------------------------------------------------------
template
matrix
matrix::inverse (void) const {
matrix m;
T d = det ();
if (almost_zero (d))
throw std::runtime_error ("non-singular matrix");
auto v = values;
m.values[0][0] = v[1][2] * v[2][3] * v[3][1] -
v[1][3] * v[2][2] * v[3][1] +
v[1][3] * v[2][1] * v[3][2] -
v[1][1] * v[2][3] * v[3][2] -
v[1][2] * v[2][1] * v[3][3] +
v[1][1] * v[2][2] * v[3][3];
m.values[0][1] = v[0][3] * v[2][2] * v[3][1] -
v[0][2] * v[2][3] * v[3][1] -
v[0][3] * v[2][1] * v[3][2] +
v[0][1] * v[2][3] * v[3][2] +
v[0][2] * v[2][1] * v[3][3] -
v[0][1] * v[2][2] * v[3][3];
m.values[0][2] = v[0][2] * v[1][3] * v[3][1] -
v[0][3] * v[1][2] * v[3][1] +
v[0][3] * v[1][1] * v[3][2] -
v[0][1] * v[1][3] * v[3][2] -
v[0][2] * v[1][1] * v[3][3] +
v[0][1] * v[1][2] * v[3][3];
m.values[0][3] = v[0][3] * v[1][2] * v[2][1] -
v[0][2] * v[1][3] * v[2][1] -
v[0][3] * v[1][1] * v[2][2] +
v[0][1] * v[1][3] * v[2][2] +
v[0][2] * v[1][1] * v[2][3] -
v[0][1] * v[1][2] * v[2][3];
m.values[1][0] = v[1][3] * v[2][2] * v[3][0] -
v[1][2] * v[2][3] * v[3][0] -
v[1][3] * v[2][0] * v[3][2] +
v[1][0] * v[2][3] * v[3][2] +
v[1][2] * v[2][0] * v[3][3] -
v[1][0] * v[2][2] * v[3][3];
m.values[1][1] = v[0][2] * v[2][3] * v[3][0] -
v[0][3] * v[2][2] * v[3][0] +
v[0][3] * v[2][0] * v[3][2] -
v[0][0] * v[2][3] * v[3][2] -
v[0][2] * v[2][0] * v[3][3] +
v[0][0] * v[2][2] * v[3][3];
m.values[1][2] = v[0][3] * v[1][2] * v[3][0] -
v[0][2] * v[1][3] * v[3][0] -
v[0][3] * v[1][0] * v[3][2] +
v[0][0] * v[1][3] * v[3][2] +
v[0][2] * v[1][0] * v[3][3] -
v[0][0] * v[1][2] * v[3][3];
m.values[1][3] = v[0][2] * v[1][3] * v[2][0] -
v[0][3] * v[1][2] * v[2][0] +
v[0][3] * v[1][0] * v[2][2] -
v[0][0] * v[1][3] * v[2][2] -
v[0][2] * v[1][0] * v[2][3] +
v[0][0] * v[1][2] * v[2][3];
m.values[2][0] = v[1][1] * v[2][3] * v[3][0] -
v[1][3] * v[2][1] * v[3][0] +
v[1][3] * v[2][0] * v[3][1] -
v[1][0] * v[2][3] * v[3][1] -
v[1][1] * v[2][0] * v[3][3] +
v[1][0] * v[2][1] * v[3][3];
m.values[2][1] = v[0][3] * v[2][1] * v[3][0] -
v[0][1] * v[2][3] * v[3][0] -
v[0][3] * v[2][0] * v[3][1] +
v[0][0] * v[2][3] * v[3][1] +
v[0][1] * v[2][0] * v[3][3] -
v[0][0] * v[2][1] * v[3][3];
m.values[2][2] = v[0][1] * v[1][3] * v[3][0] -
v[0][3] * v[1][1] * v[3][0] +
v[0][3] * v[1][0] * v[3][1] -
v[0][0] * v[1][3] * v[3][1] -
v[0][1] * v[1][0] * v[3][3] +
v[0][0] * v[1][1] * v[3][3];
m.values[2][3] = v[0][3] * v[1][1] * v[2][0] -
v[0][1] * v[1][3] * v[2][0] -
v[0][3] * v[1][0] * v[2][1] +
v[0][0] * v[1][3] * v[2][1] +
v[0][1] * v[1][0] * v[2][3] -
v[0][0] * v[1][1] * v[2][3];
m.values[3][0] = v[1][2] * v[2][1] * v[3][0] -
v[1][1] * v[2][2] * v[3][0] -
v[1][2] * v[2][0] * v[3][1] +
v[1][0] * v[2][2] * v[3][1] +
v[1][1] * v[2][0] * v[3][2] -
v[1][0] * v[2][1] * v[3][2];
m.values[3][1] = v[0][1] * v[2][2] * v[3][0] -
v[0][2] * v[2][1] * v[3][0] +
v[0][2] * v[2][0] * v[3][1] -
v[0][0] * v[2][2] * v[3][1] -
v[0][1] * v[2][0] * v[3][2] +
v[0][0] * v[2][1] * v[3][2];
m.values[3][2] = v[0][2] * v[1][1] * v[3][0] -
v[0][1] * v[1][2] * v[3][0] -
v[0][2] * v[1][0] * v[3][1] +
v[0][0] * v[1][2] * v[3][1] +
v[0][1] * v[1][0] * v[3][2] -
v[0][0] * v[1][1] * v[3][2];
m.values[3][3] = v[0][1] * v[1][2] * v[2][0] -
v[0][2] * v[1][1] * v[2][0] +
v[0][2] * v[1][0] * v[2][1] -
v[0][0] * v[1][2] * v[2][1] -
v[0][1] * v[1][0] * v[2][2] +
v[0][0] * v[1][1] * v[2][2];
m /= d;
return m;
}
//-----------------------------------------------------------------------------
template
matrix&
matrix::invert (void) {
auto m = *this;
m.invert ();
*this = m;
return *this;
}
//-----------------------------------------------------------------------------
template
matrix
matrix::inverse_affine (void) const {
return matrix(*this).invert_affine ();
}
//-----------------------------------------------------------------------------
template
matrix&
matrix::invert_affine (void) {
CHECK_HARD (is_affine ());
// inv ([ M b ] == [ inv(M) -inv(M).b ]
// [ 0 1 ]) [ 0 1 ]
// Invert the 3x3 M
T A = (values[1][1] * values[2][2] - values[1][2] * values[2][1]);
T B = (values[1][2] * values[2][0] - values[1][0] * values[2][2]);
T C = (values[1][0] * values[2][1] - values[1][1] * values[2][0]);
T D = (values[0][2] * values[2][1] - values[0][1] * values[2][2]);
T E = (values[0][0] * values[2][2] - values[0][2] * values[2][0]);
T F = (values[2][0] * values[0][1] - values[0][0] * values[2][1]);
T G = (values[0][1] * values[1][2] - values[0][2] * values[1][1]);
T H = (values[0][2] * values[1][0] - values[0][0] * values[1][2]);
T K = (values[0][0] * values[1][1] - values[0][1] * values[1][0]);
T d = values[0][0] * A + values[0][1] * B + values[0][2] * C;
CHECK_NEQ (d, 0.0);
values[0][0] = A / d;
values[0][1] = D / d;
values[0][2] = G / d;
values[1][0] = B / d;
values[1][1] = E / d;
values[1][2] = H / d;
values[2][0] = C / d;
values[2][1] = F / d;
values[2][2] = K / d;
// Multiply the b
T b0 = - values[0][0] * values[0][3] - values[0][1] * values[1][3] - values[0][2] * values[2][3];
T b1 = - values[1][0] * values[0][3] - values[1][1] * values[1][3] - values[1][2] * values[2][3];
T b2 = - values[2][0] * values[0][3] - values[2][1] * values[1][3] - values[2][2] * values[2][3];
values[0][3] = b0;
values[1][3] = b1;
values[2][3] = b2;
return *this;
}
//-----------------------------------------------------------------------------
template
T
matrix::det (void) const {
return values[0][3] * values[1][2] * values[2][1] * values[3][0] -
values[0][2] * values[1][3] * values[2][1] * values[3][0] -
values[0][3] * values[1][1] * values[2][2] * values[3][0] +
values[0][1] * values[1][3] * values[2][2] * values[3][0] +
values[0][2] * values[1][1] * values[2][3] * values[3][0] -
values[0][1] * values[1][2] * values[2][3] * values[3][0] -
values[0][3] * values[1][2] * values[2][0] * values[3][1] +
values[0][2] * values[1][3] * values[2][0] * values[3][1] +
values[0][3] * values[1][0] * values[2][2] * values[3][1] -
values[0][0] * values[1][3] * values[2][2] * values[3][1] -
values[0][2] * values[1][0] * values[2][3] * values[3][1] +
values[0][0] * values[1][2] * values[2][3] * values[3][1] +
values[0][3] * values[1][1] * values[2][0] * values[3][2] -
values[0][1] * values[1][3] * values[2][0] * values[3][2] -
values[0][3] * values[1][0] * values[2][1] * values[3][2] +
values[0][0] * values[1][3] * values[2][1] * values[3][2] +
values[0][1] * values[1][0] * values[2][3] * values[3][2] -
values[0][0] * values[1][1] * values[2][3] * values[3][2] -
values[0][2] * values[1][1] * values[2][0] * values[3][3] +
values[0][1] * values[1][2] * values[2][0] * values[3][3] +
values[0][2] * values[1][0] * values[2][1] * values[3][3] -
values[0][0] * values[1][2] * values[2][1] * values[3][3] -
values[0][1] * values[1][0] * values[2][2] * values[3][3] +
values[0][0] * values[1][1] * values[2][2] * values[3][3];
}
//-----------------------------------------------------------------------------
template
matrix
matrix::operator* (const matrix &rhs) const {
matrix m;
memset (m.values, 0, sizeof (m.values));
for (unsigned i = 0; i < 4; ++i)
for (unsigned j = 0; j < 4; ++j)
for (unsigned k = 0; k < 4; ++k)
m.values[i][j] += values[i][k] * rhs.values[k][j];
return m;
}
//-----------------------------------------------------------------------------
template
vector<4>
matrix::operator* (const vector<4> &rhs) const {
return vector<4> {
values[0][0] * rhs.x + values[0][1] * rhs.y + values[0][2] * rhs.z + values[0][3] * rhs.w,
values[1][0] * rhs.x + values[1][1] * rhs.y + values[1][2] * rhs.z + values[1][3] * rhs.w,
values[2][0] * rhs.x + values[2][1] * rhs.y + values[2][2] * rhs.z + values[2][3] * rhs.w,
values[3][0] * rhs.x + values[3][1] * rhs.y + values[3][2] * rhs.z + values[3][3] * rhs.w
};
}
//-----------------------------------------------------------------------------
template
matrix
matrix::operator/ (T s) const {
matrix m;
for (size_t r = 0; r < m.rows; ++r)
for (size_t c = 0; c < m.cols; ++c)
m.values[r][c] = values[r][c] / s;
return m;
}
//-----------------------------------------------------------------------------
template
matrix&
matrix::operator/= (T s) {
for (size_t r = 0; r < rows; ++r)
for (size_t c = 0; c < cols; ++c)
values[r][c] /= s;
return *this;
}
//-----------------------------------------------------------------------------
template
bool
matrix::operator== (const matrix &rhs) const {
for (size_t r = 0; r < rows; ++r)
for (size_t c = 0; c < cols; ++c)
if (!almost_equal (rhs.values[r][c], values[r][c]))
return false;
return true;
}
//-----------------------------------------------------------------------------
template
util::point<3>
matrix::to_local (const util::point<3> &p) const {
CHECK_SOFT (is_affine ());
return { p.x * values[0][0] +
p.y * values[0][1] +
p.z * values[0][2] + values[0][3],
p.x * values[1][0] +
p.y * values[1][1] +
p.z * values[1][2] + values[1][3],
p.x * values[2][0] +
p.y * values[2][1] +
p.z * values[2][2] + values[2][3] };
}
//-----------------------------------------------------------------------------
template
util::point<3>
matrix::to_global (const util::point<3> &p) const {
return inverse ().to_local (p);
}
//-----------------------------------------------------------------------------
template
bool
matrix::is_affine (void) const {
return exactly_equal (values[3][0], T {0}) &&
exactly_equal (values[3][1], T {0}) &&
exactly_equal (values[3][2], T {0}) &&
exactly_equal (values[3][3], T {1});
}
//-----------------------------------------------------------------------------
template
const matrix
matrix::IDENTITY = { { { 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 } } };
template
const matrix
matrix::ZEROES = { { { 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 } } };
//-----------------------------------------------------------------------------
namespace util {
template struct matrix;
template struct matrix;
}
//-----------------------------------------------------------------------------
namespace util {
template
std::ostream&
operator<< (std::ostream &os, const matrix &m) {
os << "{ {" << m.values[0][0] << ", "
<< m.values[0][1] << ", "
<< m.values[0][2] << ", "
<< m.values[0][3] << "}, "
<< "{" << m.values[1][0] << ", "
<< m.values[1][1] << ", "
<< m.values[1][2] << ", "
<< m.values[1][3] << "}, "
<< "{" << m.values[2][0] << ", "
<< m.values[2][1] << ", "
<< m.values[2][2] << ", "
<< m.values[2][3] << "}, "
<< "{" << m.values[3][0] << ", "
<< m.values[3][1] << ", "
<< m.values[3][2] << ", "
<< m.values[3][3] << "} }";
return os;
}
}
template std::ostream& util::operator<< (std::ostream&, const matrix&);
template std::ostream& util::operator<< (std::ostream&, const matrix&);