/// Update the bounding box of the path void UpdateBounds() { if (boundsUpToDate) { return; } // Loop through all segments and keep track of the minmax points of all their bounding boxes MinMax3D minMax = new MinMax3D(); for (int i = 0; i < NumSegments; i++) { Vector3[] p = GetPointsInSegment(i); minMax.AddValue(p[0]); minMax.AddValue(p[3]); List <float> extremePointTimes = CubicBezierUtility.ExtremePointTimes(p[0], p[1], p[2], p[3]); foreach (float t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(p, t)); } } boundsUpToDate = true; bounds = new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min); }
/// Update the bounding box of the path public Bounds CalculateBoundsWithTransform(Transform transform) { // Loop through all segments and keep track of the minmax points of all their bounding boxes MinMax3D minMax = new MinMax3D(); for (int i = 0; i < NumSegments; i++) { Vector3[] p = GetPointsInSegment(i); for (int j = 0; j < p.Length; j++) { p[j] = MathUtility.TransformPoint(p[j], transform, space); } minMax.AddValue(p[0]); minMax.AddValue(p[3]); List <float> extremePointTimes = CubicBezierUtility.ExtremePointTimes(p[0], p[1], p[2], p[3]); foreach (float t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(p, t)); } } return(new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min)); }
/// Update the bounding box of the path void UpdateBounds() { if (this.boundsUpToDate) { return; } // Loop through all segments and keep track of the minmax points of all their bounding boxes var minMax = new MinMax3D(); for (var i = 0; i < this.NumSegments; i++) { var p = this.GetPointsInSegment(i); minMax.AddValue(p[0]); minMax.AddValue(p[3]); var extremePointTimes = CubicBezierUtility.ExtremePointTimes(p[0], p[1], p[2], p[3]); foreach (var t in extremePointTimes) { minMax.AddValue(CubicBezierUtility.EvaluateCurve(p, t)); } } this.boundsUpToDate = true; this.bounds = new Bounds((minMax.Min + minMax.Max) / 2, minMax.Max - minMax.Min); }
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; } }
public Vector3 GetPoint(float t) { return(CubicBezierUtility.EvaluateCurve(GetPoints(), t)); }