diff --git a/ANX.Framework/Curve.cs b/ANX.Framework/Curve.cs index e4e71bad..e1362f20 100644 --- a/ANX.Framework/Curve.cs +++ b/ANX.Framework/Curve.cs @@ -51,41 +51,26 @@ namespace ANX.Framework { public class Curve { - public Curve Clone() - { - throw new NotImplementedException(); - } + private CurveKeyCollection keys; + private CurveLoopType preLoop; + private CurveLoopType postLoop; - public void ComputeTangent(Int32 value, CurveTangent tangent) - { - throw new NotImplementedException(); - } - public void ComputeTangent(Int32 value, CurveTangent tangent1, CurveTangent tangent2) - { - throw new NotImplementedException(); - } - public void ComputeTangents(CurveTangent tangent) - { - throw new NotImplementedException(); - } - public void ComputeTangents(CurveTangent tangent1, CurveTangent tangent2) - { - throw new NotImplementedException(); - } - public Single Evaluate(Single value) - { - throw new NotImplementedException(); - } public CurveLoopType PreLoop - { get; set; } + { + get { return preLoop; } + set { preLoop = value; } + } public CurveLoopType PostLoop - { get; set; } + { + get { return postLoop; } + set { postLoop = value; } + } public CurveKeyCollection Keys { get { - throw new NotImplementedException(); + return keys; } } @@ -93,8 +78,219 @@ namespace ANX.Framework { get { - throw new NotImplementedException(); + return this.keys.Count <= 1; } } + + public Curve Clone() + { + Curve result = new Curve(); + result.keys = this.keys.Clone(); + result.preLoop = this.preLoop; + result.postLoop = this.postLoop; + return result; + } + public Curve() + { + this.keys = new CurveKeyCollection(); + } + + #region tangent calculation + //formulas from: http://msdn.microsoft.com/de-de/library/microsoft.xna.framework.curvetangent%28v=xnagamestudio.40%29.aspx + public void ComputeTangent(Int32 index, CurveTangent tangentInOutType) + { + if (index < 0 || index > keys.Count) + { + throw new ArgumentOutOfRangeException(); + } + CurveKey prev = index > 0 ? this.keys[index - 1] : this.keys[index]; + CurveKey current = this.keys[index]; + current.TangentIn = 0; + CurveKey next = index < this.keys.Count - 1 ? this.keys[index + 1] : this.keys[index]; + + + switch (tangentInOutType) + { + case CurveTangent.Flat: + current.TangentIn = 0; + current.TangentOut = 0; + break; + case CurveTangent.Linear: + current.TangentIn = current.Value - prev.Value; + current.TangentOut = next.Value - current.Value; + break; + case CurveTangent.Smooth: + current.TangentIn = ((next.Value - prev.Value) * ((current.Position - prev.Position) / (next.Position - prev.Position))); + current.TangentOut = ((next.Value - prev.Value) * ((next.Position - current.Position) / (next.Position - prev.Position))); + break; + } + } + public void ComputeTangent(Int32 index, CurveTangent tangentInType, CurveTangent tangentOutType) + { + if (index < 0 || index > keys.Count) + { + throw new ArgumentOutOfRangeException(); + } + + CurveKey prev = index > 0 ? this.keys[index - 1] : this.keys[index]; + CurveKey current=this.keys[index]; + current.TangentIn = 0; + CurveKey next=index last.Position) + { + int cycle; + switch (this.PostLoop) + { + case CurveLoopType.Constant: + //The Curve will evaluate to its first key for positions before the first point in the Curve and to + //the last key for positions after the last point. + return last.Value; + + case CurveLoopType.Linear: + //Linear interpolation will be performed to determine the value. + return last.Value + last.TangentOut * (position - last.Position); + + case CurveLoopType.Cycle: + // Positions specified past the ends of the curve will wrap around to the opposite side of the Curve. + return this.interpolate(position%timeSpan); + + case CurveLoopType.CycleOffset: + //Positions specified past the ends of the curve will wrap around to the opposite side of the Curve. + //The value will be offset by the difference between the values of the first and last CurveKey + //multiplied by the number of times the position wraps around. If the position is before the first + //point in the Curve, the difference will be subtracted from its value; otherwise, the difference + //will be added. + float difference = (this.keys[this.keys.Count - 1].Value - this.keys[0].Value) * (position / timeSpan); + return this.interpolate(position % timeSpan)+difference; + + case CurveLoopType.Oscillate: + //Positions specified past the ends of the Curve act as an offset from the same side of the Curve + //toward the opposite side. + return this.interpolate(timeSpan - (position % timeSpan)); + } + } + + //in curve + return interpolate(position); + + } + + + private float interpolate(float position) + { + //interpolate inside the curve with cubic hermite: + http://forums.create.msdn.com/forums/p/53392/323814.aspx + + + //assume position is inside curve + CurveKey a = this.keys[0]; + CurveKey b; + for (int i = 1; i < this.keys.Count; i++) + { + b = this.Keys[i]; + if (b.Position >= position) + { + //stepping + if (a.Continuity == CurveContinuity.Step) + { + return a.Value; + } + //smooth + //get the location between a and b in [0,1] + float moment = (position - a.Position) / (b.Position - a.Position); + return MathHelper.Hermite(a.Value, a.TangentOut, b.Value, b.TangentOut, moment); + + } + //get next pair + a = b; + } + return 0f; + } + } }