围绕不同中心进行连续旋转?

发布于 2024-08-18 05:21:46 字数 3578 浏览 11 评论 0原文

以下代码绘制一条线,将其绕其左端旋转 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;
        }


    }
}

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


    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

短叹 2024-08-25 05:21:46

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

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

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


    }
}

I figured out one way to do this: With each rotation, compute where the line's endpoints will move to. Then before starting the next rotation, move the line so that its position and angle reflect the desired center of that rotation.

Here's the code to do it. Instead of a line, I'm now using a canvas containing a composite shape, which is a little more general purpose.

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


    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文