[英]How to subdivide Cubic Bezier curve into points
我正在使用由年度数据组成的数据集。 数组中的每个项目对应于一年。 我想扩展这个数据集并改为每月制作一次。 我一直在研究它并尝试不同的方法,但最终找到了 De Casteljau 的算法来确定贝塞尔曲线上的各个点。
https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
如果你可以看看这里的例子。 http://jsfiddle.net/vdbhc98j/
const data = [29.9, 55.5, 106.4, 1129.2, 344.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4];
// https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm
const getLinearInterpolatedValue = (t: number, p1: number, p2: number) => (1 - t) * p1 + t * p2;
const getLinearInterpolatedSegment = (...args: number[]): number[] => {
const [t, p1, p2, ...rest] = args;
return rest.length > 0
? [getLinearInterpolatedValue(t, p1, p2), ...getLinearInterpolatedSegment(t, p2, ...rest)]
: [getLinearInterpolatedValue(t, p1, p2)];
};
const findPointOnBezierCurve = (t: number, ps: number[]): number =>
ps.length > 1 ? findPointOnBezierCurve(t, getLinearInterpolatedSegment(t, ...ps)) : ps[0];
const subdividePoints = (points: number[], years: number) => {
if (points.length === 0 || years === 0) {
return points;
}
const step = 1 / years / 12;
const newPoints = [];
for (let i = 0; i <= years * 12; i++) {
newPoints.push(findPointOnBezierCurve(step * i, points));
}
return newPoints;
};
const chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'spline'
},
series: [{
data,
}, {
type: 'spline',
data: []
}]
});
const subdivided = new Highcharts.Chart({
chart: {
renderTo: 'container2',
type: 'spline'
},
series: [{
data: subdividePoints(data, 10)
}, {
type: 'spline',
data: []
}]
});
即使存在相似之处,它确实将曲线细分为 120 个不同的点,但它并没有完全保持曲线。
如果您还检查这些值,在没有细分的原始图表中,该值会上升到 1129,而在细分的图表中,它会上升到 ~427。
你能帮我吗 - 特别是我对算法的期望是错误的还是我在某个地方犯了错误? 如果你能指出这个问题是否有替代方案,那就太好了。
先感谢您。
我发现这个库叫做 Curve-Interpolator, https://www.npmjs.com/package/curve-interpolator 。
使用它的CurveInterpolator2D
class,我能够生成 output:
http://jsfiddle.net/sznjxrah/1/
const points = [29.9, 55.5, 106.4, 1129.2, 344.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4].map((v, i) => [
i * 100,
v,
]);
const tension = 0;
const arcDivisions = 1;
const spline = new CurveInterpolator2D(points, tension, arcDivisions);
spline.getPoints(120);
/**
[
29.9,
31.18203376736111,
32.681006249999996,
34.39622421875,
36.326994444444445,
38.47262369791667,
40.83241875,
43.40568637152778,
46.19173333333333,
49.189866406250005,
52.39939236111111,
55.78703431712963,
55.19179999999999,
49.24130734953704,
40.12292546296298,
30.024023437500006,
21.131970370370375,
15.634135358796314,
15.717887500000032,
23.570595891203705,
41.37962962962962,
71.33235781249996,
115.8621483796296,
184.80732167245378,
277.6864000000003,
388.07569082754674,
509.55150162037035,
635.6901398437502,
760.0679129629629,
876.2611284432877,
977.8460937500004,
1058.3991163483802,
1111.4965037037043,
1130.866071875,
1116.176286111111,
1073.0483072916666,
1007.0862000000002,
923.8940288194445,
829.0758583333331,
728.2357531249997,
626.9777777777779,
530.9059968749999,
445.6244750000001,
376.7372767361105,
328.71915555555563,
292.59375,
264.22578888888887,
242.48392222222216,
226.23679999999996,
214.3530722222223,
205.70138888888889,
199.15040000000005,
193.56875555555564,
187.8251055555556,
180.78810000000004,
171.830906394676,
163.81327407407412,
157.24243203125002,
151.9466905092592,
147.7543597511574,
144.49374999999998,
141.99317149884257,
140.08093449074073,
138.58534921874997,
137.3347259259259,
136.15737485532404,
134.97710625,
134.17229169560184,
133.8071314814815,
133.88555390624998,
134.41148726851853,
135.38885986689814,
136.8216,
138.7136359664352,
141.06889606481482,
143.89130859375,
147.1848018518519,
151.18287395833335,
156.56722500000004,
163.08477465277775,
170.39999999999998,
178.17737812500008,
186.0813861111111,
193.77650104166668,
200.92719999999997,
207.1979600694445,
212.25325833333338,
215.75757187500002,
217.69051851851853,
218.73166724537037,
218.953125,
218.38724247685184,
217.06637037037035,
215.02285937499997,
212.28906018518515,
208.8973234953704,
204.87999999999994,
200.2694403935184,
195.09799537037037,
189.00837890625004,
181.429861111111,
172.65016623263892,
162.97778125000002,
152.72119314236113,
142.1888888888889,
131.68935546875,
121.5310798611111,
112.02254904513886,
103.47224999999997,
96.18866970486107,
90.02936921296303,
84.45704453124995,
79.43045925925931,
74.91241009837958,
70.86569375000003,
67.25310691550922,
64.03744629629625,
61.18150859375002,
58.64809050925927,
56.39998874421293,
54.4
]
*/
现在看起来像这样:
De Casteljau 算法将应用于控制点,这些控制点通常不在曲线上。 您的JS代码中使用的点数据是曲线上的点,与曲线的控制点不同。 因此,本质上,您的第二条曲线是一条贝塞尔曲线,其控制点来自第一条曲线上的点。 这就是为什么第 2 条曲线与第 1 条曲线的形状相似但峰值较小的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.