/// <summary> /// Same as Spline.EvaluatePositions but the results are transformed by the computer's transform /// </summary> /// <param name="from">Start position [0-1]</param> /// <param name="to">Target position [from-1]</param> /// <returns></returns> public void EvaluatePositions(ref Vector3[] positions, double from = 0.0, double to = 1.0) { if (!hasSamples) { positions = new Vector3[0]; return; } Spline.FormatFromTo(ref from, ref to); int fromIndex, toIndex; double lerp; GetSamplingValues(from, out fromIndex, out lerp); GetSamplingValues(to, out toIndex, out lerp); if (lerp > 0.0 && toIndex < Count - 1) { toIndex++; } int clippedIterations = toIndex - fromIndex + 1; if (positions == null) { positions = new Vector3[clippedIterations]; } else if (positions.Length != clippedIterations) { positions = new Vector3[clippedIterations]; } positions[0] = EvaluatePosition(from); positions[positions.Length - 1] = EvaluatePosition(to); for (int i = 1; i < positions.Length - 1; i++) { positions[i] = samples[i + fromIndex].position; } }
/// <summary> /// Same as Spline.CalculateLength but this takes the computer's transform into account when calculating the length. /// </summary> /// <param name="from">Calculate from [0-1] default: 0f</param> /// <param name="to">Calculate to [0-1] default: 1f</param> /// <param name="resolution">Resolution [0-1] default: 1f</param> /// <param name="address">Node address of junctions</param> /// <returns></returns> public float CalculateLength(double from = 0.0, double to = 1.0) { if (!hasSamples) { return(0f); } Spline.FormatFromTo(ref from, ref to); float length = 0f; Vector3 pos = EvaluatePosition(from); int fromIndex, toIndex; double lerp; GetSamplingValues(from, out fromIndex, out lerp); GetSamplingValues(to, out toIndex, out lerp); if (lerp > 0.0 && toIndex < Count - 1) { toIndex++; } for (int i = fromIndex + 1; i < toIndex; i++) { length += Vector3.Distance(samples[i].position, pos); pos = samples[i].position; } length += Vector3.Distance(EvaluatePosition(to), pos); return(length); }
/// <summary> /// Same as Spline.Evaluate but the results are transformed by the computer's transform /// </summary> /// <param name="from">Start position [0-1]</param> /// <param name="to">Target position [from-1]</param> /// <returns></returns> public void Evaluate(ref SplineSample[] results, double from = 0.0, double to = 1.0) { if (!hasSamples) { results = new SplineSample[0]; return; } Spline.FormatFromTo(ref from, ref to); int fromIndex, toIndex; double lerp; GetSamplingValues(from, out fromIndex, out lerp); GetSamplingValues(to, out toIndex, out lerp); if (lerp > 0.0 && toIndex < Count - 1) { toIndex++; } int clippedIterations = toIndex - fromIndex + 1; if (results == null) { results = new SplineSample[clippedIterations]; } else if (results.Length != clippedIterations) { results = new SplineSample[clippedIterations]; } results[0] = Evaluate(from); results[results.Length - 1] = Evaluate(to); for (int i = 1; i < results.Length - 1; i++) { results[i] = samples[i + fromIndex]; } }
/// <summary> /// Calculates the length between <paramref name="from"/> and <paramref name="to"/> with applied local offset to to the samples /// The offset is multiplied by the sample sizes /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="offset"></param> /// <returns></returns> public float CalculateLengthWithOffset(Vector3 offset, double from = 0.0, double to = 1.0) { if (!hasSamples) { return(0f); } Spline.FormatFromTo(ref from, ref to); float length = 0f; Evaluate(from, _workSample); Vector3 pos = _workSample.position + _workSample.up * offset.y * _workSample.size + _workSample.right * offset.x * _workSample.size + _workSample.forward * offset.z * _workSample.size; int fromIndex, toIndex; double lerp; GetSamplingValues(from, out fromIndex, out lerp); GetSamplingValues(to, out toIndex, out lerp); if (lerp > 0.0 && toIndex < Count - 1) { toIndex++; } for (int i = fromIndex + 1; i < toIndex; i++) { Vector3 newPos = samples[i].position + samples[i].up * offset.y * samples[i].size + samples[i].right * offset.x * samples[i].size + samples[i].forward * offset.z * samples[i].size; length += Vector3.Distance(newPos, pos); pos = newPos; } Evaluate(to, _workSample); _workSample.position += _workSample.up * offset.y * _workSample.size + _workSample.right * offset.x * _workSample.size + _workSample.forward * offset.z * _workSample.size; length += Vector3.Distance(_workSample.position, pos); return(length); }
protected void HandleJunctions(double from, double to) { #if UNITY_EDITOR if (!Application.isPlaying) { return; } #endif if (onNode == null) { return; } if (from == to) { return; } UnclipPercent(ref from); UnclipPercent(ref to); Spline.FormatFromTo(ref from, ref to, true); int fromPoint, toPoint; fromPoint = spline.PercentToPointIndex(from, _direction); toPoint = spline.PercentToPointIndex(to, _direction); if (fromPoint != toPoint) { List <NodeConnection> queue = new List <NodeConnection>(); if (_direction == Spline.Direction.Forward) { for (int i = fromPoint + 1; i <= toPoint; i++) { NodeConnection junction = GetJunction(i); if (junction != null) { queue.Add(junction); } } } else { for (int i = toPoint - 1; i >= fromPoint; i--) { NodeConnection junction = GetJunction(i); if (junction != null) { queue.Add(junction); } } } if (queue.Count > 0) { onNode(queue); } } }
/// <summary> /// Same as Spline.Project but the point is transformed by the computer's transform. /// </summary> /// <param name="position">Point in space</param> /// <param name="subdivide">Subdivisions default: 4</param> /// <param name="from">Sample from [0-1] default: 0f</param> /// <param name="to">Sample to [0-1] default: 1f</param> /// <param name="mode">Mode to use the method in. Cached uses the cached samples while Calculate is more accurate but heavier</param> /// <param name="subdivisions">Subdivisions for the Calculate mode. Don't assign if not using Calculated mode.</param> /// <returns></returns> public void Project(Vector3 position, int controlPointCount, SplineSample result, double from = 0.0, double to = 1.0) { if (!hasSamples) { return; } if (Count == 1) { if (result == null) { result = new SplineSample(samples[0]); } else { result.CopyFrom(samples[0]); } return; } Spline.FormatFromTo(ref from, ref to); //First make a very rough sample of the from-to region int steps = (controlPointCount - 1) * 6; //Sampling six points per segment is enough to find the closest point range int step = Count / steps; if (step < 1) { step = 1; } float minDist = (position - samples[0].position).sqrMagnitude; int fromIndex = 0; int toIndex = Count - 1; double lerp; if (from != 0.0) { GetSamplingValues(from, out fromIndex, out lerp); } if (to != 1.0) { GetSamplingValues(to, out toIndex, out lerp); if (lerp > 0.0 && toIndex < Count - 1) { toIndex++; } } int checkFrom = fromIndex; int checkTo = toIndex; //Find the closest point range which will be checked in detail later for (int i = fromIndex; i <= toIndex; i += step) { if (i > toIndex) { i = toIndex; } float dist = (position - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; checkFrom = Mathf.Max(i - step, 0); checkTo = Mathf.Min(i + step, Count - 1); } if (i == toIndex) { break; } } minDist = (position - samples[checkFrom].position).sqrMagnitude; int index = checkFrom; //Find the closest result within the range for (int i = checkFrom + 1; i <= checkTo; i++) { float dist = (position - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; index = i; } } //Project the point on the line between the two closest samples int backIndex = index - 1; if (backIndex < 0) { backIndex = 0; } int frontIndex = index + 1; if (frontIndex > Count - 1) { frontIndex = Count - 1; } Vector3 back = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, position); Vector3 front = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, position); float backLength = (samples[index].position - samples[backIndex].position).magnitude; float frontLength = (samples[index].position - samples[frontIndex].position).magnitude; float backProjectDist = (back - samples[backIndex].position).magnitude; float frontProjectDist = (front - samples[frontIndex].position).magnitude; if (backIndex < index && index < frontIndex) { if ((position - back).sqrMagnitude < (position - front).sqrMagnitude) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); if (sampleMode == SplineComputer.SampleMode.Uniform) { result.percent = DMath.Lerp(GetSamplePercent(backIndex), GetSamplePercent(index), backProjectDist / backLength); } } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); if (sampleMode == SplineComputer.SampleMode.Uniform) { result.percent = DMath.Lerp(GetSamplePercent(frontIndex), GetSamplePercent(index), frontProjectDist / frontLength); } } } else if (backIndex < index) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); if (sampleMode == SplineComputer.SampleMode.Uniform) { result.percent = DMath.Lerp(GetSamplePercent(backIndex), GetSamplePercent(index), backProjectDist / backLength); } } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); if (sampleMode == SplineComputer.SampleMode.Uniform) { result.percent = DMath.Lerp(GetSamplePercent(frontIndex), GetSamplePercent(index), frontProjectDist / frontLength); } } if (Count > 1 && from == 0.0 && to == 1.0 && result.percent < samples[1].percent) //Handle looped splines { Vector3 projected = LinearAlgebraUtility.ProjectOnLine(samples[Count - 1].position, samples[Count - 2].position, position); if ((position - projected).sqrMagnitude < (position - result.position).sqrMagnitude) { double l = LinearAlgebraUtility.InverseLerp(samples[Count - 1].position, samples[Count - 2].position, projected); SplineSample.Lerp(samples[Count - 1], samples[Count - 2], l, result); if (sampleMode == SplineComputer.SampleMode.Uniform) { result.percent = DMath.Lerp(GetSamplePercent(Count - 1), GetSamplePercent(Count - 2), l); } } } }
protected void CheckNodes(double from, double to) { #if UNITY_EDITOR if (!Application.isPlaying) { return; } #endif if (onNode == null) { return; } if (from == to) { return; } UnclipPercent(ref from); UnclipPercent(ref to); Spline.FormatFromTo(ref from, ref to, true); int fromPoint, toPoint; fromPoint = spline.PercentToPointIndex(from, _direction); toPoint = spline.PercentToPointIndex(to, _direction); if (fromPoint != toPoint) { if (_direction == Spline.Direction.Forward) { for (int i = fromPoint + 1; i <= toPoint; i++) { NodeConnection junction = GetJunction(i); if (junction != null) { nodeConnectionQueue.Add(junction); } } } else { for (int i = toPoint - 1; i >= fromPoint; i--) { NodeConnection junction = GetJunction(i); if (junction != null) { nodeConnectionQueue.Add(junction); } } } } else if (from < MIN_DELTA && to > from) { NodeConnection junction = GetJunction(0); if (junction != null) { nodeConnectionQueue.Add(junction); } } else if (to > 1.0 - MIN_DELTA && from < to) { NodeConnection junction = GetJunction(spline.pointCount - 1); if (junction != null) { nodeConnectionQueue.Add(junction); } } }