2010-01-01 82 views
2

我正在嘗試做一個矩陣動畫​​,我在這裏同時縮放和轉置畫布。我發現的唯一方法是使用MatrixTransform和MatrixAnimationUsingKeyFrames。由於似乎沒有對內置矩陣進行插值(僅用於路徑/旋轉),似乎唯一的選擇是嘗試自行構建插值和DiscreteMatrixKeyFrame。使用MatrixTransform進行平滑動畫?

我做了這個基本實現,但它不完全平滑,我不知道這是最好的方式,以及如何處理framerate等任何人都有改進的建議?下面的代碼:

 MatrixAnimationUsingKeyFrames anim = new MatrixAnimationUsingKeyFrames(); 
     int duration = 1; 
     anim.KeyFrames = Interpolate(new Point(0, 0), centerPoint, 1, factor,100,duration); 
     this.matrixTransform.BeginAnimation(MatrixTransform.MatrixProperty, anim,HandoffBehavior.Compose); 


public MatrixKeyFrameCollection Interpolate(Point startPoint, Point endPoint, double startScale, double endScale, double framerate,double duration) 
    { 
     MatrixKeyFrameCollection keyframes = new MatrixKeyFrameCollection(); 

     double steps = duration * framerate; 
     double milliSeconds = 1000/framerate; 
     double timeCounter = 0; 



     double diffX = Math.Abs(startPoint.X- endPoint.X); 
     double xStep = diffX/steps; 

     double diffY = Math.Abs(startPoint.Y - endPoint.Y); 
     double yStep = diffY/steps; 

     double diffScale= Math.Abs(startScale- endScale); 
     double scaleStep = diffScale/steps; 


     if (endPoint.Y < startPoint.Y) 
     { 
      yStep = -yStep; 
     } 

     if (endPoint.X < startPoint.X) 
     { 
      xStep = -xStep; 
     } 


     if (endScale < startScale) 
     { 
      scaleStep = -scaleStep; 
     } 


     Point currentPoint = new Point(); 
     double currentScale = startScale; 

     for (int i = 0; i < steps; i++) 
     { 
      keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(currentScale, 0, 0, currentScale, currentPoint.X, currentPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(timeCounter)))); 
      currentPoint.X += xStep; 
      currentPoint.Y += yStep; 
      currentScale += scaleStep; 
      timeCounter += milliSeconds; 

     } 

     keyframes.Add(new DiscreteMatrixKeyFrame(new Matrix(endScale, 0, 0, endScale, endPoint.X, endPoint.Y), KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)))); 

     return keyframes; 

    } 

回答

3

試試這個吧!只要你不旋轉/剪切它就可以做到這一點。

using System.Windows; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 

namespace MapControl 
{ 
    public class LinearMatrixAnimation : AnimationTimeline 
    { 

     public Matrix? From 
     { 
      set { SetValue(FromProperty, value);} 
      get { return (Matrix)GetValue(FromProperty); } 
     } 
     public static DependencyProperty FromProperty = DependencyProperty.Register("From", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null)); 

     public Matrix? To 
     { 
      set { SetValue(ToProperty, value); } 
      get { return (Matrix)GetValue(ToProperty); } 
     } 
     public static DependencyProperty ToProperty = DependencyProperty.Register("To", typeof(Matrix?), typeof(LinearMatrixAnimation), new PropertyMetadata(null)); 

     public LinearMatrixAnimation() 
     {    
     } 

     public LinearMatrixAnimation(Matrix from, Matrix to, Duration duration) 
     { 
      Duration = duration; 
      From = from; 
      To = to; 
     } 

