/// <summary>
 /// Internal helper function for computing intersections.
 /// </summary>
 private static bool IntersectHorizontal(ref RCNumRectangle lRect, ref RCNumRectangle rRect, out RCNumber intersectLeft, out RCNumber intersectRight)
 {
     if ((lRect.Left <= rRect.Left && rRect.Left < lRect.Right && lRect.Right <= rRect.Right))
     {
         intersectLeft  = rRect.Left;
         intersectRight = lRect.Right;
         return(true);
     }
     else if (rRect.Left <= lRect.Left && lRect.Left < lRect.Right && lRect.Right <= rRect.Right)
     {
         intersectLeft  = lRect.Left;
         intersectRight = lRect.Right;
         return(true);
     }
     else if (rRect.Left <= lRect.Left && lRect.Left < rRect.Right && rRect.Right <= lRect.Right)
     {
         intersectLeft  = lRect.Left;
         intersectRight = rRect.Right;
         return(true);
     }
     else
     {
         intersectLeft  = 0;
         intersectRight = 0;
         return(false);
     }
 }
 /// <summary>
 /// Internal helper function for computing intersections.
 /// </summary>
 private static bool IntersectVertical(ref RCNumRectangle lRect, ref RCNumRectangle rRect, out RCNumber intersectTop, out RCNumber intersectBottom)
 {
     if (lRect.Top <= rRect.Top && rRect.Top < lRect.Bottom && lRect.Bottom <= rRect.Bottom)
     {
         intersectTop    = rRect.Top;
         intersectBottom = lRect.Bottom;
         return(true);
     }
     else if (rRect.Top <= lRect.Top && lRect.Top < lRect.Bottom && lRect.Bottom <= rRect.Bottom)
     {
         intersectTop    = lRect.Top;
         intersectBottom = lRect.Bottom;
         return(true);
     }
     else if (rRect.Top <= lRect.Top && lRect.Top < rRect.Bottom && rRect.Bottom <= lRect.Bottom)
     {
         intersectTop    = lRect.Top;
         intersectBottom = rRect.Bottom;
         return(true);
     }
     else
     {
         intersectTop    = 0;
         intersectBottom = 0;
         return(false);
     }
 }
        /// <summary>
        /// Subdivides this BspSearchTreeNode if necessary.
        /// </summary>
        /// <remarks>Subdivision is only allowed in case of leaf-nodes.</remarks>
        private void Subdivide()
        {
            if (!this.isLeaf)
            {
                throw new InvalidOperationException("Only leaf-nodes can be subdivided!");
            }

            this.isLeaf = false;
            if (this.firstChild == null || this.secondChild == null)
            {
                /// Children have to be created.
                RCNumRectangle firstChildArea = this.area.Width > this.area.Height
                                              ? new RCNumRectangle(this.area.X, this.area.Y, this.area.Width / 2, this.area.Height)
                                              : new RCNumRectangle(this.area.X, this.area.Y, this.area.Width, this.area.Height / 2);
                RCNumRectangle secondChildArea = this.area.Width > this.area.Height
                                               ? firstChildArea + new RCNumVector(firstChildArea.Width, 0)
                                               : firstChildArea + new RCNumVector(0, firstChildArea.Height);
                this.firstChild  = new BspSearchTreeNode <T>(firstChildArea, this.capacity, this.minSize);
                this.secondChild = new BspSearchTreeNode <T>(secondChildArea, this.capacity, this.minSize);
            }
            else
            {
                /// Children already exist.
                this.firstChild.isLeaf  = true;
                this.secondChild.isLeaf = true;
                this.firstChild.contents.Clear();
                this.secondChild.contents.Clear();
            }
        }
        /// <summary>
        /// Returns a third RCNumRectangle that represents the intersection of two other RCRectangles.
        /// If there is no intersection, RCNumRectangle.Undefined is returned.
        /// </summary>
        /// <param name="lRect">An RCNumRectangle to intersect.</param>
        /// <param name="rRect">An RCNumRectangle to intersect.</param>
        /// <returns>
        /// An RCNumRectangle that is the intersection of lRect and rRect or RCNumRectangle.Undefined if there is no intersection.
        /// </returns>
        public static RCNumRectangle Intersect(RCNumRectangle lRect, RCNumRectangle rRect)
        {
            if (!lRect.isDefined)
            {
                throw new ArgumentNullException("lRect");
            }
            if (!rRect.isDefined)
            {
                throw new ArgumentNullException("rRect");
            }

            RCNumber intersectLeft, intersectRight, intersectTop, intersectBottom;

            /// Compute the horizontal coordinates of the intersection
            if (!IntersectHorizontal(ref lRect, ref rRect, out intersectLeft, out intersectRight) &&
                !IntersectHorizontal(ref rRect, ref lRect, out intersectLeft, out intersectRight))
            {
                return(RCNumRectangle.Undefined);
            }

            /// Compute the vertical coordinates of the intersection
            if (!IntersectVertical(ref lRect, ref rRect, out intersectTop, out intersectBottom) &&
                !IntersectVertical(ref rRect, ref lRect, out intersectTop, out intersectBottom))
            {
                return(RCNumRectangle.Undefined);
            }

            return(new RCNumRectangle(intersectLeft, intersectTop, intersectRight - intersectLeft, intersectBottom - intersectTop));
        }
 /// <summary>
 /// Collects every content attached to this BspSearchTreeNode inside the given rectangular area.
 /// </summary>
 /// <param name="area">The rectangular area.</param>
 /// <param name="outputList">
 /// A list that contains every content attached to this BspSearchTreeNode inside the given rectangular area.
 /// </param>
 public void CollectContents(RCNumRectangle area, ref RCSet <T> outputList)
 {
     if (this.isLeaf)
     {
         /// Leaf node -> collect the contents inside the given selection box.
         foreach (T content in this.contents)
         {
             if (content.BoundingBox.IntersectsWith(area))
             {
                 outputList.Add(content);
             }
         }
     }
     else
     {
         /// Not a leaf node -> propagate the call to the appropriate child(ren).
         if (this.firstChild.area.IntersectsWith(area))
         {
             this.firstChild.CollectContents(area, ref outputList);
         }
         if (this.secondChild.area.IntersectsWith(area))
         {
             this.secondChild.CollectContents(area, ref outputList);
         }
     }
 }
 /// <summary>
 /// Constructs a BspSearchTreeNode instance.
 /// </summary>
 /// <param name="area">The rectangular area covered by this BspSearchTreeNode.</param>
 /// <param name="capacity">The maximum number of contents this node can hold without subdivision.</param>
 /// <param name="minSize">The minimum size of a BSP-node.</param>
 public BspSearchTreeNode(RCNumRectangle area, int capacity, int minSize)
 {
     this.contents    = new RCSet <T>();
     this.isLeaf      = true;
     this.capacity    = capacity;
     this.minSize     = minSize;
     this.area        = area;
     this.firstChild  = null;
     this.secondChild = null;
 }
        /// <see cref="ISearchTree<T>.GetContents"/>
        public RCSet <T> GetContents(RCNumRectangle area)
        {
            if (area == RCNumRectangle.Undefined)
            {
                throw new ArgumentNullException("area");
            }

            RCSet <T> retList = new RCSet <T>();

            this.rootNode.CollectContents(area, ref retList);
            return(retList);
        }
        /// <summary>
        /// Replaces this RCNumRectangle with the intersection of itself and the specified Rectangle.
        /// </summary>
        /// <param name="other">The other RCNumRectangle to intersect with.</param>
        /// <remarks>
        /// If this and other RCRectangles don't intersect each other, then this RCNumRectangle becomes RCNumRectangle.Undefined.
        /// </remarks>
        public void Intersect(RCNumRectangle other)
        {
            if (!this.isDefined)
            {
                throw new InvalidOperationException("Illegal use of undefined RCNumRectangle!");
            }
            if (!other.isDefined)
            {
                throw new ArgumentNullException("other");
            }

            this = RCNumRectangle.Intersect(this, other);
        }
        /// <summary>
        /// Determines if this RCNumRectangle intersects with rect.
        /// </summary>
        /// <param name="rect">The RCNumRectangle to test.</param>
        /// <returns>True if there is any intersection, false otherwise.</returns>
        public bool IntersectsWith(RCNumRectangle rect)
        {
            if (!this.isDefined)
            {
                throw new InvalidOperationException("Illegal use of undefined RCNumRectangle!");
            }
            if (!rect.isDefined)
            {
                throw new ArgumentNullException("rect");
            }

            return((this.Left < rect.Right) && (this.Right > rect.Left) && (this.Top < rect.Bottom) && (this.Bottom > rect.Top));
        }
        /// <summary>
        /// Initializes a new RCNumRectangle with the specified RCNumRectangle.
        /// </summary>
        /// <param name="other">The RCNumRectangle to initialize with.</param>
        public RCNumRectangle(RCNumRectangle other)
        {
            if (!other.isDefined)
            {
                throw new ArgumentNullException("other");
            }

            this.isDefined = true;
            this.x         = other.x;
            this.y         = other.y;
            this.width     = other.width;
            this.height    = other.height;
        }
        /// <summary>
        /// Determines if the rectangular region represented by rect is entirely contained within this RCNumRectangle.
        /// </summary>
        /// <param name="rect">The RCNumRectangle to test.</param>
        /// <returns>True if the rectangular region represented by rect is entirely contained within this RCNumRectangle, false otherwise.</returns>
        public bool Contains(RCNumRectangle rect)
        {
            if (!this.isDefined)
            {
                throw new InvalidOperationException("Illegal use of undefined RCNumRectangle!");
            }
            if (!rect.isDefined)
            {
                throw new ArgumentNullException("rect");
            }

            return(this.Contains(rect.x, rect.y) &&
                   this.Contains(rect.x + rect.width - new RCNumber(1), rect.y + rect.height - new RCNumber(1)));
        }
        /// <summary>
        /// Constructs a BspSearchTree instance.
        /// </summary>
        /// <param name="area">The rectangular area covered by this search tree.</param>
        /// <param name="nodeCapacity">The maximum number of contents a BSP-tree node can hold without subdivision.</param>
        /// <param name="minNodeSize">The minimum size of a BSP-node.</param>
        public BspSearchTree(RCNumRectangle area, int nodeCapacity, int minNodeSize)
        {
            if (area == RCNumRectangle.Undefined)
            {
                throw new ArgumentNullException("area");
            }
            if (nodeCapacity <= 0)
            {
                throw new ArgumentOutOfRangeException("nodeCapacity", "Node capacity must be greater than 0!");
            }
            if (minNodeSize <= 0)
            {
                throw new ArgumentOutOfRangeException("minNodeSize", "Minimum BSP-node size must be positive!");
            }

            this.attachedContents = new RCSet <T>();
            this.rootNode         = new BspSearchTreeNode <T>(area, nodeCapacity, minNodeSize);
        }
 /// <summary>
 /// Checks whether this RCNumRectangle has the same location and size as the specified RCNumRectangle.
 /// </summary>
 /// <param name="other">The RCNumRectangle to test.</param>
 /// <returns>True if other RCNumRectangle has same location and size as this RCNumRectangle.</returns>
 public bool Equals(RCNumRectangle other)
 {
     return((!this.isDefined && !other.isDefined) ||
            (this.isDefined && other.isDefined && this.x == other.x && this.y == other.y &&
             this.width == other.width && this.height == other.height));
 }