【问题标题】:drawing half arc of bezier curve绘制贝塞尔曲线的半弧
【发布时间】:2014-09-29 05:43:02
【问题描述】:

我想将贝塞尔曲线一分为二。例如,如果在点 (100,100) 和 (200, 100) 之间有一条贝塞尔曲线,控制点为 (150,150) 和 (175, 150),则曲线应该用两种不同的颜色(比如红色和绿色)着色,一种从 (100,100) 到 (150, 100) 的颜色表示红色,从 (150,100) 到 (200,100) 的另一种颜色表示绿色。

这是我绘制贝塞尔样条的代码:

void Form1_Paint(object sender, PaintEventArgs e)
        {
            Point startPoint = new Point(100, 100);
            Point endPoint = new Point(200, 100);
            Point ctPoint1 = new Point(150, 150);
            Point ctPoint2 = new Point(175, 150);
            GraphicsPath gp = new GraphicsPath();
            gp.AddLine(new Point(100, 0), new Point(100, 100));
            gp.AddBezier(startPoint, ctPoint1, ctPoint2, endPoint);
            gp.AddLine(new Point(200, 100), new Point(200, 0));
            gp.AddLine(new Point(100, 0), new Point(200, 0));
            e.Graphics.FillPath(Brushes.Aqua, gp);
}

我想用上面解释的两种颜色填充它。

期望的结果:

我怎样才能做到这一点

编辑:

我检查了一些用于分割贝塞尔曲线enter link description here 的链接,但它告诉我要找到曲线的中点,这不是我的情况,我正在寻找绘制半贝塞尔曲线。

已知值:两点及其控制点在两点之间绘制贝塞尔曲线

预期结果:贝塞尔曲线的一部分从起点画到中点,另一部分从中点画到终点。

【问题讨论】:

  • 最好的办法可能是创建一个自定义画笔,用颜色 1 绘制前半部分,用颜色 2 绘制后半部分。
  • 我认为您没有仔细阅读链接。两条半曲线由控制点组 P0P4P7P9 和 P9P8P6P3 生成。这是贝塞尔曲线的绝妙属性。
  • 该链接非常有趣,但我认为您是对的:根据贝塞尔曲线的形状,中点不会在中间分割形状。您可以使用一个简单的技巧,而不是进行更复杂的数学运算:在 (150,?) 处找到贝塞尔曲线上的分割点,画一条直到 (150,0) 的线,然后 floodfill你形状的一半。 FloodFill 并不难做到——wikipedia.. 中有一个不错的非递归算法。

标签: c# graphics bezier


【解决方案1】:

如果你心目中的贝塞尔曲线的“中点”实际上就是贝塞尔曲线上x=150的点,那么还是可以解析计算出来的。由于贝塞尔曲线只有 3 次,我们可以计算对应于中点的参数“t”(例如,使用 Cardano 公式)。一旦有了中点参数,就可以使用 de Cateljau 算法找到两条分割曲线的控制点。将两条分割曲线作为贝塞尔曲线后,您可以根据需要绘制这两个区域。

这是分割曲线的结果控制点:

第一条分割曲线:(100, 100) (120.196418101, 120.196418101), (136.313883161, 132.234930120) 和 (150.000000000, 136.115536​​056)。

第二条分割曲线:(150.000000000, 136.115536​​056), (170.196418101, 141.842093918), (185.098209050, 129.803581899) 和 (200, 100)。

顺便说一句,“中点”处的参数 t 约为 0.403928。

对于具有控制点 P0、P1、P2 和 p3 的三次贝塞尔曲线,给定分割参数 t,分割曲线的控制点计算如下(使用 De Casteljau 算法)

1) 将 Q0、Q1 和 Q2 计算为
Q0 = (1-t)*P0 + t*P1
Q1 = (1-t)*P1 + t*P2
Q2 = (1-t)*P2 + t*P3

2) 将 R0 和 R1 计算为
R0 = (1-t)*Q0 + t*Q1
R1 = (1-t)*Q1 + t*Q2

3) 将 S0 计算为 S0 = (1-t)*R0 + t*R1。这将是曲线上的分割点

4) 第一条分割曲线的控制点是P0、Q0、R0和S0,第二条分割曲线的控制点是S0、R1、Q2和P3。

【讨论】:

  • 请解释用于将曲线一分为二的算法,我将其标记为答案,因为您的答案是通用的并且适用于所有平台
  • TIL 您可以将贝塞尔曲线一分为二,它仍然是贝塞尔曲线。
  • @Anand:如果你有想要分割贝塞尔曲线的参数,你可以应用 De Cateljau 算法来分割曲线。您发布的题为“如何拆分三次贝塞尔曲线”的链接基本上是在 t = 0.5 时应用 de Catseljau 算法。这个link 为 De Catseljau 算法提供了一个很好的解释。
  • @Anand:我添加了更多关于应用 De Casteljau 算法在参数 t 处分割三次贝塞尔曲线的细节。希望对您有用。
【解决方案2】:

我用过Region.Exclude方法和GraphicsPath.GetBounds方法

代码:

    //Creating graphics path for drawing bezier spline
    GraphicsPath gp = new GraphicsPath();
    gp.AddLine(new Point(100, 0), new Point(100, 100));
    gp.AddBezier(startPoint, ctPoint1, ctPoint2, endPoint);
    gp.AddLine(new Point(200, 100), new Point(200, 0));
    gp.AddLine(new Point(100, 0), new Point(200, 0));

    //Dividing the path into two regions
    Rectangle bounds=Rectangle.Round(gp.GetBounds());
    Region left = new Region(gp);
    left.Exclude(new Rectangle(bounds.Left, bounds.Top, (int)(bounds.Width / 2), bounds.Height));

    Region right = new Region(gp);
    right.Exclude(new Rectangle((int)(bounds.Left + bounds.Width / 2), bounds.Top, (int)(bounds.Width / 2), bounds.Height));

    //Drawing divided regions
    e.Graphics.FillRegion(Brushes.Black, left);
    e.Graphics.FillRegion(Brushes.Aqua, right);

解释:

  1. 构造绘制贝塞尔样条的路径
  2. 为路径创建一个区域
  3. 将路径分成两个相等的区域。
  4. 使用e.Graphics.FillRegion 方法填充所需的一半贝塞尔曲线

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 2011-02-26
    • 2018-12-03
    • 1970-01-01
    • 2017-05-18
    • 1970-01-01
    相关资源
    最近更新 更多