Ejemplo n.º 1
0
        public static MonotoneLayout Split(this PlainShape shape, long maxEdge, NativeArray <IntVector> extraPoints, Allocator allocator)
        {
            var navigator   = shape.GetNavigator(maxEdge, extraPoints, Allocator.Temp);
            var links       = new DynamicArray <Link>(navigator.links, allocator);
            var natures     = navigator.natures;
            var sortIndices = navigator.indices;

            int n = sortIndices.Length;

            var subs    = new DynamicArray <Sub>(8, Allocator.Temp);
            var dSubs   = new DynamicArray <DualSub>(8, Allocator.Temp);
            var indices = new DynamicArray <int>(16, allocator);
            var slices  = new DynamicArray <Slice>(16, allocator);

            int i = 0;

nextNode:
            while (i < n)
            {
                int sortIndex = sortIndices[i];
                var node      = links[sortIndex];
                var nature    = natures[sortIndex];

                int j;
                switch (nature)
                {
                case LinkNature.start:
                    subs.Add(new Sub(node));
                    ++i;
                    goto nextNode;

                case LinkNature.extra:
                    j = 0;

                    while (j < dSubs.Count)
                    {
                        var dSub = dSubs[j];
                        var pA   = dSub.next.vertex.point;
                        var pB   = links[dSub.next.next].vertex.point;
                        var pC   = links[dSub.prev.prev].vertex.point;
                        var pD   = dSub.prev.vertex.point;

                        var p = node.vertex.point;

                        if (IsTetragonContain(p, pA, pB, pC, pD))
                        {
                            var hand = links[dSub.middle];
                            slices.Add(new Slice(hand.vertex.index, node.vertex.index));
                            links.ConnectExtraPrev(hand.self, node.self);

                            dSubs[j] = new DualSub(links[dSub.next.self], node.self, links[dSub.prev.self]);

                            i += 1;
                            goto nextNode;
                        }

                        j += 1;
                    }   //  while dSubs

                    j = 0;

                    while (j < subs.Count)
                    {
                        var sub = subs[j];

                        var pA = sub.next.vertex.point;
                        var pB = links[sub.next.next].vertex.point;
                        var pC = links[sub.prev.prev].vertex.point;
                        var pD = sub.prev.vertex.point;

                        var p = node.vertex.point;

                        if (IsTetragonContain(p, pA, pB, pC, pD))
                        {
                            if (!sub.isEmpty)
                            {
                                if (pA.x > pD.x)
                                {
                                    var hand = sub.next;
                                    slices.Add(new Slice(hand.vertex.index, node.vertex.index));
                                    var newHandIndex = links.ConnectExtraNext(hand.self, node.self);
                                    dSubs.Add(new DualSub(links[newHandIndex], node.self, links[sub.prev.self]));
                                }
                                else
                                {
                                    var hand = sub.prev;
                                    slices.Add(new Slice(hand.vertex.index, node.vertex.index));
                                    var newHandIndex = links.ConnectExtraPrev(hand.self, node.self);
                                    dSubs.Add(new DualSub(links[sub.next.self], node.self, links[newHandIndex]));
                                }
                            }
                            else
                            {
                                var hand = links[sub.next.self];
                                slices.Add(new Slice(hand.vertex.index, b: node.vertex.index));
                                var newPrev = links.ConnectExtraPrev(hand.self, node.self);
                                dSubs.Add(new DualSub(links[hand.self], node.self, links[newPrev]));
                            }
                            subs.Exclude(j);
                            i += 1;
                            goto nextNode;
                        }

                        j += 1;
                    }
                    break;

                case LinkNature.merge:

                    var newNextSub = new Sub(true);
                    var newPrevSub = new Sub(true);

                    j = 0;

                    while (j < dSubs.Count)
                    {
                        var dSub = dSubs[j];

                        if (dSub.next.next == node.self)
                        {
                            var a      = node.self;
                            var b      = dSub.middle;
                            var bridge = links.Connect(a, b);

                            indices.Add(links.FindStart(bridge.a.self));

                            slices.Add(bridge.Slice);

                            var prevSub = new Sub(links[a], dSub.prev);

                            if (!newNextSub.isEmpty)
                            {
                                dSubs[j] = new DualSub(newNextSub, prevSub);
                                ++i;
                                goto nextNode;
                            }

                            dSubs.Exclude(j);

                            newPrevSub = prevSub;
                            continue;
                        }
                        else if (dSub.prev.prev == node.self)
                        {
                            var a = dSub.middle;
                            var b = node.self;

                            var bridge = links.Connect(a, b);

                            indices.Add(links.FindStart(bridge.a.self));
                            slices.Add(bridge.Slice);

                            var nextSub = new Sub(dSub.next, links[b]);

                            if (!newPrevSub.isEmpty)
                            {
                                dSubs[j] = new DualSub(nextSub, newPrevSub);
                                ++i;
                                goto nextNode;
                            }
                            dSubs.Exclude(j);

                            newNextSub = nextSub;
                            continue;
                        }

                        ++j;
                    }       //  while dSubs

                    j = 0;

                    while (j < subs.Count)
                    {
                        var sub = subs[j];

                        if (sub.next.next == node.self)
                        {
                            sub.next = node;

                            subs.Exclude(j);

                            if (!newNextSub.isEmpty)
                            {
                                dSubs.Add(new DualSub(newNextSub, sub));
                                ++i;
                                goto nextNode;
                            }

                            newPrevSub = sub;
                            continue;
                        }
                        else if (sub.prev.prev == node.self)
                        {
                            sub.prev = node;
                            subs.Exclude(j);

                            if (!newPrevSub.isEmpty)
                            {
                                dSubs.Add(new DualSub(sub, newPrevSub));
                                ++i;
                                goto nextNode;
                            }

                            newNextSub = sub;
                            continue;
                        }

                        ++j;
                    }
                    break;

                case LinkNature.split:

                    j = 0;

                    while (j < subs.Count)
                    {
                        var sub = subs[j];


                        var pA = sub.next.vertex.point;

                        var pB = links[sub.next.next].vertex.point;

                        var pC = links[sub.prev.prev].vertex.point;

                        var pD = sub.prev.vertex.point;


                        var p = node.vertex.point;

                        if (IsTetragonContain(p, pA, pB, pC, pD))
                        {
                            var a0 = sub.next.self;
                            var a1 = sub.prev.self;
                            var b  = node.self;

                            if (pA.x > pD.x)
                            {
                                var bridge = links.Connect(a0, b);

                                subs.Add(new Sub(bridge.b, links[a1]));

                                slices.Add(bridge.Slice);
                            }
                            else
                            {
                                var bridge = links.Connect(a1, b);

                                subs.Add(new Sub(bridge.b, bridge.a));
                                slices.Add(bridge.Slice);
                            }
                            subs[j] = new Sub(links[a0], links[b]);
                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    }

                    j = 0;

                    while (j < dSubs.Count)
                    {
                        var dSub = dSubs[j];

                        var pA = dSub.next.vertex.point;

                        var pB = links[dSub.next.next].vertex.point;
                        var pC = links[dSub.prev.prev].vertex.point;
                        var pD = dSub.prev.vertex.point;
                        var p  = node.vertex.point;

                        if (IsTetragonContain(p, pA, pB, pC, pD))
                        {
                            var a = dSub.middle;

                            var b      = node.self;
                            var bridge = links.Connect(a, b);

                            subs.Add(new Sub(dSub.next, links[b]));
                            subs.Add(new Sub(bridge.b, dSub.prev));
                            slices.Add(bridge.Slice);
                            dSubs.Exclude(j);

                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    }       //  while dSubs

                    break;

                case LinkNature.end:

                    j = 0;

                    while (j < subs.Count)
                    {
                        var sub = subs[j];

                        // second condition is useless because it repeats the first
                        if (sub.next.next == node.self)    /* || sub.prev.prev.index == node.this */
                        {
                            indices.Add(links.FindStart(node.self));

                            subs.Exclude(j);

                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    }

                    j = 0;

                    while (j < dSubs.Count)
                    {
                        var dSub = dSubs[j];

                        // second condition is useless because it repeats the first
                        if (dSub.next.next == node.self)    /*|| dSub.prevSub.prev.prev.index == node.this*/
                        {
                            var a      = dSub.middle;
                            var b      = node.self;
                            var bridge = links.Connect(a, b);

                            indices.Add(links.FindStart(a));
                            indices.Add(links.FindStart(bridge.a.self));
                            slices.Add(bridge.Slice);

                            dSubs.Exclude(j);

                            // goto next node
                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    }       //  while dSubs

                    break;

                case LinkNature.simple:

                    j = 0;

                    while (j < subs.Count)
                    {
                        var sub = subs[j];

                        if (sub.next.next == node.self)
                        {
                            sub.next = node;
                            subs[j]  = sub;

                            ++i;
                            goto nextNode;
                        }
                        else if (sub.prev.prev == node.self)
                        {
                            sub.prev = node;
                            subs[j]  = sub;
                            // goto next node
                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    }

                    j = 0;

                    while (j < dSubs.Count)
                    {
                        var dSub = dSubs[j];

                        if (dSub.next.next == node.self)
                        {
                            var a = dSub.middle;
                            var b = node.self;

                            var bridge = links.Connect(a, b);

                            indices.Add(links.FindStart(node.self));
                            slices.Add(bridge.Slice);

                            var newSub = new Sub(bridge.b, dSub.prev);
                            subs.Add(newSub);

                            dSubs.Exclude(j);

                            // goto next node
                            ++i;
                            goto nextNode;
                        }
                        else if (dSub.prev.prev == node.self)
                        {
                            var a = node.self;
                            var b = dSub.middle;

                            var bridge = links.Connect(a, b);

                            indices.Add(links.FindStart(node.self));
                            slices.Add(bridge.Slice);

                            var newSub = new Sub(links[dSub.next.self], bridge.a);
                            subs.Add(newSub);

                            dSubs.Exclude(j);

                            // goto next node
                            ++i;
                            goto nextNode;
                        }

                        ++j;
                    } //  while dSubs
                    break;
                }     // switch
            }

            subs.Dispose();
            dSubs.Dispose();
            navigator.Dispose();

            int pathCount  = navigator.pathCount;
            int extraCount = navigator.extraCount;

            return(new MonotoneLayout(pathCount, extraCount, links.Convert(), slices.Convert(), indices.Convert()));
        }