private NativeArray <ECHoleData> GetHolesDataSortedByMaxX()
        {
            NativeArray <ECHoleData> holesData = new NativeArray <ECHoleData>(Polygon.HolesNum, Allocator.Temp);

            for (int hi = 0; hi < Polygon.HolesNum; ++hi)
            {
                var   hole      = Polygon.GetPolygonHole(hi);
                int   indexMaxX = -1;
                float maxX      = float.MinValue;

                for (int hvi = 0; hvi < hole.Length; ++hvi)
                {
                    if (maxX < hole[hvi].Point.x)
                    {
                        maxX      = hole[hvi].Point.x;
                        indexMaxX = hole[hvi].Index;
                    }
                }

                holesData[hi] = new ECHoleData
                {
                    HoleIndex        = hi,
                    HoleFirstIndex   = hole[0].Index,
                    HoleLength       = hole.Length,
                    BridgePointIndex = indexMaxX,
                    BridgePoint      = Polygon[indexMaxX]
                };
            }
            holesData.Sort();
            return(holesData);
        }
        public void Execute()
        {
            NativeLinkedList <int> hullVertices = StorePolygonContourAsLinkedList();

            #region Removing Holes
            //create the array containing the holes data
            NativeArray <ECHoleData> holes = GetHolesDataSortedByMaxX();
            //remove holes
            for (int hi = 0; hi < holes.Length; ++hi)
            {
                ECHoleData hole = holes[hi];
                var        intersectionEdgeP0 = hullVertices.GetEnumerator();
                var        intersectionEdgeP1 = hullVertices.GetEnumerator();
                float2     intersectionPoint  = new float2(float.MaxValue, hole.BridgePoint.y);

                for (var currentHullVertex = hullVertices.Head; currentHullVertex.IsValid; currentHullVertex.MoveNext())
                {
                    var nextHullVertex = (currentHullVertex.Next.IsValid) ? currentHullVertex.Next : hullVertices.Head;

                    float2 currPoint = Polygon[currentHullVertex.Value];
                    float2 nextPoint = Polygon[nextHullVertex.Value];

                    //M is to the left of the line containing the edge (M is inside the outer polygon)
                    bool isMOnLeftOfEdgeLine = (Math2DUtils.LineSide(hole.BridgePoint, currPoint, nextPoint) < 0f);
                    if (isMOnLeftOfEdgeLine)
                    {
                        continue;
                    }

                    // at least one point must be to right of the hole bridge point for intersection with ray to be possible
                    if (currPoint.x < hole.BridgePoint.x && nextPoint.x < hole.BridgePoint.x)
                    {
                        continue;
                    }

                    if (currPoint.y > hole.BridgePoint.y == nextPoint.y > hole.BridgePoint.y)
                    {
                        continue;
                    }

                    float intersectionX = nextPoint.x; // if line p0,p1 is vertical
                    if (math.abs(currPoint.x - nextPoint.x) > float.Epsilon)
                    {
                        float intersectY = hole.BridgePoint.y;
                        float gradient   = (currPoint.y - nextPoint.y) / (currPoint.x - nextPoint.x);
                        float c          = nextPoint.y - gradient * nextPoint.x;
                        intersectionX = (intersectY - c) / gradient;
                    }

                    if (intersectionX < intersectionPoint.x)
                    {
                        intersectionPoint.x = intersectionX;
                        intersectionEdgeP0  = currentHullVertex;
                        intersectionEdgeP1  = nextHullVertex;
                    }
                }

                var selectedHullBridgePoint = hullVertices.GetEnumerator();
                //If I is a vertex of the outer polygon, then M and I are mutually visible
                if (Math2DUtils.SamePoints(intersectionPoint, Polygon[intersectionEdgeP0.Value]))
                {
                    selectedHullBridgePoint = intersectionEdgeP0;
                }
                else if (Math2DUtils.SamePoints(intersectionPoint, Polygon[intersectionEdgeP1.Value]))
                {
                    selectedHullBridgePoint = intersectionEdgeP1;
                }
                else
                {
                    //Select P to be the endpoint of maximum x-value for this edge
                    var P = (Polygon[intersectionEdgeP0.Value].x > Polygon[intersectionEdgeP1.Value].x) ? intersectionEdgeP0 : intersectionEdgeP1;

                    bool  existReflexVertexInsideMIP = false;
                    float minAngle = float.MaxValue;
                    float minDist  = float.MaxValue;
                    for (var currOuterPolygonVertex = hullVertices.Head; currOuterPolygonVertex.IsValid; currOuterPolygonVertex.MoveNext())
                    {
                        if (currOuterPolygonVertex.Value == P.Value)
                        {
                            continue;
                        }

                        var nextOuterPolygonVertex = (currOuterPolygonVertex.Next.IsValid) ? currOuterPolygonVertex.Next : hullVertices.Head;
                        var prevOuterPolygonVertex = (currOuterPolygonVertex.Prev.IsValid) ? currOuterPolygonVertex.Prev : hullVertices.Tail;

                        if (Math2DUtils.IsVertexReflex(
                                Polygon[prevOuterPolygonVertex.Value],
                                Polygon[currOuterPolygonVertex.Value],
                                Polygon[nextOuterPolygonVertex.Value],
                                true))
                        {
                            bool isInsideMIPTriangle = Math2DUtils.IsInsideTriangle(Polygon[currOuterPolygonVertex.Value],
                                                                                    hole.BridgePoint,
                                                                                    intersectionPoint,
                                                                                    Polygon[P.Value]);
                            existReflexVertexInsideMIP |= isInsideMIPTriangle;

                            if (isInsideMIPTriangle)
                            {
                                //search for the reflex vertex R that minimizes the angle between (1,0) and the line segment M-R
                                float2 MR       = Polygon[currOuterPolygonVertex.Value] - hole.BridgePoint;
                                float  angleMRI = math.atan2(MR.y, MR.x);
                                if (angleMRI < minAngle)
                                {
                                    selectedHullBridgePoint = currOuterPolygonVertex;
                                    minAngle = angleMRI;
                                }
                                else if (math.abs(angleMRI - minAngle) <= float.Epsilon)
                                {
                                    //same angle
                                    float lengthMR = math.length(MR);
                                    if (lengthMR < minDist)
                                    {
                                        selectedHullBridgePoint = currOuterPolygonVertex;
                                        minDist = lengthMR;
                                    }
                                }
                            }
                        }

                        if (!existReflexVertexInsideMIP)
                        {
                            selectedHullBridgePoint = P;
                        }
                    }
                }

                hullVertices.InsertAfter(selectedHullBridgePoint, selectedHullBridgePoint.Value);
                for (int i = hole.BridgePointIndex - hole.HoleFirstIndex, count = 0;
                     count < hole.HoleLength;
                     i = (i + hole.HoleLength - 1) % hole.HoleLength, ++count)
                {
                    hullVertices.InsertAfter(selectedHullBridgePoint, i + hole.HoleFirstIndex);
                }
                hullVertices.InsertAfter(selectedHullBridgePoint, hole.BridgePointIndex);
            }
            holes.Dispose();
            #endregion

            Triangulate(hullVertices);
            hullVertices.Dispose();
        }