private void InspectLeaf([NotNull] QuadTreeLeaf visitedLeaf, [NotNull] IAABBox viewBox) { var planetRawData = visitedLeaf.GetPlanetsRawData(); if (planetRawData == null) { return; } for (int i = 0; i < planetRawData.Length; ++i) { if (!IsPlanetInCamera(i, viewBox, visitedLeaf)) { continue; } var posToInsert = FindPosToInsert(mVisiblePlanets, i, visitedLeaf); if (posToInsert != -1) { mVisiblePlanets.Insert(posToInsert, visitedLeaf.GetPlanetData(i)); if (mVisiblePlanets.Count > mConstants.GetPlanetsToVisualize()) { mVisiblePlanets.RemoveAt(mVisiblePlanets.Count - 1); } continue; } if (mVisiblePlanets.Count < mConstants.GetPlanetsToVisualize()) { mVisiblePlanets.Add(visitedLeaf.GetPlanetData(i)); continue; } break; } }
public IEnumerable <T> Query(float in_left, float in_top, float in_width, float in_height) { Stack <QuadTreeNode> stack = new Stack <QuadTreeNode>(); QuadTreeNode current = m_root; while (current != null) { if (current.Children != null) { QuadTreeNode[] children = current.Children; if (children[2].Bounds != null && children[2].Bounds.IsOverlapping(in_left, in_top, in_width, in_height)) { stack.Push(children[2]); } if (children[1].Bounds != null && children[1].Bounds.IsOverlapping(in_left, in_top, in_width, in_height)) { stack.Push(children[1]); } if (children[3].Bounds != null && children[3].Bounds.IsOverlapping(in_left, in_top, in_width, in_height)) { stack.Push(children[3]); } if (children[0].Bounds != null && children[0].Bounds.IsOverlapping(in_left, in_top, in_width, in_height)) { stack.Push(children[0]); } } else { QuadTreeLeaf node = current.Data; while (node != null) { if (node.Data.X > in_left && node.Data.X < in_left + in_width && node.Data.Y > in_top && node.Data.Y < in_top + in_height) { yield return(node.Data); } node = node.Next; } } if (stack.Count > 0) { current = stack.Pop(); } else { break; } } }
private bool IsPlanetInCamera(int planetIndex, [NotNull] IAABBox cameraBox, [NotNull] QuadTreeLeaf visitedLeaf) { var planetData = visitedLeaf.GetPlanetData(planetIndex); var cameraTop = cameraBox.GetY() + cameraBox.GetHeight() / 2f; var cameraBottom = cameraTop - cameraBox.GetHeight(); var cameraLeft = cameraBox.GetX() - cameraBox.GetWidth() / 2f; var cameraRight = cameraLeft + cameraBox.GetWidth(); if ((cameraTop >= planetData.Y && cameraBottom <= planetData.Y) && (cameraLeft <= planetData.X && cameraRight >= planetData.X)) { return(true); } return(false); }
public void TraverseNodesAndLeafs(DataProcessCallback in_data_process_callback, NodeProcessCallback in_node_process_callback) { Stack <QuadTreeNode> stack = new Stack <QuadTreeNode>(); QuadTreeNode current = m_root; while (true) { if (current.Children != null) { if (in_node_process_callback != null) { foreach (QuadTreeNode node in current.Children) { in_node_process_callback(node.Bounds); } } stack.Push(current.Children[2]); stack.Push(current.Children[1]); stack.Push(current.Children[3]); current = current.Children[0]; } else { QuadTreeLeaf node = current.Data; while (node != null) { in_data_process_callback(node.Data); node = node.Next; } if (stack.Count > 0) { current = stack.Pop(); } else { break; } } } }
private void Read(BinaryReader input) { flag = input.ReadInt16(); var bitMask = flag; for (int i = 0; i < 16; i++) { if ((bitMask & 1) == 1) { subTrees[i] = new QuadTreeNode(input); } else { subTrees[i] = new QuadTreeLeaf(input); } bitMask >>= 1; } }
public QuadTreeParent(Rect rect, GetBoundingRectangle getBoundingRectangle, IEnumerable <T> items) { Rect = rect; _getBounding = getBoundingRectangle; var left = rect.Left; var top = rect.Top; var halfWidth = rect.Width / 2.0; var halfHeight = rect.Height / 2.0; NodeTopLeft = new QuadTreeLeaf(new Rect(left, top, halfWidth, halfHeight), _getBounding); NodeTopRight = new QuadTreeLeaf(new Rect(left + halfWidth, top, halfWidth, halfHeight), _getBounding); NodeBottomLeft = new QuadTreeLeaf(new Rect(left, top + halfHeight, halfWidth, halfHeight), _getBounding); NodeBottomRight = new QuadTreeLeaf(new Rect(left + halfWidth, top + halfHeight, halfWidth, halfHeight), _getBounding); foreach (var item in items) { AddItem(item); } }
public IEnumerator <T> GetEnumerator() { Stack <QuadTreeNode> stack = new Stack <QuadTreeNode>(); QuadTreeNode current = m_root; while (current != null) { if (current.Children != null) { stack.Push(current.Children[2]); stack.Push(current.Children[1]); stack.Push(current.Children[3]); stack.Push(current.Children[0]); } else { QuadTreeLeaf node = current.Data; while (node != null) { yield return(node.Data); node = node.Next; } } if (stack.Count > 0) { current = stack.Pop(); } else { break; } } }
private int FindPosToInsert([NotNull] List <PlanetData> planets, int planetIndex, [NotNull] QuadTreeLeaf visitedLeaf) { var posToInsert = -1; for (int j = mConstants.GetPlanetsToVisualize() - 1; j > -1; --j) { if (j > planets.Count - 1) { continue; } var inStoreDistance = Math.Abs(mPlayer.Score - planets[j].Score); var pretenderDistance = Math.Abs(mPlayer.Score - visitedLeaf.GetPlanetRating(planetIndex)); if (inStoreDistance > pretenderDistance) { posToInsert = j; continue; } if (inStoreDistance == pretenderDistance) { var pretenderPlanet = visitedLeaf.GetPlanetData(planetIndex); var distanceToStore = (mPlayer.GetX() - planets[j].X) * (mPlayer.GetX() - planets[j].X) + (mPlayer.GetY() - planets[j].Y) * (mPlayer.GetY() - planets[j].Y); var distanceToPretender = (mPlayer.GetX() - pretenderPlanet.X) * (mPlayer.GetX() - pretenderPlanet.X) + (mPlayer.GetY() - pretenderPlanet.Y) * (mPlayer.GetY() - pretenderPlanet.Y); if (distanceToPretender < distanceToStore) { posToInsert = j; continue; } } break; } return(posToInsert); }
public void AddVisited(QuadTreeLeaf visitedLeaf) { mVisibleLeaves.Add(visitedLeaf); }
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> /// Inserts a new node /// </summary> /// <param name="in_data"></param> public void Insert(T in_data) { QuadTreeLeaf node = new QuadTreeLeaf(in_data); Insert(m_root, node); }
public QuadTreeNode(QuadTreeFloatPointRegion in_region) { Bounds = in_region; Children = null; Data = null; }
public QuadTreeLeaf(T in_data) { Data = in_data; Next = null; }