271 lines
12 KiB
C#
271 lines
12 KiB
C#
using T3.Core.Animation;
|
|
using T3.Core.DataTypes;
|
|
using Xunit;
|
|
|
|
namespace Core.Tests;
|
|
|
|
public class CurveInterpolationTests
|
|
{
|
|
[Fact]
|
|
public void LinearToLinear_InterpolatesLinearly()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 0.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 1.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
Assert.Equal(0.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(0.25, curve.GetSampledValue(0.25), 4);
|
|
Assert.Equal(0.5, curve.GetSampledValue(0.5), 4);
|
|
Assert.Equal(0.75, curve.GetSampledValue(0.75), 4);
|
|
Assert.Equal(1.0, curve.GetSampledValue(1.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void LinearToLinear_NegativeSlope()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 10.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 0.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
Assert.Equal(10.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(5.0, curve.GetSampledValue(0.5), 4);
|
|
Assert.Equal(0.0, curve.GetSampledValue(1.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void CollinearSmoothKeys_FormStraightLine()
|
|
{
|
|
// Three points on y=x: [0,0] -> [0.5,0.5] -> [1,1]
|
|
// With smooth interpolation, collinear points should produce a straight line
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 0.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
curve.AddOrUpdateV(0.5, new VDefinition
|
|
{
|
|
Value = 0.5,
|
|
InInterpolation = VDefinition.KeyInterpolation.Smooth,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 1.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
// Sample at multiple points — should all lie on y=x
|
|
Assert.Equal(0.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(0.125, curve.GetSampledValue(0.125), 4);
|
|
Assert.Equal(0.25, curve.GetSampledValue(0.25), 4);
|
|
Assert.Equal(0.5, curve.GetSampledValue(0.5), 4);
|
|
Assert.Equal(0.75, curve.GetSampledValue(0.75), 4);
|
|
Assert.Equal(0.875, curve.GetSampledValue(0.875), 4);
|
|
Assert.Equal(1.0, curve.GetSampledValue(1.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConstantToConstant_HoldsFirstValue()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 3.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 7.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
|
|
// Should hold 3.0 for everything before the second key
|
|
Assert.Equal(3.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(3.0, curve.GetSampledValue(0.25), 4);
|
|
Assert.Equal(3.0, curve.GetSampledValue(0.5), 4);
|
|
Assert.Equal(3.0, curve.GetSampledValue(0.999), 4);
|
|
// At exactly the second key, should snap to 7.0
|
|
Assert.Equal(7.0, curve.GetSampledValue(1.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void ConstantToConstant_MultipleKeys()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 1.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 5.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
curve.AddOrUpdateV(2.0, new VDefinition
|
|
{
|
|
Value = 9.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
|
|
Assert.Equal(1.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(1.0, curve.GetSampledValue(0.5), 4);
|
|
Assert.Equal(5.0, curve.GetSampledValue(1.0), 4);
|
|
Assert.Equal(5.0, curve.GetSampledValue(1.5), 4);
|
|
Assert.Equal(9.0, curve.GetSampledValue(2.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void BeforeFirstKey_ReturnsFirstValue()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 42.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
Assert.Equal(42.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(42.0, curve.GetSampledValue(-10.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void AfterLastKey_ReturnsLastValue()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 3.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 7.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
Assert.Equal(7.0, curve.GetSampledValue(2.0), 4);
|
|
Assert.Equal(7.0, curve.GetSampledValue(100.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void SingleKey_ReturnsThatValueEverywhere()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(5.0, new VDefinition
|
|
{
|
|
Value = 42.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Smooth,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Smooth,
|
|
});
|
|
|
|
Assert.Equal(42.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(42.0, curve.GetSampledValue(5.0), 4);
|
|
Assert.Equal(42.0, curve.GetSampledValue(10.0), 4);
|
|
}
|
|
|
|
[Fact]
|
|
public void EmptyCurve_ReturnsZero()
|
|
{
|
|
var curve = new Curve();
|
|
|
|
Assert.Equal(0.0, curve.GetSampledValue(0.0));
|
|
Assert.Equal(0.0, curve.GetSampledValue(1.0));
|
|
}
|
|
|
|
[Fact]
|
|
public void EqualEndpoints_WithUpwardTangents_ProducesOvershoot()
|
|
{
|
|
// Two keys at same value with tangents both pointing upward —
|
|
// spline interpolation should overshoot above 5.0 (intentional behavior).
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 5.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Tangent,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Tangent,
|
|
InTangentAngle = 0.0,
|
|
OutTangentAngle = 0.7854, // ~45 degrees up
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 5.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Tangent,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Tangent,
|
|
InTangentAngle = Math.PI - 0.7854, // ~135 degrees = coming from above
|
|
OutTangentAngle = 0.0,
|
|
});
|
|
|
|
// Endpoints must be exactly 5.0
|
|
Assert.Equal(5.0, curve.GetSampledValue(0.0), 4);
|
|
Assert.Equal(5.0, curve.GetSampledValue(1.0), 4);
|
|
|
|
// Midpoint should be above 5.0 due to both tangents pushing upward
|
|
var mid = curve.GetSampledValue(0.5);
|
|
Assert.True(mid > 5.1, $"Expected overshoot above 5.0, got {mid}");
|
|
}
|
|
|
|
[Fact]
|
|
public void MixedInterpolation_ConstantThenLinear()
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddOrUpdateV(0.0, new VDefinition
|
|
{
|
|
Value = 1.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Constant,
|
|
});
|
|
curve.AddOrUpdateV(1.0, new VDefinition
|
|
{
|
|
Value = 3.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
curve.AddOrUpdateV(2.0, new VDefinition
|
|
{
|
|
Value = 5.0,
|
|
InInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
OutInterpolation = VDefinition.KeyInterpolation.Linear,
|
|
});
|
|
|
|
// First segment: constant hold
|
|
Assert.Equal(1.0, curve.GetSampledValue(0.5), 4);
|
|
// At key 1: snap to 3.0
|
|
Assert.Equal(3.0, curve.GetSampledValue(1.0), 4);
|
|
// Second segment: linear 3→5
|
|
Assert.Equal(4.0, curve.GetSampledValue(1.5), 4);
|
|
Assert.Equal(5.0, curve.GetSampledValue(2.0), 4);
|
|
}
|
|
}
|