SlerpController.cs
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:4k
源码类别:

SilverLight

开发平台:

C#

  1. // Silver.Globe, version 0.11 for Silverlight 1.1 Alpha
  2. // Copyright © Florian Krüsch (xaml-kru.com)
  3. // xaml-kru.com/silverglobe
  4. // This source is subject to the Microsoft Public License (Ms-PL).
  5. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx.
  6. // All other rights reserved.
  7. using System;
  8. using SilverGlobe.Math3D;
  9. namespace SilverGlobe
  10. {
  11.     internal delegate Quaternion SlerpMethod(Double n);
  12.     /// <summary>
  13.     /// SlerpController controls the globe by rotating it towards another quaternion
  14.     /// performing a spherical linear interpolation.
  15.     /// </summary>
  16.     internal sealed class SlerpController
  17.     {
  18.         #region Members
  19.         private DateTime _startTime;
  20.         private Globe _globe;
  21.         public Globe Globe
  22.         {
  23.             get { return _globe; }
  24.             set { _globe = value; }
  25.         }
  26.         private Quaternion _start;
  27.         private Quaternion _end;
  28.         private Double _timeFactor;
  29.         private const Double ThresholdToLinear = 0.9995;
  30.         private SlerpMethod _doSlerp;
  31.         #endregion
  32.         #region Events
  33.         public event EventHandler SlerpCompleted;
  34.         #endregion
  35.         #region Constructor
  36.         public SlerpController(Globe globe)
  37.         {
  38.             _globe = globe;
  39.         }
  40.         #endregion
  41.         #region Methods
  42.         /// <summary>
  43.         /// Start controlling the globe.
  44.         /// </summary>
  45.         public void Init(Quaternion target)
  46.         {
  47.             _start = _globe.Orientation;
  48.             _end = target;
  49.             _startTime = DateTime.Now;
  50.             // inner product
  51.             Double dotProduct = _start.Dot(_end).Clamp(-1, 1);
  52.             // is linear sufficient?
  53.             if (dotProduct > ThresholdToLinear)
  54.             {
  55.                 _timeFactor = 1;
  56.                 // set strategy to linear
  57.                 _doSlerp = (Double u) =>
  58.                 {
  59.                     if (u >= 1) return _end;
  60.                     Quaternion q = _start + (_end - _start) * u;
  61.                     q.Normalize();
  62.                     return q;
  63.                 };
  64.             }
  65.             else
  66.             {
  67.                 Double angle = Math.Acos(dotProduct);
  68.                 Quaternion q;
  69.                 if (angle > (Math.PI / 2))
  70.                 {
  71.                     // left
  72.                     angle = Math.PI - angle;
  73.                     q = _start * dotProduct - _end;
  74.                 }
  75.                 else
  76.                 {
  77.                     // right
  78.                     q = _end - _start * dotProduct;
  79.                 }
  80.                 q.Normalize();
  81.                 _timeFactor = Math.Sqrt((Math.PI / 2) / angle);
  82.                 _doSlerp = (Double u) =>
  83.                 {
  84.                     if (u >= 1) return _end;
  85.                     Double t = angle * u;
  86.                     return _start * Math.Cos(t) + q * Math.Sin(t);
  87.                 };
  88.             }
  89.         }
  90.         #endregion
  91.         #region Implementation
  92.         /// <summary>
  93.         /// Perform update calculations
  94.         /// </summary>
  95.         public void Update()
  96.         {
  97.             // calc time factor 
  98.             TimeSpan ts = DateTime.Now - _startTime;
  99.             Double n = (ts.TotalSeconds) * 0.6 * _timeFactor;
  100.             if (n > 1) n = 1;
  101.             n = 0.5 + Math.Sin((n - 0.5) * Math.PI) * 0.5;
  102.             n = Math.Sqrt(n);
  103.             // perform slerp
  104.             _globe.Orientation = _doSlerp(n);
  105.             if (n == 1)
  106.             {
  107.                 // fire completed event
  108.                 if (SlerpCompleted != null)
  109.                 {
  110.                     EventHandler h = SlerpCompleted;
  111.                     h(this, EventArgs.Empty);
  112.                 }
  113.             }
  114.         }
  115.         #endregion
  116.     }
  117. }