internal KDTreeNode <TKey, TValue> this[int compare] { get { if (compare <= 0) { return(LeftChild); } else { return(RightChild); } } set { if (compare <= 0) { LeftChild = value; } else { RightChild = value; } } }
public static KDTreeNode BuildKdTree(BoundingBox boundingBox, int treeLevel) { treeLevel++; if ((boundingBox.Shapes.Count <= int.Parse(ConfigurationManager.AppSettings["maxBoundingBoxObjects"])) || (treeLevel >= int.Parse(ConfigurationManager.AppSettings["maxTreeDepth"]))) { return new KDTreeNode(boundingBox); } else { SplitDirection splitDirection; if (boundingBox.Width > boundingBox.Hight) { splitDirection = SplitDirection.X; } else { splitDirection = SplitDirection.Y; } BoundingBox leftBox = null; BoundingBox rightBox = null; boundingBox.Split(0.5f, splitDirection, out leftBox, out rightBox); KDTreeNode root = new KDTreeNode(boundingBox); root.LeftChild = BuildKdTree(leftBox, treeLevel); root.RightChild = BuildKdTree(rightBox, treeLevel); return root; } }
public bool Add(TKey[] point, TValue value) { var nodeToAdd = new KDTreeNode <TKey, TValue>(point, value); if (root == null) { root = new KDTreeNode <TKey, TValue>(point, value); } else { int dimension = -1; KDTreeNode <TKey, TValue> parent = root; do { // Increment the dimension we're searching in dimension = (dimension + 1) % dimensions; // Does the node we're adding have the same hyperpoint as this node? if (typeMath.AreEqual(point, parent.Point)) { switch (AddDuplicateBehavior) { case AddDuplicateBehavior.Skip: return(false); case AddDuplicateBehavior.Error: throw new DuplicateNodeError(); case AddDuplicateBehavior.Update: parent.Value = value; break; default: // Should never happen throw new Exception("Unexpected AddDuplicateBehavior"); } } // Which side does this node sit under in relation to it's parent at this level? int compare = typeMath.Compare(point[dimension], parent.Point[dimension]); if (parent[compare] == null) { parent[compare] = nodeToAdd; break; } else { parent = parent[compare]; } }while (true); } Count++; return(true); }
private void RemoveChildNodes(KDTreeNode <TKey, TValue> node) { for (var side = -1; side <= 1; side += 2) { if (node[side] != null) { RemoveChildNodes(node[side]); node[side] = null; } } }
/// <summary> /// 递归寻找方法 /// </summary> /// <param name="inputNode">输入的节点</param> /// <param name="inputValue">输入的值</param> /// <returns>找到的值若为Null则未找到</returns> private KDTreeNode searchRecursion(KDTreeNode inputNode, IDimensionValueBean inputValue) { if (null == inputNode) { return(null); } //若两节点相同 else if (UtilityMethod.IfDDimensionIsEqula (inputNode.ThisDataValue, inputValue, ifUseRecursionCheck)) { //若节点已删除 if (inputNode.IsDeleteTag) { return(null); } else { return(inputNode); } } else { //获取维度索引 int dimensionIndex = inputNode.NowDimisionIndex; //获取多维数据封装 IDimensionValueBean nodeValue = inputNode.ThisDataValue; //获得当前节点维度的值 double tempDimensionValue = nodeValue.GetValueAtDimensionIndex(dimensionIndex); //获得输入数值在节点维度的值 double tempInputValue = inputValue.GetValueAtDimensionIndex(dimensionIndex); //比较两值 CompareResultEnum compareResult = UtilityMethod.CompareDoulbe(tempInputValue, tempDimensionValue); //比较结果调整 compareResult = equalStrategy(compareResult); //次轮迭代使用的节点 KDTreeNode nextRoundNode = null; //若小于去左节点 if (compareResult == CompareResultEnum.Less) { nextRoundNode = inputNode.LeftChild; } //其它去右节点 else { nextRoundNode = inputNode.RightChild; } //递归执行 return(searchRecursion(nextRoundNode, inputValue)); } }
/// <summary> /// 寻找一个节点 /// </summary> /// <param name="inputValue">输入的多维封装</param> /// <returns>找到的节点</returns> public IDimensionValueBean Search(IDimensionValueBean inputValue) { KDTreeNode tempNode = SearchNode(inputValue); if (null == tempNode) { return(null); } else { return(tempNode.ThisDataValue); } }
public void RemoveAt(TKey[] point) { // Is tree empty? if (root == null) { return; } KDTreeNode <TKey, TValue> node; if (typeMath.AreEqual(point, root.Point)) { node = root; root = null; Count--; ReaddChildNodes(node); return; } node = root; int dimension = -1; do { dimension = (dimension + 1) % dimensions; int compare = typeMath.Compare(point[dimension], node.Point[dimension]); if (node[compare] == null) { // Can't find node return; } if (typeMath.AreEqual(point, node[compare].Point)) { var nodeToRemove = node[compare]; node[compare] = null; Count--; ReaddChildNodes(nodeToRemove); } else { node = node[compare]; } }while (node != null); }
private void ReaddChildNodes(KDTreeNode <TKey, TValue> removedNode) { if (removedNode.IsLeaf) { return; } // The folllowing code might seem a little redundant but we're using // 2 queues so we can add the child nodes back in, in (more or less) // the same order they were added in the first place var nodesToReadd = new Queue <KDTreeNode <TKey, TValue> >(); var nodesToReaddQueue = new Queue <KDTreeNode <TKey, TValue> >(); if (removedNode.LeftChild != null) { nodesToReaddQueue.Enqueue(removedNode.LeftChild); } if (removedNode.RightChild != null) { nodesToReaddQueue.Enqueue(removedNode.RightChild); } while (nodesToReaddQueue.Count > 0) { var nodeToReadd = nodesToReaddQueue.Dequeue(); nodesToReadd.Enqueue(nodeToReadd); for (int side = -1; side <= 1; side += 2) { if (nodeToReadd[side] != null) { nodesToReaddQueue.Enqueue(nodeToReadd[side]); nodeToReadd[side] = null; } } } while (nodesToReadd.Count > 0) { var nodeToReadd = nodesToReadd.Dequeue(); Count--; Add(nodeToReadd.Point, nodeToReadd.Value); } }
private void AddNodesToList(KDTreeNode <TKey, TValue> node, List <KDTreeNode <TKey, TValue> > nodes) { if (node == null) { return; } nodes.Add(node); for (var side = -1; side <= 1; side += 2) { if (node[side] != null) { AddNodesToList(node[side], nodes); node[side] = null; } } }
/// <summary> /// 节点删除(不进行平衡调整) /// </summary> /// <param name="inputValue"></param> /// <returns></returns> public bool DeleteNoneBlace(IDimensionValueBean inputValue) { //寻找节点 KDTreeNode findedNode = SearchNode(inputValue); //若没找到或目前节点已删除 if (null == findedNode || findedNode.IsDeleteTag == true) { return(false); } //正常情况仅调整标签 else { findedNode.IsDeleteTag = true; nodeCount--; return(true); } }
/// <summary> /// 节点插入(不进行平衡调整) /// </summary> /// <param name="inputValue">输入的多维数据值</param> /// <returns>插入结果</returns> public bool InsertNoneBlance(IDimensionValueBean inputValue) { //若根节点为Null if (null == rootNode) { inputCheck(inputValue, false); int tempIndex = GetUseDimensionIndex(); KDTreeNode tempTreeNode = new KDTreeNode(inputValue, tempIndex); rootNode = tempTreeNode; nodeCount++; return(true); } else { inputCheck(inputValue); return(insertLoopMethod(inputValue)); } }
/// <summary> /// 设置相应的子节点 /// </summary> /// <param name="ifLeftChild">是否是左子节点</param> /// <param name="inputTreeNode">输入的节点</param> internal void SetChildNode(bool ifLeftChild, KDTreeNode inputTreeNode) { //获得当前的相应子节点 KDTreeNode nowNode = GetChildNode(ifLeftChild); //插入位置子节点声明 KDTreeNode tempLeftNode = null; KDTreeNode tempRightNode = null; //若当前位置有子节点 if (null != nowNode) { //临时变量赋值 tempLeftNode = nowNode.LeftChild; tempRightNode = nowNode.RightChild; //清空目前节点与树的连接关系 nowNode.Parent = null; nowNode.LeftChild = null; nowNode.RightChild = null; } //将输入节点的父节点设为自身 inputTreeNode.Parent = this; //将输入节点与父节点连接 if (ifLeftChild) { this.LeftChild = inputTreeNode; } else { this.RightChild = inputTreeNode; } //将输入节点与子节点连接 inputTreeNode.LeftChild = tempLeftNode; inputTreeNode.RightChild = tempRightNode; }
public KDTreeNode <TKey, TValue>[] RangeQuery(TKey[] center, TKey radius, int count) { var nearestNeighbours = new NearestNeighbourList <KDTreeNode <TKey, TValue>, TKey>(count, typeMath); AddNearestNeighbours( root, center, KDTreeHyperRect <TKey> .Infinite(dimensions, typeMath), 0, nearestNeighbours, typeMath.Multiply(radius, radius)); count = nearestNeighbours.Count; var neighbourArray = new KDTreeNode <TKey, TValue> [count]; for (var index = 0; index < count; index++) { neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest(); } return(neighbourArray); }
private void AddNodeToStringBuilder(KDTreeNode <TKey, TValue> node, StringBuilder sb, int depth) { sb.AppendLine(node.ToString()); for (var side = -1; side <= 1; side += 2) { for (var index = 0; index <= depth; index++) { sb.Append("\t"); } sb.Append(side == -1 ? "L " : "R "); if (node[side] == null) { sb.AppendLine(""); } else { AddNodeToStringBuilder(node[side], sb, depth + 1); } } }
public static void IntersectTree(KDTreeNode node, Point point, UserMessaging messagingAgent) { if (node.IsNodeLeaf) { foreach (Shape shape in node.NodeBox.Shapes) { if (shape.Intersects(point)) { messagingAgent.SendMessage(shape.Name); } } } else { if (node.LeftChild.NodeBox.Intersects(point)) { IntersectTree(node.LeftChild, point, messagingAgent); } else { IntersectTree(node.RightChild, point, messagingAgent); } } }
public KDTreeNode <TKey, TValue>[] NearestNeighboursQuery(TKey[] point, int count) { if (count > Count) { count = Count; } if (count < 0) { throw new ArgumentException("Number of neighbors cannot be negative"); } if (count == 0) { return(new KDTreeNode <TKey, TValue> [0]); } var neighbours = new KDTreeNode <TKey, TValue> [count]; var nearestNeighbours = new NearestNeighbourList <KDTreeNode <TKey, TValue>, TKey>(count, typeMath); var rect = KDTreeHyperRect <TKey> .Infinite(dimensions, typeMath); AddNearestNeighbours(root, point, rect, 0, nearestNeighbours, typeMath.MaxValue); count = nearestNeighbours.Count; var neighbourArray = new KDTreeNode <TKey, TValue> [count]; for (var index = 0; index < count; index++) { neighbourArray[count - index - 1] = nearestNeighbours.RemoveFurtherest(); } return(neighbourArray); }
/// <summary> /// 比较输入的多维节点是否与此节点数据相同 /// </summary> /// <param name="inputValue">输入的多维节点</param> /// <returns>是否相同</returns> internal bool IfEqula(KDTreeNode inputValue) { return(IfEqula(inputValue.thisDataValue)); }
/// <summary> /// 添加节点的递归方法 /// </summary> /// <param name="inputValue">输入的值</param> /// <returns></returns> private bool insertLoopMethod(IDimensionValueBean inputValue) { //当前递归节点 KDTreeNode currentNode = rootNode; //当前节点的父节点 KDTreeNode parentNode = null; //临时节点 KDTreeNode tempNode = null; //父节点的索引 int tempDimensionIndex = -1; //当前节点应当使用的索引 int tempNowIndex = -1; //表征节点前进方向是否是向左节点 bool ifIsLeftTag = true; double tempParentValue = 0.0d; double tempCurrentValue = 0.0d; CompareResultEnum tempCompareResult; //递归寻找添加位点 while (true) { //当前递归层级节点变为父节点 parentNode = currentNode; //获得父节点的索引 tempDimensionIndex = parentNode.NowDimisionIndex; //获得父节点的值 tempParentValue = parentNode.ThisDataValue. GetValueAtDimensionIndex(tempDimensionIndex); //获取此节点的值 tempCurrentValue = inputValue. GetValueAtDimensionIndex(tempDimensionIndex); //比较节点值 tempCompareResult = UtilityMethod. CompareDoulbe(tempCurrentValue, tempParentValue); //按相等策略调整 tempCompareResult = equalStrategy(tempCompareResult); //小于:左子树方向 if (tempCompareResult == CompareResultEnum.Less) { ifIsLeftTag = true; } //其它右子树方向 else { ifIsLeftTag = false; } //获取父节点相应位置处的子节点 currentNode = parentNode.GetChildNode(ifIsLeftTag); //获得子节点的索引 tempNowIndex = GetUseDimensionInde(tempDimensionIndex); if (null == currentNode) { tempNode = new KDTreeNode(inputValue, tempNowIndex); parentNode.SetChildNode(ifIsLeftTag, tempNode); break; } //若多维值相同 if (UtilityMethod.IfDDimensionIsEqula(currentNode.ThisDataValue, inputValue)) { //若需要替换或当前节点是已删除状态 if (ifEqualValueReplace || currentNode.IsDeleteTag) { currentNode.ThisDataValue = inputValue; currentNode.IsDeleteTag = false; } break; } } nodeCount++; return(true); }
/* * 1. Search for the target * * 1.1 Start by splitting the specified hyper rect * on the specified node's point along the current * dimension so that we end up with 2 sub hyper rects * (current dimension = depth % dimensions) * * 1.2 Check what sub rectangle the the target point resides in * under the current dimension * * 1.3 Set that rect to the nearer rect and also the corresponding * child node to the nearest rect and node and the other rect * and child node to the further rect and child node (for use later) * * 1.4 Travel into the nearer rect and node by calling function * recursively with nearer rect and node and incrementing * the depth * * 2. Add leaf to list of nearest neighbours * * 3. Walk back up tree and at each level: * * 3.1 Add node to nearest neighbours if * we haven't filled our nearest neighbour * list yet or if it has a distance to target less * than any of the distances in our current nearest * neighbours. * * 3.2 If there is any point in the further rectangle that is closer to * the target than our furtherest nearest neighbour then travel into * that rect and node * * That's it, when it finally finishes traversing the branches * it needs to we'll have our list! */ private void AddNearestNeighbours( KDTreeNode <TKey, TValue> node, TKey[] target, KDTreeHyperRect <TKey> rect, int depth, NearestNeighbourList <KDTreeNode <TKey, TValue>, TKey> nearestNeighbours, TKey maxSearchRadiusSquared) { if (node == null) { return; } // Work out the current dimension int dimension = depth % dimensions; // Split our hyper-rect into 2 sub rects along the current // node's point on the current dimension var leftRect = rect.Clone(); leftRect.MaxPoint[dimension] = node.Point[dimension]; var rightRect = rect.Clone(); rightRect.MinPoint[dimension] = node.Point[dimension]; // Which side does the target reside in? int compare = typeMath.Compare(target[dimension], node.Point[dimension]); var nearerRect = compare <= 0 ? leftRect : rightRect; var furtherRect = compare <= 0 ? rightRect : leftRect; var nearerNode = compare <= 0 ? node.LeftChild : node.RightChild; var furtherNode = compare <= 0 ? node.RightChild : node.LeftChild; // Let's walk down into the nearer branch if (nearerNode != null) { AddNearestNeighbours( nearerNode, target, nearerRect, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } TKey distanceSquaredToTarget; // Walk down into the further branch but only if our capacity hasn't been reached // OR if there's a region in the further rect that's closer to the target than our // current furtherest nearest neighbour TKey[] closestPointInFurtherRect = furtherRect.GetClosestPoint(target, typeMath); distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(closestPointInFurtherRect, target); if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0) { if (nearestNeighbours.IsCapacityReached) { if (typeMath.Compare(distanceSquaredToTarget, nearestNeighbours.GetFurtherestDistance()) < 0) { AddNearestNeighbours( furtherNode, target, furtherRect, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } } else { AddNearestNeighbours( furtherNode, target, furtherRect, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } } // Try to add the current node to our nearest neighbours list distanceSquaredToTarget = typeMath.DistanceSquaredBetweenPoints(node.Point, target); if (typeMath.Compare(distanceSquaredToTarget, maxSearchRadiusSquared) <= 0) { nearestNeighbours.Add(node, distanceSquaredToTarget); } }