KeySpline.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / Media / Animation / KeySpline.cs / 1 / KeySpline.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation, 2001
//
//  File:       KeySpline.cs 
//-----------------------------------------------------------------------------
 
// Allow suppression of certain presharp messages 
#pragma warning disable 1634, 1691
 
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization; 
using System.Runtime.InteropServices;
 
using SR=MS.Internal.PresentationCore.SR; 
using SRID=MS.Internal.PresentationCore.SRID;
 
namespace System.Windows.Media.Animation
{
    /// 
    /// This class is used by a SplineKeyFrame to define a key frame animation. 
    /// 
    ///  
    /// Example of a SplineKeyFrame class: SplineDoubleKeyFrame. 
    /// Example of a key frame animation class: DoubleAnimationUsingKeyFrames.
    ///  
    [TypeConverter(typeof(KeySplineConverter))]
    [Localizability(LocalizationCategory.None, Readability=Readability.Unreadable)]
    public class KeySpline : Freezable, IFormattable
    { 
        #region Constructors
 
        ///  
        /// Creates a new KeySpline.
        ///  
        /// 
        /// Default values for control points are (0,0) and (1,1) which will
        /// have no effect on the progress of an animation or key frame.
        ///  
        public KeySpline()
            : base() 
        { 
            _controlPoint1 = new Point(0.0, 0.0);
            _controlPoint2 = new Point(1.0, 1.0); 
        }

        /// 
        /// Double constructor 
        /// 
        /// x value for the 0,0 endpoint's control point 
        /// y value for the 0,0 endpoint's control point 
        /// x value for the 1,1 endpoint's control point
        /// y value for the 1,1 endpoint's control point 
        public KeySpline(double x1, double y1, double x2, double y2)
            : this(new Point(x1, y1), new Point(x2, y2))
        {
        } 

        ///  
        /// Point constructor 
        /// 
        /// the control point for the 0,0 endpoint 
        /// the control point for the 1,1 endpoint
        public KeySpline(Point controlPoint1, Point controlPoint2)
            : base()
        { 
            if (!IsValidControlPoint(controlPoint1))
            { 
                throw new ArgumentException(SR.Get( 
                    SRID.Animation_KeySpline_InvalidValue,
                    "controlPoint1", 
                    controlPoint1));
            }

            if (!IsValidControlPoint(controlPoint2)) 
            {
                throw new ArgumentException(SR.Get( 
                    SRID.Animation_KeySpline_InvalidValue, 
                    "controlPoint2",
                    controlPoint2)); 
            }

            _controlPoint1 = controlPoint1;
            _controlPoint2 = controlPoint2; 

            _isDirty = true; 
        } 

        #endregion Constructors 

        #region Freezable

        ///  
        /// Implementation of Freezable.CreateInstanceCore.
        ///  
        /// The new Freezable. 
        protected override Freezable CreateInstanceCore()
        { 
            return new KeySpline();
        }

        ///  
        /// Implementation of Freezable.CloneCore.
        ///  
        /// The KeySpline to copy. 
        protected override void CloneCore(Freezable sourceFreezable)
        { 
            KeySpline sourceKeySpline = (KeySpline) sourceFreezable;
            base.CloneCore(sourceFreezable);
            CloneCommon(sourceKeySpline);
        } 

        ///  
        /// Implementation of Freezable.CloneCurrentValueCore. 
        /// 
        /// The KeySpline to copy. 
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            KeySpline sourceKeySpline = (KeySpline) sourceFreezable;
            base.CloneCurrentValueCore(sourceFreezable); 
            CloneCommon(sourceKeySpline);
        } 
 
        /// 
        /// Implementation of Freezable.GetAsFrozenCore. 
        /// 
        /// The KeySpline to copy.
        protected override void GetAsFrozenCore(Freezable sourceFreezable)
        { 
            KeySpline sourceKeySpline = (KeySpline) sourceFreezable;
            base.GetAsFrozenCore(sourceFreezable); 
            CloneCommon(sourceKeySpline); 
        }
 
        /// 
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore.
        /// 
        /// The KeySpline to copy. 
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
        { 
            KeySpline sourceKeySpline = (KeySpline)sourceFreezable; 
            base.GetCurrentValueAsFrozenCore(sourceFreezable);
            CloneCommon(sourceKeySpline); 
        }

        /// 
        /// Implementation of Freezable.OnChanged. 
        /// 
        protected override void OnChanged() 
        { 
            _isDirty = true;
 
            base.OnChanged();
        }

        #endregion 

        #region Public 
 
