Exploring the Microsoft Client Continuum

Trigonometry

Let's build upon the techniques we learned in the Color, Scale & Rotation Lesson and make a more robust Silverlight interface using trigonometry. The good news is that once you get down to the Math, the code techniques for trigonometry are almost identical in ActionScript and Silverlight so we can forgo the Flash example. The bad news is that not too many Flash designers feel very comfortable with the Math to begin with! But with a little investment and creativity, you can create some really interesting results you couldn't practically create any other way.

A Quick Refresher

We'll start off easy enough with a typical Page.xaml and User Control Dot.xaml. Page.xaml has a Loaded event handler setup and and empty canvas called which will contain our Dot User Controls we add in code. All the typical modifications have been made and I've also added some Ellipses to form the outline of the circle we will be dealing with as well. The files look like this:

Dot.xaml doesn't need a Loaded handler for this project, but we do add the standard X and Y properties to its code behind file Dot.xaml.cs to make positioning easier.

This is the first step we will create:

Get Microsoft Silverlight

And here is the code that gets us to this first stage:

Lines 27 - 30 create a stationary Dot and place it where our origin is. Lines 32 - 38 add a second Dot and names it follow. We then add a mouseMove handler (Line 40) which stores the cursor location in our mouse object we introduced last lesson. Every time this event is fired, it also calls setAngle(), which does all the trigonometry.

Lines 52 and 53 calculate the distance from the origin to the current mouse location. As in Flash, we invert the _y distance since Flash and Silverlight both move down the page as the y value gets bigger. Line 54 then uses these values to calculate the angle to the mouse. Since the angle is returned in the range of -180 to +180 (as in Flash), we adjust the range to push the negative values up to a more acceptable range (Line 54). Once we have the angle figured out and since we defined the radius as 100 (Line 21), we can calculate where on the screen follow should be placed by using Math.Cos() and Math.Sin(), just as we would in Flash. Also as in Flash, Cos() and Sin() expect their parameters to be in radians, not degrees, so we multiply by Math.PI/180 to do this conversion on the fly.

Fixing a Common Error with Easing Rotations

Many examples tend to stop at the above code, but there is a common error that enters in both Flash and Silverlight when you try and procedurally animate the calculated angle with a standard easing equation. Lets beef up this example to see it happen. Then we'll look at the solution.

We're going to add an animated tail to our follow to see the easing effect and where things start going wrong. First, let's add the following code to Dot.xaml.cs to have it gradually fade out and remove itself when the fade() function at Line 33 is called:

Next, we make the following changes to Page.xaml.cs to have a Dot object named tween follow the mouse and also leave behind a visual tail of where its been. Here is the code:

Here is what we get:

Get Microsoft Silverlight

If you play around with it, you'll start to notice that is doesn't ease effectively when easing between certain angles that cross the 0 degree line to the right. you may recall that we had tried to adjust negative angles in Line 75, but this still isn't enough. If you remove that line the problem is still there, only now it's more evident on the left side of the circle (180 degrees) instead of the right (0 degrees).

Fortunately, we can fix this by testing a couple values in setAngle(). The finished code looks like this:

And behaves properly like this:

Get Microsoft Silverlight

Trigonometry and 3D

Sin() and Cos() are also used for rotating objects in 3D space as well as 2D space. While a detailed analysis of this would be beyond the scope of this tutorial, I think it would be pretty cool to share a more robust 3D Silverlight application and give you pointers to work through the code.

Here is the application we'll be discussing. Use the mouse to spin the interface:

Get Microsoft Silverlight

Node.xaml is the user control that we are adding to the screen above and it has a RenderTransform that controls its Scale and Rotation. It also has a TextBlock named display that shows the text and a bkg Rectangle that serves as the background visual. Node.xaml.cs looks like this:

Each node will have a reference to its perspective_ratio (Line 26). The variable is used to calculate its Scale and Opacity during the 3D rotation calculation. Lines 27 - 29 store references to where the node's virtual position in 3D space should be. Line 30 stores a reference to the curve User Control that is used to connect each node to the location of the origin in Page.xaml.

The curve User Control is an old school Flash hack for these types of things*. In Flash, you can create a MovieClip with the registration point in the upper left corner (0,0) and draw any type of straight or curved line, as long as it ends at (100,100). This 100 x 100 MovieClip can then be set as a visual connector between any two points on your Stage by setting the _x and _y of the MovieClip at one of the points and then scaling it by the distance to the second point.

To draw the curved line in Silverlight, though, I opened curve.xaml in Expression Blend and used the Pen tool to draw a curved Path. Here is the result of the modifications:

Since each curve will be tightly coupled to the node that it points to, it doesn't need to have any 3D variables in its code behind file, only the same X and Y property we created for all of our User Controls. Its visual Width and Height will be implicitly set by referencing the ScaleTransform named scale on Line 11.

Page.xaml has a few public variables defined which we will use through out the animation logic:

With these variables defined along with the two user controls we already built, node.xaml and curve.xaml, we can add the visual elements to our Page.xaml in a setupNodes() function like this:

For each node we want to add, we also create a curve (Line 73) that will visually connect it to the origin and tie each curve to each node in Line 81. Although SIN and COS will come into play when we start rotating these nodes in our Storyboard loop, they appear here as well in Line 84 and Line 85 to create a curved path along which the nodes may be positioned in 3D space. Line 87 through Line 90 are used to center the display text and size the background for each node.xaml accordingly.

To control the dragging behavior of the interface, we've added a MouseLeftButtonDown(), MouseMove() and MouseLeftButtonUp() event as well as hooking up a Storyboard named sb to control the animation.

The actual 3D rendering happens in the Storyboard's Completed() event. It is rather lengthy, since all of the 3D rendering occurs here. This is what the whole function loops like:

Line 113 to Line 130 eases a virtual point named follow around the stage when you drag the mouse. Based on the distance between follow and mouse, we set the x_axis_rotation and y_axis_rotation accordingly. When the user stops dragging the mouse, follow slows down until it stops. This lets the user spin the 3D interface by throwing it as well.

Line 134 through Line 168 is the math that you can use on any project to rotate elements in 3D**. If the rest of your project has been setup with similar user controls and properties, this chunk of code should always work by simply tweaking the right variables.

Line 169 through Line 171 is where we modify each curve object to draw a dotted line from the origin to where the updated screen position of its node is, completing the illusion of tethered nodes in 3D space.

While this last project is a bit longer than previous lessons, it does cover most of the techniques we've introduced so far. There is, though, one more technique that no coverage of Flash to Silverlight lessons would be complete without. We'll explore this one last invaluable technique next.

Additional Resources

*I recall seeing this curved line trick years ago in New Masters of Flash: The 2002 Annual. The chapter where this was used was written by Marc Stricklin for brittle-bones.com. Unfortunately, brittle-bones.com is not online anymore though I'm sure the DVD that comes with the book has a copy of the technique. I've been grateful for this great time saver ever since!

New Masters of Flash: The 2002 Annual on Amazon.com.

**If we're going to talk about great 3D examples and code for interactive designers, the book Flash Math Creativy has been an instant classic since it was first published and has several many wonderful examples to study:

Flash Math Creativity: Second Edition published by Friends of Ed.

Andries Odendaal wrote a great chapter on 3D in the first New Masters of Flash and his discusson of 3D rotation is a great primer. He also used the 100x100 MovieClip trick in his demo as well!

New Masters of Flash on Amazon.com.

Have a question or comment on this article? Have a suggestion for new content?
Send your feedback.
Microsoft Communities