Exemplo n.º 1
0
        /// <summary>
        /// Recursive search for neighbours.
        /// </summary>
        /// <param name="query">center of the search</param>
        /// <param name="node">current checked node</param>
        /// <param name="depth">current recursion depth</param>
        /// <param name="neighbours">KDTreeNeighbours-object, collecting results of nm-search</param>
        private void NMSearch(Point query,
                              KDTreeNode node, int depth, NeigbourCollector neighbours)
        {
            // The NM-search does only look for potential neighbours. The
            // final decision if this node is to be returned or not will
            // be done by the KDTreeNeighbours-object

            // If there is no node, return.
            if (node == null)
            {
                return;
            }

            // If the node is a leaf, it will always be added to the neighbours-list
            if (node.IsLeaf())
            {
                neighbours.AddNeighbour(node.Point);
                return;
            }

            // locked to 3 axis
            int axis = depth % 3;

            // One subtree usually lies closer to the query point along the currently
            // viewed axis. This one is the close-tree. The other one is the far-tree.
            KDTreeNode farSubTree, closeSubTree;

            if (query[axis] < node.Point[axis])
            {
                farSubTree   = node.Right;
                closeSubTree = node.Left;
            }
            else
            {
                farSubTree   = node.Left;
                closeSubTree = node.Right;
            }

            // Search the close-tree first
            NMSearch(query, closeSubTree, depth + 1, neighbours);

            // Since the current point was not sortet out by the
            // previous recursion level, it needs to be added to
            // the neighbour list.
            neighbours.AddNeighbour(node.Point);

            // If the current 'boundary' lies closer to the query
            // point than the farest approved neighbour so far,
            // the other side of the boundary also needs to be
            // searched.
            if (System.Math.Pow(node.Point[axis] -
                                query[axis], 2) < neighbours.LargestSquareDistance)
            {
                NMSearch(query, farSubTree, depth + 1, neighbours);
            }

            return;
        }
Exemplo n.º 2
0
        /// <summary>
        /// creates a new kd-tree node
        /// </summary>
        /// <param name="point">point that shall be described</param>
        /// <param name="left">left child node</param>
        /// <param name="right">right child node</param>
        public KDTreeNode(TuryUtilCs.Mathmatics.Geometry.Point point, KDTreeNode left, KDTreeNode right)
        {
            this.Point = point;
            this.Left = left;
            this.Right = right;

            this.Id = TreeNodeCount;
            TreeNodeCount++;
        }
Exemplo n.º 3
0
        /// <summary>
        /// Protected constructor, create instances by using static methods!
        /// </summary>
        /// <param name="root">root node of the tree. => represents the tree</param>
        protected KDTree(KDTreeNode root)
        {
            RootNode = root;

            //turn decimal separator into points, which is needed for saving the tree
            System.Globalization.CultureInfo customCulture = (System.Globalization.
                                                              CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberDecimalSeparator    = ".";
            System.Threading.Thread.CurrentThread.CurrentCulture = customCulture;
        }
Exemplo n.º 4
0
        /// <summary>
        /// Traverses the tree and writes one line desribing each element
        /// to the list lines.
        /// This method is basically another ToString()-Method for writig
        /// the kd-tree to a file.
        /// </summary>
        /// <param name="lines">This one will be the output of the
        /// whole recursive traversation.</param>
        /// <param name="node"></param>
        private void Traverse(ref List <string> lines, KDTreeNode node)
        {
            string newline = node.Id + " " +
                             node.Point.X + " " +
                             node.Point.Y + " " +
                             node.Point.Z + " ";

            if (node.Left != null)
            {
                newline += node.Left.Id + " ";
            }
            else
            {
                newline += "null ";
            }

            if (node.Right != null)
            {
                newline += node.Right.Id + " ";
            }
            else
            {
                newline += "null ";
            }

            lines.Add(newline);

            if (node.Left != null)
            {
                Traverse(ref lines, node.Left);
            }

            if (node.Right != null)
            {
                Traverse(ref lines, node.Right);
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Find all points within a defined range around a point.
        /// </summary>
        /// <param name="query">point</param>
        /// <param name="radius">range</param>
        /// <param name="node">node currently in progress -> necessary for recursion.
        /// (Don't set this value, it will be set automatically during the recursion.)</param>
        /// <param name="depth">current recursion depth
        /// (Don't set this value, it will be set automatically during the recursion.)</param>
        /// <returns>List of all points within the radius</returns>
        public List <Point> FindWithinRadius(Point query, double radius,
                                             KDTreeNode node = null, int depth = -1)
        {
            List <Point> neighbours = new List <Point>();

            // depth == -1 means that this is the top level call of this method
            if (depth == -1)
            {
                depth = 0;
                node  = RootNode;
            }

            // if node == null, the parent node is either a leaf or at least not
            // a fork
            if (node == null)
            {
                return(neighbours);
            }

            // Locked to 3 axis
            int axis = depth % 3;

            // if this node is within the range, add it!
            if (query.SquareDistanceTo(node.Point) <= System.Math.Pow(radius, 2))
            {
                neighbours.Add(node.Point);
            }

            // in case of both-side-search:
            // rememder, which side has already been searched => alreadySearchedRight
            bool alreadySearchedRight = true;

            if (query[axis] < node.Point[axis])
            {
                neighbours = neighbours.Concat(
                    FindWithinRadius(query, radius, node.Left, depth + 1)).ToList();
                alreadySearchedRight = false;
            }
            else
            {
                neighbours = neighbours.Concat(
                    FindWithinRadius(query, radius, node.Right, depth + 1)).ToList();
            }

            // case mentioned above:
            // both subtrees have to be searched; using alreadySearchedRight for
            // chosing which side to search next.
            if (System.Math.Abs(query[axis] - node.Point[axis]) < radius)
            {
                if (alreadySearchedRight)
                {
                    neighbours = neighbours.Concat(
                        FindWithinRadius(query, radius, node.Left, depth + 1)).ToList();
                }
                else
                {
                    neighbours = neighbours.Concat(
                        FindWithinRadius(query, radius, node.Right, depth + 1)).ToList();
                }
            }
            return(neighbours);
        }