Repository navigation
Expand file tree
/
Copy pathpatch-vector.js
More file actions
158 lines (146 loc) · 4.77 KB
/
Copy pathpatch-vector.js
File metadata and controls
158 lines (146 loc) · 4.77 KB
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
import { Vector } from './p5.Vector.js';
function _vectorError(instance, message = 'Requires valid arguments') {
if (!instance.friendlyErrorsDisabled()) {
instance._friendlyError(message, 'p5.Vector');
}
return instance;
}
/**
* @private
* @internal
*/
export function _defaultEmptyVector(target) {
return function (...args) {
if (args.length === 0) {
this.constructor._friendlyError(
'In 1.x, createVector() was a shortcut for createVector(0, 0, 0). In 2.x, p5.js has vectors of any dimension, so you must provide your desired number of zeros. Use createVector(0, 0) for a 2D vector and createVector(0, 0, 0) for a 3D vector.',
'p5.createVector'
);
return target.call(this, 0, 0, 0);
} else {
if (Array.isArray(args[0])) {
args = args[0];
}
return target.call(this, ...args);
}
};
}
/**
* @private
* @internal
* @param {Boolean} expectsSoloNumberArgument whether a single number scales
* every component (mult/div/rem)
* @param {Number} [trailingArgCount=0] number of trailing args to peel off
* before treating the rest as vector components (e.g. 1 for lerp's amt)
* @param {Number[]} [trailingDefaults] if provided, used when only component
* values are passed (no trailing args), e.g. `[0]` so `v.lerp(other)` uses amt 0
*/
export function _validatedVectorOperation(
expectsSoloNumberArgument,
trailingArgCount = 0,
trailingDefaults
) {
return function(target) {
return function (...args) {
const trailing = [];
if (trailingArgCount > 0) {
const onlyValues =
args.length === 1 &&
(args[0] instanceof Vector || Array.isArray(args[0]));
if (onlyValues && trailingDefaults) {
for (let i = 0; i < trailingDefaults.length; i++) {
trailing.push(trailingDefaults[i]);
}
} else if (args.length < trailingArgCount) {
if (trailingDefaults && args.length === 0) {
// No arguments? No action (same as other vector ops)
return this;
}
return _vectorError(this);
} else {
for (let i = 0; i < trailingArgCount; i++) {
trailing.unshift(args.pop());
}
for (let i = 0; i < trailing.length; i++) {
const t = trailing[i];
if (typeof t !== 'number' || !Number.isFinite(t)) {
return _vectorError(this, 'Arguments contain non-finite numbers');
}
}
if (args.length === 0) {
return _vectorError(this);
}
}
} else if (args.length === 0) {
// No arguments? No action
return this;
}
if (args[0] instanceof Vector) {
// Do not allow extra args after a vector when trailing args are used
if (trailingArgCount > 0 && args.length > 1) {
return _vectorError(this);
}
// First argument is a vector? Make it an array
args = args[0].values;
} else if (Array.isArray(args[0])) {
if (trailingArgCount > 0 && args.length > 1) {
return _vectorError(this);
}
// First argument is an array? Great, keep it!
args = args[0];
} else if (args.length === 1) {
// Special case for a solo numeric arguments only applies sometimes
if (expectsSoloNumberArgument) {
args = args[0];
}
}
if (Array.isArray(args)) {
for (let i = 0; i < args.length; i++) {
const v = args[i];
if (typeof v !== 'number' || !Number.isFinite(v)) {
return _vectorError(this, 'Arguments contain non-finite numbers');
}
}
} else {
if (typeof args !== 'number' || !Number.isFinite(args)) {
return _vectorError(this, 'Arguments contain non-finite numbers');
}
}
return target.call(this, args, ...trailing);
};
};
}
/**
* @private
* @internal
* Each of the following decorators validates the data on vector operations.
* These ensure that the arguments are consistently formatted, and that
* pre-conditions are met.
*/
export default function vectorValidation(p5, fn, lifecycles) {
p5.registerDecorator('p5.prototype.createVector', _defaultEmptyVector);
p5.registerDecorator(
'p5.Vector.prototype.mult',
_validatedVectorOperation(true)
);
p5.registerDecorator(
'p5.Vector.prototype.rem',
_validatedVectorOperation(true)
);
p5.registerDecorator(
'p5.Vector.prototype.div',
_validatedVectorOperation(true)
);
p5.registerDecorator(
'p5.Vector.prototype.add',
_validatedVectorOperation(false)
);
p5.registerDecorator(
'p5.Vector.prototype.sub',
_validatedVectorOperation(false)
);
p5.registerDecorator(
'p5.Vector.prototype.lerp',
_validatedVectorOperation(false, 1, [0])
);
}