Ejemplo n.º 1
0
        /// <summary>
        /// Computes a triangle list that fully covers the area enclosed by the given set of points. If points are not CCW, pass false for
        /// the arePointsCCW parameter
        /// </summary>
        /// <param name="points">A list of points that defines an enclosing path.</param>
        /// <param name="count">The number of points in the path.</param>
        public void Triangulate(Vector2[] points, bool arePointsCCW = true)
        {
            var count = points.Length;

            // set up previous and next links to effectively from a double-linked vert list
            Initialize(count);

            // loop breaker for polys that are not triangulatable
            var iterations = 0;

            // start at vert 0
            var index = 0;

            // keep removing verts until just a triangle is left
            while (count > 3 && iterations < 500)
            {
                iterations++;

                // test if current vert is an ear
                var isEar = true;

                var a = points[_triPrev[index]];
                var b = points[index];
                var c = points[_triNext[index]];

                // an ear must be convex (here counterclockwise)
                if (Vector2Ext.IsTriangleCCW(a, b, c))
                {
                    // loop over all verts not part of the tentative ear
                    var k = _triNext[_triNext[index]];
                    do
                    {
                        // if vert k is inside the ear triangle, then this is not an ear
                        if (TestPointTriangle(points[k], a, b, c))
                        {
                            isEar = false;
                            break;
                        }

                        k = _triNext[k];
                    } while (k != _triPrev[index]);
                }
                else
                {
                    // the ear triangle is clockwise so points[i] is not an ear
                    isEar = false;
                }

                // if current vert is an ear, delete it and visit the previous vert
                if (isEar)
                {
                    // triangle is an ear
                    TriangleIndices.Add(_triPrev[index]);
                    TriangleIndices.Add(index);
                    TriangleIndices.Add(_triNext[index]);

                    // delete vert by redirecting next and previous links of neighboring verts past it
                    // decrement vertext count
                    _triNext[_triPrev[index]] = _triNext[index];
                    _triPrev[_triNext[index]] = _triPrev[index];
                    count--;

                    // visit the previous vert next
                    index = _triPrev[index];
                }
                else
                {
                    // current vert is not an ear. visit the next vert
                    index = _triNext[index];
                }
            }

            // output the final triangle
            TriangleIndices.Add(_triPrev[index]);
            TriangleIndices.Add(index);
            TriangleIndices.Add(_triNext[index]);

            if (!arePointsCCW)
            {
                TriangleIndices.Reverse();
            }
        }
