.NET GDI+:绘制带圆角的线条

发布于 2024-08-12 18:45:23 字数 1855 浏览 11 评论 0原文

给定一个点数组,很容易根据这些点绘制一条线,例如使用 GraphicsPath 类。

例如,下面的点数组...

[0]: (0,0)
[1]: (100,0)
[2]: (0,100)
[3]: (100,100)

...描述了一条类似于 Z 的线。

但挑战来了;我需要绘制半径为例如 10 像素的圆角。我所说的角是指线上不是起点或终点的点。在本例中,(0,100)(100,0) 处有两个角。

我尝试过贝塞尔曲线、曲线和圆弧,其中一些可能可以解决问题——我只是自己还没有找到它,因为我必须能够处理以所有角度绘制的线条,而不仅仅是水平的或垂直线。

Pen 对象的 LineJoin 设置为 Round 是不够的,因为这只在更宽的笔上显示。


编辑:澄清一下,我很清楚 GraphicsPath 类的贝塞尔曲线、曲线和圆弧功能。我正在寻找一些关于构建可以采用任意数量的点并将它们用圆角串在一起的算法的更具体的建议。


解决方案

我将以下函数放在一起,该函数返回表示带圆角的线的路径。该函数使用了 LengthenLine 函数,可以在此处找到。

protected GraphicsPath GetRoundedLine(PointF[] points, float cornerRadius)
{
  GraphicsPath path = new GraphicsPath();
  PointF previousEndPoint = PointF.Empty;
  for (int i = 1; i < points.Length; i++)
  {
    PointF startPoint = points[i - 1];
    PointF endPoint = points[i];

    if (i > 1)
    {
      // shorten start point and add bezier curve for all but the first line segment:
      PointF cornerPoint = startPoint;
      LengthenLine(endPoint, ref startPoint, -cornerRadius);
      PointF controlPoint1 = cornerPoint;
      PointF controlPoint2 = cornerPoint;
      LengthenLine(previousEndPoint, ref controlPoint1, -cornerRadius / 2);
      LengthenLine(startPoint, ref controlPoint2, -cornerRadius / 2);
      path.AddBezier(previousEndPoint, controlPoint1, controlPoint2, startPoint);
    }
    if (i + 1 < points.Length) // shorten end point of all but the last line segment.
      LengthenLine(startPoint, ref endPoint, -cornerRadius);

    path.AddLine(startPoint, endPoint);
    previousEndPoint = endPoint;
  }
  return path;
}

Given an array of points, it is easy to draw a line based on these, e.g. using the GraphicsPath class.

For instance, the following array of points...

[0]: (0,0)
[1]: (100,0)
[2]: (0,100)
[3]: (100,100)

...describes a line that resembles a Z.

But here comes the challenge; I need to draw rounded corners with a radius of e.g. 10 pixels. By corners I mean the points in the line that aren't start or end points. In this case there are two corners at (0,100) and (100,0).

I've played around with beziers, curves and arcs, some of which might hold the solution - I just haven't been able to find it myself yet, since I have to be able to handle lines drawn in all angles, not just horizontal or vertical lines.

Setting the LineJoin of the Pen object to Round isn't sufficient, since this only shows with wider pens.


Edit: To clarify, I'm well aware of the bezier, curve and arc capabilities of the GraphicsPath class. I am looking for some more specific advice in regard to building the algorithm that can take any number of points, and string them together with rounded corners.


Solution

I put together the following function which returns a path representing the line with rounded corners. The function makes use of a LengthenLine function, which can be found here.

