Trigonometry and .NET

Introduction

Hello, and welcome to today’s installment of my math-related articles that I have been doing for the past few months. As you know, I have become a math nerd by chance and haven’t had formal training. Yes, I did math in school, but let’s not talk about that today!

Trigonometry

The word trigonometry originates from the Greek trigōnon (“triangle”) and metron (“measure”). Trigonometry is a branch of mathematics that studies relationships involving lengths and angles of triangles.

Trigonometric Functions

The most familiar trigonometric functions are as follows:

  • sine: The sine of an angle is the ratio of the length of the opposite side to the length of the hypotenuse
  • cosine: The cosine of an angle is the ratio of the length of the adjacent side to the length of the hypotenuse
  • tangent: The tangent of an angle is the ratio of the length of the opposite side to the length of the adjacent side
  • cotangent: The cotangent of an angle is the reciprocal of its tangent (the ratio of the length of the adjacent side to the length of the opposite side)
  • secant: The secant of an angle is the reciprocal of its cosine (the ratio of the length of the hypotenuse to the length of the adjacent side)
  • cosecant: The cosecant of an angle is the reciprocal of its sine (the ratio of the length of the hypotenuse to the length of the opposite side)

Stop me before I get into formulas…

Our Project

Today’s project will demonstrate the three more popular trigonometric functions (sine, cosine, tangent) to draw circles and waves. Hopefully, in a follow-up article, I can delve deeper into the cotangent, secant, and cosecant functions.

Start Visual Studio and create either a C# or Visual Basic Windows Forms project.

Once the project has loaded, design your form as shown in Figure 1. Make sure of the following at design time:

  • Your PictureBox is quite big
  • Your PictureBox is Docked completely
  • Your PictureBox has a background color
  • You have a Timer
  • The Timer is Enabled
  • The Timer’s Interval is set to a relatively small number
  • You have two buttons: one labeled ‘Circle’ and the other labeled ‘Wave’
  • You keep in mind that my object names might differ from yours

Design
Figure 1: Design

Code

Add two Boolean fields to keep track of which button was clicked.

C#

   bool Wave;
   bool Circle;

   float Delta = 0;
   int X = 0;

VB.NET

   Dim Wave As Boolean
   Dim Circle As Boolean

Add the code for the buttons:

C#

   private void btnWaveMarquee_Click(object sender, EventArgs e)
   {
      Wave = true;
      Circle = false;

   }

   private void btnCircleMarquee_Click(object sender, EventArgs e)
   {
      Circle = true;
      Wave = false;

   }

VB.NET

   Private Sub btnWaveMarquee_Click(sender As Object, e As _
         EventArgs) Handles btnWaveMarquee.Click

      Wave = True
      Circle = False

   End Sub

   Private Sub btnCircleMarquee_Click(sender As Object, e As _
         EventArgs) Handles btnCircleMarquee.Click

      Circle = True
      Wave = False

   End Sub

In each button, you set the corresponding flag to True. This is so that we can make use of a simple If statement inside the Timer’s Tick event to draw the correct effect.

Add the Timer’s code:

