Silverlight & Blend动画设计系列十二:三角函数Trigonometry动画之自由旋转Free-form rotation

  说到对象的旋转,或许就会联想到对象角度的概念。对象的旋转实现实际上就是利用对象的角度改变来实现的位置变换,在《 Silverlight & Blend动画设计系列二:旋转动画(RotateTransform)》一文中有对对象的不同角度变换的实现介绍,本篇要介绍的自由旋转(Free-form rotation)将借助《Function Silverlight 3 Animation》一书中的示例项目介绍,详细敬请阅读本文。
 
  要实现自由旋转其实非常简单,需要特别注意的有四点,既旋转对象、旋转中心点、旋转角度及旋转焦点。可以简单理解为当点击对象上的某一点可以对对象实现其以某一中心点为准的不等角度旋转。为了方便控制通常会将旋转焦点设计为相对突出的UI呈现,如下图示:
        

 
   上图的UI外观设计为一个独立的UserControl,对应的xaml定义如下:
< UserControl  x:Class ="ImageRotate.RotateItem"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"  
    Width
="320"  Height ="240" >
    
< Canvas  x:Name ="ItemCanvas"  Width ="320"  Height ="240"  Canvas.Left ="77"  Canvas.Top ="57"  Background ="#FFFFFFFF"  
    RenderTransformOrigin
="0.5,0.5" >
        
< Canvas.RenderTransform >
            
< TransformGroup >
                
< RotateTransform  x:Name ="RotateItemCanvas"  Angle ="0" />
            
</ TransformGroup >
        
</ Canvas.RenderTransform >         
        
< Image  x:Name ="Image"  Width ="300"  Height ="220"  Canvas.Left ="10"  Canvas.Top ="10"  Source =""  Stretch ="Fill" />
        
< Ellipse  x:Name ="Handle"  Width ="15"  Height ="15"  Fill ="#FFEAFF00"  stroke ="#FF000000"  Canvas.Left ="313"  Canvas.Top ="233" />
    
</ Canvas >
</ UserControl >
 
  分析上面的xaml可以知道,整个界面通过基于坐标的Canvas进行布局,认设置布局容器的旋转角度为0度,在Canvas里面放置了一个图片作为可旋转的对象外观呈现,一个圆形作为旋转焦点。最终实现旋转功能的就是鼠标在Ellipse对象上的事件应用,通过事件处理函数来改变整个布局容器的旋转角度(Angle)。 
private   bool  IsMouseCaptured;
private  Point MousePosition;
private  Point LastPosition;
public  Point CanvasCenter;
private   double  LastAngle;
private   double  CurrentAngle;
private   double  AngleDelta;

public  RotateItem()
{
    InitializeComponent();
    
// 注册Ellipse对象的鼠标事件
    Handle.MouseLeftButtonDown  +=   new  MouseButtonEventHandler(Handle_MouseLeftButtonDown);
    Handle.MouseLeftButtonUp 
+=   new  MouseButtonEventHandler(Handle_MouseLeftButtonUp);
    Handle.MouseMove 
+=   new  MouseEventHandler(Handle_MouseMove);
}

private   void  Handle_MouseLeftButtonUp( object  sender, MouseButtonEventArgs e)
{
    FrameworkElement Item 
=  sender  as  FrameworkElement;
    Item.ReleaseMouseCapture();
    IsMouseCaptured 
=   false ;
    Item.Cursor 
=   null ;
}

private   void  Handle_MouseLeftButtonDown( object  sender, MouseButtonEventArgs e)
{
    FrameworkElement Item 
=  sender  as  FrameworkElement;
    Item.CaptureMouse();
    Item.Cursor 
=  Cursors.Hand;
    IsMouseCaptured 
=   true ;
    LastPosition 
=  e.GetPosition( null );
}
 
  最关键的就是MouseMove事件了,在MouseMove事件处理函数中,通过计算鼠标点下时的坐标和当前所在的坐标进行弧度转化角度的计算,将得到的角度值设置为Canvas的旋转角度就达到了实现对象的自由旋转功能
        

 
  以下为弧度转化为角度的计算公式以及MouseMove事件算法实现:
///   <summary>
///  弧度转化为角度
///   </summary>
///   <param name="radians"></param>
///   <returns></returns>
private   double  radiansTodegrees( double  radians)
{
    
return  radians  *   180   /  Math.PI;
}
 
