2010-01-20 63 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; 
     } 


    } 
}