如何通过几个点绘制贝塞尔曲线?

9

我有几个要点,我尝试使用下面的代码绘制贝塞尔曲线

 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));

我的贝塞尔曲线段看起来像这样:

  • 1、2、3号点 - 第一段
  • 3、4、5号点 - 第二段
  • 5、6、7... ...

但我得到了这个奇怪的曲线(这里有3个大的节点和7个小的椭圆形的点):

enter image description here


我看到这个是很自然的,你能否发布一个所需曲线的链接? - Hamza_L
或者,也许您想用7个控制点绘制单个线段? - Hamza_L
2个回答

23
您获得的线是三个不同贝塞尔曲线的并集 - 每组三个点对应一个曲线(每个“贝塞尔段”对应一个曲线)。
如果要得到单一平滑曲线,需要将9(或更多)个点作为一个点集(单个“贝塞尔段”)传递,而不是分成三个点一组。
编辑:显然,BezierSegment仅支持三个点,所以这就是为什么无法使用。即使'PolyBezierSegment'也只提供一组贝塞尔段而不是单一平滑贝塞尔曲线...
因此,由于WPF没有提供有用的东西,我使用这里的数学方法编写了一些代码。这是一个数值解决方案,但即使有足够的点使其看起来很平滑,它似乎也非常高效。
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);
}

使用这个,

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);
}

提供

在此输入图片描述


这太酷了!帮了我很多!谢谢! - Gilad
不正确的近似导致控制路径成为圆形,而它绘制的是椭圆形。您可能需要重新考虑近似数学。 - SoLaR
4
使用贝塞尔曲线无法绘制出一个圆形,你可能需要重新考虑如何绘制圆形。 - Rawling
非常感谢,工作得非常好,尽管我发现GetBezierPoint的第一行必须是“if(count==0)” - Nathan Williams

16

由于每个曲线都有一个控制点(影响曲线但不一定在曲线上),因此您正在使用二次贝塞尔曲线。

如果您想要绘制两条共享端点的二次曲线,并且希望接口看起来平滑,则两个共享端点的控制点必须与端点共线。也就是说,两个控制点和它们之间的端点必须位于同一条直线上。例如:

quadratics with smooth joints

实心黑色圆圈是端点。空心圆圈是控制点。实线是曲线。虚线显示每个端点与两侧的控制点共线(位于同一条直线上)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接