Пример #1
0
        /// <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;
                }
            }
        }
Пример #2
0
 // 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;
 }
Пример #3
0
        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;
                }
            }
        }
Пример #4
0
        /// <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);
                }
            }
        }
Пример #5
0
 /// <summary>
 ///   Creates a new <see cref="KDTree&lt;T&gt;"/>.
 /// </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;
 }
Пример #6
0
        /// <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);
                }
            }
        }
Пример #7
0
 // data and depth
 public KDTreeNode(Unit inputData, int inputDepth)
 {
     this.left  = null;
     this.right = null;
     this.data  = inputData;
     this.depth = inputDepth;
 }
Пример #8
0
    public void Convert(Entity entity, EntityManager manager, GameObjectConversionSystem conversionSystem)
    {
        var data = new KDTreeNode {
        };

        manager.AddComponentData(entity, data);
    }
Пример #9
0
        /// <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
        }
Пример #10
0
        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);
        }
Пример #11
0
 // data
 public KDTreeNode(Unit inputData)
 {
     this.left  = null;
     this.right = null;
     this.depth = 0;
     this.data  = inputData;
 }
Пример #12
0
    // constructors

    // no parameter
    public KDTreeNode()
    {
        this.left  = null;
        this.right = null;
        this.depth = 0;
        this.data  = null;
    }
Пример #13
0
 /// <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;
 }
Пример #14
0
        /// <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();
        }
Пример #15
0
        /// <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);
        }
Пример #16
0
    // 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();
 }
Пример #19
0
            /// <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;
            }
Пример #20
0
        /// <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);
            }
Пример #22
0
    // 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);
        }
    }
Пример #23
0
        /// <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);
        }
Пример #24
0
        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,
            });
        }
Пример #25
0
        /// <summary>
        ///   Creates a new <see cref="KDTree&lt;T&gt;"/>.
        /// </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++;
                }
            }
        }
Пример #26
0
        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);
        }
Пример #27
0
        /// <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);
                }
            }
        }
Пример #28
0
        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);
                }
            }
        }
Пример #29
0
        /// <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;
 }
Пример #31
0
        /// <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;
        }