/// <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]); }
/// <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]); }
/// <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); } }