-
Notifications
You must be signed in to change notification settings - Fork 0
/
algebra.cpp
executable file
·143 lines (125 loc) · 3.23 KB
/
algebra.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
//---------------------------------------------------------------------------
//
// CS488 -- Introduction to Computer Graphics
//
// algebra.hpp/algebra.cpp
//
// Classes and functions for manipulating points, vectors, matrices,
// and colours. You probably won't need to modify anything in these
// two files.
//
// University of Waterloo Computer Graphics Lab / 2003
//
//---------------------------------------------------------------------------
#include "algebra.hpp"
double Vector3D::normalize()
{
double denom = 1.0;
double x = (v_[0] > 0.0) ? v_[0] : -v_[0];
double y = (v_[1] > 0.0) ? v_[1] : -v_[1];
double z = (v_[2] > 0.0) ? v_[2] : -v_[2];
if(x > y) {
if(x > z) {
if(1.0 + x > 1.0) {
y = y / x;
z = z / x;
denom = 1.0 / (x * sqrt(1.0 + y*y + z*z));
}
} else { /* z > x > y */
if(1.0 + z > 1.0) {
y = y / z;
x = x / z;
denom = 1.0 / (z * sqrt(1.0 + y*y + x*x));
}
}
} else {
if(y > z) {
if(1.0 + y > 1.0) {
z = z / y;
x = x / y;
denom = 1.0 / (y * sqrt(1.0 + z*z + x*x));
}
} else { /* x < y < z */
if(1.0 + z > 1.0) {
y = y / z;
x = x / z;
denom = 1.0 / (z * sqrt(1.0 + y*y + x*x));
}
}
}
if(1.0 + x + y + z > 1.0) {
v_[0] *= denom;
v_[1] *= denom;
v_[2] *= denom;
return 1.0 / denom;
}
return 0.0;
}
/*
* Define some helper functions for matrix inversion.
*/
static void swaprows(Matrix4x4& a, size_t r1, size_t r2)
{
std::swap(a[r1][0], a[r2][0]);
std::swap(a[r1][1], a[r2][1]);
std::swap(a[r1][2], a[r2][2]);
std::swap(a[r1][3], a[r2][3]);
}
static void dividerow(Matrix4x4& a, size_t r, double fac)
{
a[r][0] /= fac;
a[r][1] /= fac;
a[r][2] /= fac;
a[r][3] /= fac;
}
static void submultrow(Matrix4x4& a, size_t dest, size_t src, double fac)
{
a[dest][0] -= fac * a[src][0];
a[dest][1] -= fac * a[src][1];
a[dest][2] -= fac * a[src][2];
a[dest][3] -= fac * a[src][3];
}
/*
* invertMatrix
*
* I lifted this code from the skeleton code of a raytracer assignment
* from a different school. I taught that course too, so I figured it
* would be okay.
*/
Matrix4x4 Matrix4x4::invert() const
{
/* The algorithm is plain old Gauss-Jordan elimination
with partial pivoting. */
Matrix4x4 a(*this);
Matrix4x4 ret;
/* Loop over cols of a from left to right,
eliminating above and below diag */
/* Find largest pivot in column j among rows j..3 */
for(size_t j = 0; j < 4; ++j) {
size_t i1 = j; /* Row with largest pivot candidate */
for(size_t i = j + 1; i < 4; ++i) {
if(fabs(a[i][j]) > fabs(a[i1][j])) {
i1 = i;
}
}
/* Swap rows i1 and j in a and ret to put pivot on diagonal */
swaprows(a, i1, j);
swaprows(ret, i1, j);
/* Scale row j to have a unit diagonal */
if(a[j][j] == 0.0) {
// Theoretically throw an exception.
return ret;
}
dividerow(ret, j, a[j][j]);
dividerow(a, j, a[j][j]);
/* Eliminate off-diagonal elems in col j of a, doing identical
ops to b */
for(size_t i = 0; i < 4; ++i) {
if(i != j) {
submultrow(ret, i, j, a[i][j]);
submultrow(a, i, j, a[i][j]);
}
}
}
return ret;
}