/// <summary> /// Pre-order tree traversal method. /// </summary> /// public static IEnumerator <KDTreeNode <T> > PreOrder <T>(KDTree <T> tree) { if (tree.Root == null) { yield break; } var stack = new Stack <KDTreeNode <T> >(); KDTreeNode <T> current = tree.Root; while (stack.Count != 0 || current != null) { if (current != null) { stack.Push(current); yield return(current); current = current.Left; } else { current = stack.Pop(); current = current.Right; } } }
// all parameter constructor public KDTreeNode(KDTreeNode inputLeft, KDTreeNode inputRight, int inputDepth, Unit inputData) { this.left = inputLeft; this.right = inputRight; this.depth = inputDepth; this.data = inputData; }
private void insert(ref KDTreeNode <T> node, double[] position, T value, int depth) { if (node == null) { // Base case: node is null node = new KDTreeNode <T>() { Axis = depth % dimensions, Position = position, Value = value }; } else { // Recursive case: keep looking for a position to insert if (position[node.Axis] < node.Position[node.Axis]) { KDTreeNode <T> child = node.Left; insert(ref child, position, value, depth + 1); node.Left = child; } else { KDTreeNode <T> child = node.Right; insert(ref child, position, value, depth + 1); node.Right = child; } } }
/// <summary> /// Returns an enumerator that iterates through the tree. /// </summary> /// /// <returns> /// An <see cref="T:System.Collections.IEnumerator"/> object /// that can be used to iterate through the collection. /// </returns> /// public IEnumerator <KDTreeNode <T> > GetEnumerator() { if (root == null) { yield break; } var stack = new Stack <KDTreeNode <T> >(new[] { root }); while (stack.Count != 0) { KDTreeNode <T> current = stack.Pop(); yield return(current); if (current.Left != null) { stack.Push(current.Left); } if (current.Right != null) { stack.Push(current.Right); } } }
/// <summary> /// Creates a new <see cref="KDTree<T>"/>. /// </summary> /// /// <param name="dimension">The number of dimensions in the tree.</param> /// <param name="root">The root node, if already existent.</param> /// <param name="count">The number of elements in the root node.</param> /// <param name="leaves">The number of leaves linked through the root node.</param> /// public KDTree(int dimension, KDTreeNode <T> root, int count, int leaves) : this(dimension) { this.root = root; this.count = count; this.leaves = leaves; }
/// <summary> /// Breadth-first tree traversal method. /// </summary> /// public static IEnumerator <KDTreeNode <T> > BreadthFirst <T>(KDTree <T> tree) { if (tree.Root == null) { yield break; } var queue = new Queue <KDTreeNode <T> >(new[] { tree.Root }); while (queue.Count != 0) { KDTreeNode <T> current = queue.Dequeue(); yield return(current); if (current.Left != null) { queue.Enqueue(current.Left); } if (current.Right != null) { queue.Enqueue(current.Right); } } }
// data and depth public KDTreeNode(Unit inputData, int inputDepth) { this.left = null; this.right = null; this.data = inputData; this.depth = inputDepth; }
public void Convert(Entity entity, EntityManager manager, GameObjectConversionSystem conversionSystem) { var data = new KDTreeNode { }; manager.AddComponentData(entity, data); }
/// <summary> /// Attempts to add a value to the collection. If the list is full /// and the value is more distant than the farthest node in the /// collection, the value will not be added. /// </summary> /// /// <param name="value">The node to be added.</param> /// <param name="distance">The node distance.</param> /// /// <returns>Returns true if the node has been added; false otherwise.</returns> /// public bool AddFarthest(KDTreeNode <T> value, double distance) { // The list does have a limit. We have to check if the list // is already full or not, to see if we can discard or keep // the point if (count < Capacity) { // The list still has room for new elements. // Just add the value at the right position. add(distance, value); return(true); // a value has been added } // The list is at its maximum capacity. Check if the value // to be added is farther than the current nearest point. if (distance > Minimum) { // Yes, it is farther. Remove the previous nearest point // and insert this new one at an appropriate position to // keep the list ordered. RemoveNearest(); add(distance, value); return(true); // a value has been added } // The value is even closer return(false); // discard it }
private bool approximate(KDTreeNode <T> current, double[] position, KDTreeNodeCollection <T> list, int maxLeaves, ref int visited) { // Compute distance from this node to the point double d = distance(position, current.Position); list.Add(current, d); if (++visited > maxLeaves) { return(true); } // Check for leafs on the opposite sides of // the subtrees to nearest possible neighbors. // Prepare for recursion. The following null checks // will be used to avoid function calls if possible double value = position[current.Axis]; double median = current.Position[current.Axis]; double u = value - median; if (u <= 0) { if (current.Left != null) { if (approximate(current.Left, position, list, maxLeaves, ref visited)) { return(true); } } if (current.Right != null && Math.Abs(u) <= list.Maximum) { if (approximate(current.Right, position, list, maxLeaves, ref visited)) { return(true); } } } else { if (current.Right != null) { approximate(current.Right, position, list, maxLeaves, ref visited); } if (current.Left != null && Math.Abs(u) <= list.Maximum) { if (approximate(current.Left, position, list, maxLeaves, ref visited)) { return(true); } } } return(false); }
// data public KDTreeNode(Unit inputData) { this.left = null; this.right = null; this.depth = 0; this.data = inputData; }
// constructors // no parameter public KDTreeNode() { this.left = null; this.right = null; this.depth = 0; this.data = null; }
/// <summary> /// Initializes a new instance of the <see cref="KDTreeNode"/> class. /// </summary> /// <param name="coordinate">The coordinate to be stored in this node.</param> /// <param name="splitDimension">The splitting dimension of this node.</param> /// <param name="numberOfDimensions">The total number of dimensions of the tree.</param> public KDTreeNode(Coordinate coordinate, Int32 splitDimension, Int32 numberOfDimensions) { this.Coordinate = coordinate; this.leftChild = null; this.rightChild = null; this.splitDimension = splitDimension; this.NumberOfDimensions = numberOfDimensions; }
/// <summary> /// Adds the specified item to the collection. /// </summary> /// /// <param name="distance">The distance from the node to the query point.</param> /// <param name="item">The item to be added.</param> /// private void add(double distance, KDTreeNode <T> item) { positions[count] = item; distances[count] = distance; count++; // Ensure it is in the right place. siftUpLast(); }
/// <summary> /// Retrieves a fixed point of nearest points to a given point. /// </summary> /// /// <param name="position">The queried point.</param> /// <param name="distance">The distance from the <paramref name="position"/> /// to its nearest neighbor found in the tree.</param> /// /// <returns>A list of neighbor points, ordered by distance.</returns> /// public KDTreeNode <T> Nearest(double[] position, out double distance) { KDTreeNode <T> result = root; distance = Distance(root.Position, position); nearest(root, position, ref result, ref distance); return(result); }
// insert a new node under this node public void insert(Unit inputUnit) { // x/z location of the thing we are inserting float unitLocation; // x/z location of the thing at the current node float dataLocation; // if the depth is even (in effect, if we comparing in the z dimension) if ((depth % 2) == 0) { // make our two variables reflect their respective z values unitLocation = inputUnit.transform.position.z; dataLocation = this.data.transform.position.z; } else // else it must be odd // make our two variables reflect their respective x values { unitLocation = inputUnit.transform.position.x; dataLocation = this.data.transform.position.x; } // if the new node should go to the left if (unitLocation < dataLocation) { // if the left child does not exist if (this.left == null) { // make it a new node with the inputted Unit and depth+1 because the node is one node down this.left = new KDTreeNode(inputUnit, this.depth + 1); } else // else the left child must exist // so we insert at that node { this.left.insert(inputUnit); } } else // if ithe values are equal or greater // if the right child node does not exist { if (this.right == null) { // make it a new node with the inputted Unit depth+1 this.right = new KDTreeNode(inputUnit, this.depth + 1); } else // else the node must exist and be occupied // so insert at that node { this.right.insert(inputUnit); } } }
public override void Clear() { if (root != null) { root.Deallocate(); Modify(); root = null; nMembers = 0; height = 0; } }
internal KDTreeEnumerator(KDTree <T> tree, T low, T high) { this.tree = tree; this.low = low; this.high = high; root = tree.root; comparator = tree.comparator; nDims = comparator.NumberOfDimensions; stack = new KDTreeNode[tree.height + 1]; Reset(); }
/// <summary> /// Removes all child nodes. /// </summary> internal void ClearChildren() { if (_child0 != null && _child1 != null) { _child0.ClearChildren(); _child1.ClearChildren(); _parent._nodeCount -= 2; } _child0 = null; _child1 = null; }
/// <summary> /// Post-order tree traversal method. /// </summary> /// public static IEnumerator <KDTreeNode <T> > PostOrder <T>(KDTree <T> tree) { if (tree.Root == null) { yield break; } var stack = new Stack <KDTreeNode <T> >(new[] { tree.Root }); KDTreeNode <T> previous = tree.Root; while (stack.Count != 0) { KDTreeNode <T> current = stack.Peek(); if (previous == current || previous.Left == current || previous.Right == current) { if (current.Left != null) { stack.Push(current.Left); } else if (current.Right != null) { stack.Push(current.Right); } else { yield return(stack.Pop()); } } else if (current.Left == previous) { if (current.Right != null) { stack.Push(current.Right); } else { yield return(stack.Pop()); } } else if (current.Right == previous) { yield return(stack.Pop()); } else { throw new InvalidOperationException(); } previous = current; } }
internal OpResult Remove(T rem, MultidimensionalComparator <T> comparator, int level) { Load(); if (obj == rem) { if (left == null && right == null) { Deallocate(); return(OpResult.TRUNCATE); } else { Modify(); obj = comparator.CloneField(obj, level % comparator.NumberOfDimensions); deleted = true; return(OpResult.OK); } } CompareResult diff = comparator.Compare(rem, obj, level % comparator.NumberOfDimensions); if (diff != CompareResult.GT && left != null) { OpResult result = left.Remove(rem, comparator, level + 1); if (result == OpResult.TRUNCATE) { Modify(); left = null; return(OpResult.OK); } else if (result == OpResult.OK) { return(OpResult.OK); } } if (diff != CompareResult.LT && right != null) { OpResult result = right.Remove(rem, comparator, level + 1); if (result == OpResult.TRUNCATE) { Modify(); right = null; return(OpResult.OK); } else if (result == OpResult.OK) { return(OpResult.OK); } } return(OpResult.NOT_FOUND); }
// other methods // insert a Unit into the tree public void insert(Unit inputUnit) { // if the root doesn't exist yet if (this.root == null) { // make the root have the Unit as data and 1 as its depth since it's the root this.root = new KDTreeNode(inputUnit, 1); } else { // call insert at the root node this.root.insert(inputUnit); } }
/// <summary> /// Retrieves a fixed point of nearest points to a given point. /// </summary> /// /// <param name="position">The queried point.</param> /// <param name="percentage">The maximum percentage of leaf nodes that /// can be visited before the search finishes with an approximate answer.</param> /// <param name="distance">The distance between the query point and its nearest neighbor.</param> /// /// <returns>A list of neighbor points, ordered by distance.</returns> /// public KDTreeNode <T> ApproximateNearest(double[] position, double percentage, out double distance) { KDTreeNode <T> result = root; distance = Distance(root.Position, position); int maxLeaves = (int)(leaves * percentage); int visited = 0; approximateNearest(root, position, ref result, ref distance, maxLeaves, ref visited); return(result); }
private static KDTreeNode <T> create(double[][] points, T[] values, int depth, int k, int start, int length, ElementComparer comparer, ref int leaves) { if (length <= 0) { return(null); } // We will be doing sorting in place int axis = comparer.Index = depth % k; Array.Sort(points, values, start, length, comparer); // Middle of the input section int half = start + length / 2; // Start and end of the left branch int leftStart = start; int leftLength = half - start; // Start and end of the right branch int rightStart = half + 1; int rightLength = length - length / 2 - 1; // The median will be located halfway in the sorted array var median = points[half]; var value = values != null ? values[half] : default(T); depth++; // Continue with the recursion, passing the appropriate left and right array sections KDTreeNode <T> left = create(points, values, depth, k, leftStart, leftLength, comparer, ref leaves); KDTreeNode <T> right = create(points, values, depth, k, rightStart, rightLength, comparer, ref leaves); if (left == null && right == null) { leaves++; } // Backtrack and create return(new KDTreeNode <T>() { Axis = axis, Position = median, Value = value, Left = left, Right = right, }); }
/// <summary> /// Creates a new <see cref="KDTree<T>"/>. /// </summary> /// /// <param name="dimension">The number of dimensions in the tree.</param> /// <param name="root">The root node, if already existent.</param> /// public KDTree(int dimension, KDTreeNode <T> root) : this(dimension) { this.root = root; foreach (var node in this) { count++; if (node.IsLeaf) { leaves++; } } }
private void testKDTree() { // This is the same example found in Wikipedia page on // k-d trees: http://en.wikipedia.org/wiki/K-d_tree // Suppose we have the following set of points: double[][] points = { new double[] { 2, 3 }, new double[] { 5, 4 }, new double[] { 9, 6 }, new double[] { 4, 7 }, new double[] { 8, 1 }, new double[] { 7, 2 }, }; // To create a tree from a set of points, we use KDTree <int> tree = KDTree.FromData <int>(points); // Now we can manually navigate the tree KDTreeNode <int> node = tree.Root.Left.Right; // Or traverse it automatically foreach (KDTreeNode <int> n in tree) { double[] location = n.Position; //Assert.AreEqual(2, location.Length); } // Given a query point, we can also query for other // points which are near this point within a radius double[] query = new double[] { 5, 3 }; // Locate all nearby points within an euclidean distance of 1.5 // (answer should be be a single point located at position (5,4)) var result = tree.Nearest(query, radius: 1.5); // We can also use alternate distance functions //tree.Distance = Accord.Math.Distance.Manhattan; // And also query for a fixed number of neighbor points // (answer should be the points at (5,4), (7,2), (2,3)) var neighbors = tree.Nearest(query, neighbors: 3); }
/// <summary> /// Radius search. /// </summary> /// private void nearest(KDTreeNode <T> current, double[] position, double radius, ICollection <KDTreeNodeDistance <T> > list) { // Check if the distance of the point from this // node is within the desired radius, and if it // is, add to the list of nearest nodes. double d = distance(position, current.Position); if (d <= radius) { list.Add(new KDTreeNodeDistance <T>(current, d)); } // Prepare for recursion. The following null checks // will be used to avoid function calls if possible double value = position[current.Axis]; double median = current.Position[current.Axis]; double u = value - median; if (u <= 0) { if (current.Left != null) { nearest(current.Left, position, radius, list); } if (current.Right != null && Math.Abs(u) <= radius) { nearest(current.Right, position, radius, list); } } else { if (current.Right != null) { nearest(current.Right, position, radius, list); } if (current.Left != null && Math.Abs(u) <= radius) { nearest(current.Left, position, radius, list); } } }
private void nearest(KDTreeNode <T> current, double[] position, ref KDTreeNode <T> match, ref double minDistance) { // Compute distance from this node to the point double d = distance(position, current.Position); if (d < minDistance) { minDistance = d; match = current; } // Check for leafs on the opposite sides of // the subtrees to nearest possible neighbors. // Prepare for recursion. The following null checks // will be used to avoid function calls if possible double value = position[current.Axis]; double median = current.Position[current.Axis]; double u = value - median; if (u <= 0) { if (current.Left != null) { nearest(current.Left, position, ref match, ref minDistance); } if (current.Right != null && u <= minDistance) { nearest(current.Right, position, ref match, ref minDistance); } } else { if (current.Right != null) { nearest(current.Right, position, ref match, ref minDistance); } if (current.Left != null && u <= minDistance) { nearest(current.Left, position, ref match, ref minDistance); } } }
/// <summary> /// Adds a coordinate to the tree. /// </summary> /// <param name="coordinate">The coordinate to be added.</param> /// <exception cref="System.ArgumentNullException">The coordinate is null.</exception> public void Add(Coordinate coordinate) { if (coordinate == null) { throw new ArgumentNullException(nameof(coordinate)); } this.NumberOfGeometries++; if (this.IsEmpty) { this.root = new KDTreeNode(coordinate, 1, this.TreeDimension); } else { this.root.Add(coordinate); } }
public override void Add(T obj) { Modify(); if (root == null) { root = new KDTreeNode(Storage, obj); height = 1; } else { int level = root.Insert(obj, comparator, 0); if (level >= height) { height = level + 1; } } nMembers += 1; }
/// <summary>KD木の生成</summary> private int generateKdTreeRecursive(List<KDTreeNode> tree, int depth, List<PaletteEntry> subPalette, ref int maxDepth) { if (subPalette.Count == 0) { return DummyIndex; } if (depth > maxDepth) { maxDepth = depth; } int nodeIndex = tree.Count; var node = new KDTreeNode(); node.Init(); tree.Add(node); // 再帰で書き換えられるので場所だけ先に確保 // 最も分割しやすそうな方向に分割する byte maxR = 0, maxG = 0, maxB = 0; byte minR = 255, minG = 255, minB = 255; foreach (var e in subPalette) { if (e.Color.B > maxB) maxB = e.Color.B; if (e.Color.G > maxG) maxG = e.Color.G; if (e.Color.R > maxR) maxR = e.Color.R; if (e.Color.B < minB) minB = e.Color.B; if (e.Color.G < minG) minG = e.Color.G; if (e.Color.R < minR) minR = e.Color.R; } int sizeR = maxR - minR; int sizeG = maxG - minG; int sizeB = maxB - minB; int divChannel; if (sizeR > sizeG && sizeR > sizeB) { divChannel = ArgbColor.ChannelR; } else if (sizeG > sizeB) { divChannel = ArgbColor.ChannelG; } else { divChannel = ArgbColor.ChannelB; } subPalette.Sort((p, q) => p.Color[divChannel].CompareTo(q.Color[divChannel])); int n = subPalette.Count(); int medianIndex = n / 2; // できるだけ前後と隙間があくように分割位置を微調整 if (n > 10) { int dMax = 0; int dMaxIndex = 0; for (int i = medianIndex - 4; i <= medianIndex + 4; i++) { int vLeft = subPalette[i].Color[divChannel] - subPalette[i - 1].Color[divChannel]; int vRight = subPalette[i + 1].Color[divChannel] - subPalette[i].Color[divChannel]; int d = vLeft * vLeft + vRight * vRight; if (d > dMax) { dMax = d; dMaxIndex = i; } } medianIndex = dMaxIndex; } // 中央値の情報を格納 node.MedianValue = subPalette[medianIndex].Color[divChannel]; node.MedianColorIndex = subPalette[medianIndex].Index; node.MedianChannel = divChannel; // 左の枝 int leftLength = medianIndex; if (leftLength > 0) { node.LeftMax = subPalette[medianIndex - 1].Color[divChannel]; node.LeftIdx = generateKdTreeRecursive(tree, depth + 1, subPalette.GetRange(0, leftLength), ref maxDepth); } // 右の枝 int rightLength = n - medianIndex - 1; if (rightLength > 0) { node.RightMin = subPalette[medianIndex + 1].Color[divChannel]; node.RightIdx = generateKdTreeRecursive(tree, depth + 1, subPalette.GetRange(medianIndex + 1, rightLength), ref maxDepth); } tree[nodeIndex] = node; return nodeIndex; }