public int Compare(int2 a, int2 b)
        {
            var e1a = edges[a.x];
            var e1b = edges[a.y];
            var e2a = edges[b.x];
            var e2b = edges[b.y];

            xvasort[0] = points[e1a.x].x;
            xvasort[1] = points[e1a.y].x;
            xvasort[2] = points[e1b.x].x;
            xvasort[3] = points[e1b.y].x;

            xvbsort[0] = points[e2a.x].x;
            xvbsort[1] = points[e2a.y].x;
            xvbsort[2] = points[e2b.x].x;
            xvbsort[3] = points[e2b.y].x;

            fixed(double *xvasortPtr = xvasort)
            {
                ModuleHandle.InsertionSort <double, XCompare>(xvasortPtr, 0, 3, new XCompare());
            }

            fixed(double *xvbsortPtr = xvbsort)
            {
                ModuleHandle.InsertionSort <double, XCompare>(xvbsortPtr, 0, 3, new XCompare());
            }

            for (int i = 0; i < 4; ++i)
            {
                if (xvasort[i] - xvbsort[i] != 0)
                {
                    return(xvasort[i] < xvbsort[i] ? -1 : 1);
                }
            }
            return(points[e1a.x].y < points[e1a.x].y ? -1 : 1);
        }
        internal bool Triangulate(NativeArray <float2> points, int pointCount, NativeArray <int2> edges, int edgeCount)
        {
            m_NumEdges  = edgeCount;
            m_NumHulls  = edgeCount * 2;
            m_NumPoints = pointCount;
            m_CellCount = 0;
            m_Cells     = new NativeArray <int3>(ModuleHandle.kMaxTriangleCount, m_Allocator);
            m_ILArray   = new NativeArray <int>(m_NumHulls * (m_NumHulls + 1), m_Allocator); // Make room for -1 node.
            m_IUArray   = new NativeArray <int>(m_NumHulls * (m_NumHulls + 1), m_Allocator); // Make room for -1 node.

            NativeArray <UHull> hulls = new NativeArray <UHull>(m_NumPoints * 8, m_Allocator);
            int hullCount             = 0;

            NativeArray <UEvent> events = new NativeArray <UEvent>(m_NumPoints + (m_NumEdges * 2), m_Allocator);
            int eventCount = 0;

            for (int i = 0; i < m_NumPoints; ++i)
            {
                UEvent evt = new UEvent();
                evt.a                = points[i];
                evt.b                = new float2();
                evt.idx              = i;
                evt.type             = (int)UEventType.EVENT_POINT;
                events[eventCount++] = evt;
            }

            for (int i = 0; i < m_NumEdges; ++i)
            {
                int2   e = edges[i];
                float2 a = points[e.x];
                float2 b = points[e.y];
                if (a.x < b.x)
                {
                    UEvent _s = new UEvent();
                    _s.a    = a;
                    _s.b    = b;
                    _s.idx  = i;
                    _s.type = (int)UEventType.EVENT_START;

                    UEvent _e = new UEvent();
                    _e.a    = b;
                    _e.b    = a;
                    _e.idx  = i;
                    _e.type = (int)UEventType.EVENT_END;

                    events[eventCount++] = _s;
                    events[eventCount++] = _e;
                }
                else if (a.x > b.x)
                {
                    UEvent _s = new UEvent();
                    _s.a    = b;
                    _s.b    = a;
                    _s.idx  = i;
                    _s.type = (int)UEventType.EVENT_START;

                    UEvent _e = new UEvent();
                    _e.a    = a;
                    _e.b    = b;
                    _e.idx  = i;
                    _e.type = (int)UEventType.EVENT_END;

                    events[eventCount++] = _s;
                    events[eventCount++] = _e;
                }
            }

            unsafe
            {
                ModuleHandle.InsertionSort <UEvent, TessEventCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(events), 0, eventCount - 1,
                    new TessEventCompare());
                ;
            }

            var   hullOp = true;
            float minX   = events[0].a.x - (1 + math.abs(events[0].a.x)) * math.pow(2.0f, -16.0f);
            UHull hull;

            hull.a.x           = minX;
            hull.a.y           = 1;
            hull.b.x           = minX;
            hull.b.y           = 0;
            hull.idx           = -1;
            hull.ilarray       = new ArraySlice <int>(m_ILArray, m_NumHulls * m_NumHulls, m_NumHulls); // Last element
            hull.iuarray       = new ArraySlice <int>(m_IUArray, m_NumHulls * m_NumHulls, m_NumHulls);
            hull.ilcount       = 0;
            hull.iucount       = 0;
            hulls[hullCount++] = hull;


            for (int i = 0, numEvents = eventCount; i < numEvents; ++i)
            {
                switch (events[i].type)
                {
                case (int)UEventType.EVENT_POINT:
                {
                    hullOp = AddPoint(hulls, hullCount, points, events[i].a, events[i].idx);
                }
                break;

                case (int)UEventType.EVENT_START:
                {
                    hullOp = SplitHulls(hulls, ref hullCount, points, events[i]);
                }
                break;

                default:
                {
                    hullOp = MergeHulls(hulls, ref hullCount, points, events[i]);
                }
                break;
                }

                if (!hullOp)
                {
                    break;
                }
            }

            events.Dispose();
            hulls.Dispose();
            return(hullOp);
        }
        void PrepareDelaunay(NativeArray <int2> edges, int edgeCount)
        {
            m_StarCount = m_CellCount * 3;
            m_Stars     = new NativeArray <UStar>(m_StarCount, m_Allocator);
            m_SPArray   = new NativeArray <int>(m_StarCount * m_StarCount, m_Allocator);

            var UEdgeCount = 0;
            var UEdges     = new NativeArray <int2>(m_StarCount, m_Allocator);

            // Input Edges.
            for (int i = 0; i < edgeCount; ++i)
            {
                int2 e = edges[i];
                e.x      = (edges[i].x < edges[i].y) ? edges[i].x : edges[i].y;
                e.y      = (edges[i].x > edges[i].y) ? edges[i].x : edges[i].y;
                edges[i] = e;
                InsertUniqueEdge(UEdges, e, ref UEdgeCount);
            }

            m_Edges = new NativeArray <int2>(UEdgeCount, m_Allocator);
            for (int i = 0; i < UEdgeCount; ++i)
            {
                m_Edges[i] = UEdges[i];
            }
            UEdges.Dispose();

            unsafe
            {
                ModuleHandle.InsertionSort <int2, TessEdgeCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(m_Edges), 0, m_Edges.Length - 1,
                    new TessEdgeCompare());
            }

            // Init Stars.
            for (int i = 0; i < m_StarCount; ++i)
            {
                UStar s = m_Stars[i];
                s.points     = new ArraySlice <int>(m_SPArray, i * m_StarCount, m_StarCount);
                s.pointCount = 0;
                m_Stars[i]   = s;
            }

            // Fill stars.
            for (int i = 0; i < m_CellCount; ++i)
            {
                int   a  = m_Cells[i].x;
                int   b  = m_Cells[i].y;
                int   c  = m_Cells[i].z;
                UStar sa = m_Stars[a];
                UStar sb = m_Stars[b];
                UStar sc = m_Stars[c];
                sa.points[sa.pointCount++] = b;
                sa.points[sa.pointCount++] = c;
                sb.points[sb.pointCount++] = c;
                sb.points[sb.pointCount++] = a;
                sc.points[sc.pointCount++] = a;
                sc.points[sc.pointCount++] = b;
                m_Stars[a] = sa;
                m_Stars[b] = sb;
                m_Stars[c] = sc;
            }
        }
        NativeArray <int3> Constrain(ref int count)
        {
            var cells = GetCells(ref count);
            int nc    = count;

            for (int i = 0; i < nc; ++i)
            {
                int3 c = cells[i];
                int  x = c.x, y = c.y, z = c.z;
                if (y < z)
                {
                    if (y < x)
                    {
                        c.x = y;
                        c.y = z;
                        c.z = x;
                    }
                }
                else if (z < x)
                {
                    c.x = z;
                    c.y = x;
                    c.z = y;
                }

                cells[i] = c;
            }

            unsafe
            {
                ModuleHandle.InsertionSort <int3, TessCellCompare>(
                    NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(cells), 0, m_CellCount - 1,
                    new TessCellCompare());
            }

            // Out
            m_Flags       = new NativeArray <int>(nc, m_Allocator);
            m_Neighbors   = new NativeArray <int>(nc * 3, m_Allocator);
            m_Constraints = new NativeArray <int>(nc * 3, m_Allocator);
            var next   = new NativeArray <int>(nc * 3, m_Allocator);
            var active = new NativeArray <int>(nc * 3, m_Allocator);

            int side = 1, nextCount = 0, activeCount = 0;

            for (int i = 0; i < nc; ++i)
            {
                int3 c = cells[i];
                for (int j = 0; j < 3; ++j)
                {
                    int x = j, y = (j + 1) % 3;
                    x = (x == 0) ? c.x : (j == 1) ? c.y : c.z;
                    y = (y == 0) ? c.x : (y == 1) ? c.y : c.z;

                    int o = OppositeOf(y, x);
                    int a = m_Neighbors[3 * i + j] = FindNeighbor(cells, count, y, x, o);
                    int b = m_Constraints[3 * i + j] = (-1 != FindConstraint(x, y)) ? 1 : 0;
                    if (a < 0)
                    {
                        if (0 != b)
                        {
                            next[nextCount++] = i;
                        }
                        else
                        {
                            active[activeCount++] = i;
                            m_Flags[i]            = 1;
                        }
                    }
                }
            }

            while (activeCount > 0 || nextCount > 0)
            {
                while (activeCount > 0)
                {
                    int t = active[activeCount - 1];
                    activeCount--;
                    if (m_Flags[t] == -side)
                    {
                        continue;
                    }

                    m_Flags[t] = side;
                    int3 c = cells[t];
                    for (int j = 0; j < 3; ++j)
                    {
                        int f = m_Neighbors[3 * t + j];
                        if (f >= 0 && m_Flags[f] == 0)
                        {
                            if (0 != m_Constraints[3 * t + j])
                            {
                                next[nextCount++] = f;
                            }
                            else
                            {
                                active[activeCount++] = f;
                                m_Flags[f]            = side;
                            }
                        }
                    }
                }

                for (int e = 0; e < nextCount; e++)
                {
                    active[e] = next[e];
                }
                activeCount = nextCount;
                nextCount   = 0;
                side        = -side;
            }

            active.Dispose();
            next.Dispose();
            return(cells);
        }