cubic 2D
parent
a4123f9c03
commit
a51e7003fe
|
@ -0,0 +1,57 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using MoonTools.Core.Curve.Extensions;
|
||||||
|
|
||||||
|
namespace MoonTools.Core.Curve
|
||||||
|
{
|
||||||
|
public struct CubicBezierCurve2D
|
||||||
|
{
|
||||||
|
public Vector2 p0;
|
||||||
|
public Vector2 p1;
|
||||||
|
public Vector2 p2;
|
||||||
|
public Vector2 p3;
|
||||||
|
|
||||||
|
public CubicBezierCurve2D(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
|
||||||
|
{
|
||||||
|
this.p0 = p0;
|
||||||
|
this.p1 = p1;
|
||||||
|
this.p2 = p2;
|
||||||
|
this.p3 = p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2 Point(float t) => Point(p0, p1, p2, p3, t);
|
||||||
|
public Vector2 Point(float t, float minT, float maxT) => Point(p0, p1, p2, p3, t, minT, maxT);
|
||||||
|
public Vector2 Velocity(float t) => Velocity(p0, p1, p2, p3, t);
|
||||||
|
public Vector2 Velocity(float t, float minT, float maxT) => Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT));
|
||||||
|
public static Vector2 Point(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
|
||||||
|
{
|
||||||
|
return CubicBezierCurve3D.Point(
|
||||||
|
new Vector3(p0.X, p0.Y, 0),
|
||||||
|
new Vector3(p1.X, p1.Y, 0),
|
||||||
|
new Vector3(p2.X, p2.Y, 0),
|
||||||
|
new Vector3(p3.X, p3.Y, 0),
|
||||||
|
t
|
||||||
|
).XY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2 Point(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t, float minT, float maxT)
|
||||||
|
{
|
||||||
|
return Point(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2 Velocity(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
|
||||||
|
{
|
||||||
|
return CubicBezierCurve3D.Velocity(
|
||||||
|
new Vector3(p0.X, p0.Y, 0),
|
||||||
|
new Vector3(p1.X, p1.Y, 0),
|
||||||
|
new Vector3(p2.X, p2.Y, 0),
|
||||||
|
new Vector3(p3.X, p3.Y, 0),
|
||||||
|
t
|
||||||
|
).XY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector2 Velocity(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t, float minT, float maxT)
|
||||||
|
{
|
||||||
|
return Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,9 +21,9 @@ namespace MoonTools.Core.Curve
|
||||||
|
|
||||||
public Vector3 Point(float t, float minT, float maxT) => Point(p0, p1, p2, p3, t, minT, maxT);
|
public Vector3 Point(float t, float minT, float maxT) => Point(p0, p1, p2, p3, t, minT, maxT);
|
||||||
|
|
||||||
public Vector3 Velocity(float t) => FirstDerivative(p0, p1, p2, p3, t);
|
public Vector3 Velocity(float t) => Velocity(p0, p1, p2, p3, t);
|
||||||
|
|
||||||
public Vector3 Velocity(float t, float minT, float maxT) => FirstDerivative(p0, p1, p2, p3, t, minT, maxT);
|
public Vector3 Velocity(float t, float minT, float maxT) => Velocity(p0, p1, p2, p3, t, minT, maxT);
|
||||||
|
|
||||||
public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||||
{
|
{
|
||||||
|
@ -37,10 +37,10 @@ namespace MoonTools.Core.Curve
|
||||||
|
|
||||||
public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float minT, float maxT)
|
public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float minT, float maxT)
|
||||||
{
|
{
|
||||||
return Point(p0, p1, p2, p3, Normalized(t, minT, maxT));
|
return Point(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 FirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
|
||||||
{
|
{
|
||||||
if (t < 0 || t > 1) { throw new System.ArgumentException($"{t} is an invalid value. Must be between 0 and 1"); }
|
if (t < 0 || t > 1) { throw new System.ArgumentException($"{t} is an invalid value. Must be between 0 and 1"); }
|
||||||
|
|
||||||
|
@ -49,11 +49,9 @@ namespace MoonTools.Core.Curve
|
||||||
3f * t * t * (p3 - p2);
|
3f * t * t * (p3 - p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 FirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float minT, float maxT)
|
public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float minT, float maxT)
|
||||||
{
|
{
|
||||||
return FirstDerivative(p0, p1, p2, p3, Normalized(t, minT, maxT));
|
return Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float Normalized(float t, float minT, float maxT) => ((t - minT)) / (maxT - minT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace MoonTools.Core.Curve.Extensions
|
||||||
|
{
|
||||||
|
public static class Vector2Extensions
|
||||||
|
{
|
||||||
|
public static Vector2 XY(this Vector3 vector) => new Vector2(vector.X, vector.Y);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace MoonTools.Core.Curve
|
||||||
|
{
|
||||||
|
public static class TimeHelper
|
||||||
|
{
|
||||||
|
public static float Normalized(float t, float minT, float maxT) => ((t - minT)) / (maxT - minT);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
using MoonTools.Core.Curve;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
public class CubicBezierCurve2DTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Point()
|
||||||
|
{
|
||||||
|
var p0 = new Vector2(-4, -4);
|
||||||
|
var p1 = new Vector2(-2, 4);
|
||||||
|
var p2 = new Vector2(2, -4);
|
||||||
|
var p3 = new Vector2(4, 4);
|
||||||
|
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 0.5f).Should().BeEquivalentTo(new Vector2(0, 0));
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 0.5f).Should().BeEquivalentTo(new Vector2(0, 0));
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 0.25f).Should().BeEquivalentTo(new Vector2(-2.1875f, -0.5f));
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 0.75f).Should().BeEquivalentTo(new Vector2(2.1875f, 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PointNormalized()
|
||||||
|
{
|
||||||
|
var p0 = new Vector2(-4, -4);
|
||||||
|
var p1 = new Vector2(-2, 4);
|
||||||
|
var p2 = new Vector2(2, -4);
|
||||||
|
var p3 = new Vector2(4, 4);
|
||||||
|
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 3, 2, 4).Should().BeEquivalentTo(new Vector2(0, 0));
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 2, 1, 5).Should().BeEquivalentTo(new Vector2(-2.1875f, -0.5f));
|
||||||
|
CubicBezierCurve2D.Point(p0, p1, p2, p3, 11, 2, 14).Should().BeEquivalentTo(new Vector2(2.1875f, 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Velocity()
|
||||||
|
{
|
||||||
|
var p0 = new Vector2(-4, -4);
|
||||||
|
var p1 = new Vector2(-2, 4);
|
||||||
|
var p2 = new Vector2(2, -4);
|
||||||
|
var p3 = new Vector2(4, 4);
|
||||||
|
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 0.5f).Should().BeEquivalentTo(new Vector2(9, 0));
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 0.25f).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 0.75f).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VelocityNormalized()
|
||||||
|
{
|
||||||
|
var p0 = new Vector2(-4, -4);
|
||||||
|
var p1 = new Vector2(-2, 4);
|
||||||
|
var p2 = new Vector2(2, -4);
|
||||||
|
var p3 = new Vector2(4, 4);
|
||||||
|
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 3, 2, 4).Should().BeEquivalentTo(new Vector2(9, 0));
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 2, 1, 5).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
CubicBezierCurve2D.Velocity(p0, p1, p2, p3, 11, 2, 14).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CubicBezierCurve2DStructTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Point()
|
||||||
|
{
|
||||||
|
var myCurve = new CubicBezierCurve2D(
|
||||||
|
new Vector2(-4, -4),
|
||||||
|
new Vector2(-2, 4),
|
||||||
|
new Vector2(2, -4),
|
||||||
|
new Vector2(4, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
myCurve.Point(0.5f).Should().BeEquivalentTo(new Vector2(0, 0));
|
||||||
|
myCurve.Point(0.25f).Should().BeEquivalentTo(new Vector2(-2.1875f, -0.5f));
|
||||||
|
myCurve.Point(0.75f).Should().BeEquivalentTo(new Vector2(2.1875f, 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PointNormalized()
|
||||||
|
{
|
||||||
|
var myCurve = new CubicBezierCurve2D(
|
||||||
|
new Vector2(-4, -4),
|
||||||
|
new Vector2(-2, 4),
|
||||||
|
new Vector2(2, -4),
|
||||||
|
new Vector2(4, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
myCurve.Point(3, 2, 4).Should().BeEquivalentTo(new Vector2(0, 0));
|
||||||
|
myCurve.Point(2, 1, 5).Should().BeEquivalentTo(new Vector2(-2.1875f, -0.5f));
|
||||||
|
myCurve.Point(11, 2, 14).Should().BeEquivalentTo(new Vector2(2.1875f, 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Velocity()
|
||||||
|
{
|
||||||
|
var myCurve = new CubicBezierCurve2D(
|
||||||
|
new Vector2(-4, -4),
|
||||||
|
new Vector2(-2, 4),
|
||||||
|
new Vector2(2, -4),
|
||||||
|
new Vector2(4, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
myCurve.Velocity(0.5f).Should().BeEquivalentTo(new Vector2(9, 0));
|
||||||
|
myCurve.Velocity(0.25f).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
myCurve.Velocity(0.75f).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void VelocityNormalized()
|
||||||
|
{
|
||||||
|
var myCurve = new CubicBezierCurve2D(
|
||||||
|
new Vector2(-4, -4),
|
||||||
|
new Vector2(-2, 4),
|
||||||
|
new Vector2(2, -4),
|
||||||
|
new Vector2(4, 4)
|
||||||
|
);
|
||||||
|
|
||||||
|
myCurve.Velocity(3, 2, 4).Should().BeEquivalentTo(new Vector2(9, 0));
|
||||||
|
myCurve.Velocity(2, 1, 5).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
myCurve.Velocity(11, 2, 14).Should().BeEquivalentTo(new Vector2(8.25f, 6f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,29 +36,29 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void FirstDerivative()
|
public void Velocity()
|
||||||
{
|
{
|
||||||
var p0 = new Vector3(-4, -4, -3);
|
var p0 = new Vector3(-4, -4, -3);
|
||||||
var p1 = new Vector3(-2, 4, 0);
|
var p1 = new Vector3(-2, 4, 0);
|
||||||
var p2 = new Vector3(2, -4, 3);
|
var p2 = new Vector3(2, -4, 3);
|
||||||
var p3 = new Vector3(4, 4, 0);
|
var p3 = new Vector3(4, 4, 0);
|
||||||
|
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 0.5f).Should().BeEquivalentTo(new Vector3(9, 0, 4.5f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 0.5f).Should().BeEquivalentTo(new Vector3(9, 0, 4.5f));
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 0.25f).Should().BeEquivalentTo(new Vector3(8.25f, 6f, 7.875f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 0.25f).Should().BeEquivalentTo(new Vector3(8.25f, 6f, 7.875f));
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 0.75f).Should().BeEquivalentTo(new Vector3(8.25f, 6f, -1.125f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 0.75f).Should().BeEquivalentTo(new Vector3(8.25f, 6f, -1.125f));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void FirstDerivativeNormalized()
|
public void VelocityNormalized()
|
||||||
{
|
{
|
||||||
var p0 = new Vector3(-4, -4, -3);
|
var p0 = new Vector3(-4, -4, -3);
|
||||||
var p1 = new Vector3(-2, 4, 0);
|
var p1 = new Vector3(-2, 4, 0);
|
||||||
var p2 = new Vector3(2, -4, 3);
|
var p2 = new Vector3(2, -4, 3);
|
||||||
var p3 = new Vector3(4, 4, 0);
|
var p3 = new Vector3(4, 4, 0);
|
||||||
|
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 3, 2, 4).Should().BeEquivalentTo(new Vector3(9, 0, 4.5f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 3, 2, 4).Should().BeEquivalentTo(new Vector3(9, 0, 4.5f));
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 2, 1, 5).Should().BeEquivalentTo(new Vector3(8.25f, 6f, 7.875f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 2, 1, 5).Should().BeEquivalentTo(new Vector3(8.25f, 6f, 7.875f));
|
||||||
CubicBezierCurve3D.FirstDerivative(p0, p1, p2, p3, 11, 2, 14).Should().BeEquivalentTo(new Vector3(8.25f, 6f, -1.125f));
|
CubicBezierCurve3D.Velocity(p0, p1, p2, p3, 11, 2, 14).Should().BeEquivalentTo(new Vector3(8.25f, 6f, -1.125f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue