From a15c5999b5ae6845457ec386c9fbb8a496ea0bf1 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Wed, 10 May 2017 16:58:51 -0700
Subject: [PATCH 01/11] first cut at octree storage of Triangle Set

---
 interface/src/Application.cpp        |   2 +-
 libraries/render-utils/src/Model.cpp |   4 +-
 libraries/shared/src/AABox.cpp       |  41 +++++++
 libraries/shared/src/AABox.h         |  15 +++
 libraries/shared/src/TriangleSet.cpp | 159 ++++++++++++++++++++++++++-
 libraries/shared/src/TriangleSet.h   |  66 ++++++++++-
 6 files changed, 274 insertions(+), 13 deletions(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 8220b3e891..01b855bb73 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -336,7 +336,7 @@ public:
 
                 // Don't actually crash in debug builds, in case this apparent deadlock is simply from
                 // the developer actively debugging code
-                #ifdef NDEBUG
+                #if 0 //def NDEBUG
                     deadlockDetectionCrash();
                 #endif
             }
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index acc84646c5..2c338674eb 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -376,7 +376,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
         glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
         glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f));
 
-        for (const auto& triangleSet : _modelSpaceMeshTriangleSets) {
+        for (auto& triangleSet : _modelSpaceMeshTriangleSets) {
             float triangleSetDistance = 0.0f;
             BoxFace triangleSetFace;
             glm::vec3 triangleSetNormal;
@@ -462,6 +462,8 @@ bool Model::convexHullContains(glm::vec3 point) {
 void Model::calculateTriangleSets() {
     PROFILE_RANGE(render, __FUNCTION__);
 
+    qDebug() << __FUNCTION__ << "url:" << _url;
+
     const FBXGeometry& geometry = getFBXGeometry();
     int numberOfMeshes = geometry.meshes.size();
 
diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp
index 3f3146cc04..cea0a83d52 100644
--- a/libraries/shared/src/AABox.cpp
+++ b/libraries/shared/src/AABox.cpp
@@ -114,6 +114,10 @@ static bool isWithin(float value, float corner, float size) {
     return value >= corner && value <= corner + size;
 }
 
+bool AABox::contains(const Triangle& triangle) const {
+    return contains(triangle.v0) && contains(triangle.v1) && contains(triangle.v2);
+}
+
 bool AABox::contains(const glm::vec3& point) const {
     return isWithin(point.x, _corner.x, _scale.x) &&
         isWithin(point.y, _corner.y, _scale.y) &&
@@ -622,3 +626,40 @@ void AABox::transform(const glm::mat4& matrix) {
     _corner = newCenter - newDir;
     _scale = newDir * 2.0f;
 }
+
+AABox AABox::getOctreeChild(OctreeChild child) const {
+    AABox result(*this); // self
+    switch (child) {
+        case topLeftNear:
+            result._corner.y += _scale.y / 2.0f;
+            break;
+        case topLeftFar:
+            result._corner.y += _scale.y / 2.0f;
+            result._corner.z += _scale.z / 2.0f;
+            break;
+        case topRightNear:
+            result._corner.y += _scale.y / 2.0f;
+            result._corner.x += _scale.x / 2.0f;
+            break;
+        case topRightFar:
+            result._corner.y += _scale.y / 2.0f;
+            result._corner.x += _scale.x / 2.0f;
+            result._corner.z += _scale.z / 2.0f;
+            break;
+        case bottomLeftNear:
+            // _corner = same as parent
+            break;
+        case bottomLeftFar:
+            result._corner.z += _scale.z / 2.0f;
+            break;
+        case bottomRightNear:
+            result._corner.x += _scale.x / 2.0f;
+            break;
+        case bottomRightFar:
+            result._corner.x += _scale.x / 2.0f;
+            result._corner.z += _scale.z / 2.0f;
+            break;
+    }
+    result._scale /= 2.0f; // everything is half the scale
+    return result;
+}
diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h
index a53cc26163..eef83974ea 100644
--- a/libraries/shared/src/AABox.h
+++ b/libraries/shared/src/AABox.h
@@ -20,6 +20,7 @@
 #include <QDebug>
 
 #include "BoxBase.h"
+#include "GeometryUtil.h"
 #include "StreamUtils.h"
 
 class AACube;
@@ -58,6 +59,7 @@ public:
     const glm::vec3& getMinimumPoint() const { return _corner; }
     glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); }
 
+    bool contains(const Triangle& triangle) const;
     bool contains(const glm::vec3& point) const;
     bool contains(const AABox& otherBox) const;
     bool touches(const AABox& otherBox) const;
@@ -112,6 +114,19 @@ public:
 
     void clear() { _corner = INFINITY_VECTOR; _scale = glm::vec3(0.0f); }
 
+    typedef enum {
+        topLeftNear,
+        topLeftFar,
+        topRightNear,
+        topRightFar,
+        bottomLeftNear,
+        bottomLeftFar,
+        bottomRightNear,
+        bottomRightFar
+    } OctreeChild;
+
+    AABox getOctreeChild(OctreeChild child) const; // returns the AABox of the would be octree child of this AABox
+
 private:
     glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
     glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index cdb3fd6b2c..e13d8b126f 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -12,7 +12,22 @@
 #include "GLMHelpers.h"
 #include "TriangleSet.h"
 
-void TriangleSet::insert(const Triangle& t) {
+
+
+bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+    float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) {
+
+    if (!_isBalanced) {
+        balanceOctree();
+    }
+
+    int trianglesTouched = 0;
+    auto result = _triangleOctree.findRayIntersection(origin, direction, distance, face, surfaceNormal, precision, trianglesTouched);
+    qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+    return result;
+}
+
+void InternalTriangleSet::insert(const Triangle& t) {
     _triangles.push_back(t);
 
     _bounds += t.v0;
@@ -20,15 +35,15 @@ void TriangleSet::insert(const Triangle& t) {
     _bounds += t.v2;
 }
 
-void TriangleSet::clear() {
+void InternalTriangleSet::clear() {
     _triangles.clear();
     _bounds.clear();
 }
 
 // Determine of the given ray (origin/direction) in model space intersects with any triangles
 // in the set. If an intersection occurs, the distance and surface normal will be provided.
-bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
-                    float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const {
+bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+            float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     bool intersectedSomething = false;
     float boxDistance = std::numeric_limits<float>::max();
@@ -38,6 +53,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
         if (precision) {
             for (const auto& triangle : _triangles) {
                 float thisTriangleDistance;
+                trianglesTouched++;
                 if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
                     if (thisTriangleDistance < bestDistance) {
                         bestDistance = thisTriangleDistance;
@@ -57,7 +73,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
 }
 
 
-bool TriangleSet::convexHullContains(const glm::vec3& point) const {
+bool InternalTriangleSet::convexHullContains(const glm::vec3& point) const {
     if (!_bounds.contains(point)) {
         return false;
     }
@@ -74,3 +90,136 @@ bool TriangleSet::convexHullContains(const glm::vec3& point) const {
     return insideMesh;
 }
 
+void TriangleSet::debugDump() {
+    qDebug() << __FUNCTION__;
+    qDebug() << "bounds:" << getBounds();
+    qDebug() << "triangles:" << size() << "at top level....";
+    qDebug() << "----- _triangleOctree -----";
+    _triangleOctree.debugDump();
+}
+
+void TriangleSet::balanceOctree() {
+    _triangleOctree.reset(_bounds, 0);
+    for (const auto& triangle : _triangles) {
+        _triangleOctree.insert(triangle);
+    }
+    _isBalanced = true;
+}
+
+static const int MAX_DEPTH = 3; // for now
+static const int MAX_CHILDREN = 8;
+
+TriangleOctreeCell::TriangleOctreeCell(const AABox& bounds, int depth) {
+    reset(bounds, depth);
+}
+
+void TriangleOctreeCell::clear() {
+    _triangleSet.clear();
+    _population = 0;
+}
+
+void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
+    //qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth;
+    clear();
+    _triangleSet._bounds = bounds;
+    _depth = depth;
+    if (depth <= MAX_DEPTH) {
+        int childDepth = depth + 1;
+        _children.clear();
+        for (int child = 0; child < MAX_CHILDREN; child++) {
+            AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
+            /*
+            qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth 
+                        << "child:" << child << "childBounds:" << childBounds << "childDepth:" << childDepth;
+            */
+
+            _children.push_back(TriangleOctreeCell(childBounds, childDepth));
+        }
+    }
+}
+
+void TriangleOctreeCell::debugDump() {
+    qDebug() << __FUNCTION__;
+    qDebug() << "bounds:" << getBounds();
+    qDebug() << "depth:" << _depth;
+    qDebug() << "triangleSet:" << _triangleSet.size() << "at this level";
+    qDebug() << "population:" << _population << "this level or below";
+    if (_depth < MAX_DEPTH) {
+        int childNum = 0;
+        for (auto& child : _children) {
+            qDebug() << "child:" << childNum;
+            child.debugDump();
+            childNum++;
+        }
+    }
+}
+
+void TriangleOctreeCell::insert(const Triangle& t) {
+    _population++;
+    // if we're not yet at the max depth, then check which child the triangle fits in
+    if (_depth < MAX_DEPTH) {
+        for (auto& child : _children) {
+            if (child.getBounds().contains(t)) {
+                child.insert(t);
+                return;
+            }
+        }
+    }
+    // either we're at max depth, or the triangle doesn't fit in one of our
+    // children and so we want to just record it here
+    _triangleSet.insert(t);
+}
+
+bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+                float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
+
+    if (_population < 1) {
+        return false; // no triangles below here, so we can't intersect
+    }
+
+    float bestLocalDistance = std::numeric_limits<float>::max();
+    BoxFace bestLocalFace;
+    glm::vec3 bestLocalNormal;
+    bool intersects = false;
+
+    // if the ray intersects our bounding box, then continue
+    if (getBounds().findRayIntersection(origin, direction, bestLocalDistance, bestLocalFace, bestLocalNormal)) {
+        bestLocalDistance = std::numeric_limits<float>::max();
+
+        float childDistance = std::numeric_limits<float>::max();
+        BoxFace childFace;
+        glm::vec3 childNormal;
+
+        // if we're not yet at the max depth, then check which child the triangle fits in
+        if (_depth < MAX_DEPTH) {
+            for (auto& child : _children) {
+                // check each child, if there's an intersection, it will return some distance that we need
+                // to compare against the other results, because there might be multiple intersections and
+                // we will always choose the best (shortest) intersection
+                if (child.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
+                    if (childDistance < bestLocalDistance) {
+                        bestLocalDistance = childDistance;
+                        bestLocalFace = childFace;
+                        bestLocalNormal = childNormal;
+                        intersects = true;
+                    }
+                }
+            }
+        }
+        // also check our local triangle set
+        if (_triangleSet.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
+            if (childDistance < bestLocalDistance) {
+                bestLocalDistance = childDistance;
+                bestLocalFace = childFace;
+                bestLocalNormal = childNormal;
+                intersects = true;
+            }
+        }
+    }
+    if (intersects) {
+        distance = bestLocalDistance;
+        face = bestLocalFace;
+        surfaceNormal = bestLocalNormal;
+    }
+    return intersects;
+}
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index b54f1a642a..c8703c6445 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -14,20 +14,21 @@
 #include "AABox.h"
 #include "GeometryUtil.h"
 
-class TriangleSet {
+class InternalTriangleSet {
 public:
+    InternalTriangleSet() { }
+
     void reserve(size_t size) { _triangles.reserve(size); } // reserve space in the datastructure for size number of triangles
     size_t size() const { return _triangles.size(); } 
 
-    const Triangle& getTriangle(size_t t) const { return _triangles[t]; }
-
-    void insert(const Triangle& t);
+    virtual void insert(const Triangle& t);
     void clear();
 
     // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
     // intersection occurs, the distance and surface normal will be provided.
+    // note: this might side-effect internal structures
     bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, 
-        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const;
+        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
 
     // Determine if a point is "inside" all the triangles of a convex hull. It is the responsibility of the caller to
     // determine that the triangle set is indeed a convex hull. If the triangles added to this set are not in fact a 
@@ -35,7 +36,60 @@ public:
     bool convexHullContains(const glm::vec3& point) const;
     const AABox& getBounds() const { return _bounds; }
 
-private:
+protected:
     std::vector<Triangle> _triangles;
     AABox _bounds;
+
+    friend class TriangleOctreeCell;
+};
+
+class TriangleOctreeCell {
+public:
+    TriangleOctreeCell() { }
+
+    void insert(const Triangle& t);
+    void reset(const AABox& bounds, int depth = 0);
+    void clear();
+
+    // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
+    // intersection occurs, the distance and surface normal will be provided.
+    bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
+
+    const AABox& getBounds() const { return _triangleSet.getBounds(); }
+
+    void debugDump();
+
+protected:
+    TriangleOctreeCell(const AABox& bounds, int depth);
+
+    InternalTriangleSet _triangleSet;
+    std::vector<TriangleOctreeCell> _children;
+    int _depth { 0 };
+    int _population { 0 };
+
+    friend class TriangleSet;
+};
+
+class TriangleSet : public InternalTriangleSet {
+    // pass through public implementation all the features of InternalTriangleSet
+public:
+    TriangleSet() { }
+
+    void debugDump();
+
+    virtual void insert(const Triangle& t) {
+        _isBalanced = false;
+        InternalTriangleSet::insert(t);
+    }
+
+    bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision);
+
+    void balanceOctree();
+
+protected:
+
+    bool _isBalanced { false };
+    TriangleOctreeCell _triangleOctree;
 };

From 6d7e98274b0a18d8ca62d8cccc54cac29ed4c884 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 17:07:00 -0700
Subject: [PATCH 02/11] revert debug change

---
 interface/src/Application.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index ded6d6b628..f4699009ac 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -336,7 +336,7 @@ public:
 
                 // Don't actually crash in debug builds, in case this apparent deadlock is simply from
                 // the developer actively debugging code
-                #if 0 //def NDEBUG
+                #ifdef NDEBUG
                     deadlockDetectionCrash();
                 #endif
             }

From eb3b27849c74e111e16cc831bfade32553c563aa Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 17:07:47 -0700
Subject: [PATCH 03/11] only keep one copy of Triangles

---
 libraries/render-utils/src/Model.cpp |   2 -
 libraries/shared/src/TriangleSet.cpp | 153 ++++++++++++++++-----------
 libraries/shared/src/TriangleSet.h   |  61 +++++++----
 3 files changed, 132 insertions(+), 84 deletions(-)

diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index 2c338674eb..9af1c6802e 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -462,8 +462,6 @@ bool Model::convexHullContains(glm::vec3 point) {
 void Model::calculateTriangleSets() {
     PROFILE_RANGE(render, __FUNCTION__);
 
-    qDebug() << __FUNCTION__ << "url:" << _url;
-
     const FBXGeometry& geometry = getFBXGeometry();
     int numberOfMeshes = geometry.meshes.size();
 
diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index e13d8b126f..ef8f3ab91e 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -13,6 +13,22 @@
 #include "TriangleSet.h"
 
 
+void TriangleSet::insert(const Triangle& t) {
+    _isBalanced = false;
+
+    _triangles.push_back(t);
+    _bounds += t.v0;
+    _bounds += t.v1;
+    _bounds += t.v2;
+}
+
+void TriangleSet::clear() {
+    _triangles.clear();
+    _bounds.clear();
+    _isBalanced = false;
+
+    // delete the octree?
+}
 
 bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
     float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) {
@@ -27,53 +43,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
     return result;
 }
 
-void InternalTriangleSet::insert(const Triangle& t) {
-    _triangles.push_back(t);
-
-    _bounds += t.v0;
-    _bounds += t.v1;
-    _bounds += t.v2;
-}
-
-void InternalTriangleSet::clear() {
-    _triangles.clear();
-    _bounds.clear();
-}
-
-// Determine of the given ray (origin/direction) in model space intersects with any triangles
-// in the set. If an intersection occurs, the distance and surface normal will be provided.
-bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
-            float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
-
-    bool intersectedSomething = false;
-    float boxDistance = std::numeric_limits<float>::max();
-    float bestDistance = std::numeric_limits<float>::max();
-
-    if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
-        if (precision) {
-            for (const auto& triangle : _triangles) {
-                float thisTriangleDistance;
-                trianglesTouched++;
-                if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
-                    if (thisTriangleDistance < bestDistance) {
-                        bestDistance = thisTriangleDistance;
-                        intersectedSomething = true;
-                        surfaceNormal = triangle.getNormal();
-                        distance = bestDistance;
-                    }
-                }
-            }
-        } else {
-            intersectedSomething = true;
-            distance = boxDistance;
-        }
-    }
-
-    return intersectedSomething;
-}
-
-
-bool InternalTriangleSet::convexHullContains(const glm::vec3& point) const {
+bool TriangleSet::convexHullContains(const glm::vec3& point) const {
     if (!_bounds.contains(point)) {
         return false;
     }
@@ -100,16 +70,76 @@ void TriangleSet::debugDump() {
 
 void TriangleSet::balanceOctree() {
     _triangleOctree.reset(_bounds, 0);
-    for (const auto& triangle : _triangles) {
-        _triangleOctree.insert(triangle);
+
+    // insert all the triangles
+
+    for (int i = 0; i < _triangles.size(); i++) {
+        _triangleOctree.insert(i);
     }
+
+    // prune the empty cells
+    _triangleOctree.prune();
+
     _isBalanced = true;
 }
 
+
+
+void InternalTriangleSet::insert(int triangleIndex) {
+    auto& triangle = _allTriangles[triangleIndex];
+
+    _triangleIndices.push_back(triangleIndex);
+
+    _bounds += triangle.v0;
+    _bounds += triangle.v1;
+    _bounds += triangle.v2;
+}
+
+void InternalTriangleSet::clear() {
+    _triangleIndices.clear();
+    _bounds.clear();
+}
+
+// Determine of the given ray (origin/direction) in model space intersects with any triangles
+// in the set. If an intersection occurs, the distance and surface normal will be provided.
+bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+            float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
+
+    bool intersectedSomething = false;
+    float boxDistance = std::numeric_limits<float>::max();
+    float bestDistance = std::numeric_limits<float>::max();
+
+    if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
+        if (precision) {
+            for (const auto& triangleIndex : _triangleIndices) {
+                const auto& triangle = _allTriangles[triangleIndex];
+                float thisTriangleDistance;
+                trianglesTouched++;
+                if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
+                    if (thisTriangleDistance < bestDistance) {
+                        bestDistance = thisTriangleDistance;
+                        intersectedSomething = true;
+                        surfaceNormal = triangle.getNormal();
+                        distance = bestDistance;
+                    }
+                }
+            }
+        } else {
+            intersectedSomething = true;
+            distance = boxDistance;
+        }
+    }
+
+    return intersectedSomething;
+}
+
 static const int MAX_DEPTH = 3; // for now
 static const int MAX_CHILDREN = 8;
 
-TriangleOctreeCell::TriangleOctreeCell(const AABox& bounds, int depth) {
+TriangleOctreeCell::TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth) :
+    _allTriangles(allTriangles),
+    _triangleSet(allTriangles)
+{
     reset(bounds, depth);
 }
 
@@ -118,8 +148,11 @@ void TriangleOctreeCell::clear() {
     _population = 0;
 }
 
+void TriangleOctreeCell::prune() {
+    // do nothing yet...
+}
+
 void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
-    //qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth;
     clear();
     _triangleSet._bounds = bounds;
     _depth = depth;
@@ -128,12 +161,7 @@ void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
         _children.clear();
         for (int child = 0; child < MAX_CHILDREN; child++) {
             AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
-            /*
-            qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth 
-                        << "child:" << child << "childBounds:" << childBounds << "childDepth:" << childDepth;
-            */
-
-            _children.push_back(TriangleOctreeCell(childBounds, childDepth));
+            _children.push_back(TriangleOctreeCell(_allTriangles, childBounds, childDepth));
         }
     }
 }
@@ -142,7 +170,7 @@ void TriangleOctreeCell::debugDump() {
     qDebug() << __FUNCTION__;
     qDebug() << "bounds:" << getBounds();
     qDebug() << "depth:" << _depth;
-    qDebug() << "triangleSet:" << _triangleSet.size() << "at this level";
+    //qDebug() << "triangleSet:" << _triangleSet.size() << "at this level";
     qDebug() << "population:" << _population << "this level or below";
     if (_depth < MAX_DEPTH) {
         int childNum = 0;
@@ -154,20 +182,21 @@ void TriangleOctreeCell::debugDump() {
     }
 }
 
-void TriangleOctreeCell::insert(const Triangle& t) {
+void TriangleOctreeCell::insert(int triangleIndex) {
+    const Triangle& triangle = _allTriangles[triangleIndex];
     _population++;
     // if we're not yet at the max depth, then check which child the triangle fits in
     if (_depth < MAX_DEPTH) {
         for (auto& child : _children) {
-            if (child.getBounds().contains(t)) {
-                child.insert(t);
+            if (child.getBounds().contains(triangle)) {
+                child.insert(triangleIndex);
                 return;
             }
         }
     }
     // either we're at max depth, or the triangle doesn't fit in one of our
     // children and so we want to just record it here
-    _triangleSet.insert(t);
+    _triangleSet.insert(triangleIndex);
 }
 
 bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index c8703c6445..d98ba86cb5 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -14,14 +14,15 @@
 #include "AABox.h"
 #include "GeometryUtil.h"
 
+
+
 class InternalTriangleSet {
 public:
-    InternalTriangleSet() { }
+    InternalTriangleSet(std::vector<Triangle>& allTriangles) :
+        _allTriangles(allTriangles)
+    { }
 
-    void reserve(size_t size) { _triangles.reserve(size); } // reserve space in the datastructure for size number of triangles
-    size_t size() const { return _triangles.size(); } 
-
-    virtual void insert(const Triangle& t);
+    virtual void insert(int triangleIndex);
     void clear();
 
     // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
@@ -30,14 +31,11 @@ public:
     bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, 
         float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
 
-    // Determine if a point is "inside" all the triangles of a convex hull. It is the responsibility of the caller to
-    // determine that the triangle set is indeed a convex hull. If the triangles added to this set are not in fact a 
-    // convex hull, the result of this method is meaningless and undetermined.
-    bool convexHullContains(const glm::vec3& point) const;
     const AABox& getBounds() const { return _bounds; }
 
 protected:
-    std::vector<Triangle> _triangles;
+    std::vector<Triangle>& _allTriangles;
+    std::vector<int> _triangleIndices;
     AABox _bounds;
 
     friend class TriangleOctreeCell;
@@ -45,11 +43,16 @@ protected:
 
 class TriangleOctreeCell {
 public:
-    TriangleOctreeCell() { }
+    TriangleOctreeCell(std::vector<Triangle>& allTriangles) :
+        _allTriangles(allTriangles),
+        _triangleSet(allTriangles)
+    { }
 
-    void insert(const Triangle& t);
+
+    void insert(int triangleIndex);
     void reset(const AABox& bounds, int depth = 0);
     void clear();
+    void prune();
 
     // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
     // intersection occurs, the distance and surface normal will be provided.
@@ -61,8 +64,9 @@ public:
     void debugDump();
 
 protected:
-    TriangleOctreeCell(const AABox& bounds, int depth);
+    TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth);
 
+    std::vector<Triangle>& _allTriangles;
     InternalTriangleSet _triangleSet;
     std::vector<TriangleOctreeCell> _children;
     int _depth { 0 };
@@ -71,25 +75,42 @@ protected:
     friend class TriangleSet;
 };
 
-class TriangleSet : public InternalTriangleSet {
+class TriangleSet {
     // pass through public implementation all the features of InternalTriangleSet
 public:
-    TriangleSet() { }
+    TriangleSet() :
+        _triangleOctree(_triangles)
+    {}
 
     void debugDump();
 
-    virtual void insert(const Triangle& t) {
-        _isBalanced = false;
-        InternalTriangleSet::insert(t);
-    }
+    void insert(const Triangle& t);
 
     bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
         float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision);
 
     void balanceOctree();
 
+    void reserve(size_t size) { _triangles.reserve(size); } // reserve space in the datastructure for size number of triangles
+    size_t size() const { return _triangles.size(); }
+    void clear();
+
+    // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
+    // intersection occurs, the distance and surface normal will be provided.
+    // note: this might side-effect internal structures
+    bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
+
+    // Determine if a point is "inside" all the triangles of a convex hull. It is the responsibility of the caller to
+    // determine that the triangle set is indeed a convex hull. If the triangles added to this set are not in fact a 
+    // convex hull, the result of this method is meaningless and undetermined.
+    bool convexHullContains(const glm::vec3& point) const;
+    const AABox& getBounds() const { return _bounds; }
+
 protected:
 
-    bool _isBalanced { false };
+    bool _isBalanced{ false };
     TriangleOctreeCell _triangleOctree;
+    std::vector<Triangle> _triangles;
+    AABox _bounds;
 };

From 89b6a79f6888e9e797c6dd2a9daa0f0a4f53c875 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 17:56:45 -0700
Subject: [PATCH 04/11] make sure to exit early if box intersection is already
 larger than best triangle intersection

---
 libraries/shared/src/TriangleSet.cpp | 63 ++++++++++++++++++++--------
 libraries/shared/src/TriangleSet.h   |  3 +-
 2 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index ef8f3ab91e..f9dea7bcc6 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -33,13 +33,16 @@ void TriangleSet::clear() {
 bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
     float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) {
 
+    // reset our distance to be the max possible, lower level tests will store best distance here
+    distance = std::numeric_limits<float>::max();
+
     if (!_isBalanced) {
         balanceOctree();
     }
 
     int trianglesTouched = 0;
     auto result = _triangleOctree.findRayIntersection(origin, direction, distance, face, surfaceNormal, precision, trianglesTouched);
-    qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+    //qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
     return result;
 }
 
@@ -77,10 +80,9 @@ void TriangleSet::balanceOctree() {
         _triangleOctree.insert(i);
     }
 
-    // prune the empty cells
-    _triangleOctree.prune();
-
     _isBalanced = true;
+
+    //debugDump();
 }
 
 
@@ -106,10 +108,17 @@ bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm
             float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     bool intersectedSomething = false;
-    float boxDistance = std::numeric_limits<float>::max();
-    float bestDistance = std::numeric_limits<float>::max();
+    float boxDistance = distance; //  std::numeric_limits<float>::max();
+    float bestDistance = distance; //  std::numeric_limits<float>::max();
 
     if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
+
+        // if our bounding box intersects at a distance greater than the current known
+        // best distance, than we can safely not check any of our triangles
+        if (boxDistance > bestDistance) {
+            return false;
+        }
+
         if (precision) {
             for (const auto& triangleIndex : _triangleIndices) {
                 const auto& triangle = _allTriangles[triangleIndex];
@@ -148,10 +157,6 @@ void TriangleOctreeCell::clear() {
     _population = 0;
 }
 
-void TriangleOctreeCell::prune() {
-    // do nothing yet...
-}
-
 void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     clear();
     _triangleSet._bounds = bounds;
@@ -159,10 +164,6 @@ void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     if (depth <= MAX_DEPTH) {
         int childDepth = depth + 1;
         _children.clear();
-        for (int child = 0; child < MAX_CHILDREN; child++) {
-            AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
-            _children.push_back(TriangleOctreeCell(_allTriangles, childBounds, childDepth));
-        }
     }
 }
 
@@ -170,8 +171,9 @@ void TriangleOctreeCell::debugDump() {
     qDebug() << __FUNCTION__;
     qDebug() << "bounds:" << getBounds();
     qDebug() << "depth:" << _depth;
-    //qDebug() << "triangleSet:" << _triangleSet.size() << "at this level";
     qDebug() << "population:" << _population << "this level or below";
+    qDebug() << "triangleSet:" << _triangleSet.size() << "in this cell";
+    qDebug() << "child cells:" << _children.size();
     if (_depth < MAX_DEPTH) {
         int childNum = 0;
         for (auto& child : _children) {
@@ -187,12 +189,30 @@ void TriangleOctreeCell::insert(int triangleIndex) {
     _population++;
     // if we're not yet at the max depth, then check which child the triangle fits in
     if (_depth < MAX_DEPTH) {
+
+        // check existing children to see if this triangle fits them...
         for (auto& child : _children) {
             if (child.getBounds().contains(triangle)) {
                 child.insert(triangleIndex);
                 return;
             }
         }
+
+        // if it doesn't exist in an existing child, then check for new possible children
+        // note: this will actually re-check the bounds of all the existing children as well, hmmm
+        for (int child = 0; child < MAX_CHILDREN; child++) {
+            AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
+            if (childBounds.contains(triangle)) {
+
+                // create a child node
+                auto child = TriangleOctreeCell(_allTriangles, childBounds, _depth + 1);
+                _children.push_back(child);
+
+                // insert this triangle into it
+                child.insert(triangleIndex);
+                return;
+            }
+        }
     }
     // either we're at max depth, or the triangle doesn't fit in one of our
     // children and so we want to just record it here
@@ -206,16 +226,23 @@ bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm:
         return false; // no triangles below here, so we can't intersect
     }
 
-    float bestLocalDistance = std::numeric_limits<float>::max();
+    float bestLocalDistance = distance; // std::numeric_limits<float>::max();
     BoxFace bestLocalFace;
     glm::vec3 bestLocalNormal;
     bool intersects = false;
 
     // if the ray intersects our bounding box, then continue
     if (getBounds().findRayIntersection(origin, direction, bestLocalDistance, bestLocalFace, bestLocalNormal)) {
-        bestLocalDistance = std::numeric_limits<float>::max();
 
-        float childDistance = std::numeric_limits<float>::max();
+        // if the intersection with our bounding box, is greater than the current best distance (the distance passed in)
+        // then we know that none of our triangles can represent a better intersection and we can return
+        if (bestLocalDistance > distance) {
+            return false;
+        }
+
+        bestLocalDistance = distance; // std::numeric_limits<float>::max();
+
+        float childDistance = distance; // std::numeric_limits<float>::max();
         BoxFace childFace;
         glm::vec3 childNormal;
 
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index d98ba86cb5..c5e4c719cf 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -33,6 +33,8 @@ public:
 
     const AABox& getBounds() const { return _bounds; }
 
+    size_t size() const { return _triangleIndices.size(); }
+
 protected:
     std::vector<Triangle>& _allTriangles;
     std::vector<int> _triangleIndices;
@@ -52,7 +54,6 @@ public:
     void insert(int triangleIndex);
     void reset(const AABox& bounds, int depth = 0);
     void clear();
-    void prune();
 
     // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
     // intersection occurs, the distance and surface normal will be provided.

From f1bd06cfa09f5065d4ea2d820242a9f068c67ce7 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 18:33:28 -0700
Subject: [PATCH 05/11] cleanup some unneeded class

---
 libraries/shared/src/TriangleSet.cpp | 42 +++++++++++-----------------
 libraries/shared/src/TriangleSet.h   | 40 ++++++--------------------
 2 files changed, 24 insertions(+), 58 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index f9dea7bcc6..99b2e2fc79 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -42,7 +42,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
 
     int trianglesTouched = 0;
     auto result = _triangleOctree.findRayIntersection(origin, direction, distance, face, surfaceNormal, precision, trianglesTouched);
-    //qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+    qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
     return result;
 }
 
@@ -82,29 +82,13 @@ void TriangleSet::balanceOctree() {
 
     _isBalanced = true;
 
-    //debugDump();
+    debugDump();
 }
 
 
-
-void InternalTriangleSet::insert(int triangleIndex) {
-    auto& triangle = _allTriangles[triangleIndex];
-
-    _triangleIndices.push_back(triangleIndex);
-
-    _bounds += triangle.v0;
-    _bounds += triangle.v1;
-    _bounds += triangle.v2;
-}
-
-void InternalTriangleSet::clear() {
-    _triangleIndices.clear();
-    _bounds.clear();
-}
-
 // Determine of the given ray (origin/direction) in model space intersects with any triangles
 // in the set. If an intersection occurs, the distance and surface normal will be provided.
-bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+bool TriangleOctreeCell::findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
             float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     bool intersectedSomething = false;
@@ -146,20 +130,20 @@ static const int MAX_DEPTH = 3; // for now
 static const int MAX_CHILDREN = 8;
 
 TriangleOctreeCell::TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth) :
-    _allTriangles(allTriangles),
-    _triangleSet(allTriangles)
+    _allTriangles(allTriangles)
 {
     reset(bounds, depth);
 }
 
 void TriangleOctreeCell::clear() {
-    _triangleSet.clear();
     _population = 0;
+    _triangleIndices.clear();
+    _bounds.clear();
 }
 
 void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     clear();
-    _triangleSet._bounds = bounds;
+    _bounds = bounds;
     _depth = depth;
     if (depth <= MAX_DEPTH) {
         int childDepth = depth + 1;
@@ -172,7 +156,7 @@ void TriangleOctreeCell::debugDump() {
     qDebug() << "bounds:" << getBounds();
     qDebug() << "depth:" << _depth;
     qDebug() << "population:" << _population << "this level or below";
-    qDebug() << "triangleSet:" << _triangleSet.size() << "in this cell";
+    qDebug() << "triangleIndices:" << _triangleIndices.size() << "in this cell";
     qDebug() << "child cells:" << _children.size();
     if (_depth < MAX_DEPTH) {
         int childNum = 0;
@@ -216,7 +200,13 @@ void TriangleOctreeCell::insert(int triangleIndex) {
     }
     // either we're at max depth, or the triangle doesn't fit in one of our
     // children and so we want to just record it here
-    _triangleSet.insert(triangleIndex);
+    _triangleIndices.push_back(triangleIndex);
+
+    /*
+    _bounds += triangle.v0;
+    _bounds += triangle.v1;
+    _bounds += triangle.v2;
+    */
 }
 
 bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -263,7 +253,7 @@ bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm:
             }
         }
         // also check our local triangle set
-        if (_triangleSet.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
+        if (findRayIntersectionInternal(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
             if (childDistance < bestLocalDistance) {
                 bestLocalDistance = childDistance;
                 bestLocalFace = childFace;
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index c5e4c719cf..65033976cf 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -16,38 +16,10 @@
 
 
 
-class InternalTriangleSet {
-public:
-    InternalTriangleSet(std::vector<Triangle>& allTriangles) :
-        _allTriangles(allTriangles)
-    { }
-
-    virtual void insert(int triangleIndex);
-    void clear();
-
-    // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
-    // intersection occurs, the distance and surface normal will be provided.
-    // note: this might side-effect internal structures
-    bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, 
-        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
-
-    const AABox& getBounds() const { return _bounds; }
-
-    size_t size() const { return _triangleIndices.size(); }
-
-protected:
-    std::vector<Triangle>& _allTriangles;
-    std::vector<int> _triangleIndices;
-    AABox _bounds;
-
-    friend class TriangleOctreeCell;
-};
-
 class TriangleOctreeCell {
 public:
     TriangleOctreeCell(std::vector<Triangle>& allTriangles) :
-        _allTriangles(allTriangles),
-        _triangleSet(allTriangles)
+        _allTriangles(allTriangles)
     { }
 
 
@@ -60,24 +32,28 @@ public:
     bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
         float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
 
-    const AABox& getBounds() const { return _triangleSet.getBounds(); }
+    const AABox& getBounds() const { return _bounds; }
 
     void debugDump();
 
 protected:
     TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth);
 
+    // checks our internal list of triangles
+    bool findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
+        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
+
     std::vector<Triangle>& _allTriangles;
-    InternalTriangleSet _triangleSet;
     std::vector<TriangleOctreeCell> _children;
     int _depth { 0 };
     int _population { 0 };
+    AABox _bounds;
+    std::vector<int> _triangleIndices;
 
     friend class TriangleSet;
 };
 
 class TriangleSet {
-    // pass through public implementation all the features of InternalTriangleSet
 public:
     TriangleSet() :
         _triangleOctree(_triangles)

From 4af3c760e6c304fbabce613ab2a4a80a6f2eaf09 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 18:57:33 -0700
Subject: [PATCH 06/11] more cleanup

---
 libraries/shared/src/TriangleSet.cpp | 34 +++++++------
 libraries/shared/src/TriangleSet.h   | 74 +++++++++++++---------------
 2 files changed, 53 insertions(+), 55 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index 99b2e2fc79..2b6e12f005 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -27,7 +27,7 @@ void TriangleSet::clear() {
     _bounds.clear();
     _isBalanced = false;
 
-    // delete the octree?
+    _triangleOctree.clear();
 }
 
 bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
@@ -42,7 +42,12 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
 
     int trianglesTouched = 0;
     auto result = _triangleOctree.findRayIntersection(origin, direction, distance, face, surfaceNormal, precision, trianglesTouched);
-    qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+
+    #if WANT_DEBUGGING
+    if (precision) {
+        qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+    }
+    #endif
     return result;
 }
 
@@ -82,13 +87,15 @@ void TriangleSet::balanceOctree() {
 
     _isBalanced = true;
 
+    #if WANT_DEBUGGING
     debugDump();
+    #endif
 }
 
 
 // Determine of the given ray (origin/direction) in model space intersects with any triangles
 // in the set. If an intersection occurs, the distance and surface normal will be provided.
-bool TriangleOctreeCell::findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
+bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
             float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     bool intersectedSomething = false;
@@ -126,22 +133,23 @@ bool TriangleOctreeCell::findRayIntersectionInternal(const glm::vec3& origin, co
     return intersectedSomething;
 }
 
-static const int MAX_DEPTH = 3; // for now
+static const int MAX_DEPTH = 4; // for now
 static const int MAX_CHILDREN = 8;
 
-TriangleOctreeCell::TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth) :
+TriangleSet::TriangleOctreeCell::TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth) :
     _allTriangles(allTriangles)
 {
     reset(bounds, depth);
 }
 
-void TriangleOctreeCell::clear() {
+void TriangleSet::TriangleOctreeCell::clear() {
     _population = 0;
     _triangleIndices.clear();
     _bounds.clear();
+    _children.clear();
 }
 
-void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
+void TriangleSet::TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     clear();
     _bounds = bounds;
     _depth = depth;
@@ -151,7 +159,7 @@ void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     }
 }
 
-void TriangleOctreeCell::debugDump() {
+void TriangleSet::TriangleOctreeCell::debugDump() {
     qDebug() << __FUNCTION__;
     qDebug() << "bounds:" << getBounds();
     qDebug() << "depth:" << _depth;
@@ -168,7 +176,7 @@ void TriangleOctreeCell::debugDump() {
     }
 }
 
-void TriangleOctreeCell::insert(int triangleIndex) {
+void TriangleSet::TriangleOctreeCell::insert(int triangleIndex) {
     const Triangle& triangle = _allTriangles[triangleIndex];
     _population++;
     // if we're not yet at the max depth, then check which child the triangle fits in
@@ -201,15 +209,9 @@ void TriangleOctreeCell::insert(int triangleIndex) {
     // either we're at max depth, or the triangle doesn't fit in one of our
     // children and so we want to just record it here
     _triangleIndices.push_back(triangleIndex);
-
-    /*
-    _bounds += triangle.v0;
-    _bounds += triangle.v1;
-    _bounds += triangle.v2;
-    */
 }
 
-bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
                 float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     if (_population < 1) {
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index 65033976cf..bedb038c58 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -14,46 +14,42 @@
 #include "AABox.h"
 #include "GeometryUtil.h"
 
-
-
-class TriangleOctreeCell {
-public:
-    TriangleOctreeCell(std::vector<Triangle>& allTriangles) :
-        _allTriangles(allTriangles)
-    { }
-
-
-    void insert(int triangleIndex);
-    void reset(const AABox& bounds, int depth = 0);
-    void clear();
-
-    // Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an 
-    // intersection occurs, the distance and surface normal will be provided.
-    bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
-        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
-
-    const AABox& getBounds() const { return _bounds; }
-
-    void debugDump();
-
-protected:
-    TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth);
-
-    // checks our internal list of triangles
-    bool findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
-        float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
-
-    std::vector<Triangle>& _allTriangles;
-    std::vector<TriangleOctreeCell> _children;
-    int _depth { 0 };
-    int _population { 0 };
-    AABox _bounds;
-    std::vector<int> _triangleIndices;
-
-    friend class TriangleSet;
-};
-
 class TriangleSet {
+
+    class TriangleOctreeCell {
+    public:
+        TriangleOctreeCell(std::vector<Triangle>& allTriangles) :
+            _allTriangles(allTriangles)
+        { }
+
+        void insert(int triangleIndex);
+        void reset(const AABox& bounds, int depth = 0);
+        void clear();
+
+        bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
+            float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
+
+        const AABox& getBounds() const { return _bounds; }
+
+        void debugDump();
+
+    protected:
+        TriangleOctreeCell(std::vector<Triangle>& allTriangles, const AABox& bounds, int depth);
+
+        // checks our internal list of triangles
+        bool findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
+            float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
+
+        std::vector<Triangle>& _allTriangles;
+        std::vector<TriangleOctreeCell> _children;
+        int _depth{ 0 };
+        int _population{ 0 };
+        AABox _bounds;
+        std::vector<int> _triangleIndices;
+
+        friend class TriangleSet;
+    };
+
 public:
     TriangleSet() :
         _triangleOctree(_triangles)

From dcb70aa50467dbdf6264cb00f3f79dd7e8da0882 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Fri, 12 May 2017 19:03:08 -0700
Subject: [PATCH 07/11] more cleanup

---
 libraries/shared/src/TriangleSet.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index 2b6e12f005..cd3f829d93 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -99,8 +99,8 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
             float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
 
     bool intersectedSomething = false;
-    float boxDistance = distance; //  std::numeric_limits<float>::max();
-    float bestDistance = distance; //  std::numeric_limits<float>::max();
+    float boxDistance = distance;
+    float bestDistance = distance;
 
     if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
 
@@ -218,7 +218,7 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origi
         return false; // no triangles below here, so we can't intersect
     }
 
-    float bestLocalDistance = distance; // std::numeric_limits<float>::max();
+    float bestLocalDistance = distance;
     BoxFace bestLocalFace;
     glm::vec3 bestLocalNormal;
     bool intersects = false;
@@ -232,9 +232,9 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origi
             return false;
         }
 
-        bestLocalDistance = distance; // std::numeric_limits<float>::max();
+        bestLocalDistance = distance;
 
-        float childDistance = distance; // std::numeric_limits<float>::max();
+        float childDistance = distance;
         BoxFace childFace;
         glm::vec3 childNormal;
 

From da404ce2ce573358344e5efb253e8edcda1659ce Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Sat, 13 May 2017 09:29:32 -0700
Subject: [PATCH 08/11] fix warning

---
 libraries/shared/src/TriangleSet.cpp | 8 ++------
 libraries/shared/src/TriangleSet.h   | 2 +-
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index cd3f829d93..d880b43a20 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -81,7 +81,7 @@ void TriangleSet::balanceOctree() {
 
     // insert all the triangles
 
-    for (int i = 0; i < _triangles.size(); i++) {
+    for (size_t i = 0; i < _triangles.size(); i++) {
         _triangleOctree.insert(i);
     }
 
@@ -153,10 +153,6 @@ void TriangleSet::TriangleOctreeCell::reset(const AABox& bounds, int depth) {
     clear();
     _bounds = bounds;
     _depth = depth;
-    if (depth <= MAX_DEPTH) {
-        int childDepth = depth + 1;
-        _children.clear();
-    }
 }
 
 void TriangleSet::TriangleOctreeCell::debugDump() {
@@ -176,7 +172,7 @@ void TriangleSet::TriangleOctreeCell::debugDump() {
     }
 }
 
-void TriangleSet::TriangleOctreeCell::insert(int triangleIndex) {
+void TriangleSet::TriangleOctreeCell::insert(size_t triangleIndex) {
     const Triangle& triangle = _allTriangles[triangleIndex];
     _population++;
     // if we're not yet at the max depth, then check which child the triangle fits in
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index bedb038c58..18494d270e 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -22,7 +22,7 @@ class TriangleSet {
             _allTriangles(allTriangles)
         { }
 
-        void insert(int triangleIndex);
+        void insert(size_t triangleIndex);
         void reset(const AABox& bounds, int depth = 0);
         void clear();
 

From 5065c7c5c45712f058e5c7c3c762eab7f6bb9a1c Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Sat, 13 May 2017 10:17:59 -0700
Subject: [PATCH 09/11] more warning fixes

---
 libraries/shared/src/TriangleSet.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index 18494d270e..3b39b935af 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -45,7 +45,7 @@ class TriangleSet {
         int _depth{ 0 };
         int _population{ 0 };
         AABox _bounds;
-        std::vector<int> _triangleIndices;
+        std::vector<size_t> _triangleIndices;
 
         friend class TriangleSet;
     };

From 149750fe216b96f067287a1d908e4010e7362fe6 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Sun, 14 May 2017 08:36:54 -0700
Subject: [PATCH 10/11] make the octree sparse

---
 libraries/shared/src/TriangleSet.cpp | 40 +++++++++++++---------------
 libraries/shared/src/TriangleSet.h   |  2 +-
 2 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp
index d880b43a20..aa21aa5cc0 100644
--- a/libraries/shared/src/TriangleSet.cpp
+++ b/libraries/shared/src/TriangleSet.cpp
@@ -45,7 +45,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
 
     #if WANT_DEBUGGING
     if (precision) {
-        qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
+        qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population << "_triangles.size:" << _triangles.size();
     }
     #endif
     return result;
@@ -80,7 +80,6 @@ void TriangleSet::balanceOctree() {
     _triangleOctree.reset(_bounds, 0);
 
     // insert all the triangles
-
     for (size_t i = 0; i < _triangles.size(); i++) {
         _triangleOctree.insert(i);
     }
@@ -159,14 +158,15 @@ void TriangleSet::TriangleOctreeCell::debugDump() {
     qDebug() << __FUNCTION__;
     qDebug() << "bounds:" << getBounds();
     qDebug() << "depth:" << _depth;
-    qDebug() << "population:" << _population << "this level or below";
-    qDebug() << "triangleIndices:" << _triangleIndices.size() << "in this cell";
+    qDebug() << "population:" << _population << "this level or below" 
+             << " ---- triangleIndices:" << _triangleIndices.size() << "in this cell";
+
     qDebug() << "child cells:" << _children.size();
     if (_depth < MAX_DEPTH) {
         int childNum = 0;
         for (auto& child : _children) {
             qDebug() << "child:" << childNum;
-            child.debugDump();
+            child.second.debugDump();
             childNum++;
         }
     }
@@ -178,26 +178,21 @@ void TriangleSet::TriangleOctreeCell::insert(size_t triangleIndex) {
     // if we're not yet at the max depth, then check which child the triangle fits in
     if (_depth < MAX_DEPTH) {
 
-        // check existing children to see if this triangle fits them...
-        for (auto& child : _children) {
-            if (child.getBounds().contains(triangle)) {
-                child.insert(triangleIndex);
-                return;
-            }
-        }
-
-        // if it doesn't exist in an existing child, then check for new possible children
-        // note: this will actually re-check the bounds of all the existing children as well, hmmm
         for (int child = 0; child < MAX_CHILDREN; child++) {
             AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
+
+
+            // if the child AABox would contain the triangle...
             if (childBounds.contains(triangle)) {
+                // if the child cell doesn't yet exist, create it...
+                if (_children.find((AABox::OctreeChild)child) == _children.end()) {
+                    _children.insert(
+                        std::pair<AABox::OctreeChild, TriangleOctreeCell>
+                        ((AABox::OctreeChild)child, TriangleOctreeCell(_allTriangles, childBounds, _depth + 1)));
+                }
 
-                // create a child node
-                auto child = TriangleOctreeCell(_allTriangles, childBounds, _depth + 1);
-                _children.push_back(child);
-
-                // insert this triangle into it
-                child.insert(triangleIndex);
+                // insert the triangleIndex in the child cell
+                _children.at((AABox::OctreeChild)child).insert(triangleIndex);
                 return;
             }
         }
@@ -224,6 +219,7 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origi
 
         // if the intersection with our bounding box, is greater than the current best distance (the distance passed in)
         // then we know that none of our triangles can represent a better intersection and we can return
+
         if (bestLocalDistance > distance) {
             return false;
         }
@@ -240,7 +236,7 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origi
                 // check each child, if there's an intersection, it will return some distance that we need
                 // to compare against the other results, because there might be multiple intersections and
                 // we will always choose the best (shortest) intersection
-                if (child.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
+                if (child.second.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
                     if (childDistance < bestLocalDistance) {
                         bestLocalDistance = childDistance;
                         bestLocalFace = childFace;
diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h
index 3b39b935af..6cedc4da7e 100644
--- a/libraries/shared/src/TriangleSet.h
+++ b/libraries/shared/src/TriangleSet.h
@@ -41,7 +41,7 @@ class TriangleSet {
             float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
 
         std::vector<Triangle>& _allTriangles;
-        std::vector<TriangleOctreeCell> _children;
+        std::map<AABox::OctreeChild, TriangleOctreeCell> _children;
         int _depth{ 0 };
         int _population{ 0 };
         AABox _bounds;

From 9c81a89ac3e43b0adc671e3233593c233b2ddcb1 Mon Sep 17 00:00:00 2001
From: ZappoMan <brad@highfidelity.io>
Date: Sun, 14 May 2017 08:37:26 -0700
Subject: [PATCH 11/11] add test script

---
 .../tests/performance/rayPickPerformance.js   | 131 ++++++++++++++++++
 1 file changed, 131 insertions(+)
 create mode 100644 scripts/developer/tests/performance/rayPickPerformance.js

diff --git a/scripts/developer/tests/performance/rayPickPerformance.js b/scripts/developer/tests/performance/rayPickPerformance.js
new file mode 100644
index 0000000000..b4faf4c1be
--- /dev/null
+++ b/scripts/developer/tests/performance/rayPickPerformance.js
@@ -0,0 +1,131 @@
+//
+//  rayPickingPerformance.js
+//  examples
+//
+//  Created by Brad Hefta-Gaub on 5/13/2017
+//  Copyright 2017 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+
+
+var MIN_RANGE = -3;
+var MAX_RANGE = 3;
+var RANGE_DELTA = 0.5;
+var OUTER_LOOPS = 10;
+
+// NOTE: These expected results depend completely on the model, and the range settings above
+var EXPECTED_TESTS = 1385 * OUTER_LOOPS;
+var EXPECTED_INTERSECTIONS = 1286 * OUTER_LOOPS;
+
+
+var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
+var model_url = "http://hifi-content.s3.amazonaws.com/caitlyn/production/Scansite/buddhaReduced.fbx";
+
+var rayPickOverlays = Array();
+
+var modelEntity = Entities.addEntity({
+    type: "Model",
+    modelURL: model_url,
+    dimensions: {
+        x: 0.671,
+        y: 1.21,
+        z: 0.938
+    },
+    position: center
+});
+
+function rayCastTest() {
+    var tests = 0;
+    var intersections = 0;
+
+    var testStart = Date.now();
+    for (var t = 0; t < OUTER_LOOPS; t++) {
+        print("beginning loop:" + t);
+        for (var x = MIN_RANGE; x < MAX_RANGE; x += RANGE_DELTA) {
+            for (var y = MIN_RANGE; y < MAX_RANGE; y += RANGE_DELTA) {
+                for (var z = MIN_RANGE; z < MAX_RANGE; z += RANGE_DELTA) {
+                    if ((x <= -2 || x >= 2) || 
+                        (y <= -2 || y >= 2) || 
+                        (z <= -2 || z >= 2)) {
+
+                        tests++;
+
+                        var origin = { x: center.x + x,
+                                       y: center.y + y,
+                                       z: center.z + z };
+                        var direction = Vec3.subtract(center, origin);
+
+                        var pickRay = { 
+                            origin: origin,
+                            direction: direction
+                        };
+
+                        var pickResults = Entities.findRayIntersection(pickRay, true);
+
+                        var color;
+                        var visible;
+
+                        if (pickResults.intersects && pickResults.entityID == modelEntity) {
+                            intersections++;
+                            color = {
+                                red: 0,
+                                green: 255,
+                                blue: 0
+                            };
+                            visible = false;
+
+                        } else {
+                            /*
+                            print("NO INTERSECTION?");
+                            Vec3.print("origin:", origin);
+                            Vec3.print("direction:", direction);
+                            */
+
+                            color = {
+                                red: 255,
+                                green: 0,
+                                blue: 0
+                            };
+                            visible = true;
+                        }
+
+                        var overlayID = Overlays.addOverlay("line3d", {
+                            color: color,
+                            alpha: 1,
+                            visible: visible,
+                            lineWidth: 2,
+                            start: origin,
+                            end: Vec3.sum(origin,Vec3.multiply(5,direction))
+                        });
+
+                        rayPickOverlays.push(overlayID);
+
+                    }
+                }
+            }
+        }
+        print("ending loop:" + t);
+    }
+    var testEnd = Date.now();
+    var testElapsed = testEnd - testStart;
+
+
+    print("EXPECTED tests:" + EXPECTED_TESTS + " intersections:" + EXPECTED_INTERSECTIONS);
+    print("ACTUAL   tests:" + tests + " intersections:" + intersections);
+    print("ELAPSED TIME:" + testElapsed + " ms");
+
+}
+
+function cleanup() {
+    Entities.deleteEntity(modelEntity);
+    rayPickOverlays.forEach(function(item){
+        Overlays.deleteOverlay(item);
+    });
+}
+
+Script.scriptEnding.connect(cleanup);
+
+rayCastTest(); // run ray cast test immediately
\ No newline at end of file