Example #1
0
        private List <RegionQuadtree <T> > getAllWhoShareEdge(QuadDirection direction, QuadType type)
        {
            QuadDirection[] dir;
            var             op = QDO.OpSide(direction);

            if ((int)direction % 2 == 0)
            {
                dir = new QuadDirection[] { QDO.Quad(op, QDO.CSide(op)), QDO.Quad(op, QDO.CCSide(op)) };
            }
            else
            {
                dir = new QuadDirection[] { QDO.OpSide(op) };
            }

            if (type == QuadType.Grey)
            {
                throw new ArgumentException("Grey isn't allowed!");
            }

            var share = new List <RegionQuadtree <T> >();

            getAllWhoShareEdgeInternal(type, this, share, dir);

            return(share);
        }
Example #2
0
        private IEnumerable <RegionQuadtree <T> > traverseInternal(RegionQuadtree <T>[] a)
        {
            var sides = QDO.Sides;

            var t = new RegionQuadtree <T> [8];

            if (Type == QuadType.Grey)
            {
                for (int i = 0; i < 4; i++)
                {
                    var d = sides[i];

                    t[(int)d] = soni(a[(int)d], QDO.Quad(QDO.OpSide(d), QDO.CSide(d)));
                    t[(int)QDO.Quad(d, QDO.CSide(d))] = soni(a[(int)QDO.Quad(d, QDO.CSide(d))], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));
                    t[(int)QDO.CSide(d)] = soni(a[(int)QDO.CSide(d)], QDO.Quad(d, QDO.CCSide(d)));
                    t[(int)QDO.Quad(QDO.OpSide(d), QDO.CSide(d))] = soni(a[(int)QDO.CSide(d)], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));
                    t[(int)QDO.OpSide(d)] = this[QDO.Quad(QDO.OpSide(d), QDO.CSide(d))];
                    t[(int)QDO.Quad(QDO.OpSide(d), QDO.CCSide(d))] = this[QDO.Quad(QDO.OpSide(d), QDO.CCSide(d))];
                    t[(int)QDO.CCSide(d)] = this[QDO.Quad(d, QDO.CCSide(d))];
                    t[(int)QDO.Quad(d, QDO.CCSide(d))] = soni(a[(int)d], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));

                    foreach (var item in this[QDO.Quad(d, QDO.CSide(d))].traverseInternal(t))
                    {
                        yield return(item);
                    }
                }
            }
            else if (Type == QuadType.Black)
            {
                for (int i = 0; i < 8; i++)
                {
                    if (a[i] != null && a[i].Type == QuadType.White)
                    {
                        a[i] = null;
                    }
                }

                yield return(this);
            }
        }
Example #3
0
        public RegionQuadtree <T> ExpandFromCenter()
        {
            if (Type != QuadType.Grey)
            {
                subdivide();
            }

            Action <RegionQuadtree <T>, Action <RegionQuadtree <T> > > doForEach = null;

            doForEach = (qt, f) =>
            {
                f(qt);

                if (qt.Type == QuadType.Grey)
                {
                    foreach (var dir in QDO.Quadrants)
                    {
                        doForEach(qt[dir], f);
                    }
                }
            };

            doForEach(this, (qt) =>
            {
                if (qt.Type == QuadType.Black)
                {
                    qt.propagateEvent(EventType.Removing);
                }
            });

            var newRoot = new RegionQuadtree <T>(resolution + 1);

            newRoot.AutoExpand = AutoExpand;
            newRoot.subdivide();
            foreach (var child in newRoot.quads)
            {
                child.subdivide();
            }

            var offset = new Point2i(newRoot.aabb.Width / 4, newRoot.aabb.Height / 4);

            var offsets = new Dictionary <QuadDirection, Point2i>
            {
                { QuadDirection.NorthWest, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) },
                { QuadDirection.SouthEast, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) },
                { QuadDirection.NorthEast, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) },
                { QuadDirection.SouthWest, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) },
            };

            // Set children

            Action <RegionQuadtree <T>, RegionQuadtree <T> > expandProcessor = null;

            expandProcessor = (qt, parent) =>
            {
                // Do this
                qt.parent     = parent;
                qt.depth      = qt.parent.depth + 1;
                qt.resolution = qt.parent.resolution;

                // Do children
                if (qt.Type == QuadType.Grey)
                {
                    foreach (var dir in QDO.Quadrants)
                    {
                        switch (dir)
                        {
                        case QuadDirection.NorthWest:
                            qt[dir].aabb.LowerBound = qt.aabb.LowerBound;
                            qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height / 2);
                            break;

                        case QuadDirection.NorthEast:
                            qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, 0);
                            qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width, qt.aabb.Height / 2);
                            break;

                        case QuadDirection.SouthEast:
                            qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height / 2);
                            qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width, qt.aabb.Height);
                            break;

                        case QuadDirection.SouthWest:
                            qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(0, qt.aabb.Height / 2);
                            qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height);
                            break;

                        default:
                            throw new ArgumentException("Invalid direction");
                        }

                        expandProcessor(qt[dir], qt);
                    }
                }
            };

            foreach (var quadDirection in QDO.Quadrants)
            {
                var oldQuad = newRoot[quadDirection][QDO.OpSide(quadDirection)];

                newRoot[quadDirection][QDO.OpSide(quadDirection)] = this[quadDirection];

                var newQuad = newRoot[quadDirection][QDO.OpSide(quadDirection)];

                newQuad.aabb = oldQuad.aabb;
                expandProcessor(newQuad, oldQuad.parent);
            }

            // Call the event
            if (OnExpand != null)
            {
                OnExpand(this, new QuadExpandEventArgs <T>(newRoot, offset));
            }

            // Move events
            // TODO: Test this works properly
            newRoot.OnQuadAdded    = OnQuadAdded;
            OnQuadAdded            = null;
            newRoot.OnQuadRemoving = OnQuadRemoving;
            OnQuadRemoving         = null;
            newRoot.OnQuadChanged  = OnQuadChanged;
            OnQuadChanged          = null;

            doForEach(newRoot, (qt) =>
            {
                if (qt.Type == QuadType.Black)
                {
                    qt.propagateEvent(EventType.Added);
                }
            });

            newRoot.OnExpand = OnExpand;

            return(newRoot);
        }
