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); } } }