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:
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:
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:
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:
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.