/// <summary>
 /// Checks if two regions are overlapping
 /// </summary>
 /// <param name="in_region">Other region to check</param>
 /// <returns>True if regions are overlapping</returns>
 public bool IsOverlapping(QuadTreeFloatPointRegion in_region)
 {
     return((Math.Abs(CenterX - in_region.CenterX) <= (in_region.HalfSize + HalfSize)) && (Math.Abs(CenterY - in_region.CenterY) <= (in_region.HalfSize + HalfSize)));
 }
        public List <T> QueryNeighbours(float in_x, float in_y, int in_neighbours_count)
        {
            QuadTreeFloatPointRegion neighbour_region = new QuadTreeFloatPointRegion(in_x, in_y, 0);
            Stack <QuadTreeNode>     stack            = new Stack <QuadTreeNode>();
            QuadTreeNode             current;

            List <T> neighbours = new List <T>();

            double[] neighbour_distances       = new double[in_neighbours_count];
            double   neighbours_worst_distance = 0;
            int      neighbours_worst_index    = 0;

            // set root node as current
            current = m_root;

            while (current != null)
            {
                // move downwards if this node has child nodes
                if (current.Children != null)
                {
                    // store regions in the stack and continue with the closest region
                    double closest_region_distance;
                    int    closest_region_index;

                    // find closest region
                    closest_region_index    = 0;
                    closest_region_distance = current.Children[0].Bounds.GetSquaredDistanceOfCenter(in_x, in_y);

                    for (int i = 0; i < 4; i++)
                    {
                        double distance = current.Children[i].Bounds.GetSquaredDistanceOfCenter(in_x, in_y);
                        if (distance < closest_region_distance)
                        {
                            closest_region_distance = distance;
                            closest_region_index    = i;
                        }
                    }

                    // store regions
                    for (int i = 0; i < 4; i++)
                    {
                        if (i == closest_region_index)
                        {
                            continue;
                        }

                        // if the neighbor region is defined then store only the overlapping regions, otherwise store all regions
                        if (neighbour_region.HalfSize == 0 || current.Children[i].Bounds.IsOverlapping(neighbour_region))
                        {
                            stack.Push(current.Children[i]);
                        }
                    }

                    // continue processing with the closest	region
                    current = current.Children[closest_region_index];
                }
                else
                {
                    // process data points
                    QuadTreeLeaf current_leaf_entry = current.Data;

                    while (current_leaf_entry != null)
                    {
                        // calculate distance (squared)
                        double squared_distance = current_leaf_entry.GetSquaredDistance(in_x, in_y);

                        if (current.Data != null)
                        {
                            // simply store data point if the list is not full
                            if (neighbours.Count < in_neighbours_count)
                            {
                                if (neighbours.Count == 0)
                                {
                                    neighbours_worst_distance = squared_distance;
                                    neighbours_worst_index    = 0;
                                }
                                else
                                {
                                    if (squared_distance > neighbours_worst_distance)
                                    {
                                        neighbours_worst_distance = squared_distance;
                                        neighbours_worst_index    = neighbours.Count;
                                    }
                                }

                                // add this item to the neighbours list
                                neighbour_distances[neighbours.Count] = squared_distance;
                                neighbours.Add(current_leaf_entry.Data);

                                // if the required number of neighbour is found store the worst distance in the region
                                if (neighbours.Count == in_neighbours_count)
                                {
                                    neighbour_region.HalfSize = (float)Math.Sqrt(neighbours_worst_distance);
                                }
                            }
                            else
                            {
                                // list is full, store only when this item is closer than the worst item (largest distance) in the list
                                if (squared_distance < neighbours_worst_distance)
                                {
                                    // replace worst element
                                    neighbour_distances[neighbours_worst_index] = squared_distance;
                                    neighbours[neighbours_worst_index]          = current_leaf_entry.Data;

                                    // find the current worst element
                                    neighbours_worst_index    = 0;
                                    neighbours_worst_distance = neighbour_distances[0];
                                    for (int i = 1; i < in_neighbours_count; i++)
                                    {
                                        if (neighbour_distances[i] > neighbours_worst_distance)
                                        {
                                            neighbours_worst_distance = neighbour_distances[i];
                                            neighbours_worst_index    = i;
                                        }
                                    }

                                    neighbour_region.HalfSize = (float)Math.Sqrt(neighbours_worst_distance);
                                }
                            }
                        }

                        current_leaf_entry = current_leaf_entry.Next;
                    }

                    // get new element from the stack or exit if no more element to investigate
                    do
                    {
                        if (stack.Count > 0)
                        {
                            current = stack.Pop();
                        }
                        else
                        {
                            current = null;
                            break;
                        }

                        // if the neighbour region is know skip all elements with a non-overlapping region
                    } while (neighbour_region.HalfSize > 0 && !current.Bounds.IsOverlapping(neighbour_region));
                }
            }

            return(neighbours);
        }
        /// <summary>
        /// Internal recursive insert function
        /// </summary>
        /// <param name="in_current_node"></param>
        /// <param name="in_node_to_insert"></param>
        private void Insert(QuadTreeNode in_current_node, QuadTreeLeaf in_node_to_insert)
        {
            // check if point ot insert is inside -> if it is not then it can not be child of this node
            if (!in_current_node.Bounds.IsPointInside(in_node_to_insert.Data))
            {
                return;
            }

            QuadTreeLeaf nodes_to_insert = null;
            QuadTreeLeaf node;
            int          quadrant;

            // if this node is leaf
            if (in_current_node.Children == null)
            {
                // this is the first data item in the leaf
                if (in_current_node.Data == null)
                {
                    in_current_node.Data = in_node_to_insert;

                    return;
                }
                else
                {
                    int item_count = 0;

                    // add to the end of list of data
                    node = in_current_node.Data;
                    while (true)
                    {
                        if (Math.Abs(in_node_to_insert.Data.X - node.Data.X) <= float.Epsilon && Math.Abs(in_node_to_insert.Data.Y - node.Data.Y) <= float.Epsilon)
                        {
                            throw new ArgumentException("Key already exists");
                        }

                        item_count++;

                        if (node.Next != null)
                        {
                            node = node.Next;
                        }
                        else
                        {
                            break;
                        }
                    }

                    // there is room for this item
                    if (item_count < m_bucket_capacity)
                    {
                        // add node to the list of data
                        node.Next = in_node_to_insert;

                        return;
                    }

                    // current node needs to be splitted
                    nodes_to_insert = (QuadTreeLeaf)in_current_node.Data;

                    // remove data
                    in_current_node.Data = null;
                }
            }
            else
            {
                // move downward on the tree following the apropriate quadrant
                quadrant = in_current_node.Bounds.GetQuadrantIndex(in_node_to_insert.Data);

                Insert(in_current_node.Children[quadrant], in_node_to_insert);

                return;
            }

            // subdivide current node
            QuadTreeFloatPointRegion bounds = in_current_node.Bounds;
            float half = bounds.HalfSize / 2;

            QuadTreeNode[] subdivision = new QuadTreeNode[4] {
                new QuadTreeNode(new QuadTreeFloatPointRegion(bounds.CenterX - half, bounds.CenterY - half, half)),
                new QuadTreeNode(new QuadTreeFloatPointRegion(bounds.CenterX + half, bounds.CenterY - half, half)),
                new QuadTreeNode(new QuadTreeFloatPointRegion(bounds.CenterX - half, bounds.CenterY + half, half)),
                new QuadTreeNode(new QuadTreeFloatPointRegion(bounds.CenterX + half, bounds.CenterY + half, half))
            };

            // insert node
            quadrant = bounds.GetQuadrantIndex(in_node_to_insert.Data);

            Insert(subdivision[quadrant], in_node_to_insert);

            // insert nodes from the splitted node
            node = nodes_to_insert;
            QuadTreeLeaf next_node;

            while (node != null)
            {
                next_node = node.Next;
                node.Next = null;

                quadrant = bounds.GetQuadrantIndex(node.Data);

                Insert(subdivision[quadrant], node);

                node = next_node;
            }

            in_current_node.Children = subdivision;
        }
 /// <summary>
 /// Creates QuadTree for the specified region with bucket capacity set to one.
 /// </summary>
 /// <param name="in_region">Region  used for the stored point</param>
 public QuadTreeFloatPoint(QuadTreeFloatPointRegion in_region) : this(in_region, 1)
 {
 }
 /// <summary>
 /// Construct QuadTree for the given region with the sepcified bucket capacity
 /// </summary>
 /// <param name="in_region">Coordinate region used for stored points</param>
 /// <param name="in_bucket_capacity">Number of points stored in one bucket</param>
 public QuadTreeFloatPoint(QuadTreeFloatPointRegion in_region, int in_bucket_capacity)
 {
     m_root            = new QuadTreeNode(in_region);
     m_bucket_capacity = in_bucket_capacity;
     m_node_count      = 0;
 }
 public QuadTreeNode(QuadTreeFloatPointRegion in_region)
 {
     Bounds   = in_region;
     Children = null;
     Data     = null;
 }