<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>IRhetoric - Karsten Januszewski   : Flash</title><link>http://blogs.msdn.com/karstenj/archive/tags/Flash/default.aspx</link><description>Tags: Flash</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Inspired By Flash Math Creativity #2: WPF Planets</title><link>http://blogs.msdn.com/karstenj/archive/2007/02/23/inspired-by-flash-math-creativity-2-wpf-planets.aspx</link><pubDate>Sat, 24 Feb 2007 00:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1749785</guid><dc:creator>karstenj</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/karstenj/comments/1749785.aspx</comments><wfw:commentRss>http://blogs.msdn.com/karstenj/commentrss.aspx?PostID=1749785</wfw:commentRss><description>&lt;P&gt;My next inspiration from the algorithms introduced in &lt;A target=_blank href="http://www.friendsofed.com/fmc/FMCv2/FMC.html" mce_href="http://www.friendsofed.com/fmc/FMCv2/FMC.html"&gt;Flash Math Creativity&lt;/A&gt;&amp;nbsp;was based on the work of &lt;A target=_blank href="http://www.nooflat.nu/" mce_href="http://www.nooflat.nu/"&gt;Jamie MacDonald&lt;/A&gt;. In looking at his work,&amp;nbsp; I quickly realized that I was going to need to brush up on my trigonometry skills. This led me to another great Friend of Ed book, &lt;A target=_blank href="http://www.friendsofed.com/book.html?isbn=1590595181" mce_href="http://www.friendsofed.com/book.html?isbn=1590595181"&gt;Foundation ActionScript Animation: Making Things Move&lt;/A&gt;, which has some great trigonometry for animation explanations.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;You can see the&amp;nbsp;results of my latest experiment &lt;A target=_blank href="http://rhizohm.net/download/netfx3/apps/planets.xbap" mce_href="http://rhizohm.net/download/netfx3/apps/planets.xbap"&gt;here&lt;/A&gt; and the code is &lt;A href="http://rhizohm.net/download/netfx3/planets/planets.zip" mce_href="http://rhizohm.net/download/netfx3/planets/planets.zip"&gt;here&lt;/A&gt;. Just to make sure I was up an running with basic trig, I created a sine wave in 01 as follows:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://wpf.netfx3.com/direct/planets"&gt;&lt;IMG style="MARGIN: 0px 10px 10px" border=0 align=left src="http://rhizohm.net/download/netfx3/p1.jpg"&gt;&lt;/A&gt;double x = 0;&lt;BR&gt;double y = 0;&lt;BR&gt;double angle = 0;&lt;BR&gt;for (int i = 0; i &amp;lt; 500; i++)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; x += 1;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; y = 200 + Math.Sin(angle) * 50;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Ellipse el = new Ellipse();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; el.Width = 2;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; el.Height = 2;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; el.Fill = Brushes.Red;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Canvas.SetLeft(el, x);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Canvas.SetTop(el, y);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; stage.Children.Add(el);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; angle += .05;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;Nothing fancy here.&amp;nbsp; To make a circle, I changed the x to be x = Math.Cos(angle) * 50.&amp;nbsp; This is the basis for doing circle and ellipse animations.&amp;nbsp; Now, instead of trying to do animations using &lt;STRONG&gt;CompositionTarget.Rendering&lt;/STRONG&gt;, I remembered that the SDK has a great sample called &lt;A target=_blank href="http://msdn2.microsoft.com/en-us/library/ms771715.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms771715.aspx"&gt;CustomAnimations&lt;/A&gt;, in which a CircleAnimation exists already using this formula.&amp;nbsp; Here's the key code where it overrides&amp;nbsp;the &lt;STRONG&gt;GetCurrentValueCore&lt;/STRONG&gt; method to create the circle effect using basic trig:&lt;/P&gt;
&lt;P&gt;protected override double GetCurrentValueCore(double defaultOriginValue, double defaultDestinationValue, AnimationClock clock)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double returnValue;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; double time = clock.CurrentProgress.Value;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // math magic: calculate new coordinates using polar coordinate equations. This requires two &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // animations to be wired up in order to move in a circle, since we don't make any assumptions&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // about what we're animating (e.g. a TranslateTransform). &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (Direction == DirectionEnum.XDirection)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; returnValue = Math.Cos(2 * Math.PI * time);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; returnValue = Math.Sin(2 * Math.PI * time);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Need to add the defaultOriginValue so that composition works.&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return returnValue * Radius + defaultOriginValue;&lt;BR&gt;}&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;At first, I used this in code to create the effect of these circles circling toward you using BeginAnimation, based on the TowardUs sample in the Flash Math Creativity book (the very first sample):&lt;/P&gt;
&lt;P&gt;&lt;A href="http://wpf.netfx3.com/direct/planets"&gt;&lt;IMG style="MARGIN: 0px 10px 10px" border=0 align=right src="http://rhizohm.net/download/netfx3/p2.jpg"&gt;&lt;/A&gt;CircleAnimation cx = new CircleAnimation();&lt;BR&gt;cx.Duration = new Duration(TimeSpan.FromSeconds(1.5));&lt;BR&gt;cx.Direction = CircleAnimation.DirectionEnum.XDirection;&lt;BR&gt;cx.Radius = 150;&lt;BR&gt;cx.RepeatBehavior = RepeatBehavior.Forever;&lt;/P&gt;
&lt;P&gt;CircleAnimation cy = new CircleAnimation();&lt;BR&gt;cy.Duration = new Duration(TimeSpan.FromSeconds(1.5));&lt;BR&gt;cy.Direction = CircleAnimation.DirectionEnum.YDirection;&lt;BR&gt;cy.Radius = 150;&lt;BR&gt;cy.RepeatBehavior = RepeatBehavior.Forever;&lt;/P&gt;
&lt;P&gt;stage.Children.Add(el);&lt;BR&gt;el.BeginAnimation(Ellipse.OpacityProperty, opacityAnimation);&lt;BR&gt;st.BeginAnimation(ScaleTransform.ScaleXProperty, d);&lt;BR&gt;st.BeginAnimation(ScaleTransform.ScaleYProperty, d);&lt;BR&gt;tt.BeginAnimation(TranslateTransform.XProperty, cx);&lt;BR&gt;tt.BeginAnimation(TranslateTransform.YProperty, cy);&lt;/P&gt;
&lt;P&gt;This resulted in 03.&amp;nbsp; It worked, but the code started getting ugly as far as getting each circle to fire when I wanted it to.&amp;nbsp; I found myself using a timer&amp;nbsp;and wiring up an anonymous delegate.&amp;nbsp;I realized &lt;STRONG&gt;Storyboards&lt;/STRONG&gt; and &lt;STRONG&gt;ParallelTimelines&lt;/STRONG&gt; would serve me much better, which are much easier to wire up in XAML than in code.&amp;nbsp; So,&amp;nbsp; 04 is the same thing, but a XAML solution instead:&lt;/P&gt;
&lt;P&gt;&amp;lt;ParallelTimeline BeginTime="0:0:0"&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DoubleAnimation&amp;nbsp; Duration="0:0:1.5" To="25" Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DoubleAnimation Duration="0:0:1.5"&amp;nbsp; To="25" Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DoubleAnimation Duration="0:0:1.5" From="1"&amp;nbsp; To="0" Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(UIElement.Opacity)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;CustomAnimations:CircleAnimation Duration="0:0:1.5" Radius="150" Direction="YDirection" Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;CustomAnimations:CircleAnimation Duration="0:0:1.5" Radius="150" Direction="XDirection" Storyboard.TargetName="ellipse0" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"/&amp;gt;&lt;BR&gt;&amp;lt;/ParallelTimeline&amp;gt;&lt;/P&gt;
&lt;P&gt;By using parallel timelines I could structure my animations and when they fired. &lt;/P&gt;
&lt;P&gt;A nice thing about this CustomAnimation is that it can be applied to 3D animations as well, applied to the &lt;STRONG&gt;TranslateTransform3D&lt;/STRONG&gt; which I did 05, changing the &lt;STRONG&gt;Radius&lt;/STRONG&gt; property to be much smaller to fit the coordinates I was using for my ViewPort.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://wpf.netfx3.com/direct/planets"&gt;&lt;IMG style="MARGIN: 0px 10px 10px" border=0 align=left src="http://rhizohm.net/download/netfx3/p3.jpg"&gt;&lt;/A&gt;void towardus3d_Loaded(object sender, RoutedEventArgs e)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sphere = new GeometryModel3D(sphereFactory.Mesh, materialGreen);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ModelVisual3D mv3d = myViewPort3D.Children[1] as ModelVisual3D;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; mv3d.Content = sphere;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CircleAnimation ca3d_y = new CircleAnimation();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_y.Duration = TimeSpan.FromSeconds(5);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_y.RepeatBehavior = RepeatBehavior.Forever;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_y.Radius = .5;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_y.Direction = CircleAnimation.DirectionEnum.YDirection;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; CircleAnimation ca3d_x = new CircleAnimation();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_x.Duration = TimeSpan.FromSeconds(5);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_x.RepeatBehavior = RepeatBehavior.Forever;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_x.Radius = .5;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ca3d_x.Direction = CircleAnimation.DirectionEnum.XDirection;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ModelTranslate.BeginAnimation(TranslateTransform3D.OffsetYProperty, ca3d_y);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ModelTranslate.BeginAnimation(TranslateTransform3D.OffsetXProperty, ca3d_x);&lt;BR&gt;}&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;It then dawned on me, as I looked at 05, an orbiting sphere, that it&amp;nbsp;would make for great planets.&amp;nbsp;&amp;nbsp;I went out to &lt;A target=_blank href="http://maps.jpl.nasa.gov/jupiter.html" mce_href="http://maps.jpl.nasa.gov/jupiter.html"&gt;NASA&lt;/A&gt; and found the texture&amp;nbsp;maps for Jupiter and its moons.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;I also wanted to do all of this 3D work in XAML, so I made a class called &lt;STRONG&gt;SphereModelVisual3D&lt;/STRONG&gt; that I could instantiate Jupiter, for example, like this:&lt;/P&gt;
&lt;P&gt;&lt;A href="http://wpf.netfx3.com/direct/planets"&gt;&lt;IMG style="MARGIN: 0px 10px 10px" border=0 align=right src="http://rhizohm.net/download/netfx3/p4.jpg"&gt;&lt;/A&gt;&amp;lt;mv3d:SphereModelVisual3D x:Name="Jupiter" &amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;mv3d:SphereModelVisual3D.Material&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;DiffuseMaterial&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;DiffuseMaterial.Brush &amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ImageBrush ImageSource="&lt;A href="http://maps.jpl.nasa.gov/pix/jup0vss1.jpg%22/"&gt;http://maps.jpl.nasa.gov/pix/jup0vss1.jpg%22/&lt;/A&gt;&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/DiffuseMaterial&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;/mv3d:SphereModelVisual3D.Material&amp;gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;mv3d:SphereModelVisual3D.Transform&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Transform3DGroup &amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;ScaleTransform3D ScaleX="2" ScaleY="2"&amp;nbsp; ScaleZ="2" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;RotateTransform3D&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;AxisAngleRotation3D Angle="0" Axis="0 1 0" x:Name="Jupiter_rotation"&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/RotateTransform3D&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;TranslateTransform3D OffsetX="0" OffsetY="0" OffsetZ="0" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/Transform3DGroup&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;/mv3d:SphereModelVisual3D.Transform&amp;gt;&lt;BR&gt;&amp;lt;/mv3d:SphereModelVisual3D&amp;gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The animation that handles the elliptical orbits needs to transform the Z property the TranslateTransform3D.&amp;nbsp; It then looks like this:&lt;/P&gt;
&lt;P&gt;&amp;lt;ParallelTimeline RepeatBehavior="Forever"&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DoubleAnimation Duration="0:0:10"&amp;nbsp; To="360"&amp;nbsp; Storyboard.TargetName="Jupiter_rotation" Storyboard.TargetProperty="Angle"/&amp;gt;&lt;BR&gt;&amp;lt;/ParallelTimeline&amp;gt;&lt;BR&gt;&amp;lt;ParallelTimeline RepeatBehavior="Forever"&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;CustomAnimations:CircleAnimation Duration="0:0:2"&amp;nbsp; Radius="9" Direction="YDirection" Storyboard.TargetName="Io" Storyboard.TargetProperty="(ModelVisual3D.Transform).(Transform3DGroup.Children)[2].(TranslateTransform3D.OffsetZ)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;CustomAnimations:CircleAnimation Duration="0:0:2"&amp;nbsp; Radius="2" Direction="XDirection" Storyboard.TargetName="Io" Storyboard.TargetProperty="(ModelVisual3D.Transform).(Transform3DGroup.Children)[2].(TranslateTransform3D.OffsetX)"/&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DoubleAnimation Duration="0:0:2"&amp;nbsp; To="360"&amp;nbsp; Storyboard.TargetName="Io_rotation" Storyboard.TargetProperty="Angle"/&amp;gt;&lt;BR&gt;&amp;lt;/ParallelTimeline&amp;gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The result is in 06. It is not astronomically correct as far as scale&amp;nbsp;-- I'll leave that for someone with some more time on their hands, but I liked the end result.&amp;nbsp; I also threw in the TrackBall control from the &lt;A target=_blank href="http://www.codeplex.com/3DTools" mce_href="http://www.codeplex.com/3DTools"&gt;3d tools project&lt;/A&gt; so you can trackball the whole model. &lt;/P&gt;
&lt;P mce_keep="true"&gt;The code is &lt;A href="http://wpf.netfx3.com/direct/planets/planets.zip" mce_href="http://wpf.netfx3.com/direct/planets/planets.zip"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1749785" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/karstenj/archive/tags/Windows+Presentation+Foundation+_2800_Avalon_2900_/default.aspx">Windows Presentation Foundation (Avalon)</category><category domain="http://blogs.msdn.com/karstenj/archive/tags/3D/default.aspx">3D</category><category domain="http://blogs.msdn.com/karstenj/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/karstenj/archive/tags/Avalon/default.aspx">Avalon</category><category domain="http://blogs.msdn.com/karstenj/archive/tags/Flash/default.aspx">Flash</category></item></channel></rss>