        /// 
        /// 
        /// 
        public Point ControlPoint1
        {
            get 
            {
                ReadPreamble(); 
 
                return _controlPoint1;
            } 
            set
            {
                WritePreamble();
 
                if (value != _controlPoint1)
                { 
                    if (!IsValidControlPoint(value)) 
                    {
                        throw new ArgumentException(SR.Get( 
                            SRID.Animation_KeySpline_InvalidValue,
                            "ControlPoint1",
                            value));
                    } 

                    _controlPoint1 = value; 
 
                    WritePostscript();
                } 
            }
        }

        ///  
        ///
        ///  
        public Point ControlPoint2 
        {
            get 
            {
                ReadPreamble();

                return _controlPoint2; 
            }
            set 
            { 
                WritePreamble();
 
                if (value != _controlPoint2)
                {
                    if (!IsValidControlPoint(value))
                    { 
                        throw new ArgumentException(SR.Get(
                            SRID.Animation_KeySpline_InvalidValue, 
                            "ControlPoint2", 
                            value));
                    } 

                    _controlPoint2 = value;

                    WritePostscript(); 
                }
            } 
        } 

        ///  
        /// Calculates spline progress from a linear progress.
        /// 
        /// the linear progress
        /// the spline progress 
        public double GetSplineProgress(double linearProgress)
        { 
            ReadPreamble(); 

            if (_isDirty) 
            {
                Build();
            }
 
            if (!_isSpecified)
            { 
                return linearProgress; 
            }
            else 
            {
                SetParameterFromX(linearProgress);

                return GetBezierValue(_By, _Cy, _parameter); 
            }
        } 
 
        #endregion
 
        #region Private

        private bool IsValidControlPoint(Point point)
        { 
            return point.X >= 0.0
                && point.X <= 1.0 
                && point.Y >= 0.0 
                && point.Y <= 1.0;
        } 

        /// 
        /// Compute cached coefficients.
        ///  
        private void Build()
        { 
            Debug.Assert(_isDirty); 

            if (   _controlPoint1 == new Point(0, 0) 
                && _controlPoint2 == new Point(1, 1))
            {
                // This KeySpline would have no effect on the progress.
 
                _isSpecified = false;
            } 
            else 
            {
                _isSpecified = true; 

                _parameter = 0;

                // X coefficients 
                _Bx = 3 * _controlPoint1.X;
                _Cx = 3 * _controlPoint2.X; 
                _Cx_Bx = 2 * (_Cx - _Bx); 
                _three_Cx = 3 - _Cx;
 
                // Y coefficients
                _By = 3 * _controlPoint1.Y;
                _Cy = 3 * _controlPoint2.Y;
            } 

            _isDirty = false; 
        } 

        ///  
        /// Get an X or Y value with the Bezier formula.
        /// 
        /// the second Bezier coefficient
        /// the third Bezier coefficient 
        /// the parameter value to evaluate at
        /// the value of the Bezier function at the given parameter 
        static private double GetBezierValue(double b, double c, double t) 
        {
            double s  = 1.0 - t; 
            double t2 = t * t;

            return b * t * s * s + c * t2 * s + t2 * t;
        } 

        ///  
        /// Get X and dX/dt at a given parameter 
        /// 
        /// the parameter value to evaluate at 
        /// the value of x there
        /// the value of dx/dt there
        private void GetXAndDx(double t, out double x, out double dx)
        { 
            Debug.Assert(_isSpecified);
 
            double s  = 1.0 - t; 
            double t2 = t * t;
            double s2 = s * s; 

            x = _Bx * t * s2  +  _Cx * t2 * s  +  t2 * t;
            dx = _Bx * s2  +  _Cx_Bx * s * t  +  _three_Cx * t2;
        } 

