2010-01-20 53 views
1

以下代码绘制一条线,将其旋转30度左右,将其恢复到其原始位置,将其绕右端旋转30度,然后重复多次。围绕不同中心进行连续旋转?

我该如何对这些旋转进行排序而不将这条线恢复到原来的位置?第一次旋转(左端点附近)导致右端点移动;所以我希望下一轮轮换在新的位置。

序列的净效应应该是使线段“前进”。

(请注意,此代码使用相同的角度一遍又一遍,但我需要一个解决方案,如果角度每次都是不同的,也将正常工作。)

XAML: -

<UserControl x:Class="Rotation.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> 
    <Grid x:Name="LayoutRoot"> 
     <Canvas Width="500" Height="500"> 
      <Line Name="TheLine" X1="100" Y1="200" X2="200" Y2="200" Stroke="Black" StrokeThickness="5"></Line>   
     </Canvas> 
    </Grid> 
</UserControl> 

代码: -

using System; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace Rotation 
{ 
    public partial class MainPage : UserControl 
    { 
     double x1, y1, x2, y2; 

     public MainPage() 
     { 
      InitializeComponent(); 

      for (int i = 0; i < 5; i++) 
      { 
       _animations.Add(() => { return rot(true, -30); }); 
       _animations.Add(() => { return rot(false, 30); }); 
      } 
      _enumerator = _animations.GetEnumerator(); 

      x1 = TheLine.X1; 
      x2 = TheLine.X2; 
      y1 = TheLine.Y1; 
      y2 = TheLine.Y2; 

      this.Loaded += delegate(object sender, RoutedEventArgs e) 
      { 
       RunNextAnimation(); 
      }; 
     } 

     List<Func<Storyboard>> _animations = new List<Func<Storyboard>>(); 
     IEnumerator<Func<Storyboard>> _enumerator; 

     public void AnimationCompleted(object sender, EventArgs args) 
     { 
      RunNextAnimation(); 
     } 

     void RunNextAnimation() 
     { 
      if (_enumerator.MoveNext()) 
      { 
       Func<Storyboard> fn = _enumerator.Current; 
       if (fn != null) 
       { 
        Storyboard board = fn(); 
        board.Completed += AnimationCompleted; 
        board.Begin(); 
       } 
      } 
     } 


     public Storyboard rot(bool aroundLeft, double angle) 
     { 
      Storyboard board = new Storyboard(); 
      int duration = 5; 


      if (true) 
      { 
       RotateTransform rot = new RotateTransform(); 

       if (aroundLeft) 
       { 
        rot.CenterX = x1; 
        rot.CenterY = y1; 
       } 
       else 
       { 
        rot.CenterX = x2; 
        rot.CenterY = y2; 
       } 

       TheLine.RenderTransform = rot; 

       DoubleAnimation an = new DoubleAnimation(); 
       an.Duration = new Duration(new TimeSpan(0, 0, duration)); 
       an.From = 0; 
       an.To = angle; 

       board.Children.Add(an); 
       Storyboard.SetTarget(an, TheLine); 
       Storyboard.SetTargetProperty(an, new PropertyPath("(UIElement.RenderTransform).Angle")); 
      } 

      return board; 
     } 


    } 
} 

回答

1

我想通了,要做到这一点的一种方法:对于每个旋转,计算直线的端点将移动到。然后在开始下一个旋转之前,移动该线,使其位置和角度反映该旋转的所需中心。

下面是执行此操作的代码。而不是一条线,我现在使用一个包含复合形状的画布,这是一个更通用的目的。

XAML:

<UserControl x:Class="Rotation.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"> 
    <Grid x:Name="LayoutRoot"> 
     <Canvas Width="500" Height="500"> 
      <Canvas Name="TheRect" Canvas.Left="100" Canvas.Top="100" Width="100" Height="20"> 
       <Rectangle Canvas.Left="0" Canvas.Top="0" Width="100" Height="20" Stroke="Black" StrokeThickness="1"></Rectangle> 
       <Ellipse Width="10" Height="10" Fill="Blue" Canvas.Left="0" Canvas.Top="0" /> 
      </Canvas> 
     </Canvas> 
    </Grid> 
