9

I have several points, and I try to draw Bezier curve using code below

 PathFigure pf = new PathFigure(points.From, ps, false); //ps - list of Bezier segments
    PathFigureCollection pfc = new PathFigureCollection();
    pfc.Add(pf);
    var pge = new PathGeometry();
    pge.Figures = pfc;
    Path p = new Path();
    p.Data = pge;
    p.Stroke = new SolidColorBrush(Color.FromRgb(244, 111, 011));

My Bezier segments look like this

  • 1,2,3 points - first segment
  • 3,4,5 points - second
  • 5,6,7.. ..

But I got this strange curve (here is 3 big (Nodes) and 7 small ellipse (is my points)):

enter image description here

Roman Bats
  • 1,775
  • 3
  • 30
  • 40

2 Answers2

23

The line you're getting is the union of three distinct Bezier curves - one for each group of three points. (One for each "Bezier segment"?)

If you want a single smooth curve, you need to pass your 9 (or more) points as a single collection of points (single "Bezier segment"?), not as groups of three points.

Edit: Apparently BezierSegment only supports three points, so no wonder this doesn't work. Even 'PolyBezierSegment' just gives a collection of Bezier segments rather than a single smooth Bezier...

So since WPF doesn't give you anything useful, I knocked something together using the maths here. It's a numeric solution, but it seems to be pretty performant even with enough points to look nice and smooth:

PolyLineSegment GetBezierApproximation(Point[] controlPoints, int outputSegmentCount)
{
    Point[] points = new Point[outputSegmentCount + 1];
    for (int i = 0; i <= outputSegmentCount; i++)
    {
        double t = (double)i / outputSegmentCount;
        points[i] = GetBezierPoint(t, controlPoints, 0, controlPoints.Length);
    }
    return new PolyLineSegment(points, true);
}

Point GetBezierPoint(double t, Point[] controlPoints, int index, int count)
{
    if (count == 1)
        return controlPoints[index];
    var P0 = GetBezierPoint(t, controlPoints, index, count - 1);
    var P1 = GetBezierPoint(t, controlPoints, index + 1, count - 1);
    return new Point((1 - t) * P0.X + t * P1.X, (1 - t) * P0.Y + t * P1.Y);
}

Using this,

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    Point[] points = new[] { 
            new Point(0, 200),
            new Point(0, 0),
            new Point(300, 0),
            new Point(350, 200),
            new Point(400, 0)
        };
    var b = GetBezierApproximation(points, 256);
    PathFigure pf = new PathFigure(b.Points[0], new[] { b }, false);
    PathFigureCollection pfc = new PathFigureCollection();
    pfc.Add(pf);
    var pge = new PathGeometry();
    pge.Figures = pfc;
    Path p = new Path();
    p.Data = pge;
    p.Stroke = new SolidColorBrush(Color.FromRgb(255, 0, 0));
    ((Grid)sender).Children.Add(p);
}

gives

enter image description here

Rawling
  • 49,248
  • 7
  • 89
  • 127
  • This is SUPER COOL! Helped me a lot! Thank you! – Gilad Sep 22 '15 at 19:09
  • Incorrect approximation, made control path to be circle and it draw's an elipsoid. You might need to rethink approximation math. – SoLaR Oct 05 '15 at 16:05
  • 4
    @SoLaR [It's impossible to make a circle using Beziers](http://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves). You might need to rethink how to draw a circle? – Rawling Oct 05 '15 at 16:29
  • Many thanks, works excellent, though I found line 1 for GetBezierPoint had to be "if(count==0)" – Nathan Williams Nov 18 '16 at 02:14
16

Since each of your curves has one control point (a point that influences the curve but isn't necessarily on the curve), you're using quadratic Bézier curves.

If you want to draw two quadratic curves that share an endpoint, and you want the joint to appear smooth, the control points on each side of the shared endpoint must be collinear with the endpoint. That is, the two control points and the endpoint between them must all lie on a straight line. Example:

quadratics with smooth joints

The solid black discs are the endpoints. The hollow circles are the control points. The solid black line is the curve. The dotted lines show that each endpoint is collinear (on a straight line with) the control point on either side.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848