1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
#pragma once
#include "Vector2.h"
#include "Vector3.h"
#include "eigen.h"
/**
* \brief A 3x3 matrix stored in double-precision floating-point.
*
* The 3 columns may regarded as 3 vectors named x, y, z:
*
* | xx yx zx |
* | xy yy zy |
* | xz yz zz |
*
*/
class Matrix3
{
// Underlying Eigen transform object (which can in turn be reduced to a 3x3 Matrix)
using Transform = Eigen::Projective2d;
Transform _transform;
// Initialising constructor, elements are passed in column-wise order
Matrix3(double xx_, double xy_, double xz_,
double yx_, double yy_, double yz_,
double zx_, double zy_, double zz_);
public:
/// Construct a matrix with uninitialised values.
Matrix3() { }
/// Construct from Eigen transform
explicit Matrix3(const Eigen::Projective2d& t) :
_transform(t)
{}
/// Get the underlying Eigen transform
Eigen::Projective2d& eigen() { return _transform; }
/// Get the underlying const Eigen transform
const Eigen::Projective2d& eigen() const { return _transform; }
/**
* Return matrix elements
* \{
*/
double& xx() { return _transform.matrix()(0, 0); }
const double& xx() const { return _transform.matrix()(0, 0); }
double& xy() { return _transform.matrix()(1, 0); }
const double& xy() const { return _transform.matrix()(1, 0); }
double& xz() { return _transform.matrix()(2, 0); }
const double& xz() const { return _transform.matrix()(2, 0); }
double& yx() { return _transform.matrix()(0, 1); }
const double& yx() const { return _transform.matrix()(0, 1); }
double& yy() { return _transform.matrix()(1, 1); }
const double& yy() const { return _transform.matrix()(1, 1); }
double& yz() { return _transform.matrix()(2, 1); }
const double& yz() const { return _transform.matrix()(2, 1); }
double& zx() { return _transform.matrix()(0, 2); }
const double& zx() const { return _transform.matrix()(0, 2); }
double& zy() { return _transform.matrix()(1, 2); }
const double& zy() const { return _transform.matrix()(1, 2); }
double& zz() { return _transform.matrix()(2, 2); }
const double& zz() const { return _transform.matrix()(2, 2); }
/**
* \}
*/
/// Obtain the identity matrix.
static Matrix3 getIdentity()
{
return Matrix3(Eigen::Projective2d::Identity());
}
/// Get a matrix representing the given 2D translation.
static Matrix3 getTranslation(const Vector2& translation)
{
return Matrix3(Transform(Eigen::Translation2d(translation.x(), translation.y())));
}
/// Get a matrix representing the given 2D rotation (counter-clockwise, angle in radians)
static Matrix3 getRotation(double angle)
{
return Matrix3(Transform(Eigen::Rotation2D(angle)));
}
/// Get a matrix representing the given 2D scale
static Matrix3 getScale(const Vector2& scale)
{
return Matrix3(Transform(Eigen::Scaling(scale.x(), scale.y())));
}
/**
* \brief
* Construct a matrix containing the given elements.
*
* The elements are specified column-wise, starting with the left-most
* column.
*/
static Matrix3 byColumns(double xx, double xy, double xz,
double yx, double yy, double yz,
double zx, double zy, double zz);
/**
* \brief
* Construct a matrix containing the given elements.
*
* The elements are specified row-wise, starting with the top row.
*/
static Matrix3 byRows(double xx, double yx, double zx,
double xy, double yy, double zy,
double xz, double yz, double zz);
/// Return the result of this matrix post-multiplied by another matrix.
Matrix3 getMultipliedBy(const Matrix3& other) const
{
return Matrix3(_transform * other.eigen());
}
/// Post-multiply this matrix by another matrix, in-place.
void multiplyBy(const Matrix3& other)
{
*this = getMultipliedBy(other);
}
/// Returns this matrix pre-multiplied by the other
Matrix3 getPremultipliedBy(const Matrix3& other) const
{
return other.getMultipliedBy(*this);
}
/// Pre-multiplies this matrix by other in-place.
void premultiplyBy(const Matrix3& other)
{
*this = getPremultipliedBy(other);
}
/// Return the full inverse of this matrix.
Matrix3 getFullInverse() const
{
return Matrix3(_transform.inverse(Eigen::Projective));
}
/// Invert this matrix in-place.
void invertFull()
{
*this = getFullInverse();
}
/**
* \brief Returns the given 2-component point transformed by this matrix.
*
* The point is assumed to have a W component of 1, and no division by W is
* performed before returning the 3-component vector.
*/
template<typename T>
BasicVector2<T> transformPoint(const BasicVector2<T>& point) const
{
auto transformed = transform(BasicVector3<T>(point.x(), point.y(), 1));
return BasicVector2<T>(transformed.x(), transformed.y());
}
/// Return the given 3-component vector transformed by this matrix.
template<typename T>
BasicVector3<T> transform(const BasicVector3<T>& vector3) const;
};
// Private constructor
inline Matrix3::Matrix3(double xx_, double xy_, double xz_,
double yx_, double yy_, double yz_,
double zx_, double zy_, double zz_)
{
xx() = xx_;
xy() = xy_;
xz() = xz_;
yx() = yx_;
yy() = yy_;
yz() = yz_;
zx() = zx_;
zy() = zy_;
zz() = zz_;
}
// Construct a matrix with given column elements
inline Matrix3 Matrix3::byColumns(double xx, double xy, double xz,
double yx, double yy, double yz,
double zx, double zy, double zz)
{
return Matrix3(xx, xy, xz,
yx, yy, yz,
zx, zy, zz);
}
// Construct a matrix with given row elements
inline Matrix3 Matrix3::byRows(double xx, double yx, double zx,
double xy, double yy, double zy,
double xz, double yz, double zz)
{
return Matrix3(xx, xy, xz,
yx, yy, yz,
zx, zy, zz);
}
template<typename T>
inline BasicVector3<T> Matrix3::transform(const BasicVector3<T>& vector3) const
{
Eigen::Matrix<T, 3, 1> eVec(static_cast<const double*>(vector3));
auto result = _transform * eVec;
return BasicVector3<T>(result[0], result[1], result[2]);
}
/// Compare two matrices elementwise for equality
inline bool operator==(const Matrix3& l, const Matrix3& r)
{
return l.eigen().matrix() == r.eigen().matrix();
}
/// Compare two matrices elementwise for inequality
inline bool operator!=(const Matrix3& l, const Matrix3& r)
{
return !(l == r);
}
/// Multiply two matrices together
inline Matrix3 operator*(const Matrix3& m1, const Matrix3& m2)
{
return m1.getMultipliedBy(m2);
}
/**
* \brief Multiply a 3-component vector by this matrix.
*
* Equivalent to m.transform(v).
*/
template<typename T>
inline BasicVector3<T> operator*(const Matrix3& m, const BasicVector3<T>& v)
{
return m.transform(v);
}
/**
* \brief Multiply a 2-component vector by this matrix.
*
* The vector is upgraded to a 3-component vector with a Z (or W) component of 1, i.e.
* equivalent to m.transformPoint(v).
*/
template<typename T>
inline BasicVector2<T> operator*(const Matrix3& m, const BasicVector2<T>& v)
{
return m.transformPoint(v);
}
|