-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVector2D.js
426 lines (401 loc) · 13.7 KB
/
Vector2D.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
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
/** GENERAL DISCLAIMER -
* This file is not designed to be reproduced or distributed, nor is it useable in content of any kind.
* It should be for the personal use of the owner, as it breaks any and all legislation regarding copyrighted code.
* - Credits : p5.js, Processing Foundation, @shiffman, @RobinLefebvre, @ */
class Vector2D
{
/** Class representing 2D Vectors on a euclidian plane. Currently relies on typeof === "number" inputs.
* @param {...any} args : values for the x and y components
* @todo : constrain to integer values
* @todo : create static functionality on Vector2D arrays.
* centroid(array) : returns the Vector2D at the center of all the Vectors in the array
* isWithin(array, vector) : returns a boolean telling whether or not the vector is within the space covered by the array of vectors
* isClosedShape(array) : returns a boolean telling whether or not the first and last elements on the array are equal
*/
constructor(...args)
{
let x, y;
if(args[0] instanceof Vector2D)
{
x = args[0].x || 0;
y = args[0].y || 0;
}
else if(args[0] instanceof Array)
{
x = args[0][0] || 0;
y = args[0][1] || 0;
}
else
{
x = args[0] || 0;
y = args[1] || 0;
}
/**@property x {Number} : The x component of the vector */
this.x = x || 0;
/**@property y {Number} : The y component of the vector */
this.y = y || 0;
}
/** Returns a clone of current vector */
copy()
{
return new Vector2D(this.x, this.y);
}
/** Equality operation, can take in a Vector2D, an Array, or simply x and y values. */
equals(...args)
{
let a, b;
if (args[0] instanceof Vector2D)
{
a = args[0].x || 0;
b = args[0].y || 0;
}
else if (args[0] instanceof Array)
{
a = args[0][0] || 0;
b = args[0][1] || 0;
}
else
{
a = args[0] || 0;
b = args[1] || 0;
}
return this.x === a && this.y === b;
}
/** Returns the string of the object formatted for console logs. */
toString()
{
return `Vector2D Object : [${this.x}, ${this.y}]`
}
/** Returns the Vector's data in an Array format. */
toArray()
{
return [this.x, this.y];
}
/** Returns the Vector's data in a JSON format, pass in a boolean to add linebreaks and indentation. */
toJSON(opts)
{
if(!opts){opts = {};}
let ret;
let obj = {x : this.x, y:this.y}
if(opts.simplest === true)
obj = this.toArray();
if(opts.beautify === true)
ret = JSON.stringify(obj, null, 4);
ret = JSON.stringify(obj)
return ret;
}
/** Sets the values of current Vector. Can take in a Vector2D, an Array, or x and y values. */
set(...args)
{
if(args[0] instanceof Vector2D)
{
this.x = args[0].x || 0 ;
this.y = args[0].y || 0 ;
return this;
}
if(args[0] instanceof Array)
{
this.x = args[0][0] || 0 ;
this.y = args[0][1] || 0 ;
return this;
}
this.x = args[0] || 0 ;
this.y = args[1] || 0 ;
return this;
}
/** Operation of mathematical addition on the current vector. Can take in a Vector2D, an Array, or x and y values. */
add(...args)
{
if(args[0] instanceof Vector2D)
{
this.x += args[0].x || 0;
this.y += args[0].y || 0 ;
return this;
}
if(args[0] instanceof Array)
{
this.x += args[0][0] || 0 ;
this.y += args[0][1] || 0 ;
return this;
}
this.x += args[0] || 0 ;
this.y += args[1] || 0 ;
return this;
}
/** Operation of mathematical substraction on the current vector. Can take in a Vector2D, an Array, or x and y values. */
sub(...args)
{
if(args[0] instanceof Vector2D)
{
this.x -= args[0].x || 0;
this.y -= args[0].y || 0;
return this;
}
if(args[0] instanceof Array)
{
this.x -= args[0][0] || 0 ;
this.y -= args[0][1] || 0 ;
return this;
}
this.x -= args[0] || 0;
this.y -= args[1] || 0;
return this;
}
/** Operation of mathematical multiplication on the current vector, by a given scalar. */
mult(value)
{
if(!isFinite(value) || typeof value !== 'number')
{
console.warn(` - Vector2D.mult() : \n
Attempting to multiply ${this.toString()} with non-number or non-finite value.`);
return this;
}
this.x *= value;
this.y *= value;
return this;
}
/** Operation of mathematical division on the current vector, by a given scalar. */
div(value)
{
if(!isFinite(value) || typeof value !== 'number')
{
console.warn(` - Vector2D.div() : \n
Attempting to divide ${this.toString()} with non-number or non-finite value.`);
return this;
}
this.x = this.x / value;
this.y = this.y / value;
return this;
}
/** Returns the magnitude (or length) of the current vector.*/
mag()
{
return Math.sqrt(this.magSq());
}
/** Returns the magnitude (or length) of the current vector squared.*/
magSq()
{
let x = this.x;
let y = this.y;
return x * x + y * y;
}
/** Returns the dot product on the current vector. Can take in a Vector2D, an Array, or x and y values. */
dot(...args)
{
if(args[0] instanceof Vector2D)
return this.dot(args[0].x, args[0].y);
if(args[0] instanceof Array)
return this.dot(args[0][0], args[0][1]);
// (x || 0) implies that an undefined value for x will default to 0.
return this.x * (args[0] || 0) + this.y * (args[1] || 0);
}
/** Returns the distance between the current vector and the passed Vector2D. */
dist(vector)
{
if(vector instanceof Vector2D)
return vector.copy().sub(this.copy()).mag();
console.warn(`- Vector2D.dist : ${this.toString()} tried to get distance to ${vector.toString()}.\n
Operation Failed, you need to provide a Vector2D as argument.`);
return false;
}
/** Sets the current vector to have a magnitude (or length) of 1.*/
normalize()
{
var len = this.mag();
if (len !== 0)
this.mult(1 / len);
return this;
}
/** Apply Math.floor() on both dimensions of current vector*/
floor()
{
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
return this;
}
/** Sets the current vector to have a magnitude (or length) bound by the argument.*/
limit(value)
{
let mSq = this.magSq();
if (mSq > (value * value) )
{
this.div( Math.sqrt(mSq) )
.mult( value );
}
return this;
}
/** Sets the current vector to have values that range from min to max, or from 0 to max.*/
constrain(...args)
{
// We received min & max values
if(typeof args[1] === 'number')
{
if(this.x < args[0])
this.x = args[0];
if(this.x > args[1])
this.x = args[1];
if(this.y < args[0])
this.y = args[0];
if(this.y > args[1])
this.y = args[1];
return this;
}
// We only received max value
if(typeof args[0] === 'number')
{
if(this.x < 0)
this.x = 0;
if(this.x > args[0])
this.x = args[0];
if(this.y < 0)
this.y = 0;
if(this.y > args[0])
this.y = args[0];
return this;
}
console.warn(`- Vector2D.constrain \n Operation failed. Check how you used this function.`)
return false;
}
/** Sets the current vector to have a magnitude (or length) equal to the argument.*/
setMag(value)
{
return this.normalize().mult( value );
}
/** Returns the angle towards which the vector points. Returns a degree value if we have access to the NobsLibrary tool for angle conversion
* @todo : insert the radiansToDegrees function as an attribute of Vector2D or something. */
heading()
{
let angle = Math.atan2(this.y, this.x);
if (N.functions.radiansToDegrees !== undefined)
return N.functions.radiansToDegrees(angle);
return angle;
}
/** Returns the angle between the current vector and the passed Vector2D. */
angleBetween(vector)
{
var dotmagmag = this.dot(vector) / (this.mag() * vector.mag()); // Dot Product divided by magnitude multiplication
var angle = Math.acos(Math.min(1, Math.max(-1, dotmagmag))); // Snap values between -1 and 1
if (N.functions.degreesToRadians !== undefined)
return N.functions.degreesToRadians(angle);
return angle;
}
/** Sets the values of the current vector as if it had been linearly interpolated according to the arguments.
* @param {Vector2D || x, y} args[0...1]: The vector or parameters to lerp towards
* @param {number} args[2] : The amount of interpolation (constrained between [0-1]) */
lerp(...args)
{
if (args[0] instanceof Vector2D)
{
return this.lerp(args[0].x, args[0].y, args[1]);
}
this.x += (args[0] - this.x) * args[2] || 0;
this.y += (args[1] - this.y) * args[2] || 0;
return this;
}
/** Sets the values of the current vector as if it had been linearly interpolated according to the arguments.
* @param {Vector2D} pivot: The Vector to rotate about
* @param {Vector2D} point: The Vector to rotate
* @param {number} args[2] : The amount of interpolation (constrained between [0-1]) */
static rotateAround(pivot, point, angle)
{
let p = point.copy();
let s = Math.sin(angle);
let c = Math.cos(angle);
// Translate to pivot as new "origin"
p.sub(pivot);
// Rotation at "origin"
let x = p.x * c - p.y * s;
let y = p.x * s + p.y * c;
let rotated = new Vector2D(x, y);
// Translate back
rotated.add(pivot);
return rotated;
}
/** Returns a random unit vector */
static getRandomUnit()
{
let angle = Math.random() * 6.28;
let length = 1;
return new Vector2D(length * Math.cos(angle), length * Math.sin(angle));
}
/** Returns a random Vector2D */
static getRandom(min, max)
{
let rX = Math.floor(Math.random() * (+max - +min) + +min) + 1
let rY = Math.floor(Math.random() * (+max - +min) + +min) + 1
return new Vector2D(rX, rY);
}
/** Returns the addition of v1 and v2. Target is the object receiving the values (v1 by default)
* @todo : make target return a new Vector by default */
static add(v1, v2, target)
{
if (!target)
target = v1.copy();
else
target.set(v1);
target.add(v2);
return target;
}
/** Returns the subtraction of v1 and v2. Target is the object receiving the values (v1 by default)
* @todo : make target return a new Vector by default */
static sub(v1, v2, target)
{
if (!target)
target = v1.copy();
else
target.set(v1);
target.sub(v2);
return target;
}
/** Returns the multiplication of v1 and v2. Target is the object receiving the values (v1 by default)
* @todo : make target return a new Vector by default */
static mult(v1, v2, target)
{
if (!target)
target = v1.copy();
else
target.set(v1);
target.mult(v2);
return target;
}
/** Returns the division of v1 and v2. Target is the object receiving the values (v1 by default)
* @todo : make target return a new Vector by default */
static div(v1, v2, target)
{
if (!target)
target = v1.copy();
else
target.set(v1);
target.div(v2);
return target;
}
/** Returns the dot product of v1 and v2. */
static dot(v1, v2)
{
return v1.dot(v2);
}
/** Returns the distance between v1 and v2. */
static dist(v1, v2)
{
return v1.dist(v2)
}
/** Returns the linear interpolation between v1 and v2. Target is the object receiving the values (v1 by default)
* @todo : make target return a new Vector by default */
static lerp(v1, v2, amt, target)
{
if (!target)
target = v1.copy();
else
target.set(v1);
target.lerp(v2, amt);
return target;
}
/** Returns the magnitude of the passed Vector2D */
static mag(vector)
{
let x = vector.x;
let y = vector.y;
let magSq = x * x + y * y + z * z;
return Math.sqrt(magSq);
}
}