简体   繁体   English

如何将三次贝塞尔曲线细分为点

[英]How to subdivide Cubic Bezier curve into points

I am working with a dataset consisting of yearly data.我正在使用由年度数据组成的数据集。 Each item in the array corresponds to a year.数组中的每个项目对应于一年。 I would to extend this dataset and make it monthly instead.我想扩展这个数据集并改为每月制作一次。 I have been researching about it and trying different methods but in the end, finding De Casteljau's algorithm to determine individual points at a Bezier curve.我一直在研究它并尝试不同的方法,但最终找到了 De Casteljau 的算法来确定贝塞尔曲线上的各个点。

https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm

If you can take a look at the example here.如果你可以看看这里的例子。 http://jsfiddle.net/vdbhc98j/ 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: []
  }]
});

It is indeed subdividing the curve into 120 distinct points even though the resemblance is there, it is not exactly maintaining the curve.即使存在相似之处,它确实将曲线细分为 120 个不同的点,但它并没有完全保持曲线。

平滑值和丢失值

If you also inspect the values, within the original chart without subdivision, the value goes up to 1129, whereas in the subdivided one it is up to ~427.如果您还检查这些值,在没有细分的原始图表中,该值会上升到 1129,而在细分的图表中,它会上升到 ~427。

Could you please help me - specifically what I am expecting from the algorithm is wrong or I am making a mistake somewhere?你能帮我吗 - 特别是我对算法的期望是错误的还是我在某个地方犯了错误? If you could point out if there are alternatives to this problem, that'd be great.如果你能指出这个问题是否有替代方案,那就太好了。

Thank you in advance.先感谢您。

I found this library called Curve-Interpolator, https://www.npmjs.com/package/curve-interpolator .我发现这个库叫做 Curve-Interpolator, https://www.npmjs.com/package/curve-interpolator

Using its CurveInterpolator2D class, I was able to generate the output:使用它的CurveInterpolator2D class,我能够生成 output:

http://jsfiddle.net/sznjxrah/1/ 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
]
*/

It looks like this now:现在看起来像这样:

在此处输入图像描述

The De Casteljau's algorithm is to be applied onto the control points, which in general do not lie on the curve. De Casteljau 算法将应用于控制点,这些控制点通常不在曲线上。 The point data used in your JS codes are points on the curve, which is not the same as control points for the curve.您的JS代码中使用的点数据是曲线上的点,与曲线的控制点不同。 So, essentially, your 2nd curve is a Bezier curve with control points from points on the 1st curve.因此,本质上,您的第二条曲线是一条贝塞尔曲线,其控制点来自第一条曲线上的点。 This is the reason why 2nd curve resembles the shape of the 1st curve but has a smaller peak value.这就是为什么第 2 条曲线与第 1 条曲线的形状相似但峰值较小的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM