/// <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 static void DrawSpline(Spline spline, Color color, double from = 0.0, double to = 1.0, bool drawThickness = false, bool thicknessAutoRotate = false) { double add = spline.moveStep; if (add < 0.0025) { add = 0.0025; } double percent = from; Color prevColor = Handles.color; Handles.color = color; if (drawThickness) { Camera editorCamera = SceneView.currentDrawingSceneView.camera; SplineResult fromResult = spline.Evaluate(percent); SplineResult toResult = new SplineResult(); Vector3 fromNormal = fromResult.normal; if (thicknessAutoRotate) { fromNormal = (editorCamera.transform.position - fromResult.position).normalized; } Vector3 fromRight = Vector3.Cross(fromResult.direction, fromNormal).normalized *fromResult.size * 0.5f; while (true) { percent = DMath.Move(percent, to, add); spline.Evaluate(toResult, percent); Vector3 toNormal = toResult.normal; if (thicknessAutoRotate) { toNormal = (editorCamera.transform.position - toResult.position).normalized; } Vector3 toRight = Vector3.Cross(toResult.direction, toNormal).normalized *toResult.size * 0.5f; Handles.DrawLine(fromResult.position + fromRight, toResult.position + toRight); Handles.DrawLine(fromResult.position - fromRight, toResult.position - toRight); Handles.DrawLine(fromResult.position + fromRight, fromResult.position - fromRight); if (percent == to) { break; } fromResult.CopyFrom(toResult); fromNormal = toNormal; fromRight = toRight; } } else { Vector3 fromPoint = spline.EvaluatePosition(percent); Vector3 toPoint = new Vector3(); while (true) { percent = DMath.Move(percent, to, add); toPoint = spline.EvaluatePosition(percent); Handles.DrawLine(fromPoint, toPoint); if (percent == to) { break; } fromPoint = toPoint; } } Handles.color = prevColor; }
public static void DrawSpline(Spline spline, Color color, double from = 0.0, double to = 1.0, bool drawThickness = false, bool thicknessAutoRotate = false) { double add = spline.moveStep; if (add < 0.0025) { add = 0.0025; } Color prevColor = Handles.color; Handles.color = color; int iterations = spline.iterations; if (drawThickness) { Transform editorCamera = SceneView.currentDrawingSceneView.camera.transform; if (positions.Length != iterations * 6) { positions = new Vector3[iterations * 6]; } SplineResult prevResult = spline.Evaluate(from); Vector3 prevNormal = prevResult.normal; if (thicknessAutoRotate) { prevNormal = (editorCamera.position - prevResult.position).normalized; } Vector3 prevRight = Vector3.Cross(prevResult.direction, prevNormal).normalized *prevResult.size * 0.5f; int pointIndex = 0; for (int i = 1; i < iterations; i++) { double p = DMath.Lerp(from, to, (double)i / (iterations - 1)); SplineResult newResult = spline.Evaluate(p); Vector3 newNormal = newResult.normal; if (thicknessAutoRotate) { newNormal = (editorCamera.position - newResult.position).normalized; } Vector3 newRight = Vector3.Cross(newResult.direction, newNormal).normalized *newResult.size * 0.5f; positions[pointIndex] = prevResult.position + prevRight; positions[pointIndex + iterations * 2] = prevResult.position - prevRight; positions[pointIndex + iterations * 4] = newResult.position - newRight; pointIndex++; positions[pointIndex] = newResult.position + newRight; positions[pointIndex + iterations * 2] = newResult.position - newRight; positions[pointIndex + iterations * 4] = newResult.position + newRight; pointIndex++; prevResult = newResult; prevRight = newRight; prevNormal = newNormal; } Handles.DrawLines(positions); } else { if (positions.Length != iterations * 2) { positions = new Vector3[iterations * 2]; } Vector3 prevPoint = spline.EvaluatePosition(from); int pointIndex = 0; for (int i = 1; i < iterations; i++) { double p = DMath.Lerp(from, to, (double)i / (iterations - 1)); positions[pointIndex] = prevPoint; pointIndex++; positions[pointIndex] = spline.EvaluatePosition(p); pointIndex++; prevPoint = positions[pointIndex - 1]; } Handles.DrawLines(positions); } Handles.color = prevColor; }
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); } } }