     public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) 
     { 
      if (animationClock.CurrentProgress == null) 
      { 
       return null; 
      } 

      double progress = animationClock.CurrentProgress.Value; 
      Matrix from = From ?? (Matrix)defaultOriginValue; 

      if (To.HasValue) 
      { 
       Matrix to = To.Value; 
       Matrix newMatrix = new Matrix(((to.M11 - from.M11) * progress)+from.M11, 0, 0, ((to.M22 - from.M22) * progress)+from.M22, 
               ((to.OffsetX - from.OffsetX) * progress) + from.OffsetX, ((to.OffsetY - from.OffsetY) * progress)+ from.OffsetY); 
       return newMatrix; 
      } 

      return Matrix.Identity; 
     } 

     protected override System.Windows.Freezable CreateInstanceCore() 
     { 
      return new LinearMatrixAnimation(); 
     } 

     public override System.Type TargetPropertyType 
     { 
      get { return typeof(Matrix); } 
     } 
    } 
} 
+0

做得很好!我爲這段代碼添加了緩動。在下面尋找我的位。 – bor 2013-04-05 06:55:52

+0

會這樣可以給你打十幾次... – Jeff 2014-03-19 00:09:00

1

好吧,如果你問在MSDN

http://msdn.microsoft.com/en-us/library/system.windows.media.animation.discretematrixkeyframe.aspx

你所得到的答案是DiscreteMatrixKeyFrame導致 突然變化,那麼你應該一起使用LinearDoubleKeyFrame 或SplineDoubleKeyFrame 源代碼

編輯:啊,我看到,矩陣轉換僅支持離散的 轉換,所以你實際上有一個跳轉問題。 所以我的建議是使用RectAnimationUsingKeyFrames

// Create a RectAnimationUsingKeyFrames to 
// animate the RectangleGeometry. 
RectAnimationUsingKeyFrames rectAnimation = new RectAnimationUsingKeyFrames(); 
rectAnimation.Duration = TimeSpan.FromSeconds(timeInSeconds); 

// Animate position, width, and height in first 2 seconds. LinearRectKeyFrame creates 
// a smooth, linear animation between values. 
rectAnimation.KeyFrames.Add(
       new LinearRectKeyFrame(
        new Rect(600,50,200,50), // Target value (KeyValue) 
        KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2))) // KeyTime 
       ); 

// In the next half second, change height to 10. 
    rectAnimation.KeyFrames.Add(
       new LinearRectKeyFrame(
        new Rect(600, 50, 200, 10), // Target value (KeyValue) 
        KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2.5))) // KeyTime 
       ); 

只需使用一個線性或SplineRectKeyFrame,設置持續時間/ Keytime和值,您 需要。要獲得比例尺,需要計算最終寬度/高度並設置它,但這不應該成爲問題。我能想到的

+0

嗯,這將是巨大的,但我真的不能使用這些關鍵幀與MatrixTransform AFAIK。我可以將動畫分成兩部分(縮放和轉換),但不會同時出現 – Homde 2010-01-01 15:08:04

0

一種方法是矩陣轉換爲TransformGroup包含ScaleTransformRotateTransformTranslateTransform,然後進行動畫處理這些使用普通的動畫,那麼一旦動畫完成,再次從價值創造的矩陣在每個變換中?

+0

這與改變MatrixTransform不同。我只知道,因爲我最初嘗試過,並且不起作用! – Jeff 2014-03-21 00:25:30

1

我已經實現了MatrixAnimation類,它支持平滑的平移,縮放和旋轉動畫。它也支持緩動功能!找到它here

1

我喜歡@LukeN答案。適用於簡單的平移/縮放動畫。
我對此代碼添加了緩動(手工製作,而不是WPF本機緩動)。

private double Sigmoid(double v) 
{ 
    double t = -6 + (v * 12.0); 
    return 1.0/(1.0 + Math.Exp(-t)); 
} 

private double EaseIn(double v) 
{ 
    return 2.0 * Sigmoid(v/2.0); 
} 

private double EaseOut(double v) 
{ 
    return 2.0 * (Sigmoid(0.5 + v/2.0) - 0.5); 
} 

然後在GetCurrentValueprogress = Sigmoid(progress)EaseIn(progress) ...