using Microsoft.Xna.Framework; namespace FSO.Common.Model { /// /// A k-d Tree for looking up rectangle intersections /// TODO: balancing? could make performance gains more stable at the cost of some of the worst case. /// public class IntersectRectTree { public IntersectRectNode Root; public void Add(Rectangle rect) { if (Root == null) { Root = new IntersectRectNode { Dimension = IntersectRectDimension.Left, Rect = rect }; } else { Root.AddAsChild(rect); } } public bool SearchForIntersect(Rectangle rect) { if (Root == null) return false; else { return Root.SearchForIntersect(rect); } } } public class IntersectRectNode { public IntersectRectNode LeftChild; public IntersectRectNode RightChild; public IntersectRectDimension Dimension; public Rectangle Rect; public void AddAsChild(Rectangle rect) { bool rightSide = false; switch (Dimension) { case IntersectRectDimension.Top: rightSide = rect.Top > Rect.Top; break; case IntersectRectDimension.Left: rightSide = rect.Left > Rect.Left; break; case IntersectRectDimension.Bottom: rightSide = rect.Bottom > Rect.Bottom; break; case IntersectRectDimension.Right: rightSide = rect.Right > Rect.Right; break; } if (rightSide) { if (RightChild != null) RightChild.AddAsChild(rect); else { RightChild = new IntersectRectNode { Dimension = (IntersectRectDimension)(((int)Dimension + 1) % 4), Rect = rect }; } } else { if (LeftChild != null) LeftChild.AddAsChild(rect); else { LeftChild = new IntersectRectNode { Dimension = (IntersectRectDimension)(((int)Dimension + 1) % 4), Rect = rect }; } } } public bool SearchForIntersect(Rectangle rect) { if (rect.Intersects(Rect)) return true; //search in child nodes. int dontSearch = 0; switch (Dimension) { case IntersectRectDimension.Top: dontSearch = (rect.Bottom < Rect.Top)?2:0; break; //if true, do not have to search right (where top greater) case IntersectRectDimension.Left: dontSearch = (rect.Right < Rect.Left)?2:0; break; //if true, do not have to search right (where left greater) case IntersectRectDimension.Bottom: dontSearch = (rect.Top > Rect.Bottom)?1:0; break; //if true, do not have to search left (where bottom less) case IntersectRectDimension.Right: dontSearch = (rect.Left > Rect.Right)?1:0; break; //if true, do not have to search left (where right less) } //may need to search both :'( won't happen often with our small rectangles over large space though. return ((dontSearch != 1 && LeftChild != null && LeftChild.SearchForIntersect(rect)) || (dontSearch != 2 && RightChild != null && RightChild.SearchForIntersect(rect))); } } public enum IntersectRectDimension : byte { Top, Left, Bottom, Right } }