-
Notifications
You must be signed in to change notification settings - Fork 838
/
bezier.mjs
175 lines (136 loc) · 5.32 KB
/
bezier.mjs
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
import { Path } from './path.mjs';
import { Curve } from './curve.mjs';
import { Point } from './point.mjs';
export const bezier = {
// Cubic Bezier curve path through points.
// @deprecated
// @param {array} points Array of points through which the smooth line will go.
// @return {array} SVG Path commands as an array
curveThroughPoints: function(points) {
console.warn('deprecated');
return new Path(Curve.throughPoints(points)).serialize();
},
// Get open-ended Bezier Spline Control Points.
// @deprecated
// @param knots Input Knot Bezier spline points (At least two points!).
// @param firstControlPoints Output First Control points. Array of knots.length - 1 length.
// @param secondControlPoints Output Second Control points. Array of knots.length - 1 length.
getCurveControlPoints: function(knots) {
console.warn('deprecated');
var firstControlPoints = [];
var secondControlPoints = [];
var n = knots.length - 1;
var i;
// Special case: Bezier curve should be a straight line.
if (n == 1) {
// 3P1 = 2P0 + P3
firstControlPoints[0] = new Point(
(2 * knots[0].x + knots[1].x) / 3,
(2 * knots[0].y + knots[1].y) / 3
);
// P2 = 2P1 – P0
secondControlPoints[0] = new Point(
2 * firstControlPoints[0].x - knots[0].x,
2 * firstControlPoints[0].y - knots[0].y
);
return [firstControlPoints, secondControlPoints];
}
// Calculate first Bezier control points.
// Right hand side vector.
var rhs = [];
// Set right hand side X values.
for (i = 1; i < n - 1; i++) {
rhs[i] = 4 * knots[i].x + 2 * knots[i + 1].x;
}
rhs[0] = knots[0].x + 2 * knots[1].x;
rhs[n - 1] = (8 * knots[n - 1].x + knots[n].x) / 2.0;
// Get first control points X-values.
var x = this.getFirstControlPoints(rhs);
// Set right hand side Y values.
for (i = 1; i < n - 1; ++i) {
rhs[i] = 4 * knots[i].y + 2 * knots[i + 1].y;
}
rhs[0] = knots[0].y + 2 * knots[1].y;
rhs[n - 1] = (8 * knots[n - 1].y + knots[n].y) / 2.0;
// Get first control points Y-values.
var y = this.getFirstControlPoints(rhs);
// Fill output arrays.
for (i = 0; i < n; i++) {
// First control point.
firstControlPoints.push(new Point(x[i], y[i]));
// Second control point.
if (i < n - 1) {
secondControlPoints.push(new Point(
2 * knots [i + 1].x - x[i + 1],
2 * knots[i + 1].y - y[i + 1]
));
} else {
secondControlPoints.push(new Point(
(knots[n].x + x[n - 1]) / 2,
(knots[n].y + y[n - 1]) / 2)
);
}
}
return [firstControlPoints, secondControlPoints];
},
// Divide a Bezier curve into two at point defined by value 't' <0,1>.
// Using deCasteljau algorithm. http://math.stackexchange.com/a/317867
// @deprecated
// @param control points (start, control start, control end, end)
// @return a function that accepts t and returns 2 curves.
getCurveDivider: function(p0, p1, p2, p3) {
console.warn('deprecated');
var curve = new Curve(p0, p1, p2, p3);
return function divideCurve(t) {
var divided = curve.divide(t);
return [{
p0: divided[0].start,
p1: divided[0].controlPoint1,
p2: divided[0].controlPoint2,
p3: divided[0].end
}, {
p0: divided[1].start,
p1: divided[1].controlPoint1,
p2: divided[1].controlPoint2,
p3: divided[1].end
}];
};
},
// Solves a tridiagonal system for one of coordinates (x or y) of first Bezier control points.
// @deprecated
// @param rhs Right hand side vector.
// @return Solution vector.
getFirstControlPoints: function(rhs) {
console.warn('deprecated');
var n = rhs.length;
// `x` is a solution vector.
var x = [];
var tmp = [];
var b = 2.0;
x[0] = rhs[0] / b;
// Decomposition and forward substitution.
for (var i = 1; i < n; i++) {
tmp[i] = 1 / b;
b = (i < n - 1 ? 4.0 : 3.5) - tmp[i];
x[i] = (rhs[i] - x[i - 1]) / b;
}
for (i = 1; i < n; i++) {
// Backsubstitution.
x[n - i - 1] -= tmp[n - i] * x[n - i];
}
return x;
},
// Solves an inversion problem -- Given the (x, y) coordinates of a point which lies on
// a parametric curve x = x(t)/w(t), y = y(t)/w(t), find the parameter value t
// which corresponds to that point.
// @deprecated
// @param control points (start, control start, control end, end)
// @return a function that accepts a point and returns t.
getInversionSolver: function(p0, p1, p2, p3) {
console.warn('deprecated');
var curve = new Curve(p0, p1, p2, p3);
return function solveInversion(p) {
return curve.closestPointT(p);
};
}
};