Home | Course Index | << Prev | PDF Version of this Page |
Course 2D_SL: 2D-Computer Graphics with Silverlight
|
||
Let me know what you think |
Preliminaries Page.XAML Page.xaml.cs |
Install 1) Visual Web Developer 2010 Express Edition English
and 2) Silverlight 4 Tools for Visual Studio 2010.
Guidance for Visual Web Developer 2010 Express: |
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="Bezier1.Page" Width="400" Height="220"> <UserControl.Resources> <Storyboard x:Name="Storyboard1" Completed="Storyboard1_Completed"/> </UserControl.Resources> <Border BorderBrush="Black" BorderThickness="2"> <StackPanel Orientation="Vertical"> <Canvas x:Name="canvas" Background="Cornsilk" Height="190"> <Path Margin="0,50,0,0" Stroke="Green" StrokeThickness="5" StrokeStartLineCap="Round" x:Name="curve_path" Loaded="curve_path_Loaded"> <Path.Data> <PathGeometry> <PathFigure StartPoint =" 140, 0" x:Name="snake"> <BezierSegment Point1=" 170, 0" Point2=" 170, 20" Point3=" 140, 5"/> <BezierSegment Point1=" 110,-30" Point2=" 100,120" Point3=" 75,30"/> <BezierSegment Point1=" 62,-20" Point2=" 50, 70" Point3=" 30,55"/> <BezierSegment Point1=" 10, 30" Point2=" 5, 60" Point3=" 0,50"/> </PathFigure> </PathGeometry> </Path.Data> </Path> <Path Margin="0,50,0,0" Stroke="Red" StrokeThickness="5" x:Name="dotted_path" Loaded="dotted_path_Loaded"> <Path.Data><PathGeometry/></Path.Data> </Path> </Canvas> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button Content="Start" Click="start_Button_Click"/> <Button Content="Step" Click="step_Button_Click"/> <TextBlock Text="Velocity: " VerticalAlignment="Center" Margin="20,0,0,0"/> <Slider x:Name="velocity_slider" Width="80" Margin="0,0,20,0" Minimum="1" Maximum="500" IsDirectionReversed="True" Value="75" ValueChanged="on_velocity_slider_value_changed"/> <CheckBox x:Name="show_bezier_points" VerticalAlignment="Center" Content="Show Bezier Points" Checked ="show_bezier_points_Checked" Unchecked="show_bezier_points_Unchecked"/> </StackPanel> </StackPanel> </Border> </UserControl>
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Animation; namespace Bezier1 { public partial class Page : UserControl { private Point[] p; //each point of the snake needs its displacement at each key time //no. of points = StartPoint + (no. of segments) * (3 BezierPoints) //no. of key times = 3 private Point[,] dp = { { new Point( 20, -10), new Point( 20, -5), new Point( 20, -5), new Point( 20, -10), new Point( 20, -10), new Point( 20, -5), new Point( 20, -5), new Point( 0, -10), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0) }, { new Point( 0, 10), new Point( 0, 5), new Point( 0, 5), new Point( 0, 10), new Point( 0, 10), new Point( 0, 5), new Point( 0, 5), new Point( 20, 10), new Point( 20, -20), new Point( 20, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0) }, { new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 0), new Point( 0, 20), new Point( 0, 0), new Point( 20, 0), new Point( 20, 0), new Point( 20, 0) } }; //3 consecutive key times defined by day, hour, minute, sec, millisec private TimeSpan[] TS = { new TimeSpan( 0, 0, 0, 0, 75 ), new TimeSpan( 0, 0, 0, 0, 150 ), new TimeSpan( 0, 0, 0, 0, 187 ) }; Boolean animation_run = true; public Page() { InitializeComponent(); p = new Point[1+snake.Segments.Count*3]; //no. of Bezier points = 10 p[0] = snake.StartPoint; //store the XAML-defined start point of snake to arry p int i = 1; //store all XAML-defined Bezier points of all snake segments to arry p foreach ( BezierSegment BS in snake.Segments ) { p[i++] = BS.Point1; p[i++] = BS.Point2; p[i++] = BS.Point3; } } //This event occurs only once at first start //creates the PointAnimations and starts the first move private void curve_path_Loaded( object sender, RoutedEventArgs e ) { String s = "(Path.Data).(PathGeometry.Figures)[0].(PathFigure."; int j = 0; create_animation( j++, s + "StartPoint)" ); for ( int a=0; a < snake.Segments.Count; a++ ) for ( int b=1; b <= 3; b++ ) create_animation( j++, s + "Segments)[" + a.ToString() + "].(BezierSegment.Point" + b.ToString() + ")" ); Storyboard1.Begin(); } //This is a subroutine of curve_path_Loaded //parameters: j = point no., s = target string //1. create an animation //2. connect it to curve_path //3. connect it to a specific Bezier Point of curve_path via string s //4. add it to Storyboard1 //5. create 3 KeyFrames per animation //6. set the destinations and durations of the first moves //7. add the KeyFrames to the animation private void create_animation( int j, string s ) { PointAnimationUsingKeyFrames PAUKF = new PointAnimationUsingKeyFrames(); Storyboard.SetTarget ( PAUKF, curve_path ); Storyboard.SetTargetProperty( PAUKF, new PropertyPath( s ) ); Storyboard1.Children.Add ( PAUKF ); for ( int i=0; i < TS.Length; i++ ) //i between 0 and 2 { LinearPointKeyFrame LPKF = new LinearPointKeyFrame(); //3 new LPKFs PAUKF.KeyFrames.Add( LPKF ); //attach this LPKF to the animation p[j].X += dp[i,j].X; //first x-step of this point p[j].Y += dp[i,j].Y; //first y-step of this point LPKF.Value = p[j]; //first movement LPKF.KeyTime = TS[i]; //set movement duration } } //This event occurs only once at first start. It creates //a dotted red line with 10 fragments looking like 10 small red rectangles private void dotted_path_Loaded( object sender, RoutedEventArgs e ) { //Fill the empty points_path with empty PFs each containing an empty LS. //Doing this here in a for-loop is much shorter than writing them many times in XAML. PathGeometry PG = (PathGeometry)dotted_path.Data; for ( int j=0; j < p.Length; j++ ) { PathFigure PF = new PathFigure (); PG.Figures .Add( PF ); //one PathFigure per point LineSegment LS = new LineSegment(); PF.Segments.Add( LS ); //one LineSegment per PathFigure } } //This event occurs after any complete move of the snake and another move is started private void Storyboard1_Completed( object sender, EventArgs e ) { //fill all PathFigures of dotted_path with a StartPoint and a horizontal 5-pixel LineSegment if ( (bool)show_bezier_points.IsChecked ) { PathGeometry PG = (PathGeometry)dotted_path.Data; for ( int j=0; j < p.Length; j++ ) { PathFigure PF = PG.Figures[j]; PF.StartPoint = new Point( p[j].X-2, p[j].Y ); ( (LineSegment)PF.Segments[0] ).Point = new Point( p[j].X+2, p[j].Y ); } } for ( int j=0; j < p.Length; j++ ) { PointAnimationUsingKeyFrames PAUKF = (PointAnimationUsingKeyFrames)Storyboard1.Children[j]; for ( int i=0; i < TS.Length; i++ ) //i between 0 and 2 { LinearPointKeyFrame LPKF = (LinearPointKeyFrame)PAUKF.KeyFrames[i]; p[j].X += dp[i,j].X; //x-step p[j].Y += dp[i,j].Y; //y-step if ( p[j].X > canvas.ActualWidth ) //right margin of canvas reached ? { p[j].X = 2* canvas.ActualWidth - p[j].X; //turn left dp[i,j].X *= -1; //reverse direction } else if ( p[j].X < 0 && dp[i,j].X < 0 ) //left margin of canvas reached ? { p[j].X *= -1; //turn right dp[i,j].X *= -1; //reverse direction } LPKF.Value = p[j]; } } if ( animation_run ) Storyboard1.Begin(); } private void start_Button_Click ( object sender, EventArgs e ) { animation_run = true; Storyboard1.Begin(); } private void step_Button_Click ( object sender, EventArgs e ) { animation_run = false; Storyboard1.Begin(); } private void show_bezier_points_Checked ( object sender, EventArgs e ) { dotted_path.Visibility = Visibility.Visible; } private void show_bezier_points_Unchecked ( object sender, EventArgs e ) { dotted_path.Visibility = Visibility.Collapsed; } private void on_velocity_slider_value_changed( object sender, EventArgs e ) { double millisec = 75; try { millisec = velocity_slider.Value; } catch { return; } TS[0] = TimeSpan.FromMilliseconds( millisec ); TS[1] = TimeSpan.FromMilliseconds( 2 *millisec ); TS[2] = TimeSpan.FromMilliseconds( 2.5*millisec ); for ( int j=0; j < Storyboard1.Children.Count; j++ ) { PointAnimationUsingKeyFrames PAUKF = (PointAnimationUsingKeyFrames)Storyboard1.Children[j]; for (int i=0; i < TS.Length; i++ ) //i between 0 and 2 { LinearPointKeyFrame LPKF = (LinearPointKeyFrame)PAUKF.KeyFrames[i]; LPKF.KeyTime = TS[i]; //set movement duration } } } //end of private void on_velocity_slider_value_changed( ... ) } //end of class Page } //end of namespace
top of page: |