SND\AstrorEnales_cp 5505f7dcbf - Added PlatformSystem Plugins layer
- Started Windows, Metro and Linux Platform-Plugins
- Moved the RecordingSample to the Samples folder
- Started two samples for using the graphics device in a WinForms and Wpf Editor
- Refactorings in the AddIn-System
- Moved the Window initialization-code to the Platform modules
- Changed the License text in all code files which is now way smaller
- Started ProjectConverter tool which converts all the projects and solution to the target configuration
- Changed the SupportedPlatform names in the Resource files
- Changed the WIN8 define to WINDOWSMETRO which is actually meant
- Removed NLog and started our own Logger class
- Many more stuff...
2012-08-09 09:45:04 +00:00

297 lines
12 KiB
C#

using System;
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework
{
public class Curve
{
private CurveKeyCollection keys;
private CurveLoopType preLoop;
private CurveLoopType postLoop;
public CurveLoopType PreLoop
{
get { return preLoop; }
set { preLoop = value; }
}
public CurveLoopType PostLoop
{
get { return postLoop; }
set { postLoop = value; }
}
public CurveKeyCollection Keys
{
get
{
return keys;
}
}
public Boolean IsConstant
{
get
{
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 < this.keys.Count - 1 ? this.keys[index + 1] : this.keys[index];
switch (tangentInType)
{
case CurveTangent.Flat:
current.TangentIn = 0;
break;
case CurveTangent.Linear:
current.TangentIn = current.Value - prev.Value;
break;
case CurveTangent.Smooth:
current.TangentIn = ((next.Value - prev.Value) * ((current.Position - prev.Position) / (next.Position - prev.Position)));
break;
}
switch (tangentOutType)
{
case CurveTangent.Flat:
current.TangentOut = 0;
break;
case CurveTangent.Linear:
current.TangentOut = next.Value - current.Value;
break;
case CurveTangent.Smooth:
current.TangentOut = ((next.Value - prev.Value) * ((next.Position - current.Position) / (next.Position - prev.Position)));
break;
}
}
public void ComputeTangents(CurveTangent tangentInOutType)
{
for (int i = 0; i < this.keys.Count; ++i)
{
this.ComputeTangent(i, tangentInOutType);
}
}
public void ComputeTangents(CurveTangent tangentInType, CurveTangent tangentOutType)
{
for (int i = 0; i < this.keys.Count; ++i)
{
this.ComputeTangent(i, tangentInType, tangentOutType);
}
}
#endregion
public Single Evaluate(Single position)
{
int wraps;
//Get first and last Point
CurveKey first = keys[0];
float firstPosition = first.Position;
CurveKey last = keys[keys.Count - 1];
float lastPosition = last.Position;
//tspan is min 1 to avoid deadlock at constant curves
float timeSpan = Math.Max(1, lastPosition - firstPosition);
//wanted point before first point
if (position < first.Position)
{
// Description from : http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.curvelooptype.aspx
switch (this.PreLoop)
{
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 first.Value;
case CurveLoopType.Linear:
// Linear interpolation will be performed to determine the value.
return first.Value - first.TangentIn * (first.Position - position);
case CurveLoopType.Cycle:
// Positions specified past the ends of the curve will wrap around to the opposite side of the Curve.
position -= timeSpan * countWraps(position);
return this.interpolate((position));
case CurveLoopType.CycleOffset:
//Positions specified past the ends of the curv 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
wraps = countWraps(position);
float difference = (this.keys[this.keys.Count - 1].Value - this.keys[0].Value) * wraps;
position -= timeSpan * countWraps(position);
return this.interpolate(position) + 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.
wraps = -countWraps(position);
if (wraps % 2 == 1)
{
return this.interpolate(lastPosition - position + firstPosition - (wraps * timeSpan));
}
return this.interpolate(position + (wraps * timeSpan));
}
}
//wanted point behind last point
else if (position > last.Position)
{
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.
position -= timeSpan * countWraps(position);
return this.interpolate((position));
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.
wraps = countWraps(position);
float difference = (this.keys[this.keys.Count - 1].Value - this.keys[0].Value) * wraps;
position -= timeSpan * countWraps(position);
return this.interpolate(position) + 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.
wraps = -countWraps(position);
position += timeSpan * wraps;
if (wraps % 2 == 1)
{
return this.interpolate(lastPosition - position + firstPosition - (wraps * timeSpan));
}
return this.interpolate(position + (wraps * timeSpan));
}
}
//in curve
return interpolate(position);
}
private int countWraps(float position)
{
float wraps = (position - keys[0].Position) / (keys[keys.Count - 1].Position - keys[0].Position);
if (wraps < 0) wraps--;
return (int)wraps;
}
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)
{
if (position == b.Position)
{
return b.Position;
}
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;
}
}
}