/// <summary>
        /// Finds the node that has the assigned user data.
        /// </summary>
        /// <param name="userData"></param>
        /// <returns></returns>
        private AABBNode FindNode(T userData)
        {
            AABBNode        foundNode     = null;
            List <AABBNode> nodesToSearch = new List <AABBNode>();

            nodesToSearch.Add(m_RootNode);

            while (nodesToSearch.Count > 0)
            {
                AABBNode currentNode = nodesToSearch[0];
                nodesToSearch.RemoveAt(0);

                if (currentNode.UserData == userData)
                {
                    foundNode = currentNode;
                    break;
                }
                else if (!currentNode.IsLeaf)
                {
                    nodesToSearch.AddRange(currentNode.Children);
                }
            }

            return(foundNode);
        }
        /// <summary>
        /// Finds the leaf node that matches bounds.
        /// </summary>
        /// <param name="bounds"></param>
        /// <returns></returns>
        private AABBNode FindNode(Bounds bounds)
        {
            AABBNode foundNode   = null;
            AABBNode currentNode = m_RootNode;

            while (currentNode != null)
            {
                if (currentNode.IsLeaf)
                {
                    foundNode = currentNode.Bounds == bounds ? currentNode : null;
                    break;
                }
                else
                {
                    //Which child node if any would the bounds be in?
                    if (currentNode.Children[0].Bounds.ContainsBounds(bounds))
                    {
                        currentNode = currentNode.Children[0];
                    }
                    else if (currentNode.Children[1].Bounds.ContainsBounds(bounds))
                    {
                        currentNode = currentNode.Children[1];
                    }
                    else
                    {
                        currentNode = null;
                    }
                }
            }

            return(foundNode);
        }
        //-----------------------------------------------------------------------------------------------------------

        #region Private Functions
        /// <summary>
        /// Recursively Insert the new Node until we hit a leaf node.  Then branch and insert both nodes.
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="newNode"></param>
        private void RecursiveInsert(AABBNode currentNode, AABBNode newNode)
        {
            AABBNode branch = currentNode;

            if (currentNode.IsLeaf)
            {
                branch        = AABBNode.CreateNode(currentNode.Bounds, newNode.Bounds);
                branch.Parent = currentNode.Parent;
                if (currentNode == m_RootNode)
                {
                    m_RootNode = branch;
                }
                else
                {
                    branch.Parent.Children[branch.Parent.Children[0] == currentNode ? 0 : 1] = branch;
                }

                branch.SetChildren(currentNode, newNode);
            }
            else
            {
                Bounds withChild1 = branch.Children[0].Bounds.ExpandToContian(newNode.Bounds);
                Bounds withChild2 = branch.Children[1].Bounds.ExpandToContian(newNode.Bounds);

                float volume1 = withChild1.Volume();
                float volume2 = withChild2.Volume();
                RecursiveInsert((volume1 <= volume2) ? branch.Children[0] : branch.Children[1], newNode);
            }

            branch.RebuildBounds();
        }
            /// <summary>
            /// Creates a node containing both bounds.
            /// </summary>
            /// <param name="rightBounds"></param>
            /// <param name="leftBounds"></param>
            /// <returns></returns>
            public static AABBNode CreateNode(Bounds rightBounds, Bounds leftBounds)
            {
                AABBNode newNode = new AABBNode();

                newNode.Bounds = rightBounds.ExpandToContian(leftBounds);
                return(newNode);
            }
