-
Notifications
You must be signed in to change notification settings - Fork 134
/
vector.js
137 lines (107 loc) · 3.61 KB
/
vector.js
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
/*
* This JavaScript file defines a Vector object and associated functions.
* The object itself is returned as the result of a function, allowing us
* to encapsulate its code and module variables.
*
* This module's approach is non-destructive: methods always return new
* Vector objects, and never modify the operands. This is a design choice.
*
* This module is designed for vectors of any number of dimensions. The
* implementations are generalized but not optimal for certain sizes of
* vectors. Specific Vector2D and Vector3D implementations can be much
* more compact, while sacrificing generality.
*/
window.Vector = (() => {
// A private method for checking dimensions,
// throwing an exception when different.
let checkDimensions = (v1, v2) => {
if (v1.dimensions !== v2.dimensions) {
throw "Vectors have different dimensions";
}
};
// Define the class.
return class Vector {
constructor() {
this.elements = [].slice.call(arguments);
}
get dimensions() {
return this.elements.length;
}
get x() {
return this.elements[0];
}
get y() {
return this.elements[1];
}
get z() {
return this.elements[2];
}
get w() {
return this.elements[3];
}
add(v) {
let result = new Vector();
checkDimensions(this, v);
for (let i = 0, max = this.dimensions; i < max; i += 1) {
result.elements[i] = this.elements[i] + v.elements[i];
}
return result;
}
subtract(v) {
let result = new Vector();
checkDimensions(this, v);
for (let i = 0, max = this.dimensions; i < max; i += 1) {
result.elements[i] = this.elements[i] - v.elements[i];
}
return result;
}
multiply(s) {
let result = new Vector();
for (let i = 0, max = this.dimensions; i < max; i += 1) {
result.elements[i] = this.elements[i] * s;
}
return result;
}
divide(s) {
let result = new Vector();
for (let i = 0, max = this.dimensions; i < max; i += 1) {
result.elements[i] = this.elements[i] / s;
}
return result;
}
dot(v) {
let result = 0;
checkDimensions(this, v);
for (let i = 0, max = this.dimensions; i < max; i += 1) {
result += this.elements[i] * v.elements[i];
}
return result;
}
cross(v) {
if (this.dimensions !== 3 || v.dimensions !== 3) {
throw "Cross product is for 3D vectors only.";
}
// With 3D vectors, we can just return the result directly.
return new Vector(
this.y * v.z - this.z * v.y,
this.z * v.x - this.x * v.z,
this.x * v.y - this.y * v.x
);
}
get magnitude() {
return Math.sqrt(this.dot(this));
}
get unit() {
// At this point, we can leverage our more "primitive" methods.
return this.divide(this.magnitude);
}
projection(v) {
checkDimensions(this, v);
// Plug and chug :)
// The projection of u onto v is u dot the unit vector of v
// times the unit vector of v.
let unitv = v.unit;
return unitv.multiply(this.dot(unitv));
}
};
})();