using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
namespace UnityEngine.Splines
{
///
/// SplineSlice represents a partial or complete range of curves from another .
/// A by itself does not store any s. It stores a reference to
/// a separate , then retrieves knots by iterating the .
/// Use in conjunction with to create seamless paths from
/// discrete segments.
///
/// This class is a data structure that defines the range of curves to associate together. This class is not meant to be
/// used intensively for runtime evaluation because it is not performant. Data is not meant to be
/// stored in that struct and that struct is not reactive to spline changes. The GameObject that contains this
/// slice can be scaled and the knots of the targeted spline that can moved around the curve length cannot be stored
/// here so evaluating positions, tangents and up vectors is expensive.
///
/// If performance is a critical requirement, create a new or
/// from the relevant or .
/// Note that you might pass a to constructors for both and .
///
///
/// Iterating a is not as efficient as iterating a or
/// because it does not cache any information. Where performance is a concern, create
/// a new or from the .
///
/// The type of spline that this slice represents.
public struct SplineSlice : ISpline where T : ISpline
{
///
/// The that this Slice will read and
/// data from.
/// A by itself does not store any s. Instead, it references
/// a partial or complete range of existing s.
///
public T Spline;
///
/// An inclusive start index, number of indices, and direction to iterate.
///
public SplineRange Range;
///
/// A transform matrix to be applied to the spline knots and tangents.
///
public float4x4 Transform;
///
/// Return the number of knots in this branch. This function clamps the to the Count of the
/// the referenced .
///
public int Count
{
get
{
if (Spline.Closed)
return math.clamp(Range.Count, 0, Spline.Count + 1);
if (Range.Direction == SliceDirection.Backward)
return math.clamp(Range.Count, 0, Range.Start + 1);
else
return math.clamp(Range.Count, 0, Spline.Count - Range.Start);
}
}
///
/// Whether the spline is open (has a start and end point) or closed (forms an unbroken loop).
///
public bool Closed => false;
static BezierKnot FlipTangents(BezierKnot knot) =>
new BezierKnot(knot.Position, knot.TangentOut, knot.TangentIn, knot.Rotation);
///
/// Get a at the zero-based index of this .
///
/// The index to get.
public BezierKnot this[int index]
{
get
{
int indexFromRange = Range[index];
indexFromRange = (indexFromRange + Spline.Count) % Spline.Count;
return Range.Direction == SliceDirection.Backward
? FlipTangents(Spline[indexFromRange]).Transform(Transform)
: Spline[indexFromRange].Transform(Transform);
}
}
///
/// Get an enumerator that iterates through the collection. Note that this will either
/// increment or decrement indices depending on the value of the .
///
/// An IEnumerator that is used to iterate the collection.
public IEnumerator GetEnumerator()
{
for (int i = 0, c = Range.Count; i < c; ++i)
yield return this[i];
}
///
/// Gets an enumerator that iterates through the collection. It either
/// increments or decrements indices depending on the value of the .
///
/// Returns an IEnumerator that is used to iterate the collection.
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
///
/// Constructor for a new SplineSlice.
///
///
/// The that this Slice will read and
/// data from.
///
/// The start index and count of knot indices that compose this slice.
public SplineSlice(T spline, SplineRange range)
: this(spline, range, float4x4.identity)
{}
///
/// Constructor for a new SplineSlice.
///
///
/// The that this Slice will read and
/// data from.
///
/// The start index and count of knot indices that compose this slice.
/// A transform matrix to be applied to the spline knots and tangents.
public SplineSlice(T spline, SplineRange range, float4x4 transform)
{
Spline = spline;
Range = range;
Transform = transform;
}
///
/// Return the sum of all curve lengths.
///
///
/// It is inefficient to call this method frequently, as it will calculate the length of all curves every time
/// it is invoked. In cases where performance is critical, create a new or
/// instead. Note that you may pass a to constructors
/// for both and .
///
///
///
/// Returns the sum length of all curves composing this spline.
///
public float GetLength()
{
var len = 0f;
for (int i = 0, c = Count; i < c; ++i)
len += GetCurveLength(i);
return len;
}
///
/// Get a from a knot index.
///
/// The knot index that serves as the first control point for this curve.
///
/// A formed by the knot at index and the next knot.
///
public BezierCurve GetCurve(int index)
{
int bi = math.min(math.max(index + 1, 0), Range.Count-1);
BezierKnot a = this[index], b = this[bi];
if (index == bi)
return new BezierCurve(a.Position, b.Position);
return new BezierCurve(a, b);
}
///
/// Return the length of a curve.
///
/// The index of the curve for which the length needs to be retrieved.
///
///
/// The curve length cannot be cached here because the transform matrix associated to this slice might impact that
/// value, like using a non-uniform scale on the GameObject associated with that slice. It is inefficient
/// to call this method frequently, because it calculates the length of the curve every time
/// it is invoked.
/// If performance is a critical requirement, create a new or
/// from the relevant or .
/// Note that you might pass a to constructors for both and .
///
///
/// Returns the length of the curve of index 'index' in the spline.
///
public float GetCurveLength(int index)
{
return CurveUtility.CalculateLength(GetCurve(index));
}
///
/// Return the up vector for a t ratio on the curve.
///
/// The index of the curve for which the length needs to be retrieved.
/// A value between 0 and 1 representing the ratio along the curve.
///
/// It is inefficient to call this method frequently, as it will calculate the up Vector of the curve every time
/// it is invoked. In cases where performance is critical, create a new or
/// instead. Note that you may pass a to constructors
/// for both and .
///
///
/// Returns the up vector at the t ratio of the curve of index 'index'.
///
public float3 GetCurveUpVector(int index, float t)
{
return SplineUtility.CalculateUpVector(this, index, t);
}
///
/// Return the normalized interpolation (t) corresponding to a distance on a .
///
///
/// It is inefficient to call this method frequently, as it will calculate the interpolation lookup table every
/// time it is invoked. In cases where performance is critical, create a new or
/// instead. Note that you may pass a to constructors
/// for both and .
///
/// The zero-based index of the curve.
/// The curve-relative distance to convert to an interpolation ratio (also referred to as 't').
/// The normalized interpolation ratio associated to distance on the designated curve.
public float GetCurveInterpolation(int curveIndex, float curveDistance)
{
return CurveUtility.GetDistanceToInterpolation(GetCurve(curveIndex), curveDistance);
}
}
}