diff --git a/Curve/CubicBezierCurve3D.cs b/Curve/CubicBezierCurve3D.cs
index 8ebf5c0..a6c6180 100644
--- a/Curve/CubicBezierCurve3D.cs
+++ b/Curve/CubicBezierCurve3D.cs
@@ -6,7 +6,7 @@ namespace MoonTools.Curve
///
/// A 3-dimensional Bezier curve defined by 4 points.
///
- public struct CubicBezierCurve3D : IEquatable
+ public struct CubicBezierCurve3D : IEquatable, ICurve3D
{
///
/// The start point.
diff --git a/Curve/Curve.csproj b/Curve/Curve.csproj
index ad7b52c..2ec8b03 100644
--- a/Curve/Curve.csproj
+++ b/Curve/Curve.csproj
@@ -19,6 +19,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Curve/ICurve3D.cs b/Curve/ICurve3D.cs
new file mode 100644
index 0000000..cf43e2e
--- /dev/null
+++ b/Curve/ICurve3D.cs
@@ -0,0 +1,10 @@
+using System.Numerics;
+
+namespace MoonTools.Curve
+{
+ public interface ICurve3D
+ {
+ Vector3 Point(float t, float startTime, float endTime);
+ Vector3 Velocity(float t, float startTime, float endTime);
+ }
+}
diff --git a/Curve/QuadraticBezierCurve3D.cs b/Curve/QuadraticBezierCurve3D.cs
index 14da833..ca16092 100644
--- a/Curve/QuadraticBezierCurve3D.cs
+++ b/Curve/QuadraticBezierCurve3D.cs
@@ -6,7 +6,7 @@ namespace MoonTools.Curve
///
/// A 3-dimensional Bezier curve defined by 3 points.
///
- public struct QuadraticBezierCurve3D : IEquatable
+ public struct QuadraticBezierCurve3D : IEquatable, ICurve3D
{
///
/// The start point.
diff --git a/Curve/SplineCurve3D.cs b/Curve/SplineCurve3D.cs
new file mode 100644
index 0000000..38b94db
--- /dev/null
+++ b/Curve/SplineCurve3D.cs
@@ -0,0 +1,60 @@
+using System.Collections.Immutable;
+using System.Numerics;
+
+namespace MoonTools.Curve
+{
+ ///
+ /// A concatenation of 3D curves with time values.
+ ///
+ public struct SplineCurve3D
+ {
+ public ImmutableArray Curves { get; }
+ public ImmutableArray Times { get; }
+ public float TotalTime { get; }
+ public bool Loop { get; }
+
+ public SplineCurve3D(ImmutableArray curves, ImmutableArray times, bool loop = false)
+ {
+ TotalTime = 0;
+
+ for (int i = 0; i < times.Length; i++)
+ {
+ TotalTime += times[i];
+ }
+
+ Curves = curves;
+ Times = times;
+ Loop = loop;
+ }
+
+ public Vector3 Point(float t)
+ {
+ if (!Loop && t >= TotalTime)
+ {
+ var lastIndex = Curves.Length - 1;
+ return Curves[lastIndex].Point(Times[lastIndex], 0, Times[lastIndex]);
+ }
+
+ t %= TotalTime;
+
+ var index = 0;
+ var startTime = 0f;
+ var incrementalTime = 0f;
+
+ for (int i = 0; i < Times.Length; i++)
+ {
+ incrementalTime += Times[i];
+
+ if (t < incrementalTime)
+ {
+ break;
+ }
+
+ index++;
+ startTime = Times[i];
+ }
+
+ return Curves[index].Point(t - startTime, 0, Times[index]);
+ }
+ }
+}