/
Matrix.cpp
275 lines (239 loc) · 5.88 KB
/
Matrix.cpp
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
269
270
271
272
273
274
275
/*
* Matrix.cpp
*
* Created on: Oct 14, 2008
* Author: the1schwartz
*/
#include <math.h>
#include "Matrix.h"
// returns an identity matrix
Matrix Matrix::Identity()
{
Matrix result;
// quick hack: diagonal elements are zero mod 5
for (int i = 0; i < 16; i++)
{
result.coords[i] = !(i%5);
}
return result;
}
// returns a zero matrix
Matrix Matrix::Zero()
{
Matrix result;
for (int i = 0; i < 16; i++)
{
result.coords[i] = 0;
}
return result;
}
void Matrix::SetElement(int row, int col, float value)
{
coords[row + 4 * col] = value;
}
// returns a specified element in the matrix
float& Matrix::Element(int row, int col)
{
// column-major, so multiply column by height
return coords[row + 4 * col];
}
// Copy another Matrix & return self
Matrix& Matrix::operator= (Matrix otherMatrix)
{
for (int i = 0; i < 16; i++)
{
coords[i] = otherMatrix.coords[i];
}
return (*this);
}
// Add another Matrix
Matrix Matrix::operator+ (Matrix otherMatrix)
{
Matrix result;
for (int i = 0; i < 16; i++)
{
result.coords[i] = coords[i] + otherMatrix.coords[i];
}
return result;
}
// Subtract another Matrix
Matrix Matrix::operator- (Matrix otherMatrix)
{
Matrix result;
for (int i = 0; i < 16; i++)
{
result.coords[i] = coords[i] - otherMatrix.coords[i];
}
return result;
}
// Scale the matrix by a constant
Matrix Matrix::operator* (float scaleFactor)
{
Matrix result;
for (int i = 0; i < 16; i++)
{
result.coords[i] = coords[i] * scaleFactor;
}
return result;
}
// Left-multiply a Point
Point Matrix::operator* (Point point)
{
Point result;
// loop through rows of matrix, multiplying by point
for (int row = 0; row < 4; row++)
{
result.coords[row] = 0.0f;
// loop along row, multiplying and adding
for (int col = 0; col < 4; col++)
{
result.coords[row] += Element(row,col) * point.coords[col];
}
}
return result;
}
// Left-multiply a Vector
Vector3 Matrix::operator* (Vector3 vector)
{
Vector3 result;
// loop through rows of matrix, multiplying by point
for (int row = 0; row < 3; row++)
{
result.coords[row] = 0.0f;
// loop along row, multiplying and adding
// note that we ignore the fourth (w) coord
for (int col = 0; col < 3; col++)
{
result.coords[row] += Element(row,col) * vector.coords[col];
}
}
return result;
}
// multiply by another matrix
Matrix Matrix::operator* (Matrix otherMatrix)
{
// make a temporary copy of the other
Matrix result;
// now do the standard loops: it's inefficient, but works
for (int row = 0; row < 4; row++)
{
for(int col = 0; col < 4; col++)
{
result.Element(row, col) = 0.0;
for (int entry = 0; entry < 4; entry++)
{
result.Element(row, col) += Element(row, entry) *
otherMatrix.Element(entry, col);
}
}
}
return result;
}
// Scales a row by a given factor
void Matrix::ScaleRow(int row, float scaleFactor)
{
for (int entry = 0; entry < 4; entry++)
{
Element(row, entry) *= scaleFactor;
}
}
// Swaps two rows
void Matrix::SwapRows(int row1, int row2)
{
float temp;
for (int entry = 0; entry < 4; entry++)
{
temp = Element(row1, entry);
Element(row1, entry) = Element(row2, entry);
Element(row2, entry) = temp;
}
}
// Adds multiple of one row to another row
void Matrix::AddRows(int row1, float multiple, int row2)
{
// simple loop to add entries
for (int entry = 0; entry < 4; entry++)
{
Element(row1, entry) += multiple * Element(row2, entry);
}
}
// Reduces all elements in a column except the diagonal element
// Returns 0 on success, 1 if the column cannot be reduced
int Matrix::ReduceColumn(int column, Matrix &inverse)
{
// loop variable for working down column
int row, pivot = column;
// find the first non-zero element in the column
// that is not above the diagonal
for (row = pivot; row < 4; row++)
if (fabs(Element(row, pivot)) > ERROR_TOLERANCE)
break;
// if we didn't find one, return an error code
if (row == 4) return 1;
// if we did, but it wasn't on the diagonal, swap with the pivot row
// this makes sure we never get divide by zero errors
if (row != pivot)
{
SwapRows(pivot, row);
inverse.SwapRows(pivot, row);
}
// now scale the pivot row so the pivot element is one
float scaleFactor = 1.0 / Element(pivot, pivot);
ScaleRow(pivot, scaleFactor);
inverse.ScaleRow(pivot, scaleFactor);
// for each row
for (row = 0; row < 4; row++)
{
// skip the row we're pivoting on
if (row == column) continue;
scaleFactor = -Element(row, pivot);
AddRows(row, scaleFactor, pivot);
inverse.AddRows(row, scaleFactor, pivot);
}
// and we're done
return 0;
}
// Computes a matrix inverse with brute force Gauss-Jordan method
// returns a zero matrix on failure
Matrix Matrix::Inverse()
{
// working copy of the matrix
Matrix workingCopy = (*this);
Matrix result = Matrix::Identity();
// now perform Gauss-Jordan reduction on the elements of each column
if (0 != workingCopy.ReduceColumn(0, result)) return Zero();
if (0 != workingCopy.ReduceColumn(1, result)) return Zero();
if (0 != workingCopy.ReduceColumn(2, result)) return Zero();
if (0 != workingCopy.ReduceColumn(3, result)) return Zero();
// and we're done!
return result;
}
// routines to extract the translation part of the matrix
// assumes no entries in perspective section of matrix
Vector3 Matrix::TranslationVector()
{
Vector3 result;
// copy last column into result vector
for (int i = 0; i < 3; i++)
result.coords[i] = coords[i,3];
return result;
}
Matrix Matrix::TranslationMatrix()
{
Matrix result = Identity();
// copy last column into result
for (int i = 0; i < 3; i++)
result.Element(i,3) = Element(i,3);
return result;
}
// routine to extract the rotation part of the matrix
// assumes no entries in perspective section of matrix
Matrix Matrix::RotationMatrix()
{
Matrix result = Identity();
// copy first three elements of first three columns into result
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
result.Element(i,j) = Element(i,j);
return result;
}