Browse Source

Finally, finally fix the linear parametric interpolation for DoubleKeyFrames 😄

Credits to Georgia Tech's keyframe slides : https://www.cc.gatech.edu/classes/AY2012/cs4496_spring/slides/Keyframe.pdf
pull/1461/head
Jumar Macato 9 years ago
parent
commit
ee1960ba00
  1. 16
      samples/RenderTest/Pages/AnimationsPage.xaml
  2. 59
      src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs

16
samples/RenderTest/Pages/AnimationsPage.xaml

@ -7,7 +7,6 @@
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="100"/>
</Style>
<Style Selector="Rectangle.Rect1:pointerover">
<Style.Animations>
<Animation Duration="0:0:2.5" Easing="BounceEaseInOut">
@ -18,7 +17,6 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="Rectangle.Rect2:pointerover">
<Style.Animations>
<Animation Duration="0:0:0.5" Easing="SineEaseInOut">
@ -33,21 +31,17 @@
</Animation>
</Style.Animations>
</Style>
<Style Selector="Rectangle.Rect3:pointerover">
<Style.Animations>
<Animation Duration="0:0:3" Easing="BounceEaseInOut">
<TransformKeyFrames Property="TranslateTransform.Y">
<KeyFrame Cue="0%" Value="0"/>
<KeyFrame Cue="48%" Value="-100"/>
<KeyFrame Cue="52%" Value="-100"/>
<KeyFrame Cue="100%" Value="0"/>
</TransformKeyFrames>
</Animation>
</Style.Animations>
</Style>
<Style Selector="Rectangle.Rect4:pointerover">
<Style.Animations>
<Animation Duration="0:0:3" Easing="CircularEaseInOut">
@ -60,12 +54,14 @@
</Animation>
</Style.Animations>
</Style>
</Styles>
</Grid.Styles>
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBlock HorizontalAlignment="Center">Hover to activate Transform Keyframe Animations.</TextBlock>
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center"
ClipToBounds="False">
<TextBlock HorizontalAlignment="Center">
Hover to activate Transform Keyframe Animations.
</TextBlock>
<StackPanel Orientation="Horizontal"
ClipToBounds="False">
<Rectangle Classes="Test Rect1" Fill="DarkRed">

59
src/Avalonia.Animation/Keyframes/DoubleKeyFrames.cs

@ -30,43 +30,56 @@ namespace Avalonia.Animation.Keyframes
// Get a pair of keyframes to make the interpolation.
KeyValuePair<double, double> firstCue, lastCue;
firstCue = sortedkeyValues.First();
lastCue = sortedkeyValues.Last();
// This should be changed later for a much more efficient one
if (sortedkeyValues.Count() > 2)
{
bool isWithinRange_Start = DoubleUtils.AboutEqual(x, 0.0) || x > 0.0;
bool isWithinRange_End = DoubleUtils.AboutEqual(x, 1.0) || x < 1.0;
bool OutsideRange_Start = DoubleUtils.AboutEqual(x, 0.0) || x < 0.0;
bool OutsideRange_End = DoubleUtils.AboutEqual(x, 1.0) || x > 1.0;
var kyF = sortedkeyValues.ToArray();
if (isWithinRange_Start && isWithinRange_End)
{
firstCue = sortedkeyValues.Where(j => j.Key <= x).Last();
lastCue = sortedkeyValues.Where(j => j.Key >= x).First();
}
else if (!isWithinRange_Start)
if (OutsideRange_Start)
{
firstCue = sortedkeyValues.First();
lastCue = sortedkeyValues.Skip(1).First();
firstCue = kyF[0];
lastCue = kyF[1];
}
else if (!isWithinRange_End)
else if (OutsideRange_End)
{
firstCue = sortedkeyValues.Skip(sortedkeyValues.Count() - 1).First();
lastCue = sortedkeyValues.Last();
var count = kyF.Count();
firstCue = kyF[count - 2];
lastCue = kyF[count - 1];
}
else
{
throw new InvalidOperationException
($"Can't find KeyFrames within the specified Easing time {x}");
firstCue = sortedkeyValues.Where(j => j.Key <= x).Last();
lastCue = sortedkeyValues.Where(j => j.Key >= x).First();
}
}
else
{
firstCue = sortedkeyValues.First();
lastCue = sortedkeyValues.Last();
}
double x0, y0, x1, y1;
// Piecewise Linear interpolation, courtesy of wikipedia
var y0 = firstCue.Value;
var x0 = firstCue.Key;
var y1 = lastCue.Value;
var x1 = lastCue.Key;
var y = ((y0 * (x1 - x)) + (y1 * (x - x0))) / x1 - x0;
// Swap interpolants if its descending
// if (firstCue.Value > lastCue.Value)
// // {
// y1 = firstCue.Value;
// x1 = firstCue.Key;
// y0 = lastCue.Value;
// x0 = lastCue.Key;
// }
// else
// {
y0 = firstCue.Value;
x0 = firstCue.Key;
y1 = lastCue.Value;
x1 = lastCue.Key;
var y = y0 + ((x - x0)/(x1 - x0)) * (y1-y0);
return y;
}

Loading…
Cancel
Save