0

enter image description here

I am trying to create one sample project to move an ellipse object along a circular path in WPF. For this I used the following equations: x = x0 + R * sin (a), y = y0 + R * cos (a), here (x0, y0) is the center of the circular path, R is the radius of the path, but my ellipse is not moving in a circle, it is moving in a line. where i made mistake?

My XAML source:

<Window x:Class="MyWpfAppSample1.MainWindow"
        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"
        xmlns:local="clr-namespace:MyWpfAppSample1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterOwner">
    <Grid>
        <Button Content="Start" x:Name="btnStart" Width="100" Height="50" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="100,10,0,0" Click="btnStart_Click"/>
        <Button Content="Stop" x:Name="btnStop" Width="100" Height="50" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="210,10,0,0" Click="btnStop_Click"/>
        <Ellipse x:Name="myEllipse" Height="10" Width="10" Fill="Aqua" Margin="400,210,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
    </Grid>
</Window>

My c# code for XAML:

public partial class MainWindow : Window
    {
        private double x;
        private double y;
        private double angle;
        private CancellationTokenSource tokenSource;
        public MainWindow()
        {
            InitializeComponent();            
        }

        
        
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            tokenSource = new CancellationTokenSource();
            var task = Task.Run(() => MoveMyEllipse(tokenSource.Token));            
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            tokenSource.Cancel();
        }

        private void MoveMyEllipse(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                angle = angle + 0.1;
                Invoke(() =>
                {
                    x = myEllipse.Margin.Top + myEllipse.Height * Math.Sin(angle);
                    y = myEllipse.Margin.Left + myEllipse.Width * Math.Cos(angle);
                    myEllipse.Margin = new Thickness(x, y, 0, 0);
                });
                Thread.Sleep(100);
            }
        }
        private void Invoke(Action action)
        {
            Dispatcher?.Invoke(action);
        }
    }

enter image description here

Mansur Kurtov
  • 726
  • 1
  • 4
  • 12
  • you are defining the radius of the circle the ellipse is supposed to be moved on by the position of the ellipse itself. Not once but at every itteration. So you move both the path and the ellipse by 0.1 in x and y at every step. – T.Schwarz Jun 30 '21 at 11:13
  • here angle is in radian and it changes from 0.1 to 3.14 – Mansur Kurtov Jun 30 '21 at 11:14

2 Answers2

5

I would suggest to take a look at Transforms and Animations.

With the follwing RenderTransform

<Canvas>
    <Ellipse Height="10" Width="10" Fill="Aqua"
             Canvas.Left="200" Canvas.Top="200"
             RenderTransformOrigin="0.5,0.5">
        <Ellipse.RenderTransform>
            <TransformGroup>
                <TranslateTransform Y="-100"/>
                <RotateTransform x:Name="rotateTransform"/>
            </TransformGroup>
        </Ellipse.RenderTransform>
    </Ellipse>
</Canvas>

you could animate the rotation like this:

var rotateAnimation = new DoubleAnimation(0, 360, TimeSpan.FromSeconds(10));

rotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation);
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thank you, for your solution, i tested it, it is cool! – Mansur Kurtov Jun 30 '21 at 11:32
  • 2
    You're welcome. There is also MatrixAnimationUsingPath which allows animations of the Matrix property of a MatrixTransform along arbitrary path geometries :-) – Clemens Jun 30 '21 at 11:34
  • @Clemens, Can you briefly say what the TranslateTransform Y="-100" does? I'm guessing it moves the ellipse down by 100, but clearly the ellipse makes a full revolution; thus it comes down and then up. Thanks! – Dave Feb 02 '22 at 20:37
  • 1
    @Dave How does it look when you comment it out, or change the Y value? – Clemens Feb 02 '22 at 21:23
  • When I make it -10 instead of -100 it makes a smaller circle path. When I make it 100 instead of -100, it starts at the bottom and make a 360 degree path clockwise. When I make it 0, nothing appear to happen. I can see it make a difference, but I'm having trouble understanding how it works. The documentation for TranslateTransform says "ranslates (moves) an object in the 2-D x-y coordinate system." I assumed it moves it in one direction. Clearly it doesn't but how? I'm guessing it has something to do with the ellipse rotating around it's own axis at the same time, but I can't figure it out! – Dave Feb 02 '22 at 22:17
  • 1
    It is a combined transformation, first translate off-center by a certain amout, (e.g. 100 units upwards by Y=-100), then rotate. Think of the hand of an analog clock. – Clemens Feb 02 '22 at 22:36
  • Thank you! I figured it out and was about to write you. I'm amazed I can't find any examples or explanations of it though. I guess everyone else considers it trivial :). Now, I'll see if I can get my actual code working which uses MVVM. I wrote that as a separate question as you saw. I'm close.... – Dave Feb 02 '22 at 23:43
0

Instead of the function that you describe, you have implemented it is not clear what.

    public partial class MainWindow : Window
    {
        private double x;
        private double y;
        private double x0 = 250;
        private double y0 = 350;
        private double r = 100;
        private double angle;
        private CancellationTokenSource tokenSource;
        public MainWindow()
        {
            InitializeComponent();
        }



        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            tokenSource = new CancellationTokenSource();
            var task = Task.Run(() => MoveMyEllipse(tokenSource.Token));
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            tokenSource.Cancel();
        }

        private void MoveMyEllipse(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                angle = angle + 0.1;
                Invoke(() =>
                {
                    x = x0 + r * Math.Sin(angle);
                    y = y0 + r * Math.Cos(angle);
                    myEllipse.Margin = new Thickness(x, y, 0, 0);
                });
                Thread.Sleep(100);
            }
        }
        private void Invoke(Action action)
        {
            Dispatcher?.Invoke(action);
        }
    }
EldHasp
  • 6,079
  • 2
  • 9
  • 24