Пример #1
0
        /// 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);
        }
Пример #2
0
        /// 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));
        }
Пример #3
0
        /// 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);
        }
Пример #4
0
        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;
                }
            }
        }
Пример #5
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;
            }
        }
Пример #6
0
 public Vector3 GetPoint(float t)
 {
     return(CubicBezierUtility.EvaluateCurve(GetPoints(), t));
 }