title: .NET GDI+: Drawing lines with rounded corners
body: <p>Given an array of points, it is easy to draw a line based on these, e.g. using the GraphicsPath class.</p>
  
  <p>For instance, the following array of points...</p>
  
  <pre><code>[0]: (0,0)
  [1]: (100,0)
  [2]: (0,100)
  [3]: (100,100)
  </code></pre>
  
  <p>...describes a line that resembles a Z.</p>
  
  <p>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 <code>(0,100)</code> and <code>(100,0)</code>.</p>
  
  <p>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.</p>
  
  <p>Setting the <code>LineJoin</code> of the <code>Pen</code> object to <code>Round</code> isn't sufficient, since this only shows with wider pens.</p>
  
  <hr>
  
  <p><strong>Edit:</strong> 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.</p>
  
  <hr>
  
  <h2>Solution</h2>
  
  <p>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 <a href="https://stackoverflow.com/questions/1866903/shorten-a-line-by-a-number-of-pixels">here</a>.</p>
  
  <pre><code>protected GraphicsPath GetRoundedLine(PointF[] points, float cornerRadius)
  {
    GraphicsPath path = new GraphicsPath();
    PointF previousEndPoint = PointF.Empty;
    for (int i = 1; i &lt; points.Length; i++)
    {
      PointF startPoint = points[i - 1];
      PointF endPoint = points[i];
  
      if (i &gt; 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 &lt; 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;
  }
  </code></pre>