示例#1
0
 public void AddOctreeItem(OctreeItem <T> octreeItem)
 {
     if (_cachedItems.Count < MaxCachedItemCount)
     {
         octreeItem.Item      = default(T);
         octreeItem.Container = null;
         _cachedItems.Push(octreeItem);
     }
 }
示例#2
0
        public OctreeNode <T> AddItem(ref BoundingBox itemBounds, T item, out OctreeItem <T> octreeItem)
        {
            if (Parent != null)
            {
                throw new InvalidOperationException("Can only add items to the root Octree node.");
            }

            octreeItem = _nodeCache.GetOctreeItem(ref itemBounds, item);
            return(CoreAddRootItem(octreeItem));
        }
示例#3
0
        private OctreeNode <T> CoreAddRootItem(OctreeItem <T> octreeItem)
        {
            OctreeNode <T> root   = this;
            bool           result = CoreAddItem(octreeItem);

            if (!result)
            {
                root = ResizeAndAdd(octreeItem);
            }

            return(root);
        }
示例#4
0
        private OctreeNode <T> ResizeAndAdd(OctreeItem <T> octreeItem)
        {
            OctreeNode <T> oldRoot            = this;
            Vector3        oldRootCenter      = Bounds.GetCenter();
            Vector3        oldRootHalfExtents = Bounds.GetDimensions() * 0.5f;

            Vector3 expandDirection = Vector3.Normalize(octreeItem.Bounds.GetCenter() - oldRootCenter);
            Vector3 newCenter       = oldRootCenter;

            if (expandDirection.X >= 0) // oldRoot = Left
            {
                newCenter.X += oldRootHalfExtents.X;
            }
            else
            {
                newCenter.X -= oldRootHalfExtents.X;
            }

            if (expandDirection.Y >= 0) // oldRoot = Bottom
            {
                newCenter.Y += oldRootHalfExtents.Y;
            }
            else
            {
                newCenter.Y -= oldRootHalfExtents.Y;
            }

            if (expandDirection.Z >= 0) // oldRoot = Far
            {
                newCenter.Z += oldRootHalfExtents.Z;
            }
            else
            {
                newCenter.Z -= oldRootHalfExtents.Z;
            }

            BoundingBox    newRootBounds = new BoundingBox(newCenter - oldRootHalfExtents * 2f, newCenter + oldRootHalfExtents * 2f);
            OctreeNode <T> newRoot       = _nodeCache.GetNode(ref newRootBounds);
            OctreeNode <T> fittingNode   = newRoot.SplitChildren(ref octreeItem.Bounds, oldRoot);

            if (fittingNode != null)
            {
                bool succeeded = fittingNode.CoreAddItem(octreeItem);
                Debug.Assert(succeeded, "Octree node returned from SplitChildren must fit the item given to it.");
                return(newRoot);
            }
            else
            {
                return(newRoot.CoreAddRootItem(octreeItem));
            }
        }
示例#5
0
        /// <summary>
        /// Move a contained OctreeItem. If the root OctreeNode needs to be resized, the new root node is returned.
        /// </summary>
        public OctreeNode <T> MoveContainedItem(OctreeItem <T> item, BoundingBox newBounds)
        {
            OctreeNode <T> newRoot = null;

            var container = item.Container;

            if (!container._items.Contains(item))
            {
                throw new InvalidOperationException("Can't move item " + item + ", its container does not contain it.");
            }

            item.Bounds = newBounds;
            if (container.Bounds.Contains(ref item.Bounds) == ContainmentType.Contains)
            {
                // Item did not leave the node.
                newRoot = null;

                // It may have moved into the bounds of a child node.
                foreach (var child in Children)
                {
                    if (child.CoreAddItem(item))
                    {
                        _items.Remove(item);
                        break;
                    }
                }
            }
            else
            {
                container._items.Remove(item);
                item.Container = null;

                var node = container;
                while (node.Parent != null && !node.CoreAddItem(item))
                {
                    node = node.Parent;
                }

                if (item.Container == null)
                {
                    // This should only occur if the item has moved beyond the root node's bounds.
                    // We need to resize the root tree.
                    Debug.Assert(node == GetRootNode());
                    newRoot = node.CoreAddRootItem(item);
                }

                container.Parent.ConsiderConsolidation();
            }

            return(newRoot);
        }
