/// <summary> /// Creates a new bezier path along the given waypoints. The algorithm will automatically create new control points /// between the given <paramref name="points"/> to guarantee a smooth curve along the path. /// </summary> /// <param name="points">The waypoints to use as bezier points for the newly created bezier path.</param> /// <returns>A bezier path through the given bezier points.</returns> public static BezierPath Interpolate(Vector3[] points) { if (points.Length < 2) { throw new ArgumentOutOfRangeException("There are at least two points required to interpolate a bezier path.", "points"); } BezierPath path = new BezierPath(); for (int i = 0; i < points.Length; i++) { if (i == 0) { Vector3 p1 = points[i]; Vector3 p2 = points[i + 1]; Vector3 tangent = (p2 - p1); Vector3 q1 = p1 + tangent; path.points.Add(p1); path.points.Add(q1); } else if (i == points.Length - 1) { Vector3 p0 = points[i - 1]; Vector3 p1 = points[i]; Vector3 tangent = (p1 - p0); Vector3 q0 = p1 - tangent; path.points.Add(q0); path.points.Add(p1); } else { Vector3 p0 = points[i - 1]; Vector3 p1 = points[i]; Vector3 p2 = points[i + 1]; Vector3 tangent = (p2 - p0).normalized; Vector3 q0 = p1 - tangent * (p1 - p0).magnitude; Vector3 q1 = p1 + tangent * (p2 - p1).magnitude; path.points.Add(q0); path.points.Add(p1); path.points.Add(q1); } } return(path); }
/// <summary> /// Reduces the number of bezier points in the bezierpath and adjusts the corresponding control /// handle points to generate a mostly accurate curve to the original one. /// </summary> /// <param name="minSqrDistance">Minimum square distance between two points.</param> /// <param name="maxSqrDistance">Maximum square distance between two points.</param> public void Optimize(float minSqrDistance, float maxSqrDistance) { if (this.points.Count < 4 || (this.points.Count - 1) % 3 != 0) { return; } Stack <Vector3> newPoints = new Stack <Vector3>(); Vector3[] bezierPoints = this.BezierPoints; newPoints.Push(bezierPoints[0]); Vector3 potentialNewPoint = bezierPoints[1]; for (int i = 2; i < bezierPoints.Length; i++) { if (((potentialNewPoint - bezierPoints[i]).sqrMagnitude > minSqrDistance) && ((newPoints.Peek() - bezierPoints[i]).sqrMagnitude < maxSqrDistance)) { newPoints.Push(potentialNewPoint); } potentialNewPoint = bezierPoints[i]; } // Correct last few points of the bezier path Vector3 p1 = newPoints.Pop(); Vector3 p0 = newPoints.Peek(); Vector3 tangent = (p0 - potentialNewPoint).normalized; float d2 = (potentialNewPoint - p1).magnitude; float d1 = (p1 - p0).magnitude; p1 = p1 + tangent * ((d1 - d2) / 2); newPoints.Push(p1); newPoints.Push(potentialNewPoint); this.Points = BezierPath.Interpolate(newPoints.ToArray()).Points.ToArray(); }