using System; using System.Text; using System.Drawing; using System.Collections.Generic; namespace Sithid.QuadTree { public class QuadNode : IQuadObject where T: IQuadObject { protected const byte _MAX_OBJECTS_ = 4; private QuadNode m_Parent; private RectangleF m_Bounds; private PointF m_Location; private List m_BranchItems; private List> m_Children; private T m_LastObject; public QuadNode Parent { get { return m_Parent; } set { m_Parent = value; } } public RectangleF Bounds { get { return m_Bounds; } set { m_Bounds = value; } } public PointF Location { get { return m_Location; } set { m_Location = value; } } public List BranchItems { get { return m_BranchItems; } set { m_BranchItems = value; } } public List> Children { get { return m_Children; } set { m_Children = value; } } public bool IsRoot { get { return ( m_Parent == this ); } } public int TotalObjects { get { int count = m_BranchItems.Count; if( m_Children != null ) { for( int i = 0; i < m_Children.Count; ++i ) { count += m_Children[i].TotalObjects; } } return count; } } public QuadNode( RectangleF bounds, QuadNode parent ) { m_Parent = parent == null ? this : parent; m_Bounds = bounds; m_BranchItems = new List(); m_Children = null; m_LastObject = default(T); } public void Add(T val) { m_LastObject = val; QuadNode node = FindParent( val.Bounds, val.Location, m_Parent ); List> m_Intersects = new List>(); if( node.Children != null ) { for( int i = 0; i < node.Children.Count; ++i ) { if( node.Children[i].Bounds.IntersectsWith( val.Bounds ) ) { m_Intersects.Add( node.Children[i] ); } } if( m_Intersects.Count > 1 ) { node.BranchItems.Add( val ); } else { m_Intersects[0].Add( val ); } } else { if( node.BranchItems != null ) { if( node.BranchItems.Count < _MAX_OBJECTS_ ) { node.BranchItems.Add( val ); } else { node.Split(); QuadNode recurse = FindParent( val.Bounds, val.Location, node ); recurse.Add( val ); } } } } private QuadNode FindParent( RectangleF bounds, PointF loc, QuadNode recurse ) { if( recurse != null ) { for( int i = 0; recurse.Children != null && i < recurse.Children.Count; ++i ) { if( recurse.Children[i].Bounds.IntersectsWith( bounds ) ) { recurse = FindParent( bounds, loc, recurse.Children[i] ); } } } else { return this; } return recurse; } public void Split() { float x = m_Bounds.Left; float y = m_Bounds.Top; float halfx = m_Bounds.Width / 2; float halfy = m_Bounds.Height / 2; m_Children = new List>(); m_Children.Add( new QuadNode( new RectangleF( x, y, halfx, halfy ), this ) ); m_Children.Add( new QuadNode( new RectangleF( x + halfx, y, halfx, halfy ), this ) ); m_Children.Add( new QuadNode( new RectangleF( x, y + halfy, halfx, halfy ), this ) ); m_Children.Add( new QuadNode( new RectangleF( x + halfx, y + halfy, halfx, halfy ), this ) ); for( int i = 0; i < m_BranchItems.Count; ++i ) { for( int j = 0; j < m_Children.Count; ++j ) { if( m_Children[j].Bounds.IntersectsWith( m_BranchItems[i].Bounds ) ) { m_Children[j].Add( m_BranchItems[i] ); m_BranchItems.Remove( m_BranchItems[i] ); --i; break; } } } } public void Draw( Graphics g, Point mousePos, bool useMouse ) { Brush b = Brushes.Black; Pen p = new Pen( Color.Red, 1f ); PointF p1, p2, p3, p4; if( useMouse ) { if( m_Bounds.Contains( mousePos ) ) { if( m_Children != null ) { for( int i = 0; i < m_Children.Count; ++i ) { m_Children[i].Draw( g, mousePos, useMouse ); } } else { p1 = new PointF( m_Bounds.Left, m_Bounds.Top ); p2 = new PointF( m_Bounds.Right, m_Bounds.Top ); p3 = new PointF( m_Bounds.Left, m_Bounds.Bottom ); p4 = new PointF( m_Bounds.Right, m_Bounds.Bottom ); g.DrawLine( p, p1, p2 ); g.DrawLine( p, p2, p4 ); g.DrawLine( p, p1, p3 ); g.DrawLine( p, p3, p4 ); for( int i = 0; i < m_BranchItems.Count; ++i ) { g.FillRectangle( b, m_BranchItems[i].Bounds ); } } } } else { if( m_Children != null ) { for( int i = 0; i < m_Children.Count; ++i ) { m_Children[i].Draw( g, mousePos, useMouse ); } } else { for( int i = 0; i < m_BranchItems.Count; ++i ) { g.FillRectangle( b, m_BranchItems[i].Bounds ); } p1 = new PointF( m_Bounds.Left, m_Bounds.Top ); p2 = new PointF( m_Bounds.Right, m_Bounds.Top ); p3 = new PointF( m_Bounds.Left, m_Bounds.Bottom ); p4 = new PointF( m_Bounds.Right, m_Bounds.Bottom ); g.DrawLine( p, p1, p2 ); g.DrawLine( p, p2, p4 ); g.DrawLine( p, p1, p3 ); g.DrawLine( p, p3, p4 ); } } p.Dispose(); } } }