예제 #5
0
    public void AddNode(AABBNode node)
    {
        node.UpdateAABB();
        if (leaves.Capacity == 0)
        {
            root = node;
            leaves.Add(node);
        }
        else
        {
            AABBNode currentNode = root;

            //Find a sibling for a new node
            while (!currentNode.IsLeaf())
            {
                currentNode = SearchNode(node, currentNode);
            }

            currentNode = InsertNode(currentNode, node);
            //Check if it's a 2nd iteration and if tree can be balanced
            Balance(currentNode);

            leaves.Add(node);
        }
    }
        private void MergeIntoBranch(AABBNode myNewNode, AABBNode currentObject)
        {
            AABBNode myNewBranch = new AABBNode();

            BoundingBox.CreateMerged(ref myNewNode.myBox, ref currentObject.myBox, out myNewBranch.myBox);
            myNewBranch.Left        = currentObject;
            myNewBranch.DepthOffset = currentObject.DepthOffset;
            currentObject.DepthOffset--;
            myNewBranch.Right = myNewNode; //Depth Offset = 0;
            myNewNode.Parent  = myNewBranch;
            if (currentObject.Parent == null)
            {
                Root = myNewBranch;
            }
            else if (currentObject.Parent.Right == currentObject)
            {
                currentObject.Parent.Right = myNewBranch;
            }
            else if (currentObject.Parent.Left == currentObject)
            {
                currentObject.Parent.Left = myNewBranch;
            }
            myNewBranch.Parent   = currentObject.Parent;
            currentObject.Parent = myNewBranch;
        }
        private int RemoveInvalidParents(AABBNode NodeBeingRemoved, out AABBNode lastModifiedNode)
        {
            int Count    = 0;
            var myParent = NodeBeingRemoved.Parent;

            if (NodeBeingRemoved.Parent.Left == NodeBeingRemoved)
            {
                NodeBeingRemoved.Parent.Left = null;
            }
            else if (NodeBeingRemoved.Parent.Right == NodeBeingRemoved)
            {
                NodeBeingRemoved.Parent.Right = null;
            }
            lastModifiedNode = NodeBeingRemoved.Parent;


            if (myParent.Right == null && myParent.Left == null) //case 1 node;
            {
                var formerChildNode = myParent;
                myParent = myParent.Parent;
                while (myParent != null)
                {
                    if (myParent.Left == formerChildNode)
                    {
                        myParent.Left = null;
                        if (myParent.Right == null)
                        {
                            formerChildNode = myParent;
                            myParent        = myParent.Parent;
                            Count++;
                        }
                        else
                        {
                            lastModifiedNode = myParent;
                            myParent         = null;
                        }
                    }
                    else
                    {
                        myParent.Right = null;
                        if (myParent.Left == null)
                        {
                            Count++;
                            formerChildNode = myParent;
                            myParent        = myParent.Parent;
                        }
                        else
                        {
                            lastModifiedNode = myParent;
                            myParent         = null;
                        }
                    }
                }
            }
            else
            {
                lastModifiedNode = myParent;
            }
            return(Count);
        }
        /// <summary>
        /// Removes a node from the tree
        /// </summary>
        /// <param name="node"></param>
        private void RemoveNode(AABBNode node)
        {
            AABBNode nodeParent = node.Parent;

            if (node == m_RootNode)
            {
                m_RootNode = null;
            }
            else
            {
                AABBNode otherChild = nodeParent.Children[0] == node ? nodeParent.Children[1] : nodeParent.Children[0];
                if (nodeParent.Parent == null)
                {
                    m_RootNode        = otherChild;
                    otherChild.Parent = null;
                }
                else
                {
                    int childIndex = nodeParent.Parent.Children[0] == nodeParent ? 0 : 1;
                    nodeParent.Parent.Children[childIndex] = otherChild;
                    otherChild.Parent = nodeParent.Parent;
                }
                UpdateNodeBoundUp(otherChild.Parent);
            }
        }
예제 #9
0
 //Adjust sizes of AABB's after insertion of a new Node
 private void AdjustSizeOfOne(AABBNode node)
 {
     while (node != null)
     {
         node.UpdateAABB();
         node = node.parent;
     }
 }
예제 #10
0
            //-----------------------------------------------------------------------------------------------------------

            #region Public Functions
            /// <summary>
            /// Sets the children for this node.
            /// </summary>
            /// <param name="child1"></param>
            /// <param name="child2"></param>
            public void SetChildren(AABBNode child1, AABBNode child2)
            {
                child1.Parent = this;
                child2.Parent = this;

                Children[0] = child1;
                Children[1] = child2;
            }
        private static void ResizeBranch(AABBNode myNewNode, AABBNode CurrentObject)
        {
            var ContainmentTypeReturned = CurrentObject.myBox.Contains(myNewNode.myBox);

            if (ContainmentTypeReturned == ContainmentType.Intersects || ContainmentTypeReturned == ContainmentType.Disjoint)
            {
                BoundingBox.CreateMerged(ref myNewNode.myBox, ref CurrentObject.myBox, out CurrentObject.myBox);
            }
        }
        /*Branch – Our branches always have exactly two children (known as left and right) and are assigned an AABB that is large enough to contain all of it’s descendants.
         * Leaf – Our leaves are associated with a game world object and through that have an AABB. A leaf’s AABB must fit entirely within it’s parents AABB and due to how our branches are defined that means it fits in every ancestors AABB.
         * Root – Our root may be a branch or a leaf*/


        public void Insert <T>(ref BoundingBox myBox, T input)
        {
            AABBNode myNewNode = new AABBNodeObject <T>()
            {
                myBox = myBox, myData = input
            };

            myNodes.Add(input, myNewNode);
            if (Root == null)
            {
                Root = myNewNode;
                return;
            }
            AABBNode CurrentObject = Root;

            while (CurrentObject != null)
            {
                if (CurrentObject.ContainsData()) //It's a game object
                {
                    MergeIntoBranch(myNewNode, CurrentObject);
                    return;
                }
                else //It's just a branch.
                {
                    ResizeBranch(myNewNode, CurrentObject);
                    ContainmentType leftContainment  = ContainmentType.Disjoint;
                    ContainmentType rightContainment = ContainmentType.Disjoint;
                    if (CurrentObject.Left != null)
                    {
                        leftContainment = CurrentObject.Left.myBox.Contains(myBox);
                    }
                    if (CurrentObject.Right != null)
                    {
                        rightContainment = CurrentObject.Right.myBox.Contains(myBox);
                    }

                    if ((leftContainment == ContainmentType.Contains || leftContainment == ContainmentType.Intersects) && rightContainment == ContainmentType.Disjoint)
                    {
                        CurrentObject = CurrentObject.Left;
                    }
                    else if ((rightContainment == ContainmentType.Contains || rightContainment == ContainmentType.Intersects) && leftContainment == ContainmentType.Disjoint)
                    {
                        CurrentObject = CurrentObject.Right;
                    }
                    else if (leftContainment == ContainmentType.Intersects && rightContainment == ContainmentType.Intersects)
                    {
                        CurrentObject = GetNextByHeuristic(myNewNode, CurrentObject);
                    }
                    else
                    {
                        throw new Exception("Remove or Insert failed to clean up AABB tree properly!");
                    }
                }
            }
        }
예제 #13
0
            /// <summary>
            /// Creates a node with the bounds and data.
            /// </summary>
            /// <param name="bounds"></param>
            /// <param name="data"></param>
            /// <returns></returns>
            public static AABBNode CreateNode(Bounds bounds, T data)
            {
                AABBNode newNode = new AABBNode();

                newNode.Bounds   = bounds;
                newNode.UserData = data;

                // Determine if we want a margin bounds;

                return(newNode);
            }
예제 #14
0
        /// <summary>
        /// Updates the bounds nonleaf node object moving up the Parent tree to Root.
        /// </summary>
        /// <param name="node"></param>
        private void UpdateNodeBoundUp(AABBNode node)
        {
            if (node != null)
            {
                if (!node.IsLeaf)
                {
                    node.RebuildBounds();
                }

                UpdateNodeBoundUp(node.Parent);
            }
        }
        public RayCastHit <T> BoundingPrimativeCast <T>(BoundingBox myTestBox)
        {
            if (Root == null)
            {
                return(new RayCastHit <T>(new List <T>()));
            }
            List <T>         myResults      = new List <T>();
            Stack <AABBNode> NodesToExplore = new Stack <AABBNode>();
            AABBNode         Current        = Root;

            while (Current != null)
            {
                ContainmentType left  = ContainmentType.Disjoint;
                ContainmentType right = ContainmentType.Disjoint;
                if (Current.Left != null)
                {
                    left = myTestBox.Contains(Current.Left.myBox);
                }
                if (Current.Right != null)
                {
                    right = myTestBox.Contains(Current.Right.myBox);
                }
                if (left == ContainmentType.Contains || left == ContainmentType.Intersects) //So it hit.
                {
                    if (Current.Left.ContainsData())
                    {
                        myResults.Add(((AABBNodeObject <T>)Current.Left).myData);
                    }
                    else
                    {
                        NodesToExplore.Push(Current.Left);
                    }
                }
                if (right == ContainmentType.Contains || right == ContainmentType.Intersects) //So it hit.
                {
                    if (Current.Right.ContainsData())
                    {
                        myResults.Add(((AABBNodeObject <T>)Current.Right).myData);
                    }
                    else
                    {
                        NodesToExplore.Push(Current.Right);
                    }
                }
                if (NodesToExplore.Count == 0)
                {
                    break;
                }
                Current = NodesToExplore.Pop();
            }
            return(new RayCastHit <T>(myResults));
        }
예제 #16
0
        //-----------------------------------------------------------------------------------------------------------

        #region Public Functions
        /// <summary>
        /// Creates a new node with the provided bounds.
        /// </summary>
        /// <param name="bounds"></param>
        /// <param name="data"></param>
        public void Insert(Bounds bounds, T data)
        {
            AABBNode newNode = AABBNode.CreateNode(bounds, data);

            if (m_RootNode == null)
            {
                m_RootNode = newNode;
            }
            else
            {
                RecursiveInsert(m_RootNode, newNode);
            }
        }
