USING TRIG TO DRAW A SIN WAVE

Since my last article on the Unit Circle was such a hit I decided to continue. In this example we move from using sin and cos to calculate points on the perimeter of a circle to making a "sin" wave.


Introduction

If you watch the values of sin as the angle moves around the circle, you may spot that the values are changing rapidly at 0 and slowly at 90 degrees. That is because at Delta = 0 you are near the X axis where the value of Y is changing rapidly as the angle delta moves at a uniform rate. At Delta = 90 you are on the top of the circle where it is flat and the y value, the sin, changes slowly until it reaches the maximum at 1.

Unit Circle showing flat and steep areas.


CODING A SIN WAVE GRAPH

Lets make a graph that plots the value of the sin in the Y direction. In the X direction we will plot the angle delta. Can you guess what the graph will look like? Its going to be steep in the area around Delta = 0 and flat around Delta = 90.

You can see in this next example 2 we use the sin function to get the value of y at the angle delta. We simply plot delta along the x axis:  (x, y)  = (delta, sin(delta)) where x is delta and y is sin(delta). See the red sin wave? Note we adjusted the x values so they fit the circle. Any scale could have been used for the x axis.




        Public Class Form4

    'Using Trigonometry to draw graphic curves in VB.NET part 2, Example 2
    'draws sin wave on unit circle
    Private WithEvents timer1 As New Windows.Forms.Timer With {.Interval = 500}
    Private Delta As Single
    Private DeltaStep As Single = 15
 
    Private Sub Form4_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim Scale As Single = 4     'create a scale of 2 units across the width of the form
        Dim ScaleRatio As Single = Me.ClientRectangle.Width / Scale         'pixels/unit
        Dim r As Single = 1         'set radius to 1 for the "Unit Circle"
        Dim fntheight As Single = Scale / 25
        Dim x, y, x1, y1 As Single
 
        With e.Graphics
            Using p As New Pen(Color.LightBlue, Scale / 1000)
                Using br As New SolidBrush(Color.Black)
                    Using f As New Font("Arial", fntheight)
                        .Clear(Color.White)
                        .SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
 
                        'scale the window
                        .ScaleTransform(ScaleRatio, ScaleRatio)
                        'move the 0,0 coordinate to the center of the window
                        .TranslateTransform(Scale / 2, Scale / 2)
 
                        'draw the axes
                        For x = -Scale To Scale
                            .DrawLine(p, x, -Scale / 2, x, Scale / 2)
                            .DrawString(x.ToString, f, br, x, -Scale / 2)
                            .DrawLine(p, -Scale / 2, x, Scale / 2, x)
                            .DrawString(x.ToString, f, br, -Scale / 2, x)
                        Next
 
                        'draw the unit circle perimeter
                        p.Width = Scale / 200
                        p.Color = Color.Blue
                        Dim rectf As RectangleF = New RectangleF(-r, -r, 2 * r, 2 * r)
                        .DrawArc(p, rectf, 0, 360)
 
                        'draw the sine wave to the current delta
                        p.Color = Color.Red
                        p.Width = Scale / 150
                        p.EndCap = Drawing2D.LineCap.DiamondAnchor
                        x1 = -r
                        y1 = 0
 
                        For d = 0 To Delta Step DeltaStep
                            'calculate the y coordinate on the circle at the angle delta.
                            'Convert degress to radians for sin function
                            'use delta for the x value
                            x = (0.4 * d / ScaleRatio) - 1
                            y = r * Math.Sin(d / 57.3)
 
                            .DrawLine(p, x, y, x1, y1)
 
                            x1 = x
                            y1 = y
                        Next
 
                        'draw the radius line at the current angle set in the timer
                        p.Color = Color.Blue
                        p.Width = 0.05
                        x = r * Math.Cos(Delta / 57.3)
                        y = r * Math.Sin(Delta / 57.3)
                        .DrawLine(p, 0, 0, x, y)
 
                        'draw the values
                        x = -0.3 * Scale
                        y = -0.4 * Scale
                        .DrawString("Delta: " & Delta.ToString, f, br, x, y)
                        Dim t As String = "Cos: " & Math.Cos(Delta / 57.3).ToString("f3") & "  Sin: " & Math.Sin(Delta / 57.3).ToString("f3")
                        .DrawString(t, f, br, x, y + (2 * fntheight))
                    End Using
                End Using
            End Using
        End With
    End Sub
 
    Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
        Delta += DeltaStep
        If Delta > 360 Then Delta -= 360
        Me.Invalidate()
    End Sub
 
    Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.DoubleBuffered = True
        timer1.Start()
    End Sub
 
    Private Sub Form4_Click(sender As Object, e As EventArgs) Handles Me.Click
        timer1.Enabled = Not timer1.Enabled
    End Sub
 
    Private Sub Form4_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        Me.Invalidate()
    End Sub
End Class


Coding a Fancy SIN Wave and Unit Circle

Now in example 3 we will get fancy and put the last two examples to work. The code produces a marquee effect with text by placing the text either around a circle (similar to example 1) or along a sin wave (similar to example 2).

In the sin wave example we just place the text at the y values calculated with the sin function y = sin(Delta). The X axis of the graph shows the Delta angle.

However, in the circle marquee we add the step of rotating the text around the circle. In this case, to rotate the text we simply use the value of the delta angle for the text rotation angle. Then we calculate the (x, y) point on the circle where the text is placed using our favorite sin and cos functions.



Example 3: drawing text as Circle or Wave (cick for animation).

Public Class DrawTextMarquee
    'Using Trigonometry to draw graphic curves in VB.NET part 2, Example 3
    'draws marquee style text animation - wave, circle
    Private WithEvents Timer1 As New System.Windows.Forms.Timer With {.Interval = 30}
 
    Private Sub DrawTextMarquee_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.BackgroundImageLayout = ImageLayout.None
        Me.DoubleBuffered = True
        RadioButton1.Checked = True
        Timer1.Start()
    End Sub
 
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim theText As String = "Fancy Marquee"
        Dim y2, x2 As Single
        Static x1 As Integer = -(theText.Length * 15 + 20)
        x1 += 3
        If x1 > Me.ClientSize.Width Then x1 = -(theText.Length * 15 + 20)
 
        Static delta As Single
        delta += 2
        If delta > 359 Then delta = 0
 
        'draw the scene on a the memory bitmap and copy to the form background
        Using bmp As Bitmap = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
            Using g As Graphics = Graphics.FromImage(bmp)
                With g
                    .Clear(Color.Black)
                    .TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
 
                    For i = 1 To theText.Length
                        If RadioButton1.Checked Then
                            'wave
                            x2 = x1 + (i * 24)
                            y2 = 65 + (20 * Math.Cos(x2 / 26))
                            g.DrawString(Mid(theText, i, 1), New Font("Arial", 18), Brushes.Red, x2, y2)
                        Else
                            'circle
                            Dim r As Single = 100
                            Dim d As Single = delta + (i * 16)
                            x2 = (r * Math.Cos(d / 57.3)) + (Me.ClientSize.Width / 2)
                            y2 = (r * Math.Sin(d / 57.3)) + (Me.ClientSize.Height / 2)
                            .ResetTransform()
                            .TranslateTransform(x2, y2)
                            .RotateTransform(d + 100)
                            .TranslateTransform(-x2, -y2)
                            .DrawString(Mid(theText, i, 1), New Font("Arial", 18), Brushes.Red, x2, y2)
                        End If
                    Next
                    Me.BackgroundImage = bmp.Clone
                    Me.Invalidate()
                End With
            End Using
        End Using
    End Sub
End Class