/// <summary>
    /// We can shrink the octree if:
    /// - This node is >= double minLength in length
    /// - All objects in the root node are within one octant
    /// - This node doesn't have children, or does but 7/8 children are empty
    /// We can also shrink it if there are no objects left at all!
    /// </summary>
    /// <param name="minLength">Minimum dimensions of a node in this octree.</param>
    /// <returns>The new root, or the existing one if we didn't shrink.</returns>
    public BoundsOctreeNode <T> ShrinkIfPossible(float minLength)
    {
        if (BaseLength < (2 * minLength))
        {
            return(this);
        }
        if (objects.Count == 0 && children.Length == 0)
        {
            return(this);
        }

        // Check objects in root
        int bestFit = -1;

        for (int i = 0; i < objects.Count; i++)
        {
            OctreeObject curObj     = objects[i];
            int          newBestFit = BestFitChild(curObj.Bounds);
            if (i == 0 || newBestFit == bestFit)
            {
                // In same octant as the other(s). Does it fit completely inside that octant?
                if (Encapsulates(childBounds[newBestFit], curObj.Bounds))
                {
                    if (bestFit < 0)
                    {
                        bestFit = newBestFit;
                    }
                }
                else
                {
                    // Nope, so we can't reduce. Otherwise we continue
                    return(this);
                }
            }
            else
            {
                return(this);                // Can't reduce - objects fit in different octants
            }
        }

        // Check objects in children if there are any
        if (children != null)
        {
            bool childHadContent = false;
            for (int i = 0; i < children.Length; i++)
            {
                if (children[i].HasAnyObjects())
                {
                    if (childHadContent)
                    {
                        return(this);                        // Can't shrink - another child had content already
                    }
                    if (bestFit >= 0 && bestFit != i)
                    {
                        return(this);                        // Can't reduce - objects in root are in a different octant to objects in child
                    }
                    childHadContent = true;
                    bestFit         = i;
                }
            }
        }

        // Can reduce
        if (children == null)
        {
            // We don't have any children, so just shrink this node to the new size
            // We already know that everything will still fit in it
            SetValues(BaseLength / 2, minSize, looseness, childBounds[bestFit].center);
            return(this);
        }

        // We have children. Use the appropriate child as the new root node
        return(children[bestFit]);
    }
Пример #2
0
        /// <summary>
        /// We can shrink the octree if:
        /// - This node is >= double minLength in length
        /// - All objects in the root node are within one octant
        /// - This node doesn't have children, or does but 7/8 children are empty
        /// We can also shrink it if there are no objects left at all!
        /// </summary>
        /// <param name="minLength">Minimum dimensions of a node in this octree.</param>
        /// <returns>The new root, or the existing one if we didn't shrink.</returns>
        public PointOctreeNode <T> ShrinkIfPossible(float minLength)
        {
            if (SideLength < (2 * minLength))
            {
                return(this);
            }
            if (objects.Count == 0 && (children == null || children.Length == 0))
            {
                return(this);
            }

            // Check objects in root
            int bestFit = -1;

            for (int i = 0; i < objects.Count; i++)
            {
                OctreeObject curObj     = objects[i];
                int          newBestFit = BestFitChild(curObj.Pos);
                if (i == 0 || newBestFit == bestFit)
                {
                    if (bestFit < 0)
                    {
                        bestFit = newBestFit;
                    }
                }
                else
                {
                    return(this); // Can't reduce - objects fit in different octants
                }
            }

            // Check objects in children if there are any
            if (children != null)
            {
                bool childHadContent = false;
                for (int i = 0; i < children.Length; i++)
                {
                    if (children[i].HasAnyObjects())
                    {
                        if (childHadContent)
                        {
                            return(this); // Can't shrink - another child had content already
                        }
                        if (bestFit >= 0 && bestFit != i)
                        {
                            return(this); // Can't reduce - objects in root are in a different octant to objects in child
                        }
                        childHadContent = true;
                        bestFit         = i;
                    }
                }
            }

            // Can reduce
            if (children == null)
            {
                // We don't have any children, so just shrink this node to the new size
                // We already know that everything will still fit in it
                SetValues(SideLength / 2, minSize, childBounds[bestFit].center);
                return(this);
            }

            // We have children. Use the appropriate child as the new root node
            return(children[bestFit]);
        }
Пример #3
0
    /// <summary>
    /// Private counterpart to the public Add method.
    /// </summary>
    /// <param name="obj">Object to add.</param>
    /// <param name="objBounds">3D bounding box around the object.</param>
    void SubAdd(T obj, Bounds objBounds)
    {
        // We know it fits at this level if we've got this far

        // We always put things in the deepest possible child
        // So we can skip some checks if there are children aleady
        if (!HasChildren)
        {
            // Just add if few objects are here, or children would be below min size
            if (objects.Count < NUM_OBJECTS_ALLOWED || (BaseLength / 2) < minSize)
            {
                OctreeObject newObj = new OctreeObject {
                    Obj = obj, Bounds = objBounds
                };
                objects.Add(newObj);
                return;                 // We're done. No children yet
            }

            // Fits at this level, but we can go deeper. Would it fit there?
            // Create the 8 children
            int bestFitChild;
            if (children == null)
            {
                Split();
                if (children == null)
                {
                    Debug.LogError("Child creation failed for an unknown reason. Early exit.");
                    return;
                }

                // Now that we have the new children, see if this node's existing objects would fit there
                for (int i = objects.Count - 1; i >= 0; i--)
                {
                    OctreeObject existingObj = objects[i];
                    // Find which child the object is closest to based on where the
                    // object's center is located in relation to the octree's center
                    bestFitChild = BestFitChild(existingObj.Bounds.center);
                    // Does it fit?
                    if (Encapsulates(children[bestFitChild].bounds, existingObj.Bounds))
                    {
                        children[bestFitChild].SubAdd(existingObj.Obj, existingObj.Bounds); // Go a level deeper
                        objects.Remove(existingObj);                                        // Remove from here
                    }
                }
            }
        }

        // Handle the new object we're adding now
        int bestFit = BestFitChild(objBounds.center);

        if (Encapsulates(children[bestFit].bounds, objBounds))
        {
            children[bestFit].SubAdd(obj, objBounds);
        }
        else
        {
            // Didn't fit in a child. We'll have to it to this node instead
            OctreeObject newObj = new OctreeObject {
                Obj = obj, Bounds = objBounds
            };
            objects.Add(newObj);
        }
    }