That Clock Thingie I Use in Presentations, or Just Say No to Trig
A few years ago, way back when .NET was new, the VB marketing team contracted with MCW to write some samples using VB.NET to be posted on MSDN. I agreed to write one showing off GDI+, and it ended up being a little clock component that I actually use often, especially when speaking. Many folks have asked where they can get it, 'cause it's not easy to find. Here's the link where you can download the original version of this little clock utility I've been using for a few years.
Of course, not willing to leave good enough alone (to be honest, I've learned a lot about .NET since writing this first version), I've totally ripped out the guts of the thing and am currently revising it for an MSDN magazine column coming up this summer. It all started when I realized that using trigonometry to calculate the rotations involved to draw the clock and its hands was only a good idea if I was trying to prove to myself that I still understood trig after all these years. What I had missed is that the .NET Framework supports rotations, translations, and other matrix operations natively. I had originally written a ton of code that used sin, cos, and tan to figure out where to put, say, the tick marks around the edge of the clock face. When I figured out that you didn't need to do any math at all, I kicked myself. And had to rewrite the whole thing.
Try this out, if you want to see the rotation and translation possibilities in the .NET Framework. Create a Windows application (I'm using VB.NET here), and add the following code to the sample form:
Private Sub Form1_Paint( _
ByVal sender As Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles MyBase.Paint
Dim gfx As Graphics = e.Graphics
Dim center As New Point(100, 100)
Dim radius As Integer = 100
Dim pt As New Point(80, 0)
For tickDegree As Integer = 0 To 360 Step 6
' Rotate and translate the graphics region
' as necessary, then draw the tick mark
gfx.ResetTransform()
gfx.RotateTransform(tickDegree, MatrixOrder.Append)
gfx.TranslateTransform(center.X, center.Y, MatrixOrder.Append)
DrawCircle(gfx, pt, 2, Pens.Black, Brushes.Black)
Next
End Sub
Private Sub DrawCircle(ByVal gfx As Graphics, ByVal pt As Point, _
ByVal Radius As Integer, ByVal pen As Pen, _
ByVal brush As Brush)
' Center the circle around the center point,
' moving back the size of the radius in both
' x and y directions.
Dim diameter As Integer = Radius * 2
pt.Offset(-Radius, -Radius)
Dim rct As _
New Rectangle(pt.X, pt.Y, diameter, diameter)
gfx.DrawEllipse(pen, rct)
If Not brush Is Nothing Then
gfx.FillEllipse(brush, rct)
End If
End Sub
When you run the form, you'll get the idea -- 60 little circles around the edge of a larger circle. The "active ingredient" code looks like this:
gfx.ResetTransform()
gfx.RotateTransform(tickDegree, MatrixOrder.Append)
gfx.TranslateTransform(center.X, center.Y, MatrixOrder.Append)
Rather than attempting to work out exactly where on the big circle these little circles go, the code simply puts every circle at the same point (80, 0), but rotates the frame of reference the correct number of degrees, and then translates the whole mess from the upper left corner to the center of the circle. Play with the code -- I found it was pretty simple to get proficient at manipulating translations and rotations with little effort. And it's a lot easier than figuring it out on your own, using trig!