Silverlight动画基础七:动画与三角函数-绘制直角三角形

这个示例主要是让我们能更加直观的观察到三角函数角边之间的关系。使用一个动画让小球围绕圆心运动,动态画出当前小球位置

与圆心之间产生的直角三角形、角度并展示出当前角度、弧度、当前角度的正弦、余弦、以及坐标值。 效果截图如下:

image

当前示例包含了以下几个对象

1.Ball:小球、围绕圆心做圆周旋转运动。

2.RightTriangle:为容器。承载Ball,并控制动画、动态绘制图形。示例中动态汇总图形主要是使用了Polyline对象,使用一系列连接的线来绘制图形。比如直角三角形,根据小球

的位置(角度),以及半径的值计算出另外两个直角边的大小,然后分别将三角形的顶点坐标传入到Polyline对象。

 

 

Ball对象

Ball对象并无主要逻辑,只是显示了自身坐标位置,其自身主要受容器控制。代码如下

 

Ball.xaml.cs代码:

<Canvas x:Name="LayoutRoot" Width="50" Height="50">
<!--大小为 50*50的红色小球-->
<Ellipse Height="50" Width="50" x:Name="RedBall">
<Ellipse.Fill>
<RadialGradientBrush>
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform X="0.16" Y="-0.2"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FFFFFFFF"/>
<GradientStop Color="#FF800000" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<TextBlock Text="400, 400" TextWrapping="Wrap" Canvas.Top="51"
FontFamily="Verdana" FontSize="12" Canvas.Left="-12"
Width="85" x:Name="MsgCoordinates"/>
</Canvas>

 

Ball.xaml.cs代码:

public partial class Ball : UserControl
{
public Ball()
{
InitializeComponent();
}

/// <summary>
/// 根据给定的x、y轴值设置当前位置
/// </summary>
/// <param name="X"></param>
/// <param name="Y"></param>
public void SetBallLocation(double X, double Y)
{
this.SetValue(Canvas.LeftProperty, X - (this.Width / 2));
this.SetValue(Canvas.TopProperty, Y - (this.Height / 2));
//显示当前坐标值
MsgCoordinates.Text = "x:" + String.Format("{0:0}", X) + ", y:" + String.Format("{0:0}", Y);
}
}

 

 

RightTriangle 对象

容器。承载Ball,控制动画、动态绘制直角三角形、角度图形、直角标识。示例中动态汇总图形主要是使用了Polyline对象,使用一系列连接的线来绘制图形。直角三角形的绘制:根据小球

的位置(角度),以及半径的值计算出另外两个直角边的大小,然后分别将三角形的顶点坐标传入到Polyline对象。角度的绘制则是每次都记录角度的坐标将每次的坐标添加到Polyline对象中。

 

RightTriangle.xaml代码:

