private void RecalculateLengths() { float curveLength = CubicBezierUtility.EstimateCurveLength(GetPoints()); int nPoints = ((int)curveLength + 1) * 10; float[] l = new float[nPoints]; l[0] = 0f; Vector3 lastPoint = GetPoint(0f); float accumulatedLength = 0f; for (int i = 1; i < nPoints; i++) { float t = 1f / nPoints * i; Vector3 p = GetPoint(t); float dst = Vector3.Distance(lastPoint, p); accumulatedLength += dst; l[i] = accumulatedLength; lastPoint = p; } _lengths = l; }
public ScreenSpacePolyLine(BezierPath bezierPath, Transform transform, float maxAngleError, float minVertexDst, float accuracy = 1) { this.transform = transform; transformPosition = transform.position; transformRotation = transform.rotation; transformScale = transform.localScale; // Split path in vertices based on angle error verticesWorld = new List <Vector3>(); vertexToPathSegmentMap = new List <int>(); segmentStartIndices = new int[bezierPath.NumSegments + 1]; verticesWorld.Add(bezierPath[0]); vertexToPathSegmentMap.Add(0); Vector3 prevPointOnPath = bezierPath[0]; float dstSinceLastVertex = 0; Vector3 lastAddedPoint = prevPointOnPath; float dstSinceLastIntermediary = 0; for (int segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { Vector3[] segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); verticesWorld.Add(segmentPoints[0]); vertexToPathSegmentMap.Add(segmentIndex); segmentStartIndices[segmentIndex] = verticesWorld.Count - 1; prevPointOnPath = segmentPoints[0]; lastAddedPoint = prevPointOnPath; dstSinceLastVertex = 0; dstSinceLastIntermediary = 0; float estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength(segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); int divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy * accuracyMultiplier); float increment = 1f / divisions; for (float t = increment; t <= 1; t += increment) { Vector3 pointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3], t); Vector3 nextPointOnPath = CubicBezierUtility.EvaluateCurve(segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3], 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) { dstSinceLastVertex = 0; dstSinceLastIntermediary = 0; verticesWorld.Add(pointOnPath); vertexToPathSegmentMap.Add(segmentIndex); lastAddedPoint = pointOnPath; } else { if (dstSinceLastIntermediary > intermediaryThreshold) { verticesWorld.Add(pointOnPath); vertexToPathSegmentMap.Add(segmentIndex); dstSinceLastIntermediary = 0; } else { dstSinceLastIntermediary += (pointOnPath - prevPointOnPath).magnitude; } dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude; } prevPointOnPath = pointOnPath; } } segmentStartIndices[bezierPath.NumSegments] = verticesWorld.Count; // ensure final point gets added (unless path is closed loop) if (!bezierPath.IsClosed) { verticesWorld.Add(bezierPath[bezierPath.NumPoints - 1]); } else { verticesWorld.Add(bezierPath[0]); } // Calculate length cumululativeLengthWorld = new float[verticesWorld.Count]; for (int i = 0; i < verticesWorld.Count; i++) { verticesWorld[i] = MathUtility.TransformPoint(verticesWorld[i], transform, bezierPath.Space); if (i > 0) { pathLengthWorld += (verticesWorld[i - 1] - verticesWorld[i]).magnitude; cumululativeLengthWorld[i] = pathLengthWorld; } } }
public ScreenSpacePolyLine(BezierPath bezierPath, float maxAngleError, float minVertexDst, float accuracy = 1) { // Split path in vertices based on angle error VerticesWorld = new List <Vector3>(); _vertexToPathSegmentMap = new List <int>(); _segmentStartIndices = new int[bezierPath.NumSegments + 1]; VerticesWorld.Add(bezierPath[0]); _vertexToPathSegmentMap.Add(0); var prevPointOnPath = bezierPath[0]; float dstSinceLastVertex = 0; var lastAddedPoint = prevPointOnPath; float dstSinceLastIntermediary = 0; for (var segmentIndex = 0; segmentIndex < bezierPath.NumSegments; segmentIndex++) { var segmentPoints = bezierPath.GetPointsInSegment(segmentIndex); VerticesWorld.Add(segmentPoints[0]); _vertexToPathSegmentMap.Add(segmentIndex); _segmentStartIndices[segmentIndex] = VerticesWorld.Count - 1; prevPointOnPath = segmentPoints[0]; lastAddedPoint = prevPointOnPath; dstSinceLastVertex = 0; dstSinceLastIntermediary = 0; var estimatedSegmentLength = CubicBezierUtility.EstimateCurveLength( segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3]); var divisions = Mathf.CeilToInt(estimatedSegmentLength * accuracy * AccuracyMultiplier); var increment = 1f / divisions; for (var t = increment; t <= 1; t += increment) { var pointOnPath = CubicBezierUtility.EvaluateCurve( segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3], t); var nextPointOnPath = CubicBezierUtility.EvaluateCurve( segmentPoints[0], segmentPoints[1], segmentPoints[2], segmentPoints[3], 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) { dstSinceLastVertex = 0; dstSinceLastIntermediary = 0; VerticesWorld.Add(pointOnPath); _vertexToPathSegmentMap.Add(segmentIndex); lastAddedPoint = pointOnPath; } else { if (dstSinceLastIntermediary > IntermediaryThreshold) { VerticesWorld.Add(pointOnPath); _vertexToPathSegmentMap.Add(segmentIndex); dstSinceLastIntermediary = 0; } else { dstSinceLastIntermediary += (pointOnPath - prevPointOnPath).magnitude; } dstSinceLastVertex += (pointOnPath - prevPointOnPath).magnitude; } prevPointOnPath = pointOnPath; } } _segmentStartIndices[bezierPath.NumSegments] = VerticesWorld.Count; // ensure final point gets added (unless path is closed loop) if (!bezierPath.IsClosed) { VerticesWorld.Add(bezierPath[bezierPath.NumPoints - 1]); } else { VerticesWorld.Add(bezierPath[0]); } // Calculate length _cumululativeLengthWorld = new float[VerticesWorld.Count]; for (var i = 1; i < VerticesWorld.Count; i++) { _pathLengthWorld += (VerticesWorld[i - 1] - VerticesWorld[i]).magnitude; _cumululativeLengthWorld[i] = _pathLengthWorld; } }