public static PathSplitData SplitBezierPathEvenly(BezierPath bezierPath, float spacing, float accuracy) { PathSplitData splitData = new PathSplitData(); splitData.vertices.Add(bezierPath.GetPoint(0)); splitData.tangents.Add(CubicBezierUtility.EvaluateCurveDerivative(bezierPath.GetPointsInSegment(0), 0).normalized); splitData.cumulativeLength.Add(0); splitData.anchorVertexMap.Add(0); splitData.minMax.AddValue(bezierPath.GetPoint(0)); Vector3 prevPointOnPath = bezierPath.GetPoint(0); Vector3 lastAddedPoint = bezierPath.GetPoint(0); float currentPathLength = 0; float dstSinceLastVertex = 0; // Go through all segments and split up into vertices for (int segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { Vector3[] segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); float estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength(segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); int divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy); float increment = 1f / divisions; for (float t = increment; t <= 1; t += increment) { bool isLastPointOnPath = (t + increment > 1 && segmentIndex == bezierPath.NumSegments - 1); if (isLastPointOnPath) { t = 1; } Vector3 pointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints, t); dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude; // If vertices are now too far apart, go back by amount we overshot by if (dstSinceLastVertex > spacing) { float overshootDst = dstSinceLastVertex - spacing; pointOnPath += (prevPointOnPath - pointOnPath).normalized * overshootDst; t -= increment; } if (dstSinceLastVertex >= spacing || isLastPointOnPath) { currentPathLength += (lastAddedPoint - pointOnPath).magnitude; splitData.cumulativeLength.Add(currentPathLength); splitData.vertices.Add(pointOnPath); splitData.tangents.Add(CubicBezierUtility.EvaluateCurveDerivative(segmentPoints, t).normalized); splitData.minMax.AddValue(pointOnPath); dstSinceLastVertex = 0; lastAddedPoint = pointOnPath; } prevPointOnPath = pointOnPath; } splitData.anchorVertexMap.Add(splitData.vertices.Count - 1); } return(splitData); }
public static Bounds CalculateSegmentBounds(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { MinMax3D minMax = new MinMax3D(); minMax.AddValue(p0); minMax.AddValue(p3); List <float> extremePointTimes = ExtremePointTimes(p0, p1, p2, p3); foreach (float t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(p0, p1, p2, p3, t)); } return(new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min)); }
public static Bounds CalculateBounds(Vector3[] points) { MinMax3D minMax = new MinMax3D(); minMax.AddValue(points[0]); minMax.AddValue(points[3]); List <float> extremePointTimes = ExtremePointTimes(points[0], points[1], points[2], points[3]); foreach (float t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(points, t)); } return(new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min)); }
public static Bounds CalculateBounds(Vector3[] points) { Debug.Assert(points.Length == 4, "Incorrect number of points supplied to cubic bezier function (expected 4)"); MinMax3D minMax = new MinMax3D(); if (points.Length >= 4) { minMax.AddValue(points[0]); minMax.AddValue(points[3]); List <float> extremePointTimes = ExtremePointTimes(points[0], points[1], points[2], points[3]); foreach (float t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(points, t)); } } return(new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min)); }
public static PathSplitData SplitBezierPathByAngleError(BezierPath bezierPath, float maxAngleError, float minVertexDst, float accuracy) { PathSplitData splitData = new PathSplitData(); splitData.vertices.Add(bezierPath.GetPoint(0)); splitData.tangents.Add(CubicBezierUtility.EvaluateCurveDerivative(bezierPath.GetPointsInSegment(0), 0).normalized); splitData.cumulativeLength.Add(0); splitData.anchorVertexMap.Add(0); splitData.minMax.AddValue(bezierPath.GetPoint(0)); Vector3 prevPointOnPath = bezierPath.GetPoint(0); Vector3 lastAddedPoint = bezierPath.GetPoint(0); float currentPathLength = 0; float dstSinceLastVertex = 0; // Go through all segments and split up into vertices for (int segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { Vector3[] segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); float estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength(segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); int divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy); float increment = 1f / divisions; for (float t = increment; t <= 1; t += increment) { bool isLastPointOnPath = (t + increment > 1 && segmentIndex == bezierPath.NumSegments - 1); if (isLastPointOnPath) { t = 1; } Vector3 pointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints, t); Vector3 nextPointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints, t + increment); // angle at current point on path float localAngle = 180 - MathUtility.MinAngle(prevPointOnPath, pointOnPath, nextPointOnPath); // angle between the last added vertex, the current point on the path, and the next point on the path float angleFromPrevVertex = 180 - MathUtility.MinAngle(lastAddedPoint, pointOnPath, nextPointOnPath); float angleError = Mathf.Max(localAngle, angleFromPrevVertex); if ((angleError > maxAngleError && dstSinceLastVertex >= minVertexDst) || isLastPointOnPath) { currentPathLength += (lastAddedPoint - pointOnPath).magnitude; splitData.cumulativeLength.Add(currentPathLength); splitData.vertices.Add(pointOnPath); splitData.tangents.Add(CubicBezierUtility.EvaluateCurveDerivative(segmentPoints, t).normalized); splitData.minMax.AddValue(pointOnPath); dstSinceLastVertex = 0; lastAddedPoint = pointOnPath; } else { dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude; } prevPointOnPath = pointOnPath; } splitData.anchorVertexMap.Add(splitData.vertices.Count - 1); } return(splitData); }