private KdTreeNode <TValue> Build(TValue[] elementsArray, int startIndex, int endIndex, int depth) { var length = endIndex - startIndex + 1; if (length == 0) { return(null); } // Sort array of elements by component of chosen dimension, in ascending magnitude. _valueComparer.Dimension = depth % _nrOfDimensions; Array.Sort(elementsArray, startIndex, length, _valueComparer); // Select median element as pivot. var medianIndex = startIndex + length / 2; var medianElement = elementsArray[medianIndex]; // Create node and construct sub-trees around pivot element. var node = new KdTreeNode <TValue>(medianElement); node.LeftChild = Build(elementsArray, startIndex, medianIndex - 1, depth + 1); node.RightChild = Build(elementsArray, medianIndex + 1, endIndex, depth + 1); return(node); }
public KdTree(IEnumerable <TValue> elements, params Func <TValue, double>[] valueSelectors) { _nrOfDimensions = valueSelectors.Length; _valueSelectors = valueSelectors; _valueComparer = new ValueLocationComparer(_valueSelectors); var elementsArray = elements.ToArray(); _root = Build(elementsArray, 0, elementsArray.Length - 1, 0); }
private void FindInRange(KdTreeNode <TValue> node, Vector location, double range, IList <TValue> valuesList, int depth) { if (node == null) { return; } var dimension = depth % _nrOfDimensions; var nodeLocation = CreateVector(node.Value); var distance = (nodeLocation - location).Abs(); // add to list if its in range if (distance < range) { valuesList.Add(node.Value); } var nearChildNode = location[dimension] < nodeLocation[dimension] ? node.LeftChild : node.RightChild; if (nearChildNode != null) { FindInRange(nearChildNode, location, range, valuesList, depth + 1); } // also other half needs to be checked? if (range > Math.Abs(nodeLocation[dimension] - location[dimension])) { // Check for nodes in sub-tree of far child. var farChildNode = nearChildNode == node.LeftChild ? node.RightChild : node.LeftChild; if (farChildNode != null) { FindInRange(farChildNode, location, range, valuesList, depth + 1); } } }