C#

   private void tmrTime_Tick(object sender, EventArgs e)
   {

      string strMarquee = "I love Trig!";

      double Xx;
      double Yy;


      X = -(strMarquee.Length * 20 + 25);

      X += 3;

      if (X > ClientSize.Width)
         X = -(strMarquee.Length * 20 + 25);

         Delta += 2;
         if (Delta > picCanvas.Width)
            Delta = 0;

         using (Bitmap bmpMarquee = new
            Bitmap(this.ClientSize.Width, this.ClientSize.Height))
         {
            using (Graphics g = Graphics.FromImage(bmpMarquee))
            {
               {
                  var withBlock = g;
                  withBlock.Clear(Color.Black);
                  withBlock.TextRenderingHint =
                     System.Drawing.Text.TextRenderingHint
                     .AntiAlias;

                  for (var i = 1; i <= strMarquee.Length; i++)
                  {
                     if (Wave)
                     {
                        Xx = X + (i * 27);
                        Yy = 75 + (float)(20 * Math.Cos(Xx /
                           (double)29));
                        g.DrawString(strMarquee.Substring(1, i),
                           new Font("Tahoma", 20), Brushes.Green,
                           (float)Xx, (float)Yy);
                     }
                     else if (Circle)
                     {
                        float Radius = 100;
                        float d = Delta + (i * 19);

                        Xx = (Radius * Math.Cos(d / 71.23)) +
                           (this.ClientSize.Width / (double)2);
                        Yy = (Radius * Math.Sin(d / 71.23)) +
                           (this.ClientSize.Height / (double)2);

                        withBlock.ResetTransform();
                        withBlock.TranslateTransform((float)Xx,
                           (float)Yy);
                        withBlock.RotateTransform(d + 100);
                        withBlock.TranslateTransform((float)-Xx,
                           (float)-Yy);

                        withBlock.DrawString(strMarquee
                           .Substring(1, i),
                           new Font("Tahoma", 20), Brushes.Blue,
                           (float)Xx, (float)Yy);
                     }
                  }

                  picCanvas.Image = (Image)bmpMarquee.Clone();

                  picCanvas.Invalidate();
               }
            }
         }

   }

VB.NET

   Private Sub tmrTime_Tick(sender As Object, e As EventArgs) _
         Handles tmrTime.Tick

      Dim strMarquee As String = "I love Trig!"

      Dim Xx As Single
      Dim Yy As Single

      Static X As Integer = -(strMarquee.Length * 20 + 25)
      Static Delta As Single

      X += 3

      If X > ClientSize.Width Then X = -(strMarquee.Length * _
         20 + 25)

      Delta += 2
      If Delta > picCanvas.Width Then Delta = 0

      Using bmpMarquee As Bitmap = New _
         Bitmap(Me.ClientSize.Width, _
         Me.ClientSize.Height)

         Using g As Graphics = Graphics.FromImage(bmpMarquee)

            With g

               .Clear(Color.Black)
               .TextRenderingHint = _
                  Drawing.Text.TextRenderingHint.AntiAlias

               For i = 1 To strMarquee.Length

                  If Wave Then

                     Xx = X + (i * 27)
                     Yy = 75 + (20 * Math.Cos(Xx / 29))
                     g.DrawString(Mid(strMarquee, i, 1), New _
                        Font("Tahoma", 20), Brushes.Green, Xx, Yy)

                  ElseIf Circle Then

                     Dim Radius As Single = 100
                     Dim d As Single = Delta + (i * 19)

                     Xx = (Radius * Math.Cos(d / 71.23)) + _
                        (Me.ClientSize.Width / 2)
                     Yy = (Radius * Math.Sin(d / 71.23)) + _
                        (Me.ClientSize.Height / 2)

                     .ResetTransform()
                    .TranslateTransform(Xx, Yy)
                    .RotateTransform(d + 100)
                    .TranslateTransform(-Xx, -Yy)

                    .DrawString(Mid(strMarquee, i, 1), New _
                       Font("Tahoma", 20), Brushes.Blue, Xx, Yy)

                  End If

               Next

               picCanvas.Image = bmpMarquee.Clone

               picCanvas.Invalidate()

            End With

         End Using

      End Using

   End Sub

First, you need the width of the canvas. The canvas in this case is obviously the PictureBox. You then create an in-memory graphics object with which to draw. Making use of the in-memory graphics object, you create a string with the font style and color and text to draw, depending on which button was clicked.

After all the objects are set up, you make use of the Cos and Sin methods inside the System.Math namespace to draw the string you created earlier in the Wave form or in Circle form. Because the calculations happen inside the Timer’s Tick event, the string continuously loops according to the desired shape.

Figures 2 and 3 show the results.

Circle
Figure 2: Circle

Wave
Figure 3: Wave

Conclusion

In today’s article, you have learned about trigonometry in general as well as how to make use of the sine, cosine, and tangent functions to create funky, loopy text. I hope you have enjoyed this article. Hopefully, in another installment, I can speak about cotangent, secant, and cosecant functions. Until then, happy coding!

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read