-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHumanTrajectory.js
More file actions
88 lines (72 loc) · 2.39 KB
/
HumanTrajectory.js
File metadata and controls
88 lines (72 loc) · 2.39 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
// HumanTrajectory.js
const { linear } = require('./tweens');
function randomNormal(mean = 0, stdev = 1) {
let u = 0, v = 0;
while (u === 0) u = Math.random();
while (v === 0) v = Math.random();
return mean + stdev * Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
}
class BezierCalculator {
static binomial(n, k) {
let coeff = 1;
for (let i = n - k + 1; i <= n; i++) coeff *= i;
for (let i = 1; i <= k; i++) coeff /= i;
return coeff;
}
static bernsteinPoint(t, i, n) {
return BezierCalculator.binomial(n, i) * t**i * (1 - t)**(n - i);
}
static calculatePointsInCurve(n, points) {
const curve = [];
const m = points.length - 1;
for (let i = 0; i < n; i++) {
const t = i / (n - 1);
let x = 0, y = 0;
for (let j = 0; j <= m; j++) {
const b = BezierCalculator.bernsteinPoint(t, j, m);
x += points[j][0] * b;
y += points[j][1] * b;
}
curve.push([x, y]);
}
return curve;
}
}
class HumanTrajectory {
constructor(from, to, params) {
this.from = from;
this.to = to;
this.offsetX = params.offsetBoundaryX;
this.offsetY = params.offsetBoundaryY;
this.knotsCount = params.knotsCount;
this.distMean = params.distortionMean;
this.distStDev = params.distortionStDev;
this.distFreq = params.distortionFrequency;
this.tween = params.tween || linear;
this.targetPoints = params.targetPoints;
}
generateCurve() {
const [fx, fy] = this.from;
const [tx, ty] = this.to;
const knots = [];
for (let i = 0; i < this.knotsCount; i++) {
knots.push([
fx + (tx - fx) * Math.random() + (Math.random() - 0.5) * this.offsetX,
fy + (ty - fy) * Math.random() + (Math.random() - 0.5) * this.offsetY
]);
}
let points = [this.from, ...knots, this.to];
points = BezierCalculator.calculatePointsInCurve(this.targetPoints, points);
points = points.map(([x, y]) => {
if (Math.random() < this.distFreq) y += randomNormal(this.distMean, this.distStDev);
return [x, y];
});
const tweened = [];
for (let i = 0; i < this.targetPoints; i++) {
const idx = Math.floor(this.tween(i / (this.targetPoints - 1)) * (points.length - 1));
tweened.push(points[idx]);
}
return tweened;
}
}
module.exports = { HumanTrajectory };