</UserControl> 

C#:

using System; 
using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace Rotation 
{ 
    public partial class MainPage : UserControl 
    { 
     double x1, y1, x2, y2, w; 
     double lastAngle; 

     public MainPage() 
     { 
      InitializeComponent(); 

      for (int i = 0; i < 10; i++) 
      { 
       _animations.Add(() => { return rot(true, 30); }); 
       _animations.Add(() => { return rot(false, -30); }); 
      } 
      _enumerator = _animations.GetEnumerator(); 

      x1 = (double)TheRect.GetValue(Canvas.LeftProperty); 
      y1 = (double)TheRect.GetValue(Canvas.TopProperty); 
      w = (double)TheRect.GetValue(Canvas.WidthProperty); 
      x2 = x1 + w; 
      y2 = y1; 
      lastAngle = 0.0; 

      this.Loaded += delegate(object sender, RoutedEventArgs e) 
      { 
       RunNextAnimation(); 
      }; 
     } 

     List<Func<Storyboard>> _animations = new List<Func<Storyboard>>(); 
     IEnumerator<Func<Storyboard>> _enumerator; 

     public void AnimationCompleted(object sender, EventArgs args) 
     { 
      RunNextAnimation(); 
     } 

     void RunNextAnimation() 
     { 
      if (_enumerator.MoveNext()) 
      { 
       Func<Storyboard> fn = _enumerator.Current; 
       if (fn != null) 
       { 
        Storyboard board = fn(); 
        board.Completed += AnimationCompleted; 
        board.Begin(); 
       } 
      } 
     } 


     public Storyboard rot(bool aroundLeft, double angle) 
     { 
      Storyboard board = new Storyboard(); 
      int duration = 5; 


      if (true) 
      { 
       TheRect.SetValue(Canvas.LeftProperty, aroundLeft ? x1 : x1 - w*(1 - Math.Cos(lastAngle * Math.PI/180))); 
       TheRect.SetValue(Canvas.TopProperty, aroundLeft ? y1 : y2); 

       RotateTransform rot = new RotateTransform(); 
       rot.CenterX = aroundLeft ? 0 : w; 
       rot.CenterY = aroundLeft ? 0 : 0; 
       rot.Angle = aroundLeft ? lastAngle : -lastAngle; 

       TheRect.RenderTransform = rot; 

       DoubleAnimation an = new DoubleAnimation(); 
       an.Duration = new Duration(new TimeSpan(0, 0, duration)); 
       an.From = lastAngle; 
       an.To = lastAngle + angle; 

       board.Children.Add(an); 
       Storyboard.SetTarget(an, TheRect); 
       Storyboard.SetTargetProperty(an, new PropertyPath("(UIElement.RenderTransform).Angle")); 

       // and for next time around: 
       lastAngle += angle; 

       if (aroundLeft) 
       { 
        // rotating will move x2,y2; compute the updated values for next time 
        double x0 = x2 - x1; 
        double y0 = y2 - y1; 

        double sin = Math.Sin(angle * Math.PI/180.0); 
        double cos = Math.Cos(angle * Math.PI/180.0); 

        x2 = x1 + (x0 * cos) - (y0 * sin); 
        y2 = y1 + (x0 * sin) + (y0 * cos); 
       } 
       else 
       { 
        // rotating will move x1, y1; compute the updated values for next time 
        double x0 = x1 - x2; 
        double y0 = y1 - y2; 

        double sin = Math.Sin(angle * Math.PI/180.0); 
        double cos = Math.Cos(angle * Math.PI/180.0); 

        x1 = x2 + (x0 * cos) - (y0 * sin); 
        y1 = y2 + (x0 * sin) + (y0 * cos); 
       } 

      } 

      return board; 
     } 


    } 
}