Search code examples
c#beziersplinemicrosoft-chart-controls

Chart C# add Data Point in cubic bezier curve


I have written a method to create a Bezier curve for rendering in a Chart control. I have a collection of data points which I retrieve from another method. I would like to form the Bezier curve on my chart to produce something similar to a spline, but instead I am receiving a blank chart. The code to produce the curve is:

public static double XChart(double t, double x0, double x1, double x2, doubl x3)
{
    return (double)(
        x0 * Math.Pow((1 - t), 3) +
        x1 * 3 * t * Math.Pow((1 - t), 2) +
        x2 * 3 * Math.Pow(t, 2) * (1 - t) +
        x3 * Math.Pow(t, 3)
    );
}

I then add the curve to the chart with the code below:

chart1.Series["Series1"].Points.AddXY(XChart(0.1, a, c, b, d), YChart(0.1, l, f, i, g));

Where a, b, c, d, l, f, i, g are the values I get from a list of data points.

List<DataPoint> dataPoints0 = new List<DataPoint>();
var a = dataPoints0[0].XValue;
var b = dataPoints0[1].XValue;
var c = dataPoints0[2].XValue;
var d = dataPoints0[3].XValue;
var l = dataPoints0[0].YValues[0];
var i = dataPoints0[1].YValues[0];
var f = dataPoints0[2].YValues[0];
var g = dataPoints0[3].YValues[0];

Now, suppose that:

a= 4 , l= 0
b= 3 , i= 3
c= 4 , f= 5
d= 3 , g= 6

I should get the curve like this:
enter image description here

However, what I get on my chart is this:
enter image description here

I'm not sure why this is happening, any help is appreciated.


Solution

  • It appears as though you're only adding a single point to your chart; to fix this, you'll need to add each point from your curve that you are concerned with:

    for (float t = 0.0f; t < 1.0f; t += 0.01f)
        chart1.Series["Series1"].Points.AddXY(XChart(t, a, b, c, d), YChart(t, l, f, i, g));
    

    The example above iterates from a start time of 0 and adds 100 points to your chart using 0.00f - 1.00f.


    The Bezier curve function you've implemented gives you a specific point in your curve based on time. You can always write a helper method to give you all points by adding an argument for the number of points that should be returned:

    public static double XChart(double t, double x0, double x1, double x2, double x3) {
        return (double)(
            x0 * Math.Pow((1 - t), 3) +
            x1 * 3 * t * Math.Pow((1 - t), 2) +
            x2 * 3 * Math.Pow(t, 2) * (1 - t) +
            x3 * Math.Pow(t, 3));
    }
    public static double[] XChart(double x0, double x1, double x2, double x3, int totalPoints) {
        List<double> points = new List<double>();
        for (float t = 0.0f; t < 1.0f; t += (1 / (float)totalPoints))
            points.Add(XChart(t, x0, x1, x2, x3));
    
        return points.ToArray();
    }
    

    You can then utilize this helper method to build your chart as below:

    double[] xPoints = XChart(a, b, c, d, 100);
    double[] yPoints = YChart(l, f, i, g, 100);
    if (xPoints.Length != yPoints.Length)
        throw new InvalidOperationException("The number of points between axes must match.");
    
    for (int i = 0; i < xPoints.Length; i++)
        chart1.Series["Series1"].Points.AddXY(xPoints[i], yPoints[i]);
    

    I would take a look at the Wikipedia page regarding the construction of Bezier curves. I would start with the Quadratic curve, and then after understanding how it works I would progress to your representation of high-order curves.

    For quadratic Bézier curves one can construct intermediate points Q0 and Q1 such that as t varies from 0 to 1:

    • Point Q0(t) varies from P0 to P1 and describes a linear Bézier curve.

    • Point Q1(t) varies from P1 to P2 and describes a linear Bézier curve.

    • Point B(t) is interpolated linearly between Q0(t) to Q1(t) and describes a quadratic Bézier curve.