1 /////////////////////////////////////////////////////////////////////
4 // Class for representing and manipulating 2D vectors
6 /////////////////////////////////////////////////////////////////////
8 // TODO: Type errors if v not instanceof Vector classes
9 // TODO: Possibly implement in C++
11 function Vector2D(x = 0, y = 0)
16 Vector2D.prototype.clone = function()
18 return new Vector2D(this.x, this.y);
21 // Mutating 2D functions
23 // These functions modify the current object,
24 // and always return this object to allow chaining
26 Vector2D.prototype.set = function(x, y)
33 Vector2D.prototype.setFrom = function(v)
40 Vector2D.prototype.add = function(v)
47 Vector2D.prototype.sub = function(v)
54 Vector2D.prototype.mult = function(f)
61 Vector2D.prototype.div = function(f)
68 Vector2D.prototype.normalize = function()
70 let magnitude = this.length();
74 return this.div(magnitude);
78 * Rotate a radians anti-clockwise
80 Vector2D.prototype.rotate = function(angle)
82 let sin = Math.sin(angle);
83 let cos = Math.cos(angle);
86 this.x * cos + this.y * sin,
87 -this.x * sin + this.y * cos);
91 * Rotate radians anti-clockwise around the specified rotation center.
93 Vector2D.prototype.rotateAround = function(angle, center)
95 return this.sub(center).rotate(angle).add(center);
99 * Convert to integer coordinates.
101 Vector2D.prototype.round = function()
103 return this.set(Math.round(this.x), Math.round(this.y));
106 Vector2D.prototype.floor = function()
108 return this.set(Math.floor(this.x), Math.floor(this.y));
111 Vector2D.prototype.toFixed = function(digits)
113 return this.set(this.x.toFixed(digits), this.y.toFixed(digits));
116 // Numeric 2D info functions (non-mutating)
118 // These methods serve to get numeric info on the vector, they don't modify the vector
121 * Returns a vector that forms a right angle with this one.
123 Vector2D.prototype.perpendicular = function()
125 return new Vector2D(-this.y, this.x);
129 * Computes the scalar product of the two vectors.
130 * Geometrically, this is the product of the length of the two vectors and the cosine of the angle between them.
131 * If the vectors are orthogonal, the product is zero.
133 Vector2D.prototype.dot = function(v)
135 return this.x * v.x + this.y * v.y;
139 * Computes the non-zero coordinate of the cross product of the two vectors.
140 * Geometrically, the cross of the vectors is a 3D vector perpendicular to the two 2D vectors.
141 * The returned number corresponds to the area of the parallelogram with the vectors for sides.
143 Vector2D.prototype.cross = function(v)
145 return this.x * v.y - this.y * v.x;
148 Vector2D.prototype.lengthSquared = function()
150 return this.dot(this);
153 Vector2D.prototype.length = function()
155 return Math.sqrt(this.lengthSquared());
159 * Compare this length to the length of v.
160 * @return 0 if the lengths are equal
161 * @return 1 if this is longer than v
162 * @return -1 if this is shorter than v
163 * @return NaN if the vectors aren't comparable
165 Vector2D.prototype.compareLength = function(v)
167 return Math.sign(this.lengthSquared() - v.lengthSquared());
170 Vector2D.prototype.distanceToSquared = function(v)
172 return Math.euclidDistance2DSquared(this.x, this.y, v.x, v.y);
175 Vector2D.prototype.distanceTo = function(v)
177 return Math.euclidDistance2D(this.x, this.y, v.x, v.y);
181 * Returns the angle going from this position to v.
182 * Angles are between -PI and PI. E.g., north is 0, east is PI/2.
184 Vector2D.prototype.angleTo = function(v)
186 return Math.atan2(v.x - this.x, v.y - this.y);
189 // Static 2D functions
191 // Static functions that return a new vector object.
192 // Note that object creation is slow in JS, so use them only when necessary
194 Vector2D.from3D = function(v)
196 return new Vector2D(v.x, v.z);
199 Vector2D.add = function(v1, v2)
201 return new Vector2D(v1.x + v2.x, v1.y + v2.y);
204 Vector2D.sub = function(v1, v2)
206 return new Vector2D(v1.x - v2.x, v1.y - v2.y);
209 Vector2D.isEqualTo = function(v1, v2)
211 return v1.x == v2.x && v1.y == v2.y;
214 Vector2D.mult = function(v, f)
216 return new Vector2D(v.x * f, v.y * f);
219 Vector2D.div = function(v, f)
221 return new Vector2D(v.x / f, v.y / f);
224 Vector2D.min = function(v1, v2)
226 return new Vector2D(Math.min(v1.x, v2.x), Math.min(v1.y, v2.y));
229 Vector2D.max = function(v1, v2)
231 return new Vector2D(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y));
234 Vector2D.average = function(vectorList)
236 return Vector2D.sum(vectorList).div(vectorList.length);
239 Vector2D.sum = function(vectorList)
241 // Do not use for...of nor array functions for performance
242 let sum = new Vector2D();
244 for (let i = 0; i < vectorList.length; ++i)
245 sum.add(vectorList[i]);
250 Vector2D.dot = function(v1, v2)
252 return v1.x * v2.x + v1.y * v2.y;
255 /////////////////////////////////////////////////////////////////////
258 // Class for representing and manipulating 3D vectors
260 /////////////////////////////////////////////////////////////////////
262 function Vector3D(x = 0, y = 0, z = 0)
267 Vector3D.prototype.clone = function()
269 return new Vector3D(this.x, this.y, this.z);
272 // Mutating 3D functions
274 // These functions modify the current object,
275 // and always return this object to allow chaining
277 Vector3D.prototype.set = function(x, y, z)
285 Vector3D.prototype.add = function(v)
293 Vector3D.prototype.sub = function(v)
301 Vector3D.prototype.mult = function(f)
309 Vector3D.prototype.div = function(f)
317 Vector3D.prototype.normalize = function()
319 let magnitude = this.length();
323 return this.div(magnitude);
327 * Convert to integer coordinates.
329 Vector3D.prototype.round = function()
331 return this.set(Math.round(this.x), Math.round(this.y), Math.round(this.z));
334 Vector3D.prototype.floor = function()
336 return this.set(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z));
339 Vector3D.prototype.toFixed = function(digits)
341 return this.set(this.x.toFixed(digits), this.y.toFixed(digits), this.z.toFixed(digits));
344 // Numeric 3D info functions (non-mutating)
346 // These methods serve to get numeric info on the vector, they don't modify the vector
348 Vector3D.prototype.dot = function(v)
350 return this.x * v.x + this.y * v.y + this.z * v.z;
354 * Returns a vector perpendicular to the two given vectors.
355 * The length of the returned vector corresponds to the area of the parallelogram with the vectors for sides.
357 Vector3D.prototype.cross = function(v)
360 this.y * v.z - this.z * v.y,
361 this.z * v.x - this.x * v.z,
362 this.x * v.y - this.y * v.x);
365 Vector3D.prototype.lengthSquared = function()
367 return this.dot(this);
370 Vector3D.prototype.length = function()
372 return Math.sqrt(this.lengthSquared());
376 * Compare this length to the length of v,
377 * @return 0 if the lengths are equal
378 * @return 1 if this is longer than v
379 * @return -1 if this is shorter than v
380 * @return NaN if the vectors aren't comparable
382 Vector3D.prototype.compareLength = function(v)
384 return Math.sign(this.lengthSquared() - v.lengthSquared());
387 Vector3D.prototype.distanceToSquared = function(v)
389 return Math.euclidDistance3DSquared(this.x, this.y, this.z, v.x, v.y, v.z);
392 Vector3D.prototype.distanceTo = function(v)
394 return Math.euclidDistance3D(this.x, this.y, this.z, v.x, v.y, v.z);
397 Vector3D.prototype.horizDistanceToSquared = function(v)
399 return Math.euclidDistance2DSquared(this.x, this.z, v.x, v.z);
402 Vector3D.prototype.horizDistanceTo = function(v)
404 return Math.sqrt(this.horizDistanceToSquared(v));
408 * Returns the angle going from this position to v.
410 Vector3D.prototype.horizAngleTo = function(v)
412 return Math.atan2(v.x - this.x, v.z - this.z);
415 // Static 3D functions
417 // Static functions that return a new vector object.
418 // Note that object creation is slow in JS, so use them only when really necessary
420 Vector3D.add = function(v1, v2)
422 return new Vector3D(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
425 Vector3D.sub = function(v1, v2)
427 return new Vector3D(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
430 Vector3D.isEqualTo = function(v1, v2)
432 return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
435 Vector3D.mult = function(v, f)
437 return new Vector3D(v.x * f, v.y * f, v.z * f);
440 Vector3D.div = function(v, f)
442 return new Vector3D(v.x / f, v.y / f, v.z / f);