first of all I'll try to explain what I'm trying to do. The task looks quite simple at first look, but it took me some time to realize its very complex. What I'm trying to do is simple animation with easing at the beginning and at the end - I know how to use easing, the hard part is that I'm trying to do something like Orbit - Elliptical orbit with lets say 5 rectangles attached to it. I want to move the rectangles along the Elliptical orbit (elliptical path) without changing the rotation angle of each rectangle.
I've tried with Path animation, but it seems that motion path animations don't support easing ? Am I wrong ? Second solution was to group the path and the rectangles and rotate the whole group, but this changes rectangles rotation angle too. Is there a simple way to do this ? Please point me to an article or something, or if you have a similar scenario please share the solution. Thanks.
There are four basic types of orbitals: s, p, d, and f. An s orbital has a spherical shape and can hold two electrons.
There are five 7d orbitals. These are labelled 7dxy, 7dxz, 7dyz, 7dx2-y 2 and 7dz2. Four of these functions have the same shape but are aligned differently in space. The fifth function (7dz2) has a different shape.
Named for their energy sublevels, there are four types of orbitals: s, p, d, and f. Each orbital type has a unique shape based on the energy of its electrons. The s orbital is a spherical shape. The p orbital is a dumbbell shape.
The 3d orbitals are quite compactly arranged around the nucleus. Introducing a second electron into a 3d orbital produces more repulsion than if the next electron went into the 4s orbital. There is not a very big gap between the energies of the 3d and 4s orbitals.
Try this, it's great fun:
<Canvas Height="100" Width="100" RenderTransformOrigin="0.5,0.5">
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="360"
RepeatBehavior="Forever"
Duration="0:0:1"
Storyboard.TargetProperty="RenderTransform.Angle">
<DoubleAnimation.EasingFunction>
<CubicEase EasingMode="EaseInOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Canvas.RenderTransform>
<RotateTransform />
</Canvas.RenderTransform>
<Canvas.Resources>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="RenderTransform" Value="{Binding RenderTransform.Inverse, RelativeSource={RelativeSource AncestorType=Canvas}}"/>
</Style>
</Canvas.Resources>
<Rectangle Fill="Red" Height="20" Width="20" Canvas.Left="40" Canvas.Top="0"/>
<Rectangle Fill="Green" Height="20" Width="20" Canvas.Left="40" Canvas.Top="80"/>
</Canvas>
Key Points:
RotateTransform
as RenderTransform
on the Canvas which is animated.Canvas.Resources
binds the RenderTransform
of Rectangles to the inverse RotateTransform of the parent canvas.Here's another approach...
What you want to do is not actually a rotation, but a translation along an elliptic path. The trouble is, a TranslateTransform
is defined by an X and Y, not an angle and radius... But it's easier to animate an angle, so you have to convert polar coordinates to cartesian coordinates.
To do that, let's define two converters: SinConverter
and CosConverter
:
public class SinConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
double angle = System.Convert.ToDouble(value);
double angleRad = Math.PI * angle / 180;
double radius = System.Convert.ToDouble(parameter);
return radius * Math.Sin(angleRad);
}
catch
{
return Binding.DoNothing;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
public class CosConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
try
{
double angle = System.Convert.ToDouble(value);
double angleRad = Math.PI * angle / 180;
double radius = System.Convert.ToDouble(parameter);
return radius * Math.Cos(angleRad);
}
catch
{
return Binding.DoNothing;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Now, we need an angle property to animate: so we define a dummy RotateTransform
in the resources, that will be the target of the animation.
Next, we apply a TranslateTransform
on the "satellite", and we bind the X and Y to the angle, using our converters.
Eventually, we just need to create the animation itself that will animate the angle.
Here's the complete XAML:
<Window x:Class="WpfCS.Orbit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfCS"
Title="Orbit"
Height="300" Width="300">
<Window.Resources>
<my:SinConverter x:Key="sinConverter" />
<my:CosConverter x:Key="cosConverter" />
<RotateTransform x:Key="rotate" Angle="0" />
</Window.Resources>
<Grid>
<Rectangle Width="30" Height="30" Fill="Blue">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding Path=Angle,
Source={StaticResource rotate},
Converter={StaticResource cosConverter},
ConverterParameter=100}"
Y="{Binding Path=Angle,
Source={StaticResource rotate},
Converter={StaticResource sinConverter},
ConverterParameter=60}"/>
</Rectangle.RenderTransform>
</Rectangle>
<Ellipse Width="5" Height="5" Fill="White" Stroke="Black" StrokeThickness="1" />
</Grid>
<Window.Style>
<Style TargetType="Window">
<Style.Triggers>
<EventTrigger RoutedEvent="Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.Target="{StaticResource rotate}"
Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:5"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Style>
</Window>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With