<UserControl.Resources>
<Storyboard x:Name="MoveTimer" Duration="00:00:00.02"/>
</UserControl.Resources>
<Canvas x:Name="LayoutRoot" Width="800" Height="600" Background="#FFFFFFFF">
<!--中心圆-->
<Ellipse Height="400" Width="400" Stroke="#FF000000" Canvas.Left="200" Canvas.Top="100" StrokeDashOffset="0"
x:Name="Circle" Opacity="0.2"/>
<!--表示坐标系-->
<Path Height="600" Width="1" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" StrokeThickness="1"
Data="M412,59 L412,129" Opacity="0.2" Canvas.Left="600"/>
<Path Height="1" Width="800" Opacity="0.2" Canvas.Left="0" Canvas.Top="100" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="1" Data="M44,72 L275.17526,72"/>
<Path Height="1" Width="800" Canvas.Left="0" Canvas.Top="300" Fill="#FFFFFFFF" Stretch="Fill"
Stroke="#FF000000" StrokeThickness="1" Data="M70,110 L210.08926,110" Opacity="0.2"/>
<Path Height="600" Width="1" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" StrokeThickness="1"
Data="M412,59 L412,129" Opacity="0.2" Canvas.Left="200"/>
<Path Height="1" Width="800" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" StrokeThickness="1"
Data="M44,72 L275.17526,72" Opacity="0.2" Canvas.Top="500"/>
<Path Height="600" Width="1" Canvas.Left="400" Canvas.Top="0" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"
StrokeThickness="1" Data="M412,59 L412,129" Opacity="0.2"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="0" TextWrapping="Wrap"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="200" TextWrapping="Wrap" Canvas.Left="187"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="400" TextWrapping="Wrap" Canvas.Left="387"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="600" TextWrapping="Wrap" Canvas.Left="587"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="800" TextWrapping="Wrap" Canvas.Left="772"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="100" TextWrapping="Wrap" Canvas.Top="91"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="300" TextWrapping="Wrap" Canvas.Top="292"/>
<TextBlock Opacity="0.65" FontFamily="Verdana" FontSize="14" Text="500" TextWrapping="Wrap" Canvas.Top="492"/>
<!--用于绘制角度图形-->
<Polyline x:Name="Angle" Points="" Stroke="#FF0000FF" StrokeThickness="2" FillRule="EvenOdd" Opacity="1"/>
<!--绘制表示直角的小正方形 15*15-->
<Polyline x:Name="Square" Points="" Stroke="#FF0000FF" StrokeThickness="0.5" FillRule="EvenOdd" Fill="#330000FF" Opacity="1"/>
<!--用于绘制直角三角形-->
<Polyline x:Name="Triangle" Points="" Stroke="#FFFF0000" StrokeThickness="1" FillRule="EvenOdd" Fill="#33FF0000" Opacity="1"/>

<!--分别用于显示两条直角边的计算公式-->
<Canvas Height="29" Width="129.81" x:Name="CosText" Canvas.Top="272">
<TextBlock FontFamily="Verdana" FontSize="10" Text="Math.Cos(角度) * 弧度" TextWrapping="Wrap" Canvas.Top="4"/>
<Path Height="10" Width="1" Canvas.Left="64.405" Canvas.Top="19" Fill="#FFFFFFFF" Stretch="Fill"
Stroke="#FF000000" StrokeThickness="1" Data="M64,38 L64,12"/>
</Canvas>
<Canvas Height="12.153" Width="136.456" Canvas.Left="21" Canvas.Top="10" x:Name="SinText">
<TextBlock FontFamily="Verdana" FontSize="10" Text="Math.Sin(角度) * 弧度" TextWrapping="Wrap" Canvas.Left="14"/>
<Path Height="10" Width="1" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" StrokeThickness="1"
Data="M64,38 L64,12" RenderTransformOrigin="0.5,0.5" Canvas.Top="1" Canvas.Left="5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="90"/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
</Canvas>
<!--显示当前角度、弧度值-->
<Canvas Height="54.584" Width="106.695" Canvas.Left="605" Canvas.Top="441.416" x:Name="AngleCanvas">
<TextBlock Height="14.584" Width="69.695" FontFamily="Verdana" FontSize="14" Foreground="#FF0000FF"
Text="角度" TextWrapping="Wrap" FontWeight="Bold"/>
<TextBlock FontFamily="Verdana" FontSize="12" Text="角度:" TextWrapping="Wrap" Height="14.584"
x:Name="MsgDegrees_Copy" Width="106.695" Foreground="#FF000000" Canvas.Top="20" Canvas.Left="10"/>
<TextBlock FontFamily="Verdana" FontSize="12" Text="0" TextWrapping="Wrap" Height="14.584"
x:Name="MsgDegrees" Width="47.695" Canvas.Top="20" Foreground="#FF0000FF" Canvas.Left="69"/>
<TextBlock FontFamily="Verdana" FontSize="12" Text="弧度:" TextWrapping="Wrap" Height="14.584" Width="106.695"
x:Name="MsgRadians_Copy" Foreground="#FF000000" Canvas.Top="40" Canvas.Left="10"/>
<TextBlock FontFamily="Verdana" FontSize="12" Text="0" TextWrapping="Wrap" Height="14.584" Width="49.695"
x:Name="MsgRadians" Canvas.Top="40" Foreground="#FF0000FF" Canvas.Left="67"/>
</Canvas>
<!--显示当前正弦、余弦函数的计算结果-->
<Canvas Height="54.584" x:Name="Sin_CosOutput" Width="106.695" Canvas.Left="605" Canvas.Top="505">
<TextBlock Height="14.584" Width="69.695" FontFamily="Verdana" FontSize="14"
FontWeight="Bold" Foreground="#FFFF0000" Text="Sin/Cos" TextWrapping="Wrap"/>
<TextBlock FontFamily="Verdana" FontSize="10" Text="Math.Sin(角度) * 弧度:" TextWrapping="Wrap" Height="14.584"
x:Name="MsgSin_Copy" Width="200" Foreground="#FF000000" Canvas.Top="20" Canvas.Left="10"/>
<TextBlock FontFamily="Verdana" FontSize="10" Text="0" TextWrapping="Wrap" Height="14.584" x:Name="MsgSin" Width="44"
Canvas.Left="145" Canvas.Top="20" Foreground="#FFFF0000"/>
<TextBlock FontFamily="Verdana" FontSize="10" Text="Math.Cos(角度) * 弧度:" TextWrapping="Wrap" Height="14.584" Width="200"
x:Name="MsgCos_Copy" Foreground="#FF000000" Canvas.Top="40" Canvas.Left="10"/>
<TextBlock FontFamily="Verdana" FontSize="10" Text="0" TextWrapping="Wrap" Height="14.584" Width="44"
x:Name="MsgCos" Canvas.Left="145" Canvas.Top="40" Foreground="#FFFF0000"/>
</Canvas>
<Button Height="31" Width="100" Content="暂停" x:Name="BtnPause" Canvas.Top="544" Canvas.Left="350"/>
</Canvas>

 

 

