/
Matrix3.h
268 lines (237 loc) · 7.23 KB
/
Matrix3.h
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#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 alignas(16) 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); }
/**
* \}
*/
/**
* Return columns of the matrix as vectors.
* \{
*/
Vector3& xCol()
{
return reinterpret_cast<Vector3&>(xx());
}
const Vector3& xCol() const
{
return reinterpret_cast<const Vector3&>(xx());
}
Vector3& yCol()
{
return reinterpret_cast<Vector3&>(yx());
}
const Vector3& yCol() const
{
return reinterpret_cast<const Vector3&>(yx());
}
Vector3& zCol()
{
return reinterpret_cast<Vector3&>(zx());
}
const Vector3& zCol() const
{
return reinterpret_cast<const Vector3&>(zx());
}
/**
* \}
*/
/// Obtain the identity matrix.
static Matrix3 getIdentity()
{
return Matrix3(Eigen::Projective2d::Identity());
}
/**
* \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
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>
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>
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>
BasicVector2<T> operator*(const Matrix3& m, const BasicVector2<T>& v)
{
return m.transformPoint(v);
}