protected GraphicsPath GetRoundedLine(PointF[] points, float cornerRadius)
{
  GraphicsPath path = new GraphicsPath();
  PointF previousEndPoint = PointF.Empty;
  for (int i = 1; i < points.Length; i++)
  {
    PointF startPoint = points[i - 1];
    PointF endPoint = points[i];

    if (i > 1)
    {
      // shorten start point and add bezier curve for all but the first line segment:
      PointF cornerPoint = startPoint;
      LengthenLine(endPoint, ref startPoint, -cornerRadius);
      PointF controlPoint1 = cornerPoint;
      PointF controlPoint2 = cornerPoint;
      LengthenLine(previousEndPoint, ref controlPoint1, -cornerRadius / 2);
      LengthenLine(startPoint, ref controlPoint2, -cornerRadius / 2);
      path.AddBezier(previousEndPoint, controlPoint1, controlPoint2, startPoint);
    }
    if (i + 1 < points.Length) // shorten end point of all but the last line segment.
      LengthenLine(startPoint, ref endPoint, -cornerRadius);

    path.AddLine(startPoint, endPoint);
    previousEndPoint = endPoint;
  }
  return path;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掌心的温暖 2024-08-19 18:45:23

这是我用来绘制圆角矩形的函数......
由此您可以计算每条线的角度。

Public Sub DrawRoundRect(ByVal g As Graphics, ByVal p As Pen, ByVal x As Single, ByVal y As Single, ByVal width As Single, ByVal height As Single, ByVal radius As Single)
    Dim gp As GraphicsPath = New GraphicsPath
    gp.AddLine(x + radius, y, x + width - (radius * 2), y)
    gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90)
    gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2))
    gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90)
    gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height)
    gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90)
    gp.AddLine(x, y + height - (radius * 2), x, y + radius)
    gp.AddArc(x, y, radius * 2, radius * 2, 180, 90)
    gp.CloseFigure()
    g.DrawPath(p, gp)
    gp.Dispose()
End Sub

希望这可以帮助您解决三角学中较难的部分;)

This is the function I use to draw a rectangle with rounded corners...
from this you may calculate the angle of each line.

Public Sub DrawRoundRect(ByVal g As Graphics, ByVal p As Pen, ByVal x As Single, ByVal y As Single, ByVal width As Single, ByVal height As Single, ByVal radius As Single)
    Dim gp As GraphicsPath = New GraphicsPath
    gp.AddLine(x + radius, y, x + width - (radius * 2), y)
    gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90)
    gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2))
    gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90)
    gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height)
    gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90)
    gp.AddLine(x, y + height - (radius * 2), x, y + radius)
    gp.AddArc(x, y, radius * 2, radius * 2, 180, 90)
    gp.CloseFigure()
    g.DrawPath(p, gp)
    gp.Dispose()
End Sub

Hope this help you in the harder part of trigonometry ;)

江挽川 2024-08-19 18:45:23

贝塞尔曲线的实现非常简单:

http://www.codeproject.com/KB/ Recipes/BezirCurves.aspx

幸运的是,如果您想省略血淋淋的细节,您也可以将它们作为 GraphicsPath 类的一部分:

http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath.addbezier.aspx

和您还可以查看样条曲线:

http:// /msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath.addcurve.aspx

Bezier curves are pretty straightforward to implement:

http://www.codeproject.com/KB/recipes/BezirCurves.aspx

Luckily you also have them as part of the GraphicsPath class if you wanna omit the gory details:

http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath.addbezier.aspx

And you can also look into splines:

http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.graphicspath.addcurve.aspx

高冷爸爸 2024-08-19 18:45:23

网址描述了如何绘制圆角矩形,可能会帮助您入门。

但我认为,如果没有别的办法,你将能够在你的路径上添加更多点,以产生圆角的错觉。因此添加 0,0 和 100,0 之间的几个点。一个例子可能是:

(0,0)
(90,0)
(95,5)
(95,10)
(0,100)

我没有以任何方式测试该路径,只是提取了一些可能凭空产生的数字:)。

This url has a description of how to draw rounded rectangles that might help you start out.

But I would think that if nothing else you would be able to add more points to your path, to give the illusion of rounded corners. So add in several points between 0,0 and 100,0. An example might be:

(0,0)
(90,0)
(95,5)
(95,10)
(0,100)

I have not tested that path in any way, just pulled some numbers that might work out of the air :).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文