简体   繁体   中英

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.

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

If you can take a look at the example here. 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.

平滑值和丢失值

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.

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 .

Using its CurveInterpolator2D class, I was able to generate the 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
]
*/

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. The point data used in your JS codes are points on the curve, which is not the same as control points for the curve. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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