public static PathSplitData SplitBezierPathEvenly(BezierPath bezierPath, float spacing, float accuracy) { var splitData = new PathSplitData(); splitData.vertices.Add(bezierPath[0]); splitData.tangents.Add( CubicBezierUtility.EvaluateCurveDerivative(bezierPath.GetPointsInSegment(0), 0).normalized); splitData.cumulativeLength.Add(0); splitData.anchorVertexMap.Add(0); splitData.minMax.AddValue(bezierPath[0]); var prevPointOnPath = bezierPath[0]; var lastAddedPoint = bezierPath[0]; float currentPathLength = 0; float dstSinceLastVertex = 0; // Go through all segments and split up into vertices for (var segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { var segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); var estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength( segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); var divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy); var increment = 1f / divisions; for (var t = increment; t <= 1; t += increment) { var isLastPointOnPath = (t + increment > 1 && segmentIndex == bezierPath.NumSegments - 1); if (isLastPointOnPath) { t = 1; } var 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) { var 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 PathSplitData SplitBezierPathByAngleError( BezierPath bezierPath, float maxAngleError, float minVertexDst, float accuracy) { var splitData = new PathSplitData(); splitData.vertices.Add(bezierPath[0]); splitData.tangents.Add( CubicBezierUtility.EvaluateCurveDerivative(bezierPath.GetPointsInSegment(0), 0).normalized); splitData.cumulativeLength.Add(0); splitData.anchorVertexMap.Add(0); splitData.minMax.AddValue(bezierPath[0]); var prevPointOnPath = bezierPath[0]; var lastAddedPoint = bezierPath[0]; float currentPathLength = 0; float dstSinceLastVertex = 0; // Go through all segments and split up into vertices for (var segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { var segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); var estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength( segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); var divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy); var increment = 1f / divisions; for (var t = increment; t <= 1; t += increment) { var isLastPointOnPath = (t + increment > 1 && segmentIndex == bezierPath.NumSegments - 1); if (isLastPointOnPath) { t = 1; } var pointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints, t); var nextPointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints, t + increment); // angle at current point on path var 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 var angleFromPrevVertex = 180 - MathUtility.MinAngle(lastAddedPoint, pointOnPath, nextPointOnPath); var 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); }