示例#6
0
        /// <summary>
        /// Mark an item as having moved, but do not alter the octree structure. Call <see cref="Octree{T}.ApplyPendingMoves"/> to update the octree structure.
        /// </summary>
        public void MarkItemAsMoved(OctreeItem <T> octreeItem, BoundingBox newBounds)
        {
            if (!_items.Contains(octreeItem))
            {
                throw new InvalidOperationException("Cannot mark item as moved which doesn't belong to this OctreeNode.");
            }
            if (newBounds.ContainsNaN())
            {
                throw new InvalidOperationException("Invalid bounds: " + newBounds);
            }

            octreeItem.HasPendingMove = true;
            octreeItem.Bounds         = newBounds;
        }
示例#7
0
        public void MoveItem(OctreeItem <T> octreeItem, BoundingBox newBounds)
        {
            if (newBounds.ContainsNaN())
            {
                throw new VeldridException("Invalid bounds: " + newBounds);
            }
            var newRoot = octreeItem.Container.MoveContainedItem(octreeItem, newBounds);

            if (newRoot != null)
            {
                _currentRoot = newRoot;
            }

            _currentRoot = _currentRoot.TryTrimChildren();
        }
示例#8
0
        public void RemoveItem(OctreeItem <T> octreeItem)
        {
            var container = octreeItem.Container;

            if (!container._items.Remove(octreeItem))
            {
                throw new InvalidOperationException("Item isn't contained in its container.");
            }

            if (container.Parent != null)
            {
                container.Parent.ConsiderConsolidation();
            }

            _nodeCache.AddOctreeItem(octreeItem);
        }
示例#9
0
        private bool CoreAddItem(OctreeItem <T> item)
        {
            if (Bounds.Contains(ref item.Bounds) != ContainmentType.Contains)
            {
                return(false);
            }

            if (_items.Count >= MaxChildren && Children.Length == 0)
            {
                OctreeNode <T> newNode = SplitChildren(ref item.Bounds, null);
                if (newNode != null)
                {
                    bool succeeded = newNode.CoreAddItem(item);
                    Debug.Assert(succeeded, "Octree node returned from SplitChildren must fit the item given to it.");
                    return(true);
                }
            }
            else if (Children.Length > 0)
            {
                foreach (var child in Children)
                {
                    if (child.CoreAddItem(item))
                    {
                        return(true);
                    }
                }
            }

            // Couldn't fit in any children.
#if DEBUG
            foreach (var child in Children)
            {
                Debug.Assert(child.Bounds.Contains(ref item.Bounds) != ContainmentType.Contains);
            }
#endif

            _items.Add(item);
            item.Container = this;

            return(true);
        }
示例#10
0
        /// <summary>
        /// Attempts to find an OctreeNode for the given item, in this OctreeNode and its children.
        /// </summary>
        /// <param name="item">The item to find.</param>
        /// <param name="octreeItem">The contained OctreeItem.</param>
        /// <returns>true if the item was contained in the Octree; false otherwise.</returns>
        internal bool TryGetContainedOctreeItem(T item, out OctreeItem <T> octreeItem)
        {
            foreach (var containedItem in _items)
            {
                if (containedItem.Item.Equals(item))
                {
                    octreeItem = containedItem;
                    return(true);
                }
            }

            foreach (var child in Children)
            {
                Debug.Assert(child != null, "node child cannot be null.");
                if (child.TryGetContainedOctreeItem(item, out octreeItem))
                {
                    return(true);
                }
            }

            octreeItem = null;
            return(false);
        }
示例#11
0
 public void RemoveItem(OctreeItem <T> octreeItem)
 {
     octreeItem.Container.RemoveItem(octreeItem);
     _currentRoot = _currentRoot.TryTrimChildren();
 }
示例#12
0
 public OctreeNode <T> AddItem(BoundingBox itemBounds, T item, out OctreeItem <T> itemContainer)
 {
     return(AddItem(ref itemBounds, item, out itemContainer));
 }