public virtual void Project(SplineResult result, Vector3 point, double from = 0.0, double to = 1.0) { if (samples.Length == 0) { return; } if (samples.Length == 1) { if (result == null) { result = new SplineResult(samples[0]); } else { result.CopyFrom(samples[0]); } return; } if (computer == null) { result = new SplineResult(); return; } //First make a very rough sample of the from-to region int steps = (computer.pointCount - 1) * 6; //Sampling six points per segment is enough to find the closest point range int step = samples.Length / steps; if (step < 1) { step = 1; } float minDist = (point - samples[0].position).sqrMagnitude; int fromIndex = 0; int toIndex = samples.Length - 1; if (from != 0.0) { fromIndex = GetSampleIndex(from); } if (to != 1.0) { toIndex = Mathf.CeilToInt((float)to * (samples.Length - 1)); } 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 = (point - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; checkFrom = Mathf.Max(i - step, 0); checkTo = Mathf.Min(i + step, samples.Length - 1); } if (i == toIndex) { break; } } minDist = (point - samples[checkFrom].position).sqrMagnitude; int index = checkFrom; //Find the closest result within the range for (int i = checkFrom + 1; i <= checkTo; i++) { float dist = (point - 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 > samples.Length - 1) { frontIndex = samples.Length - 1; } Vector3 back = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, point); Vector3 front = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, point); 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 ((point - back).sqrMagnitude < (point - front).sqrMagnitude) { SplineResult.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineResult.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } } else if (backIndex < index) { SplineResult.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineResult.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } if (from == 0.0 && to == 1.0 && result.percent < _address.moveStep / _resolution) //Handle looped splines { Vector3 projected = LinearAlgebraUtility.ProjectOnLine(samples[samples.Length - 1].position, samples[samples.Length - 2].position, point); if ((point - projected).sqrMagnitude < (point - result.position).sqrMagnitude) { SplineResult.Lerp(samples[samples.Length - 1], samples[samples.Length - 2], LinearAlgebraUtility.InverseLerp(samples[samples.Length - 1].position, samples[samples.Length - 2].position, projected), result); } } }
/// <summary> /// Project a world space point onto the spline and write to a SplineSample. /// </summary> /// <param name="point">3D Point in world space</param> /// <param name="result">The SplineSample object to write the result into</param> /// <param name="from">Sample from [0-1] default: 0.0</param> /// <param name="to">Sample to [0-1] default: 1.0</param> /// <returns></returns> public virtual void Project(Vector3 point, SplineSample result, double from = 0.0, double to = 1.0, EvaluateMode mode = EvaluateMode.Cached) { if (mode == EvaluateMode.Accurate) { spline.Evaluate(result, spline.Project(point, 4, from, to)); return; } if (samples.Length == 0) { return; } if (samples.Length == 1) { if (result == null) { result = new SplineSample(samples[0]); } else { result.CopyFrom(samples[0]); } return; } //First make a very rough sample of the from-to region int steps = 2; if (spline != null) { steps = (spline.points.Length - 1) * 6; //Sampling six points per segment is enough to find the closest point range } int step = samples.Length / steps; if (step < 1) { step = 1; } float minDist = (point - samples[0].position).sqrMagnitude; int fromIndex = 0; int toIndex = samples.Length - 1; if (from != 0.0) { fromIndex = DMath.FloorInt(from * (samples.Length - 1)); } if (to != 1.0) { toIndex = Mathf.CeilToInt((float)to * (samples.Length - 1)); } 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 = (point - samples[i].position).sqrMagnitude; if (dist < minDist) { minDist = dist; checkFrom = Mathf.Max(i - step, 0); checkTo = Mathf.Min(i + step, samples.Length - 1); } if (i == toIndex) { break; } } minDist = (point - samples[checkFrom].position).sqrMagnitude; int index = checkFrom; //Find the closest result within the range for (int i = checkFrom + 1; i <= checkTo; i++) { float dist = (point - 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 > samples.Length - 1) { frontIndex = samples.Length - 1; } Vector3 back = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, point); Vector3 front = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, point); 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 ((point - back).sqrMagnitude < (point - front).sqrMagnitude) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } } else if (backIndex < index) { SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result); } else { SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result); } }
/// <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); } } } }
public virtual void Project(SplineResult result, Vector3 point, double from = 0.0, double to = 1.0) { if (samples.Length == 0) { return; } if (samples.Length == 1) { if (result == null) { result = new SplineResult(samples[0]); } else { result.CopyFrom(samples[0]); } return; } if (computer == null) { result = new SplineResult(); return; } int num = (computer.pointCount - 1) * 6; int num2 = samples.Length / num; if (num2 < 1) { num2 = 1; } float num3 = (point - samples[0].position).sqrMagnitude; int num4 = 0; int num5 = samples.Length - 1; if (from != 0.0) { num4 = GetSampleIndex(from); } if (to != 1.0) { num5 = Mathf.CeilToInt((float)to * (float)(samples.Length - 1)); } int num6 = num4; int num7 = num5; for (int i = num4; i <= num5; i += num2) { if (i > num5) { i = num5; } float sqrMagnitude = (point - samples[i].position).sqrMagnitude; if (sqrMagnitude < num3) { num3 = sqrMagnitude; num6 = Mathf.Max(i - num2, 0); num7 = Mathf.Min(i + num2, samples.Length - 1); } if (i == num5) { break; } } num3 = (point - samples[num6].position).sqrMagnitude; int num8 = num6; for (int j = num6 + 1; j <= num7; j++) { float sqrMagnitude2 = (point - samples[j].position).sqrMagnitude; if (sqrMagnitude2 < num3) { num3 = sqrMagnitude2; num8 = j; } } int num9 = num8 - 1; if (num9 < 0) { num9 = 0; } int num10 = num8 + 1; if (num10 > samples.Length - 1) { num10 = samples.Length - 1; } Vector3 vector = LinearAlgebraUtility.ProjectOnLine(samples[num9].position, samples[num8].position, point); Vector3 vector2 = LinearAlgebraUtility.ProjectOnLine(samples[num8].position, samples[num10].position, point); float magnitude = (samples[num8].position - samples[num9].position).magnitude; float magnitude2 = (samples[num8].position - samples[num10].position).magnitude; float magnitude3 = (vector - samples[num9].position).magnitude; float magnitude4 = (vector2 - samples[num10].position).magnitude; if (num9 < num8 && num8 < num10) { if ((point - vector).sqrMagnitude < (point - vector2).sqrMagnitude) { SplineResult.Lerp(samples[num9], samples[num8], magnitude3 / magnitude, result); } else { SplineResult.Lerp(samples[num10], samples[num8], magnitude4 / magnitude2, result); } } else if (num9 < num8) { SplineResult.Lerp(samples[num9], samples[num8], magnitude3 / magnitude, result); } else { SplineResult.Lerp(samples[num10], samples[num8], magnitude4 / magnitude2, result); } if (from == 0.0 && to == 1.0 && result.percent < _address.moveStep / _resolution) { Vector3 vector3 = LinearAlgebraUtility.ProjectOnLine(samples[samples.Length - 1].position, samples[samples.Length - 2].position, point); if ((point - vector3).sqrMagnitude < (point - result.position).sqrMagnitude) { SplineResult.Lerp(samples[samples.Length - 1], samples[samples.Length - 2], LinearAlgebraUtility.InverseLerp(samples[samples.Length - 1].position, samples[samples.Length - 2].position, vector3), result); } } }