diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index d1524ca1ec..59f7aeb1fd 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -158,6 +158,13 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe if (operatorObject->PreRecursion(element)) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElement* child = element->getChildAtIndex(i); + + // If there is now child at that location, the Operator may want to create a child at that location. + // So give the operator a chance to do so.... + if (!child) { + child = operatorObject->PossiblyCreateChildAt(element, i); + } + if (child) { if (!recurseElementWithOperator(child, operatorObject, recursionCount + 1)) { break; // stop recursing if operator returns false... @@ -587,7 +594,6 @@ OctreeElement* Octree::getOrCreateChildElementContaining(const AACube& box) { return getRoot()->getOrCreateChildElementContaining(box); } - // combines the ray cast arguments into a single object class RayArgs { public: diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 1d61dfe6c3..822ac4dc9b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -41,6 +41,7 @@ class RecurseOctreeOperator { public: virtual bool PreRecursion(OctreeElement* element) = 0; virtual bool PostRecursion(OctreeElement* element) = 0; + virtual OctreeElement* PossiblyCreateChildAt(OctreeElement* element, int childIndex) { return NULL; } }; // Callback function, for recuseTreeWithOperation diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 4e14f603e8..19a2768dce 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -1358,6 +1358,7 @@ bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, } +// TODO: consider removing this, or switching to using getOrCreateChildElementContaining(const AACube& box)... OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float z, float s) { OctreeElement* child = NULL; // If the requested size is less than or equal to our scale, but greater than half our scale, then @@ -1434,28 +1435,13 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) { OctreeElement* child = NULL; - float ourScale = getScale(); - float cubeScale = cube.getScale(); - - if(cubeScale > ourScale) { - qDebug("UNEXPECTED -- OctreeElement::getOrCreateChildElementContaining() " - "cubeScale=[%f] > ourScale=[%f] ", cubeScale, ourScale); - } - - // Determine which of our children the minimum and maximum corners of the cube live in... - glm::vec3 cubeCornerMinimum = cube.getCorner(); - glm::vec3 cubeCornerMaximum = cube.calcTopFarLeft(); - - int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); - int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum); - - // If the minimum and maximum corners of the cube are in two different children's cubes, then we are the containing element - if (childIndexCubeMinimum != childIndexCubeMaximum) { + int childIndex = getMyChildContaining(cube); + + // If getMyChildContaining() returns CHILD_UNKNOWN then it means that our level + // is the correct level for this cube + if (childIndex == CHILD_UNKNOWN) { return this; } - - // otherwise, they are the same and that child should be considered as the correct element - int childIndex = childIndexCubeMinimum; // both the same... // Now, check if we have a child at that location child = getChildAtIndex(childIndex); @@ -1472,6 +1458,31 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cu return child->getOrCreateChildElementContaining(cube); } +int OctreeElement::getMyChildContaining(const AACube& cube) const { + float ourScale = getScale(); + float cubeScale = cube.getScale(); + + // TODO: consider changing this to assert() + if(cubeScale > ourScale) { + qDebug("UNEXPECTED -- OctreeElement::getMyChildContaining() " + "cubeScale=[%f] > ourScale=[%f] ", cubeScale, ourScale); + } + + // Determine which of our children the minimum and maximum corners of the cube live in... + glm::vec3 cubeCornerMinimum = cube.getCorner(); + glm::vec3 cubeCornerMaximum = cube.calcTopFarLeft(); + + int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum); + int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum); + + // If the minimum and maximum corners of the cube are in two different children's cubes, then we are the containing element + if (childIndexCubeMinimum != childIndexCubeMaximum) { + return CHILD_UNKNOWN; + } + + return childIndexCubeMinimum; // either would do, they are the same +} + int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const { glm::vec3 ourCenter = _cube.calcCenter(); int childIndex = CHILD_UNKNOWN; diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 6a8628979a..a410168a87 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -237,6 +237,7 @@ public: OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); OctreeElement* getOrCreateChildElementContaining(const AACube& box); + int getMyChildContaining(const AACube& cube) const; int getMyChildContainingPoint(const glm::vec3& point) const; protected: