.NET GDI+: Drawing lines with rounded corners

≡放荡痞女 提交于 2019-12-20 02:41:49

问题


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

回答1:


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




回答2:


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




回答3:


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 :).



来源:https://stackoverflow.com/questions/1805582/net-gdi-drawing-lines-with-rounded-corners

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!