private void SplitHulls(WorkBuffer <PartialHull> hulls, Event e)
        {
            var splitIdx = BinarySearch.LE(hulls.Data, e, FindSplit.Default, 0, hulls.UsedSize - 1);
            var hull     = hulls.Data[splitIdx];
            var upperIds = hull.UpperIds;
            var x        = upperIds.Data[upperIds.UsedSize - 1];

            hull.UpperIds = new WorkBuffer <int>(8);
            hull.UpperIds.Push(ref x);
            var h = hulls.Insert(splitIdx + 1);

            h.A     = e.A;
            h.B     = e.B;
            h.Index = e.Index;
            h.LowerIds.Clear();
            h.LowerIds.Push(ref x);
            h.UpperIds = upperIds;

            if (Verbose)
            {
                Debug.Log("Split: " + splitIdx);
                DumpHulls(hulls);
                hulls.Dump();
            }
        }
        private void AddPoint(List <int> cells, WorkBuffer <PartialHull> hulls, List <Vector3> points, Vector2 p, int idx)
        {
            var lo = BinarySearch.LT(hulls.Data, p, TestPoint.Default, 0, hulls.UsedSize - 1);
            var hi = BinarySearch.GT(hulls.Data, p, TestPoint.Default, 0, hulls.UsedSize - 1);

            for (var i = lo; i < hi; ++i)
            {
                var hull = hulls.Data[i];

                //Insert p into lower hull
                {
                    var lowerIds     = hull.LowerIds;
                    var m            = lowerIds.UsedSize;
                    var lowerIdsData = lowerIds.Data;
                    while (m > 1 && Robust.Orientation(points[lowerIdsData[m - 2]], points[lowerIdsData[m - 1]], p) > 0f)
                    {
                        cells.Add(lowerIdsData[m - 1]);
                        cells.Add(lowerIdsData[m - 2]);
                        cells.Add(idx);
                        m -= 1;
                    }

                    if (m < lowerIds.UsedSize)
                    {
                        lowerIds.RemoveLast(lowerIds.UsedSize - m);
                    }

                    lowerIds.Push(ref idx);
                }

                //Insert p into upper hull
                {
                    var upperIds     = hull.UpperIds;
                    var m            = upperIds.UsedSize;
                    var upperIdsData = upperIds.Data;
                    while (m > 1 && Robust.Orientation(points[upperIdsData[m - 2]], points[upperIdsData[m - 1]], p) < 0f)
                    {
                        cells.Add(upperIdsData[m - 2]);
                        cells.Add(upperIdsData[m - 1]);
                        cells.Add(idx);
                        m -= 1;
                    }

                    if (m < upperIds.UsedSize)
                    {
                        upperIds.RemoveLast(upperIds.UsedSize - m);
                    }

                    upperIds.Push(ref idx);
                }
            }

            if (Verbose)
            {
                Debug.Log("Add");
                DumpHulls(hulls);
                hulls.Dump();
            }
        }
        private void MergeHulls(WorkBuffer <PartialHull> hulls, Event e)
        {
            //Swap pointers for merge search
            var tmp = e.A;

            e.A = e.B;
            e.B = tmp;
            var mergeIdx = BinarySearch.EQ(hulls.Data, e, FindSplit.Default, 0, hulls.UsedSize - 1);
            var upper    = hulls.Data[mergeIdx];
            var lower    = hulls.Data[mergeIdx - 1];

            lower.UpperIds = upper.UpperIds;
            hulls.RemoveAt(mergeIdx);

            if (Verbose)
            {
                Debug.Log("Merge: " + mergeIdx);
                DumpHulls(hulls);
                hulls.Dump();
            }
        }