RightTriangle.xaml.cs代码:

public partial class RightTriangle : Page
{
private double SinAngle = 0;
//每次移动1弧度
private double RotateSpeed = .01745;
private Line SineRadius = new Line();
//圆心位置
    private Point CircleCenter = new Point();
private Ball MyBall;

//直角三角形的顶点集合,用于绘制三角形
    private PointCollection RightTriAnglePoints = new PointCollection();
private Point TriAnglePoint = new Point();

//表示直角的正方形的坐标点集合
    private PointCollection SquarePoints = new PointCollection();
private Point SquarePoint = new Point();
//小正方形的大小
    private int Y_Adj = 15;
private int X_Adj = 15;

//角度坐标点集合
    private PointCollection AnglePoints = new PointCollection();
private Point AnglePoint = new Point();

private bool Paused = false;

public RightTriangle()
{
InitializeComponent();
MyBall = new Ball();
SineRadius.StrokeThickness = 2;
SolidColorBrush SineStroke = new SolidColorBrush();
SineStroke.Color = Color.FromArgb(255, 255, 0, 0);
SineRadius.Stroke = SineStroke;
LayoutRoot.Children.Add(SineRadius);
//计算圆心坐标
        CircleCenter.X = (double)Circle.GetValue(Canvas.LeftProperty) + Circle.Width / 2;
CircleCenter.Y = (double)Circle.GetValue(Canvas.TopProperty) + Circle.Height / 2;
SineRadius.X1 = SineRadius.X2 = CircleCenter.X;
SineRadius.Y1 = SineRadius.Y2 = CircleCenter.Y;

MoveTimer.Completed += new EventHandler(moveTimer_Completed);
MoveTimer.Begin();

LayoutRoot.Children.Add(MyBall);

BtnPause.Click += new RoutedEventHandler(BtnPause_Click);
}


private void BtnPause_Click(object sender, RoutedEventArgs e)
{
//控制动画
if (!Paused)
{
MoveTimer.Pause();
BtnPause.Content = "开始";
Paused = true;
}
else
{
MoveTimer.Resume();
BtnPause.Content = "暂停";
Paused = false;
}
}

private void moveTimer_Completed(object sender, EventArgs e)
{
//清理直角三角形的坐标集合
        RightTriAnglePoints.Clear();
//清理直角正方形的坐标集合
        SquarePoints.Clear();

//当沿圆运行一周后,重新设置角度起始角度为0度
        if (Angle.Points.Count == 360)
{
Angle.Points.Clear();
SinAngle = 0;
}

//计算当前角度的坐标,半径为20.用于绘制表示角度的图形
        AnglePoint.X = CircleCenter.X + Math.Cos(SinAngle) * 20;
AnglePoint.Y = CircleCenter.Y + Math.Sin(SinAngle) * 20;
AnglePoints.Add(AnglePoint);
Angle.Points = AnglePoints;

//根据角度计算出小球的当前位置.此坐标位置同样也为直角三角形中另一个顶点的值
        double RadiusX = CircleCenter.X + Math.Cos(SinAngle) * Circle.Width / 2;
double RadiusY = CircleCenter.Y + Math.Sin(SinAngle) * Circle.Height / 2;
MyBall.SetBallLocation(RadiusX, RadiusY);

//计算直角三角形的各个顶点
        //使用圆心点,因为这个顶多的坐标与圆心重叠
        TriAnglePoint.X = CircleCenter.X;
TriAnglePoint.Y = CircleCenter.Y;
RightTriAnglePoints.Add(TriAnglePoint);
//根据角度计算出的顶点值
        TriAnglePoint.X = RadiusX;
TriAnglePoint.Y = RadiusY;
RightTriAnglePoints.Add(TriAnglePoint);

CosText.SetValue(Canvas.LeftProperty, TriAnglePoint.X / 2 + 130);
SinText.SetValue(Canvas.TopProperty, (TriAnglePoint.Y - CircleCenter.Y) / 2 +
(double)Circle.GetValue(Canvas.TopProperty) + Circle.Height / 2);

SinText.SetValue(Canvas.LeftProperty, RadiusX);

//直角顶点坐标
        TriAnglePoint.X = RadiusX;
TriAnglePoint.Y = CircleCenter.Y;
RightTriAnglePoints.Add(TriAnglePoint);

TriAnglePoint.X = CircleCenter.X;
TriAnglePoint.Y = CircleCenter.Y;
RightTriAnglePoints.Add(TriAnglePoint);
//将坐标集合赋予Polyline
Triangle.Points = RightTriAnglePoints;

// 创建直角正方形的Points,大小为15*15,
        if (RadiusY > CircleCenter.Y) Y_Adj = -15;
if (RadiusX < CircleCenter.X) X_Adj = -15;
if (RadiusY < CircleCenter.Y) Y_Adj = 15;
if (RadiusX > CircleCenter.X) X_Adj = 15;
//顶点1
SquarePoint.X = RadiusX;
SquarePoint.Y = CircleCenter.Y;
SquarePoints.Add(SquarePoint);
//顶点2
SquarePoint.X = RadiusX - X_Adj;
SquarePoint.Y = CircleCenter.Y;
SquarePoints.Add(SquarePoint);
//顶点3
SquarePoint.X = RadiusX - X_Adj;
SquarePoint.Y = CircleCenter.Y - Y_Adj;
SquarePoints.Add(SquarePoint);
//顶点4
SquarePoint.X = RadiusX;
SquarePoint.Y = CircleCenter.Y - Y_Adj;
SquarePoints.Add(SquarePoint);
//顶点1
SquarePoint.X = RadiusX;
SquarePoint.Y = CircleCenter.Y;
SquarePoints.Add(SquarePoint);
//将坐标集合赋予Polyline
Square.Points = SquarePoints;

//当前角度
        MsgDegrees.Text = String.Format("{0:0.00}", SinAngle * 180 / Math.PI);
//当前弧度
        MsgRadians.Text = String.Format("{0:0.00}", SinAngle);
//当前角度的正弦、余弦函数值
        MsgSin.Text = String.Format("{0:0.00}", Math.Sin(SinAngle) * Circle.Width / 2);
MsgCos.Text = String.Format("{0:0.00}", Math.Cos(SinAngle) * Circle.Width / 2);
//弧度累加
        SinAngle += RotateSpeed;
MoveTimer.Begin();
}

}

 

 

代码完成.

运行效果演示地址:点击查看

 

总结:主要是更加只管的展示了三角函数边角关系以及三角函数的运用。下面这个图或许会让你有更多想法:

 

  image

 

【注:本文技术论点源于《Foundation Silverlight 3 Animation》,个人理解可能存在差异,请参考原著】

posted @ 2011-04-12 22:52  vvince  阅读(1379)  评论(0编辑  收藏  举报