private void  Handle_MouseMove( object  sender, MouseEventArgs e)
{
    MousePosition 
=  e.GetPosition( null );

    
if  (IsMouseCaptured)
    {
        LastAngle 
=  Math.atan2(LastPosition.Y  -  CanvasCenter.Y, LastPosition.X  -  CanvasCenter.X);
        CurrentAngle 
=  Math.atan2(MousePosition.Y  -  CanvasCenter.Y, MousePosition.X  -  CanvasCenter.X);
        AngleDelta 
=  CurrentAngle  -  LastAngle;
        RotateItemCanvas.Angle 
+=  radiansTodegrees(AngleDelta);
        LastPosition 
=  MousePosition;
    }
}
 

可旋转UserControl完整代码
public   partial   class  RotateItem : UserControl
{
    
private   bool  IsMouseCaptured;
    
private  Point MousePosition;
    
private  Point LastPosition;
    
public  Point CanvasCenter;
    
private   double  LastAngle;
    
private   double  CurrentAngle;
    
private   double  AngleDelta;

    
public  RotateItem()
    {
        InitializeComponent();
        Handle.MouseLeftButtonDown 
+=   new  MouseButtonEventHandler(Handle_MouseLeftButtonDown);
        Handle.MouseLeftButtonUp 
+=   new  MouseButtonEventHandler(Handle_MouseLeftButtonUp);
        Handle.MouseMove 
+=   new  MouseEventHandler(Handle_MouseMove);
    }

    
private   void  Handle_MouseLeftButtonUp( object  sender, MouseButtonEventArgs e)
    {
        FrameworkElement Item 
=  sender  as  FrameworkElement;
        Item.ReleaseMouseCapture();
        IsMouseCaptured 
=   false ;
        Item.Cursor 
=   null ;
    }

    
private   void  Handle_MouseLeftButtonDown( object  sender, MouseButtonEventArgs e)
    {
        FrameworkElement Item 
=  sender  as  FrameworkElement;
        Item.CaptureMouse();
        Item.Cursor 
=  Cursors.Hand;
        IsMouseCaptured 
=   true ;
        LastPosition 
=  e.GetPosition( null );
    }

    
private   void  Handle_MouseMove( object  sender, MouseEventArgs e)
    {
        MousePosition 
=  e.GetPosition( null );

        
if  (IsMouseCaptured)
        {
            LastAngle 
=  Math.atan2(LastPosition.Y  -  CanvasCenter.Y, LastPosition.X  -  CanvasCenter.X);
            CurrentAngle 
=  Math.atan2(MousePosition.Y  -  CanvasCenter.Y, MousePosition.X  -  CanvasCenter.X);
            AngleDelta 
=  CurrentAngle  -  LastAngle;
            RotateItemCanvas.Angle 
+=  radiansTodegrees(AngleDelta);
            LastPosition 
=  MousePosition;
        }
    }

        
    
///   <summary>
    
///  弧度转化为角度
    
///   </summary>
    
///   <param name="radians"></param>
    
///   <returns></returns>
     private   double  radiansTodegrees( double  radians)
    {
        
return  radians  *   180   /  Math.PI;
    }
}
 
  使用也是非常简单的,动态创建上面所创建的UserControl然后将其添加到主容器控件中就可以了,如下演示代码
 
public   partial   class  MainPage : UserControl
{
    
public  MainPage()
    {
        InitializeComponent();

        var Picture1 
=   new  RotateItem();
        Picture1.Image.source 
=   new  BitmapImage( new  Uri( " Marigold.jpg " , UriKind.Relative));
        Picture1.SetValue(Canvas.LeftProperty, 
100.00 );
        Picture1.SetValue(Canvas.TopProperty, 
100.00 );
        Picture1.CanvasCenter.X 
=  ( double )Picture1.GetValue(Canvas.LeftProperty)  +  Picture1.Width  /   2 ;
        Picture1.CanvasCenter.Y 
=  ( double )Picture1.GetValue(Canvas.TopProperty)  +  Picture1.Height  /   2 ;
        Picture1.RotateItemCanvas.Angle 
=   - 15 ;
        LayoutRoot.Children.Add(Picture1);
    }
}
 
         

 
  推荐资源:
  《Function Silverlight 3 Animation》----本篇中使用的示例素材选自此书
 
    

相关文章

如何在Silverlight4(XAML)中绑定IsEnabled属性?我试过简单的...
我正在编写我的第一个vb.net应用程序(但我也会在这里标记c#,...
ProcessFile()是在UIThread上运行还是在单独的线程上运行.如...
我从同行那里听说,对sharepoint的了解对职业生涯有益.我们不...
我正在尝试保存一个类我的类对象的集合.我收到一个错误说明:...
我需要根据Silverlight中的某些配置值设置给定控件的Style.我...