Ejemplo n.º 2
0
        void CalculateVertices()
        {
            if (!_areVertsDirty || _points.Length < 2)
            {
                return;
            }

            _areVertsDirty = false;
            _indices.Reset();
            _vertices.Reset();

            var maxX = float.MinValue;
            var minX = float.MaxValue;
            var maxY = float.MinValue;
            var minY = float.MaxValue;

            if (_useStartEndWidths)
            {
                _maxWidth = System.Math.Max(_startWidth, _endWidth);
            }

            // calculate line length first and simulataneously get our min/max points for the bounds
            var lineLength   = 0f;
            var halfMaxWidth = _maxWidth * 0.5f;

            _points.Buffer[0].LengthFromPreviousPoint = 0;
            for (var i = 0; i < _points.Length - 1; i++)
            {
                var distance = Vector2.Distance(_points.Buffer[i].Position, _points.Buffer[i + 1].Position);
                _points.Buffer[i + 1].LengthFromPreviousPoint = distance;
                lineLength += distance;

                maxX = Mathf.MaxOf(maxX, _points.Buffer[i].Position.X + halfMaxWidth,
                                   _points.Buffer[i + 1].Position.X + halfMaxWidth);
                minX = Mathf.MinOf(minX, _points.Buffer[i].Position.X - halfMaxWidth,
                                   _points.Buffer[i + 1].Position.X - halfMaxWidth);
                maxY = Mathf.MaxOf(maxY, _points.Buffer[i].Position.Y + halfMaxWidth,
                                   _points.Buffer[i + 1].Position.Y + halfMaxWidth);
                minY = Mathf.MinOf(minY, _points.Buffer[i].Position.Y - halfMaxWidth,
                                   _points.Buffer[i + 1].Position.Y - halfMaxWidth);
            }

            _bounds.X      = minX;
            _bounds.Y      = minY;
            _bounds.Width  = maxX - minX;
            _bounds.Height = maxY - minY;

            // special case: single segment
            if (_points.Length == 2)
            {
                if (_useStartEndWidths)
                {
                    _points.Buffer[0].Width = _startWidth;
                    _points.Buffer[1].Width = _endWidth;
                }

                if (_useStartEndColors)
                {
                    _points.Buffer[0].Color = _startColor;
                    _points.Buffer[1].Color = _endColor;
                }

                _firstSegment.SetPoints(ref _points.Buffer[0], ref _points.Buffer[1]);
                AddSingleSegmentLine(ref _firstSegment, _points.Buffer[1].Color);
                return;
            }

            var distanceSoFar = 0f;
            var fusedPoint    = Vector2.Zero;
            var vertIndex     = 0;
            var thirdPoint    = new SegmentPoint();

            for (var i = 0; i < _points.Length - 1; i++)
            {
                var firstPoint  = _points.Buffer[i];
                var secondPoint = _points.Buffer[i + 1];

                var hasThirdPoint = _points.Length > i + 2;
                if (hasThirdPoint)
                {
                    thirdPoint = _points.Buffer[i + 2];
                }

                // we need the distance along the line of both the first and second points. distanceSoFar will always be for the furthest point
                // which is the previous point before adding the current segment distance.
                var firstPointDistance = distanceSoFar;
                distanceSoFar += secondPoint.LengthFromPreviousPoint;

                var firstPointRatio  = firstPointDistance / lineLength;
                var secondPointRatio = distanceSoFar / lineLength;
                var thirdPointRatio  = 0f;
                if (hasThirdPoint)
                {
                    thirdPointRatio = (distanceSoFar + thirdPoint.LengthFromPreviousPoint) / lineLength;
                }

                if (_useStartEndColors)
                {
                    ColorExt.Lerp(ref _startColor, ref _endColor, out firstPoint.Color, firstPointRatio);
                    ColorExt.Lerp(ref _startColor, ref _endColor, out secondPoint.Color, secondPointRatio);

                    if (hasThirdPoint)
                    {
                        ColorExt.Lerp(ref _startColor, ref _endColor, out thirdPoint.Color, thirdPointRatio);
                    }
                }

                if (_useStartEndWidths)
                {
                    firstPoint.Width  = Mathf.Lerp(_startWidth, _endWidth, firstPointRatio);
                    secondPoint.Width = Mathf.Lerp(_startWidth, _endWidth, secondPointRatio);

                    if (hasThirdPoint)
                    {
                        thirdPoint.Width = Mathf.Lerp(_startWidth, _endWidth, thirdPointRatio);
                    }
                }


                if (i == 0)
                {
                    _firstSegment.SetPoints(ref firstPoint, ref secondPoint);
                    _secondSegment.SetPoints(ref secondPoint, ref thirdPoint);
                }
                else
                {
                    Utils.Swap(ref _firstSegment, ref _secondSegment);
                    if (hasThirdPoint)
                    {
                        _secondSegment.SetPoints(ref secondPoint, ref thirdPoint);
                    }
                }

                // dont recalculate the fusedPoint for the last segment since there will be no third point to work with
                if (hasThirdPoint)
                {
                    var shouldFuseBottom =
                        Vector2Ext.IsTriangleCCW(firstPoint.Position, secondPoint.Position, thirdPoint.Position);
                    _secondSegment.SetFusedData(shouldFuseBottom, ref _firstSegment);
                }

                // special care needs to be take with the first segment since it has a different vert count
                if (i == 0)
                {
                    AddFirstSegment(ref _firstSegment, ref _secondSegment, ref vertIndex);
                }
                else
                {
                    AddSegment(ref _firstSegment, ref vertIndex);
                }

                _lastSegment.CloneFrom(ref _firstSegment);
            }
        }