Drawing GDI+ Splines and Curves in VB.NET

In this article I will explain how to draw Splines and Curves in GDI+.
  • 1313

A curve is a sequence of adjoining point with a tension. The tension of a curve provides its smoothness and removes corners. A cardinal spline is a sequence of multiple joined curves. Basically, in a curve there is no straight line between two points. To illustrate, Figure 3.17 shows two curves.

There are two types of curves: open and closed. A closed curve is a curve whose starting point is the ending point. A curve that is not a closed curve is called an open curve. In Figure 3.18 the first curve is an open curve, and the second curve is a closed curve.

Drawing Open Curves

Programmatically, a curve is an array of connected point with a tension. A curve has a starting point and an ending point. Between these two points can be many intermediate points. The Graphics class provides two methods for drawing curves: DrawCurve and DrawClosedCurve. The DrawCurve method draws a curve specified by an array of Point structures. The DrawClosedCurve draws a closed curve specified by an array of point structures. Both DrawCurve and DrawClosedCurve have overloaded methods.

DrawCurve has the following overloaded forms:


Public DrawCurveCType(As void, Pen,Point())
Public DrawCurveCType(As void, Pen,PointF())
Public DrawCurveCType(As void, Pen,Point(),single)
Public DrawCurve(Pen As void,PointF() As void,float As void
Public DrawCurveCType(As void, Pen,PointF(),int,Integer)
Public DrawCurveCType(As void, Pen,Point(),int,int,single)
Public DrawCurveCType(As void, Pen,PointF(),int,int,single)

The simplest form of DrawCurve is

3_17.gif

FIGURE 3.17: Two curves

3_18.gif

FIGURE 3.18: Open and closed curves


    Public Sub DrawCurve(ByVal pen As Pen, ByVal pointer As Point())
    End Sub


where points is an array of points.

To test the DrawCurve methods, we create a Windows
application and add Listing 3.13 to the form's paint event handler. It creates an array of points and draws a curve using the DrawCurve method.

LISTING 3.13: Drawing a curve

    Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        ' Create a pen
        Dim bluePen As New Pen(Color.Blue, 1)

        ' Create an array of points
        Dim pt1 As New PointF(40.0F, 50.0F)
        Dim pt2 As New PointF(50.0F, 75.0F)
        Dim pt3 As New PointF(100.0F, 115.0F)
        Dim pt4 As New PointF(200.0F, 180.0F)
        Dim pt5 As New PointF(200.0F, 90.0F)

        Dim ptsArray As PointF() = {pt1, pt2, pt3, pt4, pt5}

        ' Draw curve
        e.Graphics.DrawCurve(bluePen, ptsArray)

        ' Dispose of object
        bluePen.Dispose()
    End Sub

Figure 3.19 shows the output from our Listing 3.13.

NOTE

The default tension is 0.5 for this overloaded version of DrawCurve.

The second form of DrawCurve is


Public void DrawCurve(Pen pen, Point() points, single tension)

Here the tension parameter determines the shape of the curve. If the value of tension is 0.0F, the method draws a straight line between the points. The value of tension should vary between 0.0F and 1.0F.
3_19.gif

FIGURE 3.19: Drawing a curve

3_20.gif

FIGURE 3.20: A curve-drawing application

Now let's update the example in Listing 3.13. We add a
text box, a label, and a button to the form. We change the properties of these controls, and the form looks like Figure 3.20.

Now we will update our sample code to draw a curve using the tension value entered in the text box. We add a float type variable, tension at the class level.


      Private tension As Single = 0.5F

Then we update the form's paint event handlers as shown in Listing 3.14. We provide tension as the third argument to the DrawCurve method.

LISTING 3.14: Drawing a curve with tension


    Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        ' Create a pen
        Dim bluePen As New Pen(Color.Blue, 1)

        ' Create an array of points
        Dim pt1 As New PointF(40.0F, 50.0F)
        Dim pt2 As New PointF(50.0F, 75.0F)
        Dim pt3 As New PointF(100.0F, 115.0F)
        Dim pt4 As New PointF(200.0F, 180.0F)
        Dim pt5 As New PointF(200.0F, 90.0F)

        Dim ptsArray As PointF() = {pt1, pt2, pt3, pt4, pt5}

        ' Draw curve
        e.Graphics.DrawCurve(bluePen, ptsArray, tension)

        ' Dispose of object
        bluePen.Dispose()

    End Sub

Now we add code for the Apply button, which simply reads the text box's value and sets it as the tension, as in Listing 3.15.

LISTING 3.15: The Apply button click even handle


    Private Sub ApplyBtn_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        tension = CSng(Convert.ToDouble(textBox1.Text))
        Invalidate()
    End Sub


If you enter "0.0" in the text box and hit Apply, the output looks like Figure 3.21, and if you enter the value "1.0" in the text box and hit Apply the output looks like Figure 3.22.

The offset specifies the number of elements to skip in the array of points. The first element after the skipped elements in the array of points becomes the starting point of the curve.

3_21.gif

FIGURE 3.21: Drawing a curve with a tension of 0.0F

3_22.gif

FIGURE 3.22: Drawing a curve with a tension of 1.0F

The numberOfSegments property specifies the number of segments after the starting point, to draw in the curve. It must be at least 1. The offset plus the number of segments must be less then the number of elements in the array of the points.

The following methods skips the first element of the array of points and starts drawing a curve from the second point in the array, stopping after three segments:


        Dim offset As Integer = 1
        Dim segments As Integer = 3

e.Graphics.DrawCurve (bluePen, ptsArray, offset, segments);


The final version of DrawCurve takes a pen, point array, offset, number of segments, and tension:


    Public Sub DrawCurve(ByVal pen As Pen, ByVal points As Point(), ByVal offset As Integer, ByVal numberOfSegments As Integer, ByVal tension As Single)
    End Sub

Here's an example:


        Dim offset As Integer = 1
        Dim segments As Integer = 3
        e.Graphics.DrawCurve(bluePen, ptsArray, offset, segments, tension)


Drawing Closed Curves

As stated earlier, a closed curve is a curve whose starting and ending points are the same. The Graphics class provides the DrawCloseCurve method to draw closed curves. It has the following overloaded forms:


Public DrawClosedCurveCType(As void, Pen,Point())
Public DrawClosedCurveCType(As void, Pen,PointF())
Public DrawClosedCurveCType(As void, Pen,Point(),float,FillMode)
Public DrawClosedCurveCType(As void, Pen,Point()F,float,FillMode)

The simplest form of DrawClosedCurve takes two parameters: a pen and an array of points. Listing 3.16 creates an array of points and a pen and calls the DrawClosedCurve method.

LISTING 3.16: Drawing closed curves


    Private Sub Form1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        ' Create a pen
        Dim bluePen As New Pen(Color.Blue, 1)

        ' Create an array of points
        Dim pt1 As New PointF(40.0F, 50.0F)
        Dim pt2 As New PointF(50.0F, 75.0F)
        Dim pt3 As New PointF(100.0F, 115.0F)
        Dim pt4 As New PointF(200.0F, 180.0F)
        Dim pt5 As New PointF(200.0F, 90.0F)

        Dim ptsArray As PointF() = {pt1, pt2, pt3, pt4, pt5}

        ' Draw curve
        e.Graphics.DrawClosedCurve(bluePen, ptsArray)
 
        ' Dispose of object
       bluePen.Dispose()

     End Sub

Figure 3.23 shows the output from Listing 3.16. The result is a closed curve.

The second form of DrawClosedCurve takes as arguments the tension of the curve and FillMode. We have already discussed tension. FillMode specifies how the interior of a closed path is filled and clipped. The FillMode enumeration represents the fill mode of graphics object. It has two modes: Alternate (the default mode) and Winding.

As the documentation says,

To determine the interiors of a closed curve in the Alternate mode, draw a line from any arbitrary start point in the path to some point obviously outside the path. If the line crosses an odd number of path segments, the starting point is inside the closed region and is therefore part of the fill or clipping area. An even number of crossings means that the point is not in an area to be filled or clipped. An open figure is filled or clipped by using a line to connect the last point to the first point of the figure.

The Winding mode considers the direction of the path segments at each intersection. It adds one for every clockwise intersection, and subtracts one for very counterclockwise intersection. If the result is nonzero, the point is considered inside the fill or clip area. A zero counts means that the point lies outside the fill or clip area.

3_23.gif

FIGURE 3.23: Drawing a closed curve

LISTING 3.17 Drawing a closed curve with a tension and fill mode.


        ' Draw curve
        Dim tension As Single = 0.5F
        e.Graphics.DrawClosedCurve(bluePen, ptsArray, tension, FillMode.Alternate)


Conclusion

Hope the article would have helped you in understanding how to draw Splines and Curves in GDI+. Read other articles on GDI+ on the website.

Categories

More Articles

© 2013 dotNetheaven. All rights reserved.