예제 #17
0
 //Find deepest node that does not contain placingNode 's bounds and makes smallest AABB with new node
 private AABBNode SearchNode(AABBNode placingNode, AABBNode currentNode)
 {
     if (currentNode.left.nodeBounds.Contains(placingNode.nodeBounds))
     {
         return(currentNode.left);
     }
     else if (currentNode.right.nodeBounds.Contains(placingNode.nodeBounds))
     {
         return(currentNode.right);
     }
     else
     {
         return(CheckSize(placingNode, currentNode));
     }
 }
        private void BuildRecursive(int nodeIndex, int start, int numFaces)
        {
            int MaxFacesPerLeaf = 6;

            // a reference to the current node, need to be careful here as this reference may become invalid if array is resized
            AABBNode n = GetNode(nodeIndex);

            // track max tree depth
            ++CurrentDepth;
            MaxDepth = Math.Max(MaxDepth, CurrentDepth);

            int[] faces = GetFaces(start, numFaces);

            Vector3 min, max;

            CalculateFaceBounds(faces, out min, out max);

            n.Bounds = new Box3(min, max);
            n.Level  = CurrentDepth - 1;

            // calculate bounds of faces and add node
            if (numFaces <= MaxFacesPerLeaf)
            {
                n.Faces = faces;
                ++LeafNodes;
            }
            else
            {
                ++InnerNodes;

                // face counts for each branch
                //const uint32_t leftCount = PartitionMedian(n, faces, numFaces);
                int leftCount  = PartitionSAH(faces);
                int rightCount = numFaces - leftCount;

                // alloc 2 nodes
                Nodes[nodeIndex].Children = FreeNode;

                // allocate two nodes
                FreeNode += 2;

                // split faces in half and build each side recursively
                BuildRecursive(GetNode(nodeIndex).Children + 0, start, leftCount);
                BuildRecursive(GetNode(nodeIndex).Children + 1, start + leftCount, rightCount);
            }

            --CurrentDepth;
        }
        public RayCastHit <T> RaycastReturnFirst <T>(Ray aRay)
        {
            if (Root == null)
            {
                return(new RayCastHit <T>(new List <T>()));
            }
            List <T>         myResults      = new List <T>();
            Stack <AABBNode> NodesToExplore = new Stack <AABBNode>();
            AABBNode         Current        = Root;

            while (Current != null)
            {
                if (aRay.Intersects(Current.Left.myBox).HasValue) //So it hit.
                {
                    if (Current.Left.ContainsData() && Current.Left is AABBNodeObject <T> )
                    {
                        myResults.Add(((AABBNodeObject <T>)Current.Left).myData);
                        break;
                    }
                    else
                    {
                        NodesToExplore.Push(Current.Left);
                    }
                }
                if (aRay.Intersects(Current.Right.myBox).HasValue) //So it hit.
                {
                    if (Current.Right.ContainsData() && Current.Right is AABBNodeObject <T> )
                    {
                        myResults.Add(((AABBNodeObject <T>)Current.Right).myData);
                        break;
                    }
                    else
                    {
                        NodesToExplore.Push(Current.Right);
                    }
                }
                if (NodesToExplore.Count == 0)
                {
                    break;
                }
                Current = NodesToExplore.Pop();
            }
            return(new RayCastHit <T>(myResults));
        }
        private AABBNode GetNextByHeuristic(AABBNode myNewNode, AABBNode CurrentObject)
        {
            float DistanceLeft  = -1;
            float DistanceRight = -1;

            DistanceLeft  = DistanceApproximation.DistanceTaxiCab(CurrentObject.Left.myBox.Center, myNewNode.myBox.Center);
            DistanceRight = DistanceApproximation.DistanceTaxiCab(CurrentObject.Right.myBox.Center, myNewNode.myBox.Center);
            AABBNode Closest;

            if (DistanceLeft >= DistanceRight)
            {
                CurrentObject = CurrentObject.Right;
            }
            else
            {
                CurrentObject = CurrentObject.Left;
            }

            return(CurrentObject);
        }