Example #4
0
        private void cclInternal(RegionQuadtree <T>[] a, List <DisjointSet <int> > linked, Dictionary <RegionQuadtree <T>, int> labels, QuadDirection[] sides, bool quadrants)
        {
            var t = new RegionQuadtree <T> [8];

            if (Type == QuadType.Grey)
            {
                for (int i = 0; i < 4; i++)
                {
                    var d = sides[i];

                    t[(int)d]             = soni(a[(int)d], QDO.Quad(QDO.OpSide(d), QDO.CSide(d)));
                    t[(int)QDO.CSide(d)]  = soni(a[(int)QDO.CSide(d)], QDO.Quad(d, QDO.CCSide(d)));
                    t[(int)QDO.OpSide(d)] = this[QDO.Quad(QDO.OpSide(d), QDO.CSide(d))];
                    t[(int)QDO.CCSide(d)] = this[QDO.Quad(d, QDO.CCSide(d))];

                    if (quadrants)
                    {
                        t[(int)QDO.Quad(d, QDO.CSide(d))]              = soni(a[(int)QDO.Quad(d, QDO.CSide(d))], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));
                        t[(int)QDO.Quad(QDO.OpSide(d), QDO.CSide(d))]  = soni(a[(int)QDO.CSide(d)], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));
                        t[(int)QDO.Quad(QDO.OpSide(d), QDO.CCSide(d))] = this[QDO.Quad(QDO.OpSide(d), QDO.CCSide(d))];
                        t[(int)QDO.Quad(d, QDO.CCSide(d))]             = soni(a[(int)d], QDO.Quad(QDO.OpSide(d), QDO.CCSide(d)));
                    }

                    this[QDO.Quad(d, QDO.CSide(d))].cclInternal(t, linked, labels, sides, quadrants);
                }
            }
            else if (Type == QuadType.Black)
            {
                bool noNeighbors    = true;
                var  neighborLabels = new List <int>();
                for (int i = 0; i < 8; i++)
                {
                    if (a[i] != null && a[i].Type == QuadType.White)
                    {
                        a[i] = null;
                    }

                    if (a[i] != null)
                    {
                        if (a[i].Type == QuadType.Black && labels.ContainsKey(a[i]))
                        {
                            neighborLabels.Add(labels[a[i]]);
                            noNeighbors = false;
                        }
                        else if (a[i].Type == QuadType.Grey)
                        {
                            var share = getAllWhoShareEdge((QuadDirection)i, QuadType.Black);
                            foreach (var shareBlack in share)
                            {
                                if (labels.ContainsKey(shareBlack))
                                {
                                    neighborLabels.Add(labels[shareBlack]);
                                    noNeighbors = false;
                                }
                            }
                        }
                    }
                }

                if (noNeighbors)
                {
                    var nextLabel = linked.Count;
                    linked.Add(new DisjointSet <int>(nextLabel));
                    labels[this] = nextLabel;
                }
                else
                {
                    labels[this] = neighborLabels.Min();
                    for (int i = 0; i < neighborLabels.Count; i++)
                    {
                        for (int j = 0; j < neighborLabels.Count; j++)
                        {
                            linked[neighborLabels[i]].Union(linked[neighborLabels[j]]);
                        }
                    }
                }
            }
        }