围绕不同的中心组成顺序旋转?

时间:2010-01-20 22:48:45

标签: silverlight animation rotatetransform

以下代码绘制一条线,围绕其左端旋转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 个答案:

答案 0 :(得分: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;
        }


    }
}