예제 #21
0
    //Insert new nodeToAdd to node tree, creating new parent if needed and reassigning hierarchy
    private AABBNode InsertNode(AABBNode currentNode, AABBNode nodeToAdd)
    {
        AABBNode newParent = new AABBNode(new AABB(currentNode.nodeBounds, nodeToAdd.nodeBounds));
        AABBNode oldParent = null;

        if (currentNode.parent != null)
        {
            oldParent = currentNode.parent;
            if (currentNode == currentNode.parent.left)
            {
                currentNode.parent.left = newParent;
            }
            else
            {
                currentNode.parent.right = newParent;
            }
        }
        else
        {
            root = newParent;
        }

        newParent.left  = currentNode;
        newParent.right = nodeToAdd;

        currentNode.parent = newParent;
        nodeToAdd.parent   = newParent;

        if (oldParent != null)
        {
            newParent.parent = oldParent;
        }

        AdjustSizeOfOne(newParent);

        return(newParent);
        //MassAdjustment
    }
예제 #22
0
    //check if newParents sibling makes smaller AABB with newParents parent's sibling than current newParents parent AABB, and if it does restructure tree accordingly
    private void Balance(AABBNode newParent)
    {
        if (leaves.Count < 4)
        {
            return;
        }

        while (AABB.GetSize(newParent.GetSibling().nodeBounds, newParent.parent.GetSibling().nodeBounds) < AABB.GetSize(newParent.parent.nodeBounds))
        {
            InsertNode(newParent.parent.GetSibling(), newParent.GetSibling());
            if (newParent.parent.parent.left == newParent.parent)
            {
                newParent.parent.parent.left = newParent;
            }
            else
            {
                newParent.parent.parent.right = newParent;
            }
            newParent.parent = newParent.parent.parent;

            newParent = newParent.parent;
        }
    }
        private void TraceRecursive(int nodeIndex, Vector3 start, Vector3 dir, ref MeshRay ray)
        {
            AABBNode node = Nodes[nodeIndex];

            if (node.Faces == null)
            {
                // find closest node
                AABBNode leftChild  = Nodes[node.Children + 0];
                AABBNode rightChild = Nodes[node.Children + 1];

                float[] dist = new float[] { float.PositiveInfinity, float.PositiveInfinity };

                IntersectRayAABB(start, dir, leftChild.Bounds.Min, leftChild.Bounds.Max, out dist[0]);
                IntersectRayAABB(start, dir, rightChild.Bounds.Min, rightChild.Bounds.Max, out dist[1]);

                int closest  = 0;
                int furthest = 1;

                if (dist[1] < dist[0])
                {
                    closest  = 1;
                    furthest = 0;
                }

                if (dist[closest] < ray.distance)
                {
                    TraceRecursive(node.Children + closest, start, dir, ref ray);
                }

                if (dist[furthest] < ray.distance)
                {
                    TraceRecursive(node.Children + furthest, start, dir, ref ray);
                }
            }
            else
            {
                float t, u, v, w, s;

                for (int i = 0; i < node.Faces.Length; ++i)
                {
                    int indexStart = node.Faces[i] * 3;

                    Vector3 a = Vertices[Indices[indexStart + 0]];
                    Vector3 b = Vertices[Indices[indexStart + 1]];
                    Vector3 c = Vertices[Indices[indexStart + 2]];

                    if (IntersectRayTriTwoSided(start, dir, a, b, c, out t, out u, out v, out w, out s))
                    {
                        if (t < ray.distance)
                        {
                            ray.distance  = t;
                            ray.u         = u;
                            ray.v         = v;
                            ray.w         = w;
                            ray.faceSign  = s;
                            ray.faceIndex = node.Faces[i];
                        }
                    }
                }
            }
        }
예제 #24
0
 //return out of children of currentNode node that makes smallest AABB with nodeToAdd
 public AABBNode CheckSize(AABBNode nodeToAdd, AABBNode currentNode)
 {
     return(AABB.GetSize(nodeToAdd.nodeBounds, currentNode.left.nodeBounds) < AABB.GetSize(nodeToAdd.nodeBounds, currentNode.right.nodeBounds) ? currentNode.left : currentNode.right);
 }
 internal void Clear()
 {
     myNodes.Clear();
     Root = null;
 }
예제 #26
0
        /// <summary>
        /// Removes the node containing data.
        /// </summary>
        /// <param name="data"></param>
        public void Remove(T data)
        {
            AABBNode node = FindNode(data);

            RemoveNode(node);
        }
예제 #27
0
        /// <summary>
        /// Removes the node with the bounds.  If two nodes have the exact same bounds only the first one found will be removed.
        /// </summary>
        /// <param name="bounds"></param>
        public void Remove(Bounds bounds)
        {
            AABBNode node = FindNode(bounds);

            RemoveNode(node);
        }
예제 #28
0
 /// <summary>
 /// Destroys all nodes in the tree.
 /// </summary>
 public void Clear()
 {
     // All we need to do is remove the root node reference.  The garbage collector will do the rest.
     m_RootNode = null;
 }