        ///  
        /// Compute the parameter value that corresponds to a given X value, using a modified 
        /// clamped Newton-Raphson algorithm to solve the equation X(t) - time = 0. We make
        /// use of some known properties of this particular function: 
        /// * We are only interested in solutions in the interval [0,1]
        /// * X(t) is increasing, so we can assume that if X(t) > time t > solution.  We use
        ///   that to clamp down the search interval with every probe.
        /// * The derivative of X and Y are between 0 and 3. 
        /// 
        /// the time, scaled to fit in [0,1] 
        private void SetParameterFromX(double time) 
        {
            Debug.Assert(_isSpecified); 

            // Dynamic search interval to clamp with
            double bottom = 0;
            double top = 1; 

            if (time == 0) 
            { 
                _parameter = 0;
            } 
            else if (time == 1)
            {
                _parameter = 1;
            } 
            else
            { 
                // Loop while improving the guess 
                while (top - bottom > fuzz)
                { 
                    double x, dx, absdx;

                    // Get x and dx/dt at the current parameter
                    GetXAndDx(_parameter, out x, out dx); 
                    absdx = Math.Abs(dx);
 
                    // Clamp down the search interval, relying on the monotonicity of X(t) 
                    if (x > time)
                    { 
                        top = _parameter;      // because parameter > solution
                    }
                    else
                    { 
                        bottom = _parameter;  // because parameter < solution
                    } 
 
                    // The desired accuracy is in ultimately in y, not in x, so the
                    // accuracy needs to be multiplied by dx/dy = (dx/dt) / (dy/dt). 
                    // But dy/dt <=3, so we omit that
                    if (Math.Abs(x - time) < accuracy * absdx)
                    {
                        break; // We're there 
                    }
 
                    if (absdx > fuzz) 
                    {
                        // Nonzero derivative, use Newton-Raphson to obtain the next guess 
                        double next = _parameter - (x - time) / dx;

                        // If next guess is out of the search interval then clamp it in
                        if (next >= top) 
                        {
                            _parameter = (_parameter + top) / 2; 
                        } 
                        else if (next <= bottom)
                        { 
                            _parameter = (_parameter + bottom) / 2;
                        }
                        else
                        { 
                            // Next guess is inside the search interval, accept it
                            _parameter = next; 
                        } 
                    }
                    else    // Zero derivative, halve the search interval 
                    {
                        _parameter = (bottom + top) / 2;
                    }
                } 
            }
        } 
 

        ///  
         /// Copy the common fields for the various Clone methods
        /// 
        /// The KeySpline to copy.
        private void CloneCommon(KeySpline sourceKeySpline) 
        {
            _controlPoint1 = sourceKeySpline._controlPoint1; 
            _controlPoint2 = sourceKeySpline._controlPoint2; 
            _isDirty = true;
        } 

        #endregion

        #region IFormattable 

        ///  
        /// Creates a string representation of this KeySpline based on the current culture. 
        /// 
        ///  
        /// A string representation of this KeySpline.
        /// 
        public override string ToString()
        { 
            ReadPreamble();
 
            return InternalConvertToString(null, null); 
        }
 
        /// 
        /// Creates a string representation of this KeySpline based on the IFormatProvider
        /// passed in.
        ///  
        /// 
        /// The format provider to use.  If the provider is null, the CurrentCulture is used. 
        ///  
        /// 
        /// A string representation of this KeySpline. 
        /// 
        public string ToString(IFormatProvider formatProvider)
        {
            ReadPreamble(); 

            return InternalConvertToString(null, formatProvider); 
        } 

        ///  
        /// Creates a string representation of this KeySpline based on the IFormatProvider
        /// passed in.
        /// 
        ///  
        /// The format string to use.
        ///  
        ///  
        /// The format provider to use.  If the provider is null, the CurrentCulture is used.
        ///  
        /// 
        /// A string representation of this KeySpline.
        /// 
        string IFormattable.ToString(string format, IFormatProvider formatProvider) 
        {
            ReadPreamble(); 
 
            return InternalConvertToString(format, formatProvider);
        } 

        /// 
        /// Creates a string representation of this KeySpline based on the IFormatProvider
        /// passed in. 
        /// 
        ///  
        /// The format string to use. 
        /// 
        ///  
        /// The format provider to use.  If the provider is null, the CurrentCulture is used.
        /// 
        /// 
        /// A string representation of this KeySpline. 
        /// 
        internal string InternalConvertToString(string format, IFormatProvider formatProvider) 
        { 
            // Helper to get the numeric list separator for a given culture.
            char separator = MS.Internal.TokenizerHelper.GetNumericListSeparator(formatProvider); 

            return String.Format(
                formatProvider,
                "{1}{0}{2}", 
                separator,
                _controlPoint1, 
                _controlPoint2); 
        }
 
        #endregion

        #region Data
 
        //
 
 

 

        // Control points
        private Point _controlPoint1;
        private Point _controlPoint2; 
        private bool _isSpecified;
        private bool _isDirty; 
 
        // The parameter that corresponds to the most recent time
        private    double     _parameter; 

        // Cached coefficients
        private double _Bx;        // 3*points[0].X
        private double _Cx;        // 3*points[1].X 
        private double _Cx_Bx;     // 2*(Cx - Bx)
        private double _three_Cx;  // 3 - Cx 
 
        private double _By;        // 3*points[0].Y
        private double _Cy;        // 3*points[1].Y 

        // constants
        private const double accuracy = .001;   // 1/3 the desired accuracy in X
        private const double fuzz = .000001;    // computational zero 

        #endregion 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK