Home

Drawing Curves

 

Curves

 

Introduction to Curves

A curve is a line that joins two or more points. If only two points are involved, the line would join them but the line is not straight. If there are three points A, B, and C, the line would start on the first point A, cross the second point B, and stop at the last point C. If more than three points are involved, the line would start on the first, cross the second, cross the third and each line before stopping on the last. The points of a curve don't have to be aligned. In fact, the whole idea of drawing a curve is to have a non-straight line that joins different non-aligned points. This can be illustrated with the following three curves labeled C1, C2, and C3:

   

The first curve, C1, includes only two points. The second, C2 includes three points. The third, C3, includes four points.

The section between two points is called a segment. This also means that a curve can be distinguished by the number of segments it has. If a curve is made of only two points, this means that it has only one segment from the first to the second, which is the last, point. If a curve includes three points, it has two segments. The first segment spans from the first point to the second point and the second segment spans from the second point to the third point. Based on this, the number of segments of a curve is equal to the number of its points - 1.

A curve can be drawn in GDI+ using the Graphics.DrawCurve() method. When drawing a curve, you must specify how many points would be involved. This means that you can first declare an array of Point or PointF values. Because it is left up to you to decide on this issue, the Graphics class provides the following syntaxes of the DrawCurve() method:

Public Sub DrawCurve(pen As Pen, points As Point())
Public Sub DrawCurve(pen As Pen, points As PointF())

This version of the method takes an array of Point or PointF values as arguments. The number of members of the array depends on you. Here is an example that uses four points to draw a curve with three segments:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {New Point(40, 42), _
                                 New Point(188, 246), _
                                 New Point(484, 192), _
                                 New Point(350, 48)}

            e.Graphics.DrawCurve(penCurrent, pt)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

This would produce:

Curve

As you can see, when the curve is drawn, a bent line crosses the intermediary points between the first and the last. To make the lines non-straight, the compiler uses a value called tension used to bend the line. If you want, you can specify the bending factor that should be applied. To do this, you would use the following version of the DrawCurve() method:

Public Sub DrawCurve(pen As Pen, points As Point(), tension As Single)
Public Sub DrawCurve(pen As Pen, points As PointF(), tension As Single)

The amount of bending to apply is passed as the tension argument. It can be passed as a decimal value >= 0.00. If this value is passed as 0.00, the lines would be drawn straight. Here is an example:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {New Point(40, 42), _
                   New Point(188, 246), _
                                  New Point(484, 192), _
                   New Point(350, 48)}

            e.Graphics.DrawCurve(penCurrent, pt, 0.0F)

End Sub

Curve

This means that, if you want a real curve, either you don't pass the tension argument and use the first version of the method or you pass the tension argument as a value higher than 0.00. Here is an example:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {New Point(40, 42), _
                   New Point(188, 246), _
                                  New Point(484, 192), _
                   New Point(350, 48)}

            e.Graphics.DrawCurve(penCurrent, pt, 2.15F)

End Sub

This would produce:

A curve with a tension value of 2.15

Both versions of the DrawCurve() method that we have used allow you to start the curve on the first point. Consider the following example that draws a curve of five points resulting in four segments:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As PointF() = {New PointF(20.0F, 322.0F), _
           New PointF(124, 24), _
                       New PointF(214, 242), _
           New PointF(275, 28), _
                        New PointF(380.0F, 322.0)}

            e.Graphics.DrawCurve(penCurrent, pt)

End Sub

This would produce:

Curve

If you want, you can start the curve on any point instead of the first. To support this, the Graphics class provides the following version of the DrawCurve() method:

Public Sub DrawCurve(pen As Pen, points As PointF(), _
	                   offset As Integer, numberOfSegments As Integer)

The offset argument allows you to specify how many points should be skipped before starting to draw. The first conclusion is that the value of the offset must be 0 or higher. If you pass this argument as 0, the curve would be drawn from the first point. If you pass this argument as 1, the first point would not be considered in the curve. This means that the drawing of the curve would start on the second point and so on. If you pass it as 2, the first and the second point would not be part of the curve, meaning that the curve would start on the third point. 

After the curve has started from the point you specify using the offset argument, you can then specify how many segments of the curve would be drawn. This number must be lower than the number of available segments, that is after subtracting the offset value from the total number of segments of the array. Here is an example:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As PointF() = {	New PointF(20.0F, 322.0F), _
		              	New PointF(124, 24), _
                 		New PointF(214, 242), _
      			New PointF(275, 28), _
                        		New PointF(380.0F, 322.0F) }

            e.Graphics.DrawCurve(penCurrent, pt, 1, 2)

End Sub

This would produce:

A curve with an offset value and a limited number of segments

Once again, the compiler arranges to apply a tension when drawing the curve. If you would prefer to use straight lines or to apply a different tension than the default, you can use the following version of the Graphics.DrawCurve() method:

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

This time, you can pass the value of the tension as 0 to get straight lines:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As PointF() = {	New PointF(20.0F, 322.0), _
      			New PointF(124, 24), _
                    		New PointF(214, 242), _
      			New PointF(275, 28), _
                    		New PointF(380.0F, 322.0) }

            e.Graphics.DrawCurve(penCurrent, pt, 0, 4, 0)

End Sub

This would produce:

Curve

Or you can pass the tension with any positive value of your choice. Here is an example:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As PointF() = {New PointF(20.0F, 322.0F), New PointF(124, 24), _
                               New PointF(214, 242), New PointF(275, 28), _
                                   New PointF(380.0F, 322.0F)}

            e.Graphics.DrawCurve(penCurrent, pt, 1, 3, 1.75F)

End Sub

This would produce:

Curve

 

A Bézier Curve

A bézier curve is a continuous line that is drawn using four points that are not necessarily aligned. It can be illustrated as follows:

Bezier

To draw this line (with four points), the compiler would draw a curve from the first point to the fourth point. Then it would bend the curve by bringing each middle (half-center) side close to the second and the third points respectively, without touching those second and third points. For example, the above bézier curve could have been drawn using the following four points:

Bezier Illustration

To draw a bézier curve, the Graphics class provides the DrawBezier() method that is overloaded in three versions whose syntaxes are:

Public Sub DrawBezier ( _
	pen As Pen, _
	pt1 As Point, _
	pt2 As Point, _
	pt3 As Point, _
	pt4 As Point _
)
Public Sub DrawBezier ( _
	pen As Pen, _
	pt1 As PointF, _
	pt2 As PointF, _
	pt3 As PointF, _
	pt4 As PointF _
)
Public Sub DrawBezier ( _
	pen As Pen, _
	x1 As Single, _
	y1 As Single, _
	x2 As Single, _
	y2 As Single, _
	x3 As Single, _
	y3 As Single, _
	x4 As Single, _
	y4 As Single _
)

Based on this, to draw a bézier line, you can use either four Point or PointF values or the coordinates of the four points. Here is an example:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt1 As Point = New Point(20, 12)
            Dim pt2 As Point = New Point(88, 246)
            Dim pt3 As Point = New Point(364, 192)
            Dim pt4 As Point = New Point(250, 48)

            e.Graphics.DrawBezier(penCurrent, pt1, pt2, pt3, pt4)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

This would produce:

Bezier Curve

A Series of Bézier Curves

The Graphics.DrawBezier() method is used to draw one bézier curve. If you want to draw many bézier curves, you can call the Graphics.DrawBeziers() method that is overloaded in two versions as follows:

Public Sub DrawBeziers(pen As Pen, points As Point())
Public Sub DrawBeziers(pen As Pen, points As PointF())

The DrawBeziers() method requires an array of Point of PointF values. When working with only four coordinates, the DrawBeziers() method works exactly like DrawBezier(), the different is that, while DrawBezier() expects four Point or four PointF values, DrawBeziers() expects an array of Point or PointF values. Using, DrawBeziers(), the above bézier curve can be drawn as follows and produce the same result:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {	New Point(20, 12), New Point(88, 246), _
                            		New Point(364, 192), New Point(250, 48)}

            e.Graphics.DrawBeziers(penCurrent, pt)

End Sub

This would produce:

Curve

A characteristic of using DrawBeziers() is that it allows you to draw a bézier curve using 7 Point or PointF values. Here is an example:

Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {	New Point(10, 5), New Point(340, 60), _
                              		New Point(320, 148), New Point(150, 120), _
                       		New Point(24, 220), New Point(250, 150), _
                       		New Point(304, 240) }

            e.Graphics.DrawBeziers(penCurrent, pt)

End Sub

This would produce:

Beziers
 

A Closed Curve

If you use either the DrawLines(), the DrawBezier() or the DrawBeziers() methods, you would get a continuous line or a series of lines that has a beginning and an end. Alternatively, GDI+ allows you to draw a series of lines but join the end of the last line to the beginning of the first line to have a closed shape. To draw this figure, you can call the Graphics.DrawClosedCurve() method that is overloaded in four versions. Two of them have the following syntaxes:

Public Sub DrawClosedCurve(pen As Pen, points As Point())
Public Sub DrawClosedCurve(pen As Pen, points As PointF())

These two versions are the easiest to use. They allow you to provide an array of four Point or four PointF values. When executed, each of these methods draws a curve that passes through each coordinate and closes the curve by joining the end point to the first unless both points are the same. Here is an example:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Blue)
            Dim pt As Point() = {New Point(40, 42), New Point(188, 246), _
                              New Point(484, 192), New Point(350, 48)}

            e.Graphics.DrawClosedCurve(penCurrent, pt)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

This would produce:

Closed Curve

The first two versions are used to draw the lines but curve them in order to make the shape appear smooth. If you want, you can draw the lines straight from one point to the next without curving them. To draw this type of shape using the DrawClosedCurve() method, you can use one of the following versions of the method:

Public Sub DrawClosedCurve(pen As Pen, points As Point(), _
		              tension As Single, fillmode As FillMode)
Public Sub DrawClosedCurve(pen As Pen, points As PointF(), _
		              tension As Single, fillmode As FillMode)

These versions allow you to specify the tension and the fill mode. The tension factor allow you to specify how much curve would be applied. If this value is passed as 0.00, the points would be joined with straight lines as follows:

Closed Shape With Straight Lines

 Otherwise, you can apply a tension using an appropriate decimal value.

The fillmode factor determines how the interior of the curve would be filled. It is controlled through the FillMode enumeration that is defined in the System.Drawing.Drawing2D namespace. The FillMode enumeration has two members: Alternate and Winding. Here is an example:

Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Red)
            Dim pt As Point() = {New Point(40, 42), New Point(188, 246), _
                              New Point(484, 192), New Point(350, 48)}

            e.Graphics.DrawClosedCurve(penCurrent, pt, 0.75, _
                     FillMode.Winding)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

This would produce:

Closed Curve

Remember that the higher the tension, the sharper the corners. If you want the shape to show straight lines, pass a tension of 0.00F.

Pies

A pie is a fraction of an ellipse delimited by a starting angle and an angle that constitutes the desired portion to make up a pie. It can be illustrated as follows:

Pie Illustration

To draw a pie, you can use the Graphics.DrawPie() method that comes in various versions as follows:

Public Sub DrawPie ( _
	pen As Pen, _
	rect As Rectangle, _
	startAngle As Single, _
	sweepAngle As Single _
)
Public Sub DrawPie ( _
	pen As Pen, _
	rect As RectangleF, _
	startAngle As Single, _
	sweepAngle As Single _
)
Public Sub DrawPie ( _
	pen As Pen, _
	x As Integer, _
	y As Integer, _
	width As Integer, _
	height As Integer, _
	startAngle As Integer, _
	sweepAngle As Integer _
)
Public Sub DrawPie ( _
	pen As Pen, _
	x As Single, _
	y As Single, _
	width As Single, _
	height As Single, _
	startAngle As Single, _
	sweepAngle As Single _
)

A pie is based on an ellipse (like an arc). The ellipse would fit in a rectangle passed as the rect argument. The rectangle can also be specified by its location (x, y) and its dimensions (width and height).

Inside of the parent rectangle in which an ellipse would be drawn, you set a starting angle. This angle is measured from 0 up counted clockwise (like the numbers of an analog clock). This means that an angle of 90 represents 6 o'clock and not 12 o'clock. This starting angle is passed as the startAngle argument.

After specifying the starting angle, you must specify the amount of angle covered by the pie. This also is measured clockwise. This value is passed as the sweepAngle argument.

Here is an example:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Red)
            e.Graphics.DrawPie(penCurrent, 20, 20, 200, 100, 45, 255)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

This would produce:

Pie

Practical LearningPractical Learning: Drawing an Ellipse

  1. Start Microsoft Visual Basic and create a new Windows Application named SchoolEnrolment1
  2. Design the form as follows:
     
    School Enrolment
    Control Name Text
    Label Label   Enrolment / Program ___________________________
    Label Label   Graduates
    Label Label   Undergraduates
    Label Label   Certificates
    TextBox TextBox txtGraduates 0
    TextBox TextBox txtUndergraduates 0
    TextBox TextBox txtCertificates 0
    Button Button btnCreateChart Create Chart
    PictureBox PictureBox pbxChart  
    Label Label   ____Legend____
    Label Label lblGraduates Graduates
    Label Label lblUndergraduates Undergraduates
    Label Label lblCertificates Certificates
    Button Button btnClose Close
  3. Right-click the form and click View Code
  4. Declare three variables as follows:
     
    Public Class Form1
        Private Graduates As Single
        Private Undergraduates As Single
        Private Certificates As Single
    End Class
  5. In the Class Name combo box, select (Form1 Events)
  6. In the Method Name combo box, select Paint and implement the event as follows:
     
    pbxChart.CreateGraphics().DrawEllipse(New Pen(Color.Red), _
                                  New Rectangle(0, 0, 260, 200))
            pbxChart.CreateGraphics().DrawPie(New Pen(Color.Blue), _
                                      0.0F, 0.0F, 260.0F, 200.0F, _
    				0.0F, Graduates)
            pbxChart.CreateGraphics().DrawPie(New Pen(Color.Green), _
                                      0.0F, 0.0F, 260.0F, 200.0F, _
    				Graduates, Undergraduates)
            pbxChart.CreateGraphics().DrawPie(New Pen(Color.Fuchsia), _
                                      0.0F, 0.0F, 260.0F, 200.0F, _
    				Graduates + Undergraduates, Certificates)
    
            e.Graphics.DrawEllipse(New Pen(Color.Blue), _
                                  New Rectangle(lblGraduates.Left, _
                                lblGraduates.Top + 20, _
                        lblUndergraduates.Width, 20))
    
            e.Graphics.DrawEllipse(New Pen(Color.Green), _
                                  New Rectangle(lblUndergraduates.Left, _
                                lblUndergraduates.Top + 20, _
                        lblUndergraduates.Width, 20))
    
            e.Graphics.DrawEllipse(New Pen(Color.Fuchsia), _
                                  New Rectangle(lblCertificates.Left, _
                                lblCertificates.Top + 20, _
                        lblUndergraduates.Width, 20))
    End Sub
  7. In the Class Name combo box, select pbxChart
  8. In the Method Name combo box, select Paint and implement its event as follows:
     
    Private Sub pbxChart_Paint(ByVal sender As Object, _
                        ByVal e As System.Windows.Forms.PaintEventArgs) _
                                   Handles pbxChart.Paint
            Invalidate()
    End Sub
  9. In the Class Name combo box, select pbxCreateChart
  10. In the Method Name combo box, select Click and implement the event as follows:
     
    Private Sub btnCreateChart_Click(ByVal sender As Object, _
                                         ByVal e As System.EventArgs) _
                                         Handles btnCreateChart.Click
            Dim Grad As Single = 0.0
            Dim Under As Single = 0.0
            Dim Cert As Single = 0.0
            Dim Total As Single = 0.0
            Dim PercentGraduates As Single
            Dim PercentUndergraduates As Single
            Dim PercentCertificates As Single
    
            Try
                Grad = CSng(txtGraduates.Text)
            Catch ex As FormatException
                MsgBox("Invalid graduate value")
            End Try
    
            Try
                Under = CSng(txtUndergraduates.Text)
            Catch
                MsgBox("Invalid graduate value")
            End Try
    
            Try
                Cert = CSng(txtCertificates.Text)
            Catch
                MsgBox("Invalid graduate value")
            End Try
    
            Total = Grad + Under + Cert
            PercentGraduates = (Grad / Total) * 100
            PercentUndergraduates = (Under / Total) * 100
            PercentCertificates = (Cert / Total) * 100
    
            Graduates = (360 * PercentGraduates) / 100
            Undergraduates = (360 * PercentUndergraduates) / 100
            Certificates = (360 * PercentCertificates) / 100
    
            pbxChart.Invalidate()
    End Sub
  11. Execute the application and test the form
     
     School Enrolment
  12. After using it, close the form

Arcs

An arc is a portion or segment of an ellipse, meaning an arc is a non-complete ellipse. While a pie is a closed shape, an arc is not: it uses only a portion of the line that defines an ellipse. Because an arc must confirm to the shape of an ellipse, it is defined as it fits in a rectangle and can be illustrated as follows:

Arc

To support arcs, the Graphics class is equipped with the DrawArc() method that is provided in four versions whose syntaxes are:

Public Sub DrawArc ( _
	pen As Pen, _
	rect As Rectangle, _
	startAngle As Single, _
	sweepAngle As Single _
)
Public Sub DrawArc ( _
	pen As Pen, _
	rect As RectangleF, _
	startAngle As Single, _
	sweepAngle As Single _
)
Public Sub DrawArc ( _
	pen As Pen, _
	x As Integer, _
	y As Integer, _
	width As Integer, _
	height As Integer, _
	startAngle As Integer, _
	sweepAngle As Integer _
)
Public Sub DrawArc ( _
	pen As Pen, _
	x As Single, _
	y As Single, _
	width As Single, _
	height As Single, _
	startAngle As Single, _
	sweepAngle As Single _
)

The ellipse that would contain the arc must be drawn in a Rectangle or a RectangleF rect. You can also define that ellipse by the coordinates of its inscribed rectangle x, y, and its dimensions width, height.  Besides the borders of the rectangle in which the arc would fit, an arc must specify its starting angle, startAngle, measured clockwise from the x-axis its starting point. An arc must also determine its sweep angle measured clockwise from the startAngle parameter to the end of the arc. These two value follow the same definitions we reviewed for the Graphics.Pie() method.

Here is an example:

Imports System.Drawing
Imports System.Windows.Forms

Module Exercise

    Public Class Starter
        Inherits Form

        Dim components As System.ComponentModel.Container

        Public Sub New()
            InitializeComponent()
        End Sub

        Public Sub InitializeComponent()

        End Sub

        Private Sub FormPaint(ByVal sender As Object, _
                              ByVal e As PaintEventArgs) _
                              Handles MyBase.Paint

            Dim penCurrent As Pen = New Pen(Color.Red)
            e.Graphics.DrawArc(penCurrent, 20, 20, 200, 150, 225, 200)

        End Sub
    End Class

    Function Main() As Integer

        Dim frmStart As Starter = New Starter

        Application.Run(frmStart)

        Return 0
    End Function

End Module

Arc

 
 

Previous Copyright © 2008-2009, yevol.com Next