/// <summary>Attempts to add a rectangle of the given size to this node. The X and Y offsets keep track of the /// offset of this node from the origin. /// </summary> public Point?TryAdd(int width, int height, int spacing) { if (width > this.Width || height > this.Height) { return(null); } if (RectangleStored) { // if this node has a rectangle stored here already, delegate to the children if (Child1 != null) // try adding it to the right first { Point?pt = Child1.TryAdd(width, height, spacing); // as an optimization, we'll prevent degenerate subtrees (linked lists) from forming by replacing this // child with our grandchild if it's an only child, or removing this child if we have no grandchildren if (pt.HasValue && (Child1.Child1 == null || Child1.Child2 == null)) { Child1 = Child1.Child1 == null ? Child1.Child2 : Child1.Child1; if (Child1 != null) { Child1.Parent = this; } } if (pt.HasValue || Child2 == null) { return(pt); } } if (Child2 != null) // if we couldn't add it to the first child, try adding it to the second { Point?pt = Child2.TryAdd(width, height, spacing); if (pt.HasValue) { // prevent degenerate subtrees (linked lists) from forming (see comment above for details) if (Child2.Child1 == null || Child2.Child2 == null) { Child2 = Child2.Child1 == null ? Child2.Child2 : Child2.Child1; if (Child2 != null) { Child2.Parent = this; } } } return(pt); } return(null); } else // this node does not have a rectangle stored here yet, so store it here and subdivide this space { // only add children if they'd have a non-empty area if (this.Width > width + spacing) { Child1 = new Node(this, X + (width + spacing), Y, this.Width - (width + spacing), height); } if (this.Height > height + spacing) { Child2 = new Node(this, X, Y + (height + spacing), this.Width, this.Height - (height + spacing)); } RectangleStored = true; return(new Point(X, Y)); } }