using System.Collections.Generic;
using UnityEngine;
namespace ARLocation
{
public enum SplineType
{
CatmullromSpline,
LinearSpline,
}
public abstract class Spline
{
///
/// The points interpolated of the spline.
///
public Vector3[] Points { get; protected set; }
///
/// The CatmullRom curve-segments of the spline.
///
protected Curve[] segments;
///
/// The number of segments that make up the spline.
///
protected int segmentCount = 0;
///
/// The full (estimated) length of the spline.
///
public float Length { get; protected set; }
protected float[] lengths;
///
/// Calculate the catmull-rom segments. Also estimates the curve's length.
///
/// The number sample points used to estimate each segment's length.
public abstract void CalculateSegments(int n);
///
/// Returns the point of the spline at a given arc-length.
///
/// The arc-length.
///
public Vector3 GetPointAtArcLength(float s)
{
s = Mathf.Clamp(s, 0, Length);
for (var i = 0; i < segmentCount; i++)
{
if (s <= lengths[i])
{
var offset = i == 0 ? 0 : lengths[i - 1];
return segments[i].GetPointAtLength(s - offset);
}
}
return segments[segmentCount - 1].GetPoint(1);
}
///
/// Returns a CurvePointData whith the point and tangent of the spline
/// at a given arc-length.
///
/// The arc-length.
///
public CurvePointData GetPointAndTangentAtArcLength(float s)
{
s = Mathf.Clamp(s, 0, Length);
for (var i = 0; i < segmentCount; i++)
{
if (s <= lengths[i])
{
var offset = i == 0 ? 0 : lengths[i - 1];
return segments[i].GetPointAndTangentAtLength(s - offset);
}
}
return segments[segmentCount - 1].GetPointAndTangentAtLength(1);
}
///
/// Draws the curve using a given LineRenderer, with points being processed by a given
/// function beforehand.
///
///
///
///
public void DrawCurveWithLineRenderer(LineRenderer renderer, System.Func func, int n = 100)
{
var points = new List();
float s = 0.0f;
while (s <= Length)
{
var pointData = GetPointAndTangentAtArcLength(s);
points.Add(func(pointData.point));
s += Length / (n + 1.0f);
}
var arr = points.ToArray();
renderer.positionCount = arr.Length;
renderer.SetPositions(arr);
}
///
/// Calculates a sample of (N+2) equidistant points along the spline.
///
/// The number of points in the sample will be (N+2).
/// A function that can be used to transform the sampled poins.
///
public Vector3[] SamplePoints(int n, System.Func func)
{
var sample = new Vector3[n + 2];
var delta = Length / (n + 1.0f);
var s = 0.0f;
for (var i = 0; i < (n + 2); i++)
{
sample[i] = func(GetPointAtArcLength(s));
s += delta;
}
return sample;
}
///
/// Calculates a sample of (N+2) equidistant points along the spline.
///
/// The number of points in the sample will be (N+2).
///
public Vector3[] SamplePoints(int n)
{
return SamplePoints(n, (p) => p);
}
///
/// Draw the curve and sample point using Gizmos.
///
public void DrawGizmos()
{
DrawPointsGizmos();
DrawCurveLengthGizmos();
}
private void DrawPointsGizmos()
{
foreach (var p in Points)
{
Gizmos.color = Color.blue;
Gizmos.DrawSphere(p, 0.1f);
}
}
private void DrawCurveLengthGizmos()
{
var p = GetPointAtArcLength(0f);
float s = 0.0f;
while (s <= Length)
{
Gizmos.color = Color.green;
var pointData = GetPointAndTangentAtArcLength(s);
Vector3 n = pointData.point;
Gizmos.DrawLine(p, n);
p = n;
s += 0.1f;
Gizmos.color = Color.magenta;
var tan = pointData.tangent;
Gizmos.color = Color.blue;
Gizmos.DrawLine(n, n + tan);
}
}
}
}