Example #1
0
    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;
                }
            }
        }
Example #3
0
        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;
            }
        }