1

The following code draws a line, rotates it 30 degrees around its left end, restores it to its original position, rotates it 30 degrees around its right end, and then repeats several times.

How can I sequence these rotations without restoring the line to its original position in between? The first rotation (around the left endpoint) causes the right endpoint to move; so I would like the next rotation to be around its new position.

The net effect of the sequence should be to make the line segment "walk" forward.

(Note that this code uses the same angle over and over again. But I need a solution that will also work if the angle is different every time.)

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>

Code:-

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;
        }


    }
}
4

1 回答 1

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;
        }


    }
}
于 2010-01-22T02:38:33.047 回答