Revision: 68934
          http://sourceforge.net/p/brlcad/code/68934
Author:   brlcad
Date:     2016-09-30 03:29:52 +0000 (Fri, 30 Sep 2016)
Log Message:
-----------
merge the prep-cache branch into trunk, so it can be closed without any 
apparent prejudice.  some tidying up needed and different cache storage layout 
so it is multiuser safe, but this is looking like solid forward progress.  all 
testing is looking great too -- consistently seeing results like: 8min prep + 
140sec render reduced to 40sec prep + 120sec render.  well done jon!

Modified Paths:
--------------
    brlcad/trunk/include/brep/bbnode.h
    brlcad/trunk/include/brep/brnode.h
    brlcad/trunk/include/brep/curvetree.h
    brlcad/trunk/include/brep/util.h
    brlcad/trunk/include/rt/func.h
    brlcad/trunk/include/rt/functab.h
    brlcad/trunk/src/libbrep/BBNode.cpp
    brlcad/trunk/src/libbrep/BRNode.cpp
    brlcad/trunk/src/libbrep/opennurbs_ext.cpp
    brlcad/trunk/src/librt/CMakeLists.txt
    brlcad/trunk/src/librt/primitives/brep/brep.cpp
    brlcad/trunk/src/librt/primitives/brep/brep_debug.cpp
    brlcad/trunk/src/librt/primitives/obj_prep.c
    brlcad/trunk/src/librt/primitives/table.c
    brlcad/trunk/src/librt/tree.c

Added Paths:
-----------
    brlcad/trunk/src/librt/cache.c
    brlcad/trunk/src/librt/cache.h

Property Changed:
----------------
    brlcad/trunk/
    brlcad/trunk/NEWS
    brlcad/trunk/src/libged/polyclip.cpp

Index: brlcad/trunk
===================================================================
--- brlcad/trunk        2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk        2016-09-30 03:29:52 UTC (rev 68934)

Property changes on: brlcad/trunk
___________________________________________________________________
Modified: svn:mergeinfo
## -5,3 +5,4 ##
 /brlcad/branches/gct:62423-62425
 /brlcad/branches/opencl:65867-66137
 /brlcad/branches/osg:62110-62113
+/brlcad/branches/prep-cache:68236-68933
\ No newline at end of property
Index: brlcad/trunk/NEWS
===================================================================
--- brlcad/trunk/NEWS   2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/NEWS   2016-09-30 03:29:52 UTC (rev 68934)

Property changes on: brlcad/trunk/NEWS
___________________________________________________________________
Modified: svn:mergeinfo
## -5,3 +5,4 ##
 /brlcad/branches/gct/NEWS:62423-62425
 /brlcad/branches/opencl/NEWS:65867-66137
 /brlcad/branches/osg/NEWS:62110-62113
+/brlcad/branches/prep-cache/NEWS:68236-68933
\ No newline at end of property
Modified: brlcad/trunk/include/brep/bbnode.h
===================================================================
--- brlcad/trunk/include/brep/bbnode.h  2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/include/brep/bbnode.h  2016-09-30 03:29:52 UTC (rev 68934)
@@ -28,12 +28,9 @@
 #define BREP_BBNODE_H
 
 #include "common.h"
-#include "brep/defines.h"
-#include "brep/ray.h"
-#include "brep/brnode.h"
-#include "brep/curvetree.h"
-#include "brep/util.h"
 
+#include "brep.h"
+
 /** @{ */
 /** @file brep/bbnode.h */
 
@@ -65,18 +62,22 @@
        /**
         * Bounding Box Hierarchy Node
         */
-       class BREP_EXPORT BBNode {
+       class BREP_EXPORT BBNode : public PooledObject<BBNode> {
            public:
                explicit BBNode(const ON_BoundingBox &node, const CurveTree *ct 
= NULL);
                BBNode(const CurveTree *ct,
                        const ON_BoundingBox &node,
-                       const ON_BrepFace *face,
                        const ON_Interval &u,
                        const ON_Interval &v,
                        bool checkTrim,
                        bool trimmed);
                ~BBNode();
 
+               BBNode(Deserializer &deserieralizer, const CurveTree &ctree);
+               void serialize(Serializer &serializer) const;
+
+               const ON_BrepFace &get_face() const;
+
                /** Test if this node is a leaf node in the hierarchy */
                bool isLeaf() const;
 
@@ -122,14 +123,12 @@
                void BuildBBox();
                bool prepTrims();
 
-               /** List of all children of a given node */
-               std::vector<BBNode *> * const m_children;
+               const std::vector<BBNode *> &get_children() const;
 
                /** Bounding Box */
                ON_BoundingBox m_node;
 
                /** Surface Information */
-               const ON_BrepFace *m_face;
                ON_Interval m_u;
                ON_Interval m_v;
 
@@ -145,12 +144,15 @@
                /* Normal at the m_estimate point */
                ON_3dVector m_normal;
 
+               /** Curve Tree associated with the parent Surface Tree */
+               const CurveTree * const m_ctree;
+
+
            private:
                BBNode(const BBNode &source);
                BBNode &operator=(const BBNode &source);
 
                void removeChild(BBNode *child);
-
                bool intersectedBy(const ON_Ray &ray, double *tnear = NULL, 
double *tfar = NULL) const;
 
                /** Report if a given uv point is within the uv boundaries 
defined
@@ -158,76 +160,22 @@
                 */
                bool containsUV(const ON_2dPoint &uv) const;
 
-               bool doTrimming() const;
                void getTrimsAbove(const ON_2dPoint &uv, std::list<const BRNode 
*> &out_leaves) const;
-
                const BBNode *closer(const ON_3dPoint &pt, const BBNode *left, 
const BBNode *right) const;
 
-               /** Curve Tree associated with the parent Surface Tree */
-               const CurveTree * const m_ctree;
+               struct Stl : public PooledObject<Stl> {
+                   Stl() : m_children(), m_trims_above() {}
 
-               std::list<const BRNode *> * const m_trims_above;
+                   std::vector<BBNode *> m_children;
+                   std::list<const BRNode *> m_trims_above;
+               } * const m_stl;
        };
 
-       inline
-           BBNode::BBNode(const ON_BoundingBox &node, const CurveTree *ct) :
-               m_children(new std::vector<BBNode *>),
-               m_node(node),
-               m_face(NULL),
-               m_u(),
-               m_v(),
-               m_checkTrim(true),
-               m_trimmed(false),
-               m_estimate(),
-               m_normal(),
-               m_ctree(ct),
-               m_trims_above(new std::list<const BRNode *>)
-       {
-           for (int i = 0; i < 3; i++) {
-               double d = m_node.m_max[i] - m_node.m_min[i];
-               if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
-                   m_node.m_min[i] -= 0.001;
-                   m_node.m_max[i] += 0.001;
-               }
-           }
-       }
-
-       inline
-           _BU_ATTR_ALWAYS_INLINE
-           BBNode::BBNode(
-                   const CurveTree *ct,
-                   const ON_BoundingBox &node,
-                   const ON_BrepFace *face,
-                   const ON_Interval &u,
-                   const ON_Interval &v,
-                   bool checkTrim,
-                   bool trimmed):
-               m_children(new std::vector<BBNode *>),
-               m_node(node),
-               m_face(face),
-               m_u(u),
-               m_v(v),
-               m_checkTrim(checkTrim),
-               m_trimmed(trimmed),
-               m_estimate(),
-               m_normal(),
-               m_ctree(ct),
-               m_trims_above(new std::list<const BRNode *>)
-       {
-           for (int i = 0; i < 3; i++) {
-               double d = m_node.m_max[i] - m_node.m_min[i];
-               if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
-                   m_node.m_min[i] -= 0.001;
-                   m_node.m_max[i] += 0.001;
-               }
-           }
-       }
-
        inline void
            BBNode::addChild(BBNode *child)
            {
                if (LIKELY(child != NULL)) {
-                   m_children->push_back(child);
+                   m_stl->m_children.push_back(child);
                }
            }
 
@@ -235,23 +183,33 @@
            BBNode::removeChild(BBNode *child)
            {
                std::vector<BBNode *>::iterator i;
-               for (i = m_children->begin(); i != m_children->end();) {
+               for (i = m_stl->m_children.begin(); i != 
m_stl->m_children.end();) {
                    if (*i == child) {
                        delete *i;
-                       i = m_children->erase(i);
+                       i = m_stl->m_children.erase(i);
                    } else {
                        ++i;
                    }
                }
            }
 
+
+       inline const ON_BrepFace &
+           BBNode::get_face() const
+           {
+               return *m_ctree->m_face;
+           }
+
+       inline const std::vector<BBNode *> &
+           BBNode::get_children() const
+       {
+           return m_stl->m_children;
+       }
+
        inline bool
            BBNode::isLeaf() const
            {
-               if (m_children->empty()) {
-                   return true;
-               }
-               return false;
+               return m_stl->m_children.empty();
            }
 
        inline void
@@ -276,55 +234,7 @@
                max[2] = m_node.m_max[2];
            }
 
-       inline bool
-           BBNode::intersectedBy(const ON_Ray &ray, double *tnear_opt /* = 
NULL */, double *tfar_opt /* = NULL */) const
-           {
-               double tnear = -DBL_MAX;
-               double tfar = DBL_MAX;
-               bool untrimmedresult = true;
-               for (int i = 0; i < 3; i++) {
-                   if (UNLIKELY(ON_NearZero(ray.m_dir[i]))) {
-                       if (ray.m_origin[i] < m_node.m_min[i] || 
ray.m_origin[i] > m_node.m_max[i]) {
-                           untrimmedresult = false;
-                       }
-                   } else {
-                       double t1 = (m_node.m_min[i] - ray.m_origin[i]) / 
ray.m_dir[i];
-                       double t2 = (m_node.m_max[i] - ray.m_origin[i]) / 
ray.m_dir[i];
-                       if (t1 > t2) {
-                           double tmp = t1;    /* swap */
-                           t1 = t2;
-                           t2 = tmp;
-                       }
 
-                       V_MAX(tnear, t1);
-                       V_MIN(tfar, t2);
-
-                       if (tnear > tfar) { /* box is missed */
-                           untrimmedresult = false;
-                       }
-                       /* go ahead and solve hits behind us
-                          if (tfar < 0) untrimmedresult = false;
-                          */
-                   }
-               }
-               if (LIKELY(tnear_opt != NULL && tfar_opt != NULL)) {
-                   *tnear_opt = tnear;
-                   *tfar_opt = tfar;
-               }
-               if (isLeaf()) {
-                   return !m_trimmed && untrimmedresult;
-               } else {
-                   return untrimmedresult;
-               }
-           }
-
-       inline bool
-           BBNode::doTrimming() const
-           {
-               return m_checkTrim;
-           }
-
-
     } /* namespace brlcad */
 } /* extern C++ */
 

Modified: brlcad/trunk/include/brep/brnode.h
===================================================================
--- brlcad/trunk/include/brep/brnode.h  2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/include/brep/brnode.h  2016-09-30 03:29:52 UTC (rev 68934)
@@ -36,7 +36,7 @@
 /* @endcond */
 }
 #endif
-#include "brep/defines.h"
+#include "brep.h"
 
 /** @{ */
 /** @file brep/brnode.h */
@@ -51,10 +51,11 @@
        /**
         * Bounding Rectangle Hierarchy
         */
-       class BREP_EXPORT BRNode {
+       class BREP_EXPORT BRNode : public PooledObject<BRNode> {
            public:
                explicit BRNode(const ON_BoundingBox &node);
                BRNode(const ON_Curve *curve,
+                       int trim_index,
                        int adj_face_index,
                        const ON_BoundingBox &node,
                        const ON_BrepFace *face,
@@ -64,6 +65,9 @@
                        bool trimmed);
                ~BRNode();
 
+               BRNode(Deserializer &deserializer, const ON_Brep &brep);
+               void serialize(Serializer &serializer) const;
+
                /** Node management functions */
                void addChild(BRNode *child);
 
@@ -107,7 +111,7 @@
                bool m_XIncreasing;
                bool m_Horizontal;
                bool m_Vertical;
-               const bool m_innerTrim;
+               bool m_innerTrim;
 
            private:
                BRNode(const BRNode &source);
@@ -118,152 +122,34 @@
                /** Test if this node is a leaf node (i.e. m_children is empty) 
*/
                bool isLeaf() const;
 
-               bool doTrimming() const;
-
                fastf_t getLinearEstimateOfV(fastf_t u) const;
-
                const BRNode *closer(const ON_3dPoint &pt, const BRNode *left, 
const BRNode *right) const;
 
-               /** List of all children of a given node */
-               std::vector<const BRNode *> * const m_children;
+               struct Stl : public PooledObject<Stl> {
+                   Stl() : m_children() {}
 
-               const ON_BrepFace * const m_face;
+                   std::vector<const BRNode *> m_children;
+               } * const m_stl;
+
+               const ON_BrepFace *m_face;
                ON_Interval m_u;
-
-               const ON_Curve * const m_trim;
+               const ON_Curve *m_trim;
+               int m_trim_index;
                ON_Interval m_t;
-
-               const bool m_checkTrim;
-               const bool m_trimmed;
-
-               const ON_3dPoint m_estimate;
-
+               bool m_checkTrim;
+               bool m_trimmed;
+               ON_3dPoint m_estimate;
                fastf_t m_slope;
                fastf_t m_bb_diag;
                ON_3dPoint m_start;
                ON_3dPoint m_end;
        };
 
-       inline
-           _BU_ATTR_ALWAYS_INLINE
-           BRNode::BRNode(
-                   const ON_Curve *curve,
-                   int adj_face_index,
-                   const ON_BoundingBox &node,
-                   const ON_BrepFace *face,
-                   const ON_Interval &t,
-                   bool innerTrim,
-                   bool checkTrim,
-                   bool trimmed) :
-               m_node(node),
-               m_v(),
-               m_adj_face_index(adj_face_index),
-               m_XIncreasing(false),
-               m_Horizontal(false),
-               m_Vertical(false),
-               m_innerTrim(innerTrim),
-               m_children(new std::vector<const BRNode *>),
-               m_face(face),
-               m_u(),
-               m_trim(curve),
-               m_t(t),
-               m_checkTrim(checkTrim),
-               m_trimmed(trimmed),
-               m_estimate(),
-               m_slope(0.0),
-               m_bb_diag(0.0),
-               m_start(curve->PointAt(m_t[0])),
-               m_end(curve->PointAt(m_t[1]))
-       {
-           /* check for vertical segments they can be removed from trims
-            * above (can't tell direction and don't need
-            */
-           m_Horizontal = false;
-           m_Vertical = false;
-
-           /*
-            * should be okay since we split on Horz/Vert tangents
-            */
-           if (m_end[X] < m_start[X]) {
-               m_u[0] = m_end[X];
-               m_u[1] = m_start[X];
-           } else {
-               m_u[0] = m_start[X];
-               m_u[1] = m_end[X];
-           }
-           if (m_end[Y] < m_start[Y]) {
-               m_v[0] = m_end[Y];
-               m_v[1] = m_start[Y];
-           } else {
-               m_v[0] = m_start[Y];
-               m_v[1] = m_end[Y];
-           }
-
-           if (NEAR_EQUAL(m_end[X], m_start[X], 0.000001)) {
-               m_Vertical = true;
-               if (m_innerTrim) {
-                   m_XIncreasing = false;
-               } else {
-                   m_XIncreasing = true;
-               }
-           } else if (NEAR_EQUAL(m_end[Y], m_start[Y], 0.000001)) {
-               m_Horizontal = true;
-               if ((m_end[X] - m_start[X]) > 0.0) {
-                   m_XIncreasing = true;
-               } else {
-                   m_XIncreasing = false;
-               }
-               m_slope = 0.0;
-           } else {
-               if ((m_end[X] - m_start[X]) > 0.0) {
-                   m_XIncreasing = true;
-               } else {
-                   m_XIncreasing = false;
-               }
-               m_slope = (m_end[Y] - m_start[Y]) / (m_end[X] - m_start[X]);
-           }
-           m_bb_diag = DIST_PT_PT(m_start, m_end);
-       }
-
-       inline
-           _BU_ATTR_ALWAYS_INLINE
-           BRNode::BRNode(const ON_BoundingBox &node) :
-               m_node(node),
-               m_v(),
-               m_adj_face_index(-99),
-               m_XIncreasing(false),
-               m_Horizontal(false),
-               m_Vertical(false),
-               m_innerTrim(false),
-               m_children(new std::vector<const BRNode *>),
-               m_face(NULL),
-               m_u(),
-               m_trim(NULL),
-               m_t(),
-               m_checkTrim(true),
-               m_trimmed(false),
-               m_estimate(),
-               m_slope(0.0),
-               m_bb_diag(0.0),
-               m_start(ON_3dPoint::UnsetPoint),
-               m_end(ON_3dPoint::UnsetPoint)
-       {
-               for (int i = 0; i < 3; i++) {
-                   double d = m_node.m_max[i] - m_node.m_min[i];
-                   if (NEAR_ZERO(d, ON_ZERO_TOLERANCE)) {
-                       m_node.m_min[i] -= 0.001;
-                       m_node.m_max[i] += 0.001;
-                   }
-               }
-               m_start = m_node.m_min;
-               m_end = m_node.m_max;
-           }
-
        inline void
            BRNode::addChild(BRNode *child)
            {
                if (LIKELY(child != NULL)) {
-                   m_children->push_back(child);
+                   m_stl->m_children.push_back(child);
                }
            }
 
@@ -271,10 +157,10 @@
            BRNode::removeChild(BRNode *child)
            {
                std::vector<const BRNode *>::iterator i;
-               for (i = m_children->begin(); i != m_children->end();) {
+               for (i = m_stl->m_children.begin(); i != 
m_stl->m_children.end();) {
                    if (*i == child) {
                        delete *i;
-                       i = m_children->erase(i);
+                       i = m_stl->m_children.erase(i);
                    } else {
                        ++i;
                    }
@@ -284,14 +170,13 @@
        inline bool
            BRNode::isLeaf() const
            {
-               if (m_children->empty()) {
+               if (m_stl->m_children.empty()) {
                    return true;
                }
                return false;
            }
 
        inline void
-           _BU_ATTR_ALWAYS_INLINE
            BRNode::GetBBox(fastf_t *min, fastf_t *max) const
            {
                VSETALL(min, INFINITY);
@@ -304,12 +189,6 @@
                }
            }
 
-       inline bool
-           BRNode::doTrimming() const
-           {
-               return m_checkTrim;
-           }
-
        extern bool sortX(const BRNode *first, const BRNode *second);
        extern bool sortY(const BRNode *first, const BRNode *second);
 

Modified: brlcad/trunk/include/brep/curvetree.h
===================================================================
--- brlcad/trunk/include/brep/curvetree.h       2016-09-29 16:23:24 UTC (rev 
68933)
+++ brlcad/trunk/include/brep/curvetree.h       2016-09-30 03:29:52 UTC (rev 
68934)
@@ -28,9 +28,9 @@
 #define BREP_CURVETREE_H
 
 #include "common.h"
-#include "brep/defines.h"
-#include "brep/brnode.h"
 
+#include "brep.h"
+
 /** @{ */
 /** @file brep/curvetree.h */
 
@@ -39,16 +39,24 @@
 __BEGIN_DECLS
 
 extern "C++" {
+#include <map>
+
     namespace brlcad {
 
        /**
         * CurveTree declaration
         */
-       class BREP_EXPORT CurveTree {
+       class BREP_EXPORT CurveTree : public PooledObject<CurveTree> {
            public:
                explicit CurveTree(const ON_BrepFace *face);
                ~CurveTree();
 
+               CurveTree(Deserializer &deserializer, const ON_BrepFace &face);
+               void serialize(Serializer &serializer) const;
+               std::vector<std::size_t> serialize_get_leaves_keys(const 
std::list<const BRNode *> &leaves) const;
+               std::list<const BRNode *> serialize_get_leaves(const 
std::size_t *keys, std::size_t num_keys) const;
+               void serialize_cleanup() const;
+
                /**
                 * Return just the leaves of the surface tree
                 */
@@ -58,6 +66,8 @@
                void getLeavesRight(std::list<const BRNode *> &out_leaves, 
const ON_2dPoint &pt, fastf_t tol) const;
 
            private:
+               friend class BBNode;
+
                CurveTree(const CurveTree &source);
                CurveTree &operator=(const CurveTree &source);
 
@@ -77,13 +87,21 @@
 
                bool getHVTangents(const ON_Curve *curve, const ON_Interval &t, 
std::list<fastf_t> &list) const;
                bool isLinear(const ON_Curve *curve, double min, double max) 
const;
-               BRNode *subdivideCurve(const ON_Curve *curve, int 
adj_face_index, double min, double max, bool innerTrim, int depth) const;
-               BRNode *curveBBox(const ON_Curve *curve, int adj_face_index, 
const ON_Interval &t, bool isLeaf, bool innerTrim, const ON_BoundingBox &bb) 
const;
-               BRNode *initialLoopBBox() const;
+               BRNode *subdivideCurve(const ON_Curve *curve, int trim_index, 
int adj_face_index, double min, double max, bool innerTrim, int depth) const;
+               BRNode *curveBBox(const ON_Curve *curve, int trim_index, int 
adj_face_index, const ON_Interval &t, bool isLeaf, bool innerTrim, const 
ON_BoundingBox &bb) const;
+               static ON_BoundingBox initialLoopBBox(const ON_BrepFace &face);
 
                const ON_BrepFace * const m_face;
-               BRNode * const m_root;
-               std::list<const BRNode *> * const m_sortedX;
+               BRNode *m_root;
+
+
+               struct Stl : public PooledObject<Stl> {
+                   Stl() : m_sortedX() {}
+
+                   std::vector<const BRNode *> m_sortedX;
+               } * const m_stl;
+
+               mutable std::map<const BRNode *, std::size_t> 
*m_sortedX_indices;
        };
 
 

Modified: brlcad/trunk/include/brep/util.h
===================================================================
--- brlcad/trunk/include/brep/util.h    2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/include/brep/util.h    2016-09-30 03:29:52 UTC (rev 68934)
@@ -28,16 +28,26 @@
 #define BREP_UTIL_H
 
 #include "common.h"
-#include "brep/defines.h"
 
 /** @{ */
 /** @file brep/util.h */
 
 #ifdef __cplusplus
 
+#include "brep.h"
+
+#include "bu/cv.h"
+#include "bu/endian.h"
+#include "bu/log.h"
+#include "bu/malloc.h"
+#include "bu/parse.h"
+
+#include <arpa/inet.h>
+
 __BEGIN_DECLS
 
 extern "C++" {
+#include <cstring>
 
     BREP_EXPORT bool ON_NearZero(double x, double tolerance = 
ON_ZERO_TOLERANCE);
 
@@ -93,6 +103,237 @@
 
     BREP_EXPORT void set_key(struct bu_vls *key, int k, int *karray);
 
+
+    class Serializer
+    {
+       public:
+           Serializer() :
+               m_capacity(1024 * 1024),
+               m_external()
+       {
+           BU_EXTERNAL_INIT(&m_external);
+
+           m_external.ext_buf = static_cast<uint8_t *>(bu_malloc(m_capacity, 
"m_external"));
+       }
+
+
+           ~Serializer()
+           {
+               bu_free_external(&m_external);
+           }
+
+
+           bu_external take()
+           {
+               const bu_external result = m_external;
+               m_capacity = 1024 * 1024;
+               BU_EXTERNAL_INIT(&m_external);
+               m_external.ext_buf = static_cast<uint8_t 
*>(bu_malloc(m_capacity, "m_external"));
+               return result;
+           }
+
+
+           void write_uint8(uint8_t value)
+           {
+               uint8_t * const dest = extend(sizeof(value));
+               *dest = value;
+           }
+
+
+           void write_uint32(uint32_t value)
+           {
+               uint8_t * const dest = extend(SIZEOF_NETWORK_LONG);
+               const uint32_t out_value = htonl(value);
+               std::memcpy(dest, &out_value, SIZEOF_NETWORK_LONG);
+           }
+
+
+           void write_int32(int32_t value)
+           {
+               uint8_t * const dest = extend(SIZEOF_NETWORK_LONG);
+               long out_value = value;
+
+               if (UNLIKELY(1 != bu_cv_htonsl(dest, SIZEOF_NETWORK_LONG, 
&out_value, 1)))
+                   bu_bomb("bu_cv_htonsl() failed");
+           }
+
+
+           void write_double(double value)
+           {
+               uint8_t * const dest = extend(SIZEOF_NETWORK_DOUBLE);
+               bu_cv_htond(dest, reinterpret_cast<const unsigned char 
*>(&value), 1);
+           }
+
+
+           void write(const ON_3dPoint &value)
+           {
+               write_double(value.x);
+               write_double(value.y);
+               write_double(value.z);
+           }
+
+
+           void write(const ON_BoundingBox &value)
+           {
+               write(value.m_min);
+               write(value.m_max);
+           }
+
+
+           void write(const ON_Interval &value)
+           {
+               write_double(value.m_t[0]);
+               write_double(value.m_t[1]);
+           }
+
+
+       private:
+           Serializer(const Serializer &source);
+           Serializer &operator=(const Serializer &source);
+
+
+           uint8_t *extend(std::size_t size)
+           {
+               const std::size_t position = m_external.ext_nbytes;
+               m_external.ext_nbytes += size;
+
+               if (m_external.ext_nbytes > m_capacity) {
+                   m_capacity = m_external.ext_nbytes * 2;
+                   m_external.ext_buf = static_cast<uint8_t 
*>(bu_realloc(m_external.ext_buf, m_capacity, "m_external"));
+               }
+
+               return &m_external.ext_buf[position];
+           }
+
+
+           std::size_t m_capacity;
+           bu_external m_external;
+    };
+
+
+    class Deserializer
+    {
+       public:
+           Deserializer(const bu_external &external) :
+               m_position(0),
+               m_external(external)
+       {
+           BU_CK_EXTERNAL(&m_external);
+       }
+
+
+           ~Deserializer()
+           {
+               if (m_position != m_external.ext_nbytes)
+                   bu_bomb("did not deserialize entire stream");
+           }
+
+
+           uint8_t read_uint8()
+           {
+               return *get(1);
+           }
+
+
+           uint32_t read_uint32()
+           {
+               uint32_t result;
+               std::memcpy(&result, get(SIZEOF_NETWORK_LONG), 
SIZEOF_NETWORK_LONG);
+               return ntohl(result);
+           }
+
+
+           int32_t read_int32()
+           {
+               long result;
+
+               if (UNLIKELY(1 != bu_cv_ntohsl(&result, sizeof(result), 
const_cast<void *>(reinterpret_cast<const void *>(get(SIZEOF_NETWORK_LONG))), 
1)))
+                   bu_bomb("bu_cv_ntohsl() failed");
+
+               return result;
+           }
+
+
+           double read_double()
+           {
+               double result;
+               bu_cv_ntohd(reinterpret_cast<unsigned char *>(&result), 
get(SIZEOF_NETWORK_DOUBLE), 1);
+               return result;
+           }
+
+
+           void read(ON_3dPoint &value)
+           {
+               value.x = read_double();
+               value.y = read_double();
+               value.z = read_double();
+           }
+
+
+           void read(ON_3dVector &value)
+           {
+               value.x = read_double();
+               value.y = read_double();
+               value.z = read_double();
+           }
+
+
+           void read(ON_BoundingBox &value)
+           {
+               read(value.m_min);
+               read(value.m_max);
+           }
+
+
+           void read(ON_Interval &value)
+           {
+               value.m_t[0] = read_double();
+               value.m_t[1] = read_double();
+           }
+
+
+       private:
+           Deserializer(const Deserializer &source);
+           Deserializer &operator=(const Deserializer &source);
+
+
+           const uint8_t *get(std::size_t size)
+           {
+               const std::size_t result_position = m_position;
+               m_position += size;
+
+               if (UNLIKELY(m_position > m_external.ext_nbytes))
+                   bu_bomb("invalid position");
+
+               return &m_external.ext_buf[result_position];
+           }
+
+
+           std::size_t m_position;
+           const bu_external &m_external;
+    };
+
+
+    template <typename T>
+       class PooledObject
+       {
+           public:
+               static void *operator new(std::size_t size)
+               {
+                   if (UNLIKELY(size != sizeof(T)))
+                       throw std::bad_alloc();
+
+                   return bu_heap_get(size);
+               }
+
+
+               static void operator delete(void *pointer)
+               {
+                   bu_heap_put(pointer, sizeof(T));
+               }
+       };
+
+
 } /* extern C++ */
 
 __END_DECLS

Modified: brlcad/trunk/include/rt/func.h
===================================================================
--- brlcad/trunk/include/rt/func.h      2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/include/rt/func.h      2016-09-30 03:29:52 UTC (rev 68934)
@@ -177,6 +177,11 @@
  */
 RT_EXPORT extern int rt_obj_mirror(struct rt_db_internal *ip, const plane_t 
*plane);
 
+/**
+ * if `stp` is prepped, serialize; otherwise, deserialize from `external`
+ */
+RT_EXPORT extern int rt_obj_prep_serialize(struct soltab *stp, const struct 
rt_db_internal *ip, struct bu_external *external, uint32_t *version);
+
 __END_DECLS
 
 #endif  /* RT_FUNC_H */

Modified: brlcad/trunk/include/rt/functab.h
===================================================================
--- brlcad/trunk/include/rt/functab.h   2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/include/rt/functab.h   2016-09-30 03:29:52 UTC (rev 68934)
@@ -73,46 +73,46 @@
 
     int ft_use_rpp;
     int (*ft_prep)(struct soltab *stp,
-                   struct rt_db_internal *ip,
-                   struct rt_i *rtip);
+                  struct rt_db_internal *ip,
+                  struct rt_i *rtip);
 #define RTFUNCTAB_FUNC_PREP_CAST(_func) ((int (*)(struct soltab *, struct 
rt_db_internal *, struct rt_i *))_func)
 
     int (*ft_shot)(struct soltab *stp,
-                   struct xray *rp,
-                   struct application *ap, /* has resource */
-                   struct seg *seghead);
+                  struct xray *rp,
+                  struct application *ap, /* has resource */
+                  struct seg *seghead);
 #define RTFUNCTAB_FUNC_SHOT_CAST(_func) ((int (*)(struct soltab *, struct xray 
*, struct application *, struct seg *))_func)
 
     void (*ft_print)(const struct soltab *stp);
 #define RTFUNCTAB_FUNC_PRINT_CAST(_func) ((void (*)(const struct soltab 
*))_func)
 
     void (*ft_norm)(struct hit *hitp,
-                    struct soltab *stp,
-                    struct xray *rp);
+                   struct soltab *stp,
+                   struct xray *rp);
 #define RTFUNCTAB_FUNC_NORM_CAST(_func) ((void (*)(struct hit *, struct soltab 
*, struct xray *))_func)
 
     int (*ft_piece_shot)(struct rt_piecestate *psp,
-                         struct rt_piecelist *plp,
-                         double dist, /* correction to apply to hit distances 
*/
-                         struct xray *ray, /* ray transformed to be near cut 
cell */
-                         struct application *ap, /* has resource */
-                         struct seg *seghead);  /* used only for PLATE mode 
hits */
+                        struct rt_piecelist *plp,
+                        double dist, /* correction to apply to hit distances */
+                        struct xray *ray, /* ray transformed to be near cut 
cell */
+                        struct application *ap, /* has resource */
+                        struct seg *seghead);  /* used only for PLATE mode 
hits */
 #define RTFUNCTAB_FUNC_PIECE_SHOT_CAST(_func) ((int (*)(struct rt_piecestate 
*, struct rt_piecelist *, double dist, struct xray *, struct application *, 
struct seg *))_func)
 
     void (*ft_piece_hitsegs)(struct rt_piecestate *psp,
-                             struct seg *seghead,
-                             struct application *ap); /* has resource */
+                            struct seg *seghead,
+                            struct application *ap); /* has resource */
 #define RTFUNCTAB_FUNC_PIECE_HITSEGS_CAST(_func) ((void (*)(struct 
rt_piecestate *, struct seg *, struct application *))_func)
 
     void (*ft_uv)(struct application *ap, /* has resource */
-                  struct soltab *stp,
-                  struct hit *hitp,
-                  struct uvcoord *uvp);
+                 struct soltab *stp,
+                 struct hit *hitp,
+                 struct uvcoord *uvp);
 #define RTFUNCTAB_FUNC_UV_CAST(_func) ((void (*)(struct application *, struct 
soltab *, struct hit *, struct uvcoord *))_func)
 
     void (*ft_curve)(struct curvature *cvp,
-                     struct hit *hitp,
-                     struct soltab *stp);
+                    struct hit *hitp,
+                    struct soltab *stp);
 #define RTFUNCTAB_FUNC_CURVE_CAST(_func) ((void (*)(struct curvature *, struct 
hit *, struct soltab *))_func)
 
     int (*ft_classify)(const struct soltab * /*stp*/, const vect_t /*min*/, 
const vect_t /*max*/, const struct bn_tol * /*tol*/);
@@ -122,83 +122,83 @@
 #define RTFUNCTAB_FUNC_FREE_CAST(_func) ((void (*)(struct soltab *))_func)
 
     int (*ft_plot)(struct bu_list * /*vhead*/,
-                   struct rt_db_internal * /*ip*/,
-                   const struct rt_tess_tol * /*ttol*/,
-                   const struct bn_tol * /*tol*/,
-                   const struct rt_view_info * /*view info*/);
+                  struct rt_db_internal * /*ip*/,
+                  const struct rt_tess_tol * /*ttol*/,
+                  const struct bn_tol * /*tol*/,
+                  const struct rt_view_info * /*view info*/);
 #define RTFUNCTAB_FUNC_PLOT_CAST(_func) ((int (*)(struct bu_list *, struct 
rt_db_internal *, const struct rt_tess_tol *, const struct bn_tol *, const 
struct rt_view_info *))_func)
 
     int (*ft_adaptive_plot)(struct rt_db_internal * /*ip*/,
-                   const struct rt_view_info * /*view info*/);
+                  const struct rt_view_info * /*view info*/);
 #define RTFUNCTAB_FUNC_ADAPTIVE_PLOT_CAST(_func) ((int (*)(struct 
rt_db_internal *, const struct rt_view_info *))_func)
 
     void (*ft_vshot)(struct soltab * /*stp*/[],
-                     struct xray *[] /*rp*/,
-                     struct seg * /*segp*/,
-                     int /*n*/,
-                     struct application * /*ap*/);
+                    struct xray *[] /*rp*/,
+                    struct seg * /*segp*/,
+                    int /*n*/,
+                    struct application * /*ap*/);
 #define RTFUNCTAB_FUNC_VSHOT_CAST(_func) ((void (*)(struct soltab *[], struct 
xray *[], struct seg *, int, struct application *))_func)
 
     int (*ft_tessellate)(struct nmgregion ** /*r*/,
-                         struct model * /*m*/,
-                         struct rt_db_internal * /*ip*/,
-                         const struct rt_tess_tol * /*ttol*/,
-                         const struct bn_tol * /*tol*/);
+                        struct model * /*m*/,
+                        struct rt_db_internal * /*ip*/,
+                        const struct rt_tess_tol * /*ttol*/,
+                        const struct bn_tol * /*tol*/);
 #define RTFUNCTAB_FUNC_TESS_CAST(_func) ((int (*)(struct nmgregion **, struct 
model *, struct rt_db_internal *, const struct rt_tess_tol *, const struct 
bn_tol *))_func)
     int (*ft_tnurb)(struct nmgregion ** /*r*/,
-                    struct model * /*m*/,
-                    struct rt_db_internal * /*ip*/,
-                    const struct bn_tol * /*tol*/);
+                   struct model * /*m*/,
+                   struct rt_db_internal * /*ip*/,
+                   const struct bn_tol * /*tol*/);
 #define RTFUNCTAB_FUNC_TNURB_CAST(_func) ((int (*)(struct nmgregion **, struct 
model *, struct rt_db_internal *, const struct bn_tol *))_func)
 
     void (*ft_brep)(ON_Brep ** /*b*/,
-                    struct rt_db_internal * /*ip*/,
-                    const struct bn_tol * /*tol*/);
+                   struct rt_db_internal * /*ip*/,
+                   const struct bn_tol * /*tol*/);
 #define RTFUNCTAB_FUNC_BREP_CAST(_func) ((void (*)(ON_Brep **, struct 
rt_db_internal *, const struct bn_tol *))_func)
 
     int (*ft_import5)(struct rt_db_internal * /*ip*/,
-                      const struct bu_external * /*ep*/,
-                      const mat_t /*mat*/,
-                      const struct db_i * /*dbip*/,
-                      struct resource * /*resp*/);
+                     const struct bu_external * /*ep*/,
+                     const mat_t /*mat*/,
+                     const struct db_i * /*dbip*/,
+                     struct resource * /*resp*/);
 #define RTFUNCTAB_FUNC_IMPORT5_CAST(_func) ((int (*)(struct rt_db_internal *, 
const struct bu_external *, const mat_t, const struct db_i *, struct resource 
*))_func)
 
     int (*ft_export5)(struct bu_external * /*ep*/,
-                      const struct rt_db_internal * /*ip*/,
-                      double /*local2mm*/,
-                      const struct db_i * /*dbip*/,
-                      struct resource * /*resp*/);
+                     const struct rt_db_internal * /*ip*/,
+                     double /*local2mm*/,
+                     const struct db_i * /*dbip*/,
+                     struct resource * /*resp*/);
 #define RTFUNCTAB_FUNC_EXPORT5_CAST(_func) ((int (*)(struct bu_external *, 
const struct rt_db_internal *, double, const struct db_i *, struct resource 
*))_func)
 
    int (*ft_import4)(struct rt_db_internal * /*ip*/,
-                      const struct bu_external * /*ep*/,
-                      const mat_t /*mat*/,
-                      const struct db_i * /*dbip*/,
-                      struct resource * /*resp*/);
+                     const struct bu_external * /*ep*/,
+                     const mat_t /*mat*/,
+                     const struct db_i * /*dbip*/,
+                     struct resource * /*resp*/);
 #define RTFUNCTAB_FUNC_IMPORT4_CAST(_func) ((int (*)(struct rt_db_internal *, 
const struct bu_external *, const mat_t, const struct db_i *, struct resource 
*))_func)
 
     int (*ft_export4)(struct bu_external * /*ep*/,
-                      const struct rt_db_internal * /*ip*/,
-                      double /*local2mm*/,
-                      const struct db_i * /*dbip*/,
-                      struct resource * /*resp*/);
+                     const struct rt_db_internal * /*ip*/,
+                     double /*local2mm*/,
+                     const struct db_i * /*dbip*/,
+                     struct resource * /*resp*/);
 #define RTFUNCTAB_FUNC_EXPORT4_CAST(_func) ((int (*)(struct bu_external *, 
const struct rt_db_internal *, double, const struct db_i *, struct resource 
*))_func)
 
     void (*ft_ifree)(struct rt_db_internal * /*ip*/);
 #define RTFUNCTAB_FUNC_IFREE_CAST(_func) ((void (*)(struct rt_db_internal 
*))_func)
 
     int (*ft_describe)(struct bu_vls * /*str*/,
-                       const struct rt_db_internal * /*ip*/,
-                       int /*verbose*/,
-                       double /*mm2local*/,
-                       struct resource * /*resp*/,
-                       struct db_i *);
+                      const struct rt_db_internal * /*ip*/,
+                      int /*verbose*/,
+                      double /*mm2local*/,
+                      struct resource * /*resp*/,
+                      struct db_i *);
 #define RTFUNCTAB_FUNC_DESCRIBE_CAST(_func) ((int (*)(struct bu_vls *, const 
struct rt_db_internal *, int, double, struct resource *, struct db_i *))_func)
 
     int (*ft_xform)(struct rt_db_internal * /*op*/,
-                    const mat_t /*mat*/, struct rt_db_internal * /*ip*/,
-                    int /*free*/, struct db_i * /*dbip*/,
-                    struct resource * /*resp*/);
+                   const mat_t /*mat*/, struct rt_db_internal * /*ip*/,
+                   int /*free*/, struct db_i * /*dbip*/,
+                   struct resource * /*resp*/);
 #define RTFUNCTAB_FUNC_XFORM_CAST(_func) ((int (*)(struct rt_db_internal *, 
const mat_t, struct rt_db_internal *, int, struct db_i *, struct resource 
*))_func)
 
     const struct bu_structparse *ft_parsetab;   /**< @brief  rt_xxx_parse */
@@ -222,9 +222,9 @@
 
     /* Axis aligned bounding box */
     int (*ft_bbox)(struct rt_db_internal * /*ip*/,
-                   point_t * /*min X, Y, Z of bounding RPP*/,
-                   point_t * /*max X, Y, Z of bounding RPP*/,
-                   const struct bn_tol *);
+                  point_t * /*min X, Y, Z of bounding RPP*/,
+                  point_t * /*max X, Y, Z of bounding RPP*/,
+                  const struct bn_tol *);
 #define RTFUNCTAB_FUNC_BBOX_CAST(_func) ((int (*)(struct rt_db_internal *, 
point_t *, point_t *, const struct bn_tol *))_func)
 
     void (*ft_volume)(fastf_t * /*vol*/, const struct rt_db_internal * /*ip*/);
@@ -237,31 +237,33 @@
 #define RTFUNCTAB_FUNC_CENTROID_CAST(_func) ((void (*)(point_t *, const struct 
rt_db_internal *))_func)
 
     int (*ft_oriented_bbox)(struct rt_arb_internal * /* bounding arb8 */,
-                   struct rt_db_internal * /*ip*/,
-                   const fastf_t);
+                  struct rt_db_internal * /*ip*/,
+                  const fastf_t);
 #define RTFUNCTAB_FUNC_ORIENTED_BBOX_CAST(_func) ((int (*)(struct 
rt_arb_internal *, struct rt_db_internal *, const fastf_t))_func)
 
     /** get a list of the selections matching a query */
     struct rt_selection_set *(*ft_find_selections)(const struct rt_db_internal 
*,
-                                                   const struct 
rt_selection_query *);
+                                                  const struct 
rt_selection_query *);
 #define RTFUNCTAB_FUNC_FIND_SELECTIONS_CAST(_func) ((struct rt_selection_set 
*(*)(const struct rt_db_internal *, const struct rt_selection_query *))_func)
 
     /** evaluate a logical selection expression (e.g. a INTERSECT b,
      *  NOT a) to create a new selection
      */
     struct rt_selection *(*ft_evaluate_selection)(const struct rt_db_internal 
*,
-                                                 int op,
-                                                 const struct rt_selection *,
-                                                 const struct rt_selection *);
+                                                int op,
+                                                const struct rt_selection *,
+                                                const struct rt_selection *);
 #define RTFUNCTAB_FUNC_EVALUATE_SELECTION_CAST(_func) ((struct rt_selection 
*(*)(const struct rt_db_internal *, int op, const struct rt_selection *, const 
struct rt_selection *))_func)
 
     /** apply an operation to a selected subset of a primitive */
     int (*ft_process_selection)(struct rt_db_internal *,
-                                struct db_i *,
-                                const struct rt_selection *,
-                                const struct rt_selection_operation *);
+                               struct db_i *,
+                               const struct rt_selection *,
+                               const struct rt_selection_operation *);
 #define RTFUNCTAB_FUNC_PROCESS_SELECTION_CAST(_func) ((int (*)(struct 
rt_db_internal *, struct db_i *, const struct rt_selection *, const struct 
rt_selection_operation *))_func)
 
+    int (*ft_prep_serialize)(struct soltab *stp, const struct rt_db_internal 
*ip, struct bu_external *external, uint32_t *version);
+#define RTFUNCTAB_FUNC_PREP_SERIALIZE_CAST(_func) ((int (*)(struct soltab *, 
const struct rt_db_internal *, struct bu_external *, uint32_t *))_func)
 };
 
 

Modified: brlcad/trunk/src/libbrep/BBNode.cpp
===================================================================
--- brlcad/trunk/src/libbrep/BBNode.cpp 2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/src/libbrep/BBNode.cpp 2016-09-30 03:29:52 UTC (rev 68934)
@@ -25,18 +25,178 @@
 
 
 namespace brlcad {
+
+
+BBNode::BBNode(const ON_BoundingBox &node, const CurveTree *ct) :
+    m_node(node),
+    m_u(),
+    m_v(),
+    m_checkTrim(true),
+    m_trimmed(false),
+    m_estimate(),
+    m_normal(),
+    m_ctree(ct),
+    m_stl(new Stl)
+{
+    for (int i = 0; i < 3; i++) {
+       double d = m_node.m_max[i] - m_node.m_min[i];
+       if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
+           m_node.m_min[i] -= 0.001;
+           m_node.m_max[i] += 0.001;
+       }
+    }
+}
+
+
+BBNode::BBNode(
+       const CurveTree *ct,
+       const ON_BoundingBox &node,
+       const ON_Interval &u,
+       const ON_Interval &v,
+       bool checkTrim,
+       bool trimmed):
+    m_node(node),
+    m_u(u),
+    m_v(v),
+    m_checkTrim(checkTrim),
+    m_trimmed(trimmed),
+    m_estimate(),
+    m_normal(),
+    m_ctree(ct),
+    m_stl(new Stl)
+{
+    for (int i = 0; i < 3; i++) {
+       double d = m_node.m_max[i] - m_node.m_min[i];
+       if (ON_NearZero(d, ON_ZERO_TOLERANCE)) {
+           m_node.m_min[i] -= 0.001;
+           m_node.m_max[i] += 0.001;
+       }
+    }
+}
+
+
 BBNode::~BBNode()
 {
     /* delete the children */
-    for (size_t i = 0; i < m_children->size(); i++) {
-       delete (*m_children)[i];
+    for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+       delete m_stl->m_children[i];
     }
 
-    delete m_children;
-    delete m_trims_above;
+    delete m_stl;
 }
 
+
+BBNode::BBNode(Deserializer &deserializer, const CurveTree &ctree) :
+    m_node(),
+    m_u(),
+    m_v(),
+    m_checkTrim(false),
+    m_trimmed(false),
+    m_estimate(),
+    m_normal(),
+    m_ctree(&ctree),
+    m_stl(new Stl)
+{
+    deserializer.read(m_node);
+    deserializer.read(m_u);
+    deserializer.read(m_v);
+    deserializer.read(m_estimate);
+    deserializer.read(m_normal);
+
+    const uint8_t bool_flags = deserializer.read_uint8();
+    const std::size_t num_leaves_keys = deserializer.read_uint32();
+    const std::size_t num_children = deserializer.read_uint32();
+
+    m_checkTrim = bool_flags & (1 << 0);
+    m_trimmed = bool_flags & (1 << 1);
+
+    m_stl->m_children.resize(num_children);
+    for (std::vector<BBNode *>::iterator it = m_stl->m_children.begin(); it != 
m_stl->m_children.end(); ++it)
+       *it = new BBNode(deserializer, ctree);
+
+    std::size_t buffer[8];
+    std::size_t *leaves_keys = buffer;
+    if (num_leaves_keys > sizeof(buffer) / sizeof(buffer[0]))
+       leaves_keys = new std::size_t[num_leaves_keys];
+
+    for (std::size_t i = 0; i < num_leaves_keys; ++i)
+       leaves_keys[i] = deserializer.read_uint32();
+
+    m_stl->m_trims_above = m_ctree->serialize_get_leaves(leaves_keys, 
num_leaves_keys);
+
+    if (leaves_keys != buffer)
+       delete[] leaves_keys;
+}
+
+
+void
+BBNode::serialize(Serializer &serializer) const
+{
+    const std::vector<std::size_t> leaves_keys = 
m_ctree->serialize_get_leaves_keys(m_stl->m_trims_above);
+    const uint8_t bool_flags = (m_checkTrim << 0) | (m_trimmed << 1);
+
+    serializer.write(m_node);
+    serializer.write(m_u);
+    serializer.write(m_v);
+    serializer.write(m_estimate);
+    serializer.write(m_normal);
+
+    serializer.write_uint8(bool_flags);
+    serializer.write_uint32(leaves_keys.size());
+    serializer.write_uint32(m_stl->m_children.size());
+
+    for (std::vector<std::size_t>::const_iterator it = leaves_keys.begin(); it 
!= leaves_keys.end(); ++it)
+       serializer.write_uint32(*it);
+
+    for (std::vector<BBNode *>::const_iterator it = m_stl->m_children.begin(); 
it != m_stl->m_children.end(); ++it)
+       (*it)->serialize(serializer);
+}
+
+
 bool
+BBNode::intersectedBy(const ON_Ray &ray, double *tnear_opt /* = NULL */, 
double *tfar_opt /* = NULL */) const
+{
+    double tnear = -DBL_MAX;
+    double tfar = DBL_MAX;
+    bool untrimmedresult = true;
+    for (int i = 0; i < 3; i++) {
+       if (UNLIKELY(ON_NearZero(ray.m_dir[i]))) {
+           if (ray.m_origin[i] < m_node.m_min[i] || ray.m_origin[i] > 
m_node.m_max[i]) {
+               untrimmedresult = false;
+           }
+       } else {
+           double t1 = (m_node.m_min[i] - ray.m_origin[i]) / ray.m_dir[i];
+           double t2 = (m_node.m_max[i] - ray.m_origin[i]) / ray.m_dir[i];
+           if (t1 > t2) {
+               double tmp = t1;    /* swap */
+               t1 = t2;
+               t2 = tmp;
+           }
+
+           V_MAX(tnear, t1);
+           V_MIN(tfar, t2);
+
+           if (tnear > tfar) { /* box is missed */
+               untrimmedresult = false;
+           }
+           /* go ahead and solve hits behind us
+              if (tfar < 0) untrimmedresult = false;
+              */
+       }
+    }
+    if (LIKELY(tnear_opt != NULL && tfar_opt != NULL)) {
+       *tnear_opt = tnear;
+       *tfar_opt = tfar;
+    }
+    if (isLeaf()) {
+       return !m_trimmed && untrimmedresult;
+    } else {
+       return untrimmedresult;
+    }
+}
+
+
+bool
 BBNode::intersectsHierarchy(const ON_Ray &ray, std::list<const BBNode *> 
&results_opt) const
 {
     double tnear, tfar;
@@ -44,8 +204,8 @@
     if (intersects && isLeaf()) {
        results_opt.push_back(this);
     } else if (intersects) {
-       for (size_t i = 0; i < m_children->size(); i++) {
-           (*m_children)[i]->intersectsHierarchy(ray, results_opt);
+       for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+           m_stl->m_children[i]->intersectsHierarchy(ray, results_opt);
        }
     }
     return intersects;
@@ -65,8 +225,8 @@
 BBNode::depth() const
 {
     int d = 0;
-    for (size_t i = 0; i < m_children->size(); i++) {
-       d = 1 + std::max(d, (*m_children)[i]->depth());
+    for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+       d = 1 + std::max(d, m_stl->m_children[i]->depth());
     }
     return d;
 }
@@ -74,9 +234,9 @@
 void
 BBNode::getLeaves(std::list<const BBNode *> &out_leaves) const
 {
-    if (!m_children->empty()) {
-       for (size_t i = 0; i < m_children->size(); i++) {
-           (*m_children)[i]->getLeaves(out_leaves);
+    if (!m_stl->m_children.empty()) {
+       for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+           m_stl->m_children[i]->getLeaves(out_leaves);
        }
     } else {
        out_leaves.push_back(this);
@@ -112,7 +272,7 @@
            {m_u.Mid(), m_v.Mid()}
        }; /* include the estimate */
        ON_3dPoint corners[5];
-       const ON_Surface *surf = m_face->SurfaceOf();
+       const ON_Surface *surf = get_face().SurfaceOf();
 
        u = m_u;
        v = m_v;
@@ -144,10 +304,10 @@
        TRACE("Closest: " << mindist << "; " << PT2(uvs[mini]));
        return ON_2dPoint(uvs[mini][0], uvs[mini][1]);
     } else {
-       if (!m_children->empty()) {
-           const BBNode *closestNode = (*m_children)[0];
-           for (size_t i = 1; i < m_children->size(); i++) {
-               closestNode = closer(pt, closestNode, (*m_children)[i]);
+       if (!m_stl->m_children.empty()) {
+           const BBNode *closestNode = m_stl->m_children[0];
+           for (size_t i = 1; i < m_stl->m_children.size(); i++) {
+               closestNode = closer(pt, closestNode, m_stl->m_children[i]);
                TRACE("\t" << PT(closestNode->m_estimate));
            }
            return closestNode->getClosestPointEstimate(pt, u, v);
@@ -173,8 +333,8 @@
        return 0;
     } else {
        int sum = 0;
-       for (size_t i = 0; i < m_children->size(); i++) {
-           sum += (*m_children)[i]->getLeavesBoundingPoint(pt, out);
+       for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+           sum += m_stl->m_children[i]->getLeavesBoundingPoint(pt, out);
        }
        return sum;
     }
@@ -301,7 +461,7 @@
 {
     point_t bmin, bmax;
     double dist;
-    for (std::list<const BRNode *>::const_iterator i = m_trims_above->begin(); 
i != m_trims_above->end(); i++) {
+    for (std::list<const BRNode *>::const_iterator i = 
m_stl->m_trims_above.begin(); i != m_stl->m_trims_above.end(); i++) {
        const BRNode *br = *i;
        br->GetBBox(bmin, bmax);
        dist = 0.000001; /* 0.03*DIST_PT_PT(bmin, bmax); */
@@ -313,12 +473,12 @@
 
 void BBNode::BuildBBox()
 {
-    if (!m_children->empty()) {
-       for (std::vector<BBNode *>::const_iterator childnode = 
m_children->begin(); childnode != m_children->end(); childnode++) {
+    if (!m_stl->m_children.empty()) {
+       for (std::vector<BBNode *>::const_iterator childnode = 
m_stl->m_children.begin(); childnode != m_stl->m_children.end(); childnode++) {
            if (!(*childnode)->isLeaf()) {
                (*childnode)->BuildBBox();
            }
-           if (childnode == m_children->begin()) {
+           if (childnode == m_stl->m_children.begin()) {
                m_node = ON_BoundingBox((*childnode)->m_node.m_min, 
(*childnode)->m_node.m_max);
            } else {
                for (int j = 0; j < 3; j++) {
@@ -340,17 +500,17 @@
     double dist = 0.000001;
     bool trim_already_assigned = false;
 
-    m_trims_above->clear();
+    m_stl->m_trims_above.clear();
 
     if (LIKELY(ct != NULL)) {
-       ct->getLeavesAbove(*m_trims_above, m_u, m_v);
+       ct->getLeavesAbove(m_stl->m_trims_above, m_u, m_v);
     }
 
-    m_trims_above->sort(sortY);
+    m_stl->m_trims_above.sort(sortY);
 
-    if (!m_trims_above->empty()) {
-       i = m_trims_above->begin();
-       while (i != m_trims_above->end()) {
+    if (!m_stl->m_trims_above.empty()) {
+       i = m_stl->m_trims_above.begin();
+       while (i != m_stl->m_trims_above.end()) {
            br = *i;
            if (br->m_Vertical) { /* check V to see if trim possibly overlaps */
                br->GetBBox(curvemin, curvemax);
@@ -361,7 +521,7 @@
                    trim_already_assigned = true;
                    i++;
                } else {
-                   i = m_trims_above->erase(i);
+                   i = m_stl->m_trims_above.erase(i);
                }
            } else {
                i++;
@@ -370,18 +530,18 @@
     }
 
     if (!trim_already_assigned) { /* already contains possible vertical trim */
-       if (m_trims_above->empty() /*|| m_trims_right.empty()*/) {
+       if (m_stl->m_trims_above.empty() /*|| m_trims_right.empty()*/) {
            m_trimmed = true;
            m_checkTrim = false;
-       } else if (!m_trims_above->empty()) { /*trimmed above check contains */
-           i = m_trims_above->begin();
+       } else if (!m_stl->m_trims_above.empty()) { /*trimmed above check 
contains */
+           i = m_stl->m_trims_above.begin();
            br = *i;
            br->GetBBox(curvemin, curvemax);
            dist = 0.000001; /* 0.03*DIST_PT_PT(curvemin, curvemax); */
            if (curvemin[Y] - dist > m_v[1]) {
                i++;
 
-               if (i == m_trims_above->end()) { /* easy only trim in above 
list */
+               if (i == m_stl->m_trims_above.end()) { /* easy only trim in 
above list */
                    if (br->m_XIncreasing) {
                        m_trimmed = true;
                        m_checkTrim = false;

Modified: brlcad/trunk/src/libbrep/BRNode.cpp
===================================================================
--- brlcad/trunk/src/libbrep/BRNode.cpp 2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/src/libbrep/BRNode.cpp 2016-09-30 03:29:52 UTC (rev 68934)
@@ -25,23 +25,234 @@
 
 
 namespace brlcad {
+
+
+BRNode::BRNode(
+       const ON_Curve *curve,
+       int trim_index,
+       int adj_face_index,
+       const ON_BoundingBox &node,
+       const ON_BrepFace *face,
+       const ON_Interval &t,
+       bool innerTrim,
+       bool checkTrim,
+       bool trimmed) :
+    m_node(node),
+    m_v(),
+    m_adj_face_index(adj_face_index),
+    m_XIncreasing(false),
+    m_Horizontal(false),
+    m_Vertical(false),
+    m_innerTrim(innerTrim),
+    m_stl(new Stl),
+    m_face(face),
+    m_u(),
+    m_trim(curve),
+    m_trim_index(trim_index),
+    m_t(t),
+    m_checkTrim(checkTrim),
+    m_trimmed(trimmed),
+    m_estimate(),
+    m_slope(0.0),
+    m_bb_diag(0.0),
+    m_start(curve->PointAt(m_t[0])),
+    m_end(curve->PointAt(m_t[1]))
+{
+    /* check for vertical segments they can be removed from trims
+     * above (can't tell direction and don't need
+     */
+    m_Horizontal = false;
+    m_Vertical = false;
+
+    /*
+     * should be okay since we split on Horz/Vert tangents
+     */
+    if (m_end[X] < m_start[X]) {
+       m_u[0] = m_end[X];
+       m_u[1] = m_start[X];
+    } else {
+       m_u[0] = m_start[X];
+       m_u[1] = m_end[X];
+    }
+    if (m_end[Y] < m_start[Y]) {
+       m_v[0] = m_end[Y];
+       m_v[1] = m_start[Y];
+    } else {
+       m_v[0] = m_start[Y];
+       m_v[1] = m_end[Y];
+    }
+
+    if (NEAR_EQUAL(m_end[X], m_start[X], 0.000001)) {
+       m_Vertical = true;
+       if (m_innerTrim) {
+           m_XIncreasing = false;
+       } else {
+           m_XIncreasing = true;
+       }
+    } else if (NEAR_EQUAL(m_end[Y], m_start[Y], 0.000001)) {
+       m_Horizontal = true;
+       if ((m_end[X] - m_start[X]) > 0.0) {
+           m_XIncreasing = true;
+       } else {
+           m_XIncreasing = false;
+       }
+       m_slope = 0.0;
+    } else {
+       if ((m_end[X] - m_start[X]) > 0.0) {
+           m_XIncreasing = true;
+       } else {
+           m_XIncreasing = false;
+       }
+       m_slope = (m_end[Y] - m_start[Y]) / (m_end[X] - m_start[X]);
+    }
+    m_bb_diag = DIST_PT_PT(m_start, m_end);
+}
+
+
+BRNode::BRNode(const ON_BoundingBox &node) :
+    m_node(node),
+    m_v(),
+    m_adj_face_index(-1),
+    m_XIncreasing(false),
+    m_Horizontal(false),
+    m_Vertical(false),
+    m_innerTrim(false),
+    m_stl(new Stl),
+    m_face(NULL),
+    m_u(),
+    m_trim(NULL),
+    m_trim_index(-1),
+    m_t(),
+    m_checkTrim(true),
+    m_trimmed(false),
+    m_estimate(),
+    m_slope(0.0),
+    m_bb_diag(0.0),
+    m_start(ON_3dPoint::UnsetPoint),
+    m_end(ON_3dPoint::UnsetPoint)
+{
+       for (int i = 0; i < 3; i++) {
+           double d = m_node.m_max[i] - m_node.m_min[i];
+           if (NEAR_ZERO(d, ON_ZERO_TOLERANCE)) {
+               m_node.m_min[i] -= 0.001;
+               m_node.m_max[i] += 0.001;
+           }
+       }
+       m_start = m_node.m_min;
+       m_end = m_node.m_max;
+}
+
+
 BRNode::~BRNode()
 {
     /* delete the children */
-    for (size_t i = 0; i < m_children->size(); i++) {
-       delete (*m_children)[i];
+    for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+       delete m_stl->m_children[i];
     }
 
-    delete m_children;
+    delete m_stl;
 }
 
 
+BRNode::BRNode(Deserializer &deserializer, const ON_Brep &brep) :
+    m_node(),
+    m_v(),
+    m_adj_face_index(-1),
+    m_XIncreasing(false),
+    m_Horizontal(false),
+    m_Vertical(false),
+    m_innerTrim(false),
+    m_stl(new Stl),
+    m_face(NULL),
+    m_u(),
+    m_trim(NULL),
+    m_trim_index(-1),
+    m_t(),
+    m_checkTrim(false),
+    m_trimmed(false),
+    m_estimate(),
+    m_slope(0.0),
+    m_bb_diag(0.0),
+    m_start(ON_3dPoint::UnsetPoint),
+    m_end(ON_3dPoint::UnsetPoint)
+{
+    deserializer.read(m_node);
+    deserializer.read(m_u);
+    deserializer.read(m_v);
+    deserializer.read(m_t);
+    deserializer.read(m_start);
+    deserializer.read(m_end);
+    deserializer.read(m_estimate);
+
+    m_slope = deserializer.read_double();
+    m_bb_diag = deserializer.read_double();
+
+    const uint8_t bool_flags = deserializer.read_uint8();
+    const int face_index = deserializer.read_int32();
+    m_trim_index = deserializer.read_int32();
+    m_adj_face_index = deserializer.read_uint32();
+    const std::size_t num_children = deserializer.read_uint32();
+
+    m_XIncreasing = bool_flags & (1 << 0);
+    m_Horizontal = bool_flags & (1 << 1);
+    m_Vertical = bool_flags & (1 << 2);
+    m_innerTrim = bool_flags & (1 << 3);
+    m_checkTrim = bool_flags & (1 << 4);
+    m_trimmed = bool_flags & (1 << 5);
+
+    if (face_index != -1) {
+       if (const ON_BrepFace * const face = brep.m_F.At(face_index))
+           m_face = face;
+       else
+           bu_bomb("invalid face index");
+    }
+
+    if (m_trim_index != -1) {
+       if (const ON_BrepTrim * const trim = brep.m_T.At(m_trim_index))
+           m_trim = trim->TrimCurveOf();
+       else
+           bu_bomb("invalid face index");
+    }
+
+    m_stl->m_children.resize(num_children);
+    for (std::vector<const BRNode *>::iterator it = m_stl->m_children.begin(); 
it != m_stl->m_children.end(); ++it)
+       *it = new BRNode(deserializer, brep);
+}
+
+
+void
+BRNode::serialize(Serializer &serializer) const
+{
+    const uint8_t bool_flags = (m_XIncreasing << 0) | (m_Horizontal << 1) | 
(m_Vertical << 2) | (m_innerTrim << 3) | (m_checkTrim << 4) | (m_trimmed << 5);
+
+    serializer.write(m_node);
+    serializer.write(m_u);
+    serializer.write(m_v);
+    serializer.write(m_t);
+    serializer.write(m_start);
+    serializer.write(m_end);
+    serializer.write(m_estimate);
+
+    serializer.write_double(m_slope);
+    serializer.write_double(m_bb_diag);
+
+    serializer.write_uint8(bool_flags);
+    serializer.write_int32(m_face ? m_face->m_face_index : -1);
+    serializer.write_int32(m_trim_index);
+    serializer.write_uint32(m_adj_face_index);
+    serializer.write_uint32(m_stl->m_children.size());
+
+    for (std::vector<const BRNode *>::const_iterator it = 
m_stl->m_children.begin(); it != m_stl->m_children.end(); ++it)
+       (*it)->serialize(serializer);
+}
+
+
 int
 BRNode::depth() const
 {
     int d = 0;
-    for (size_t i = 0; i < m_children->size(); i++) {
-       d = 1 + std::max(d, (*m_children)[i]->depth());
+    for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+       d = 1 + std::max(d, m_stl->m_children[i]->depth());
     }
     return d;
 }
@@ -49,9 +260,9 @@
 void
 BRNode::getLeaves(std::list<const BRNode *> &out_leaves) const
 {
-    if (!m_children->empty()) {
-       for (size_t i = 0; i < m_children->size(); i++) {
-           (*m_children)[i]->getLeaves(out_leaves);
+    if (!m_stl->m_children.empty()) {
+       for (size_t i = 0; i < m_stl->m_children.size(); i++) {
+           m_stl->m_children[i]->getLeaves(out_leaves);
        }
     } else {
        out_leaves.push_back(this);
@@ -155,10 +366,10 @@
        TRACE("Closest: " << mindist << "; " << PT2(uvs[mini]));
        return ON_2dPoint(uvs[mini][0], uvs[mini][1]);
     } else {
-       if (!m_children->empty()) {
-           const BRNode *closestNode = (*m_children)[0];
-           for (size_t i = 1; i < m_children->size(); i++) {
-               closestNode = closer(pt, closestNode, (*m_children)[i]);
+       if (!m_stl->m_children.empty()) {
+           const BRNode *closestNode = m_stl->m_children[0];
+           for (size_t i = 1; i < m_stl->m_children.size(); i++) {
+               closestNode = closer(pt, closestNode, m_stl->m_children[i]);
            }
            return closestNode->getClosestPointEstimate(pt, u, v);
        } else {

Modified: brlcad/trunk/src/libbrep/opennurbs_ext.cpp
===================================================================
--- brlcad/trunk/src/libbrep/opennurbs_ext.cpp  2016-09-29 16:23:24 UTC (rev 
68933)
+++ brlcad/trunk/src/libbrep/opennurbs_ext.cpp  2016-09-30 03:29:52 UTC (rev 
68934)
@@ -132,16 +132,18 @@
 // CurveTree
 CurveTree::CurveTree(const ON_BrepFace* face) :
     m_face(face),
-    m_root(initialLoopBBox()),
-    m_sortedX(new std::list<const BRNode *>)
+    m_root(new BRNode(initialLoopBBox(*face))),
+    m_stl(new Stl),
+    m_sortedX_indices(NULL)
 {
     for (int li = 0; li < face->LoopCount(); li++) {
        bool innerLoop = (li > 0) ? true : false;
        const ON_BrepLoop* loop = face->Loop(li);
        // for each trim
        for (int ti = 0; ti < loop->m_ti.Count(); ti++) {
-           int adj_face_index = -99;
-           const ON_BrepTrim& trim = face->Brep()->m_T[loop->m_ti[ti]];
+           int adj_face_index = -1;
+           const int trim_index = loop->m_ti[ti];
+           const ON_BrepTrim& trim = face->Brep()->m_T[trim_index];
 
            if (trim.m_ei != -1) { // does not lie on a portion of a singular 
surface side
                const ON_BrepEdge& edge = face->Brep()->m_E[trim.m_ei];
@@ -216,7 +218,7 @@
                for (std::list<fastf_t>::const_iterator l = splitlist.begin(); 
l != splitlist.end(); l++) {
                    double xmax = *l;
                    if (!NEAR_EQUAL(xmax, min, TOL)) {
-                       m_root->addChild(subdivideCurve(trimCurve, 
adj_face_index, min, xmax, innerLoop, 0));
+                       m_root->addChild(subdivideCurve(trimCurve, trim_index, 
adj_face_index, min, xmax, innerLoop, 0));
                    }
                    min = xmax;
                }
@@ -229,7 +231,7 @@
                for (int knot_index = 1; knot_index <= knotcnt; knot_index++) {
                    double xmax = knots[knot_index];
                    if (!NEAR_EQUAL(xmax, min, TOL)) {
-                       m_root->addChild(subdivideCurve(trimCurve, 
adj_face_index, min, xmax, innerLoop, 0));
+                       m_root->addChild(subdivideCurve(trimCurve, trim_index, 
adj_face_index, min, xmax, innerLoop, 0));
                    }
                    min = xmax;
                }
@@ -237,13 +239,15 @@
            }
 
            if (!NEAR_EQUAL(max, min, TOL)) {
-               m_root->addChild(subdivideCurve(trimCurve, adj_face_index, min, 
max, innerLoop, 0));
+               m_root->addChild(subdivideCurve(trimCurve, trim_index, 
adj_face_index, min, max, innerLoop, 0));
            }
        }
     }
 
-    getLeaves(*m_sortedX);
-    m_sortedX->sort(sortX);
+    std::list<const BRNode *> temp;
+    getLeaves(temp);
+    temp.sort(sortX);
+    m_stl->m_sortedX.insert(m_stl->m_sortedX.end(), temp.begin(), temp.end());
 
     return;
 }
@@ -252,10 +256,73 @@
 CurveTree::~CurveTree()
 {
     delete m_root;
-    delete m_sortedX;
+    delete m_stl;
+    delete m_sortedX_indices;
 }
 
 
+CurveTree::CurveTree(Deserializer &deserializer, const ON_BrepFace &face) :
+    m_face(&face),
+    m_root(NULL),
+    m_stl(new Stl),
+    m_sortedX_indices(NULL)
+{
+    m_root = new BRNode(deserializer, *m_face->Brep());
+
+    std::list<const BRNode *> temp;
+    getLeaves(temp);
+    temp.sort(sortX);
+    m_stl->m_sortedX.insert(m_stl->m_sortedX.end(), temp.begin(), temp.end());
+}
+
+
+void
+CurveTree::serialize(Serializer &serializer) const
+{
+    m_root->serialize(serializer);
+}
+
+
+std::vector<std::size_t>
+CurveTree::serialize_get_leaves_keys(const std::list<const BRNode *> &leaves) 
const
+{
+    if (!m_sortedX_indices) {
+       m_sortedX_indices = new std::map<const BRNode *, std::size_t>;
+       std::size_t index = 0;
+
+       for (std::vector<const BRNode *>::const_iterator it = 
m_stl->m_sortedX.begin(); it != m_stl->m_sortedX.end(); ++it, ++index)
+           m_sortedX_indices->insert(std::make_pair(*it, index));
+    }
+
+    std::vector<std::size_t> result;
+
+    for (std::list<const BRNode *>::const_iterator it = leaves.begin(); it != 
leaves.end(); ++it)
+       result.push_back(m_sortedX_indices->at(*it));
+
+    return result;
+}
+
+
+std::list<const BRNode *>
+CurveTree::serialize_get_leaves(const std::size_t *keys, std::size_t num_keys) 
const
+{
+    std::list<const BRNode *> result;
+
+    for (std::size_t i = 0; i < num_keys; ++i)
+       result.push_back(m_stl->m_sortedX.at(keys[i]));
+
+    return result;
+}
+
+
+void
+CurveTree::serialize_cleanup() const
+{
+    delete m_sortedX_indices;
+    m_sortedX_indices = NULL;
+}
+
+
 const BRNode*
 CurveTree::getRootNode() const
 {
@@ -296,7 +363,7 @@
 {
     point_t bmin, bmax;
     double dist;
-    for (std::list<const BRNode*>::const_iterator i = m_sortedX->begin(); i != 
m_sortedX->end(); i++) {
+    for (std::vector<const BRNode*>::const_iterator i = 
m_stl->m_sortedX.begin(); i != m_stl->m_sortedX.end(); i++) {
        const BRNode* br = *i;
        br->GetBBox(bmin, bmax);
 
@@ -316,7 +383,7 @@
 CurveTree::getLeavesAbove(std::list<const BRNode*>& out_leaves, const 
ON_2dPoint& pt, fastf_t tol) const
 {
     point_t bmin, bmax;
-    for (std::list<const BRNode*>::const_iterator i = m_sortedX->begin(); i != 
m_sortedX->end(); i++) {
+    for (std::vector<const BRNode*>::const_iterator i = 
m_stl->m_sortedX.begin(); i != m_stl->m_sortedX.end(); i++) {
        const BRNode* br = *i;
        br->GetBBox(bmin, bmax);
 
@@ -336,7 +403,7 @@
 {
     point_t bmin, bmax;
     double dist;
-    for (std::list<const BRNode*>::const_iterator i = m_sortedX->begin(); i != 
m_sortedX->end(); i++) {
+    for (std::vector<const BRNode*>::const_iterator i = 
m_stl->m_sortedX.begin(); i != m_stl->m_sortedX.end(); i++) {
        const BRNode* br = *i;
        br->GetBBox(bmin, bmax);
 
@@ -356,7 +423,7 @@
 CurveTree::getLeavesRight(std::list<const BRNode*>& out_leaves, const 
ON_2dPoint& pt, fastf_t tol) const
 {
     point_t bmin, bmax;
-    for (std::list<const BRNode*>::const_iterator i = m_sortedX->begin(); i != 
m_sortedX->end(); i++) {
+    for (std::vector<const BRNode*>::const_iterator i = 
m_stl->m_sortedX.begin(); i != m_stl->m_sortedX.end(); i++) {
        const BRNode* br = *i;
        br->GetBBox(bmin, bmax);
 
@@ -409,14 +476,14 @@
 
 
 BRNode*
-CurveTree::curveBBox(const ON_Curve* curve, int adj_face_index, const 
ON_Interval& t, bool isLeaf, bool innerTrim, const ON_BoundingBox& bb) const
+CurveTree::curveBBox(const ON_Curve* curve, int trim_index, int 
adj_face_index, const ON_Interval& t, bool isLeaf, bool innerTrim, const 
ON_BoundingBox& bb) const
 {
     BRNode* node;
     bool vdot = true;
 
     if (isLeaf) {
        TRACE("creating leaf: u(" << u.Min() << ", " << u.Max() << ") v(" << 
v.Min() << ", " << v.Max() << ")");
-       node = new BRNode(curve, adj_face_index, bb, m_face, t, vdot, 
innerTrim, false);
+       node = new BRNode(curve, trim_index, adj_face_index, bb, m_face, t, 
vdot, innerTrim, false);
     } else {
        node = new BRNode(bb);
     }
@@ -426,14 +493,14 @@
 }
 
 
-BRNode*
-CurveTree::initialLoopBBox() const
+ON_BoundingBox
+CurveTree::initialLoopBBox(const ON_BrepFace &face)
 {
     ON_BoundingBox bb;
-    m_face->SurfaceOf()->GetBBox(bb[0], bb[1]);
+    face.SurfaceOf()->GetBBox(bb[0], bb[1]);
 
-    for (int i = 0; i < m_face->LoopCount(); i++) {
-       const ON_BrepLoop* loop = m_face->Loop(i);
+    for (int i = 0; i < face.LoopCount(); i++) {
+       const ON_BrepLoop* loop = face.Loop(i);
        if (loop->m_type == ON_BrepLoop::outer) {
            if (loop->GetBBox(bb[0], bb[1], 0)) {
                TRACE("BBox for Loop min<" << bb[0][0] << ", " << bb[0][1] ", " 
<< bb[0][2] << ">");
@@ -442,13 +509,13 @@
            break;
        }
     }
-    BRNode* node = new BRNode(bb);
-    return node;
+
+    return bb;
 }
 
 
 BRNode*
-CurveTree::subdivideCurve(const ON_Curve* curve, int adj_face_index, double 
min, double max, bool innerTrim, int divDepth) const
+CurveTree::subdivideCurve(const ON_Curve* curve, int trim_index, int 
adj_face_index, double min, double max, bool innerTrim, int divDepth) const
 {
     ON_Interval dom = curve->Domain();
     ON_3dPoint points[2];
@@ -484,14 +551,14 @@
        bb.Set(pnt, false);
        VMOVE(pnt, maxpt);
        bb.Set(pnt, true);
-       return curveBBox(curve, adj_face_index, t, true, innerTrim, bb);
+       return curveBBox(curve, trim_index, adj_face_index, t, true, innerTrim, 
bb);
     }
 
     // else subdivide
-    BRNode* parent = curveBBox(curve, adj_face_index, t, false, innerTrim, bb);
+    BRNode* parent = curveBBox(curve, trim_index, adj_face_index, t, false, 
innerTrim, bb);
     double mid = (max+min)/2.0;
-    BRNode* l = subdivideCurve(curve, adj_face_index, min, mid, innerTrim, 
divDepth+1);
-    BRNode* r = subdivideCurve(curve, adj_face_index, mid, max, innerTrim, 
divDepth+1);
+    BRNode* l = subdivideCurve(curve, trim_index, adj_face_index, min, mid, 
innerTrim, divDepth+1);
+    BRNode* r = subdivideCurve(curve, trim_index, adj_face_index, mid, max, 
innerTrim, divDepth+1);
     parent->addChild(l);
     parent->addChild(r);
     return parent;
@@ -691,7 +758,7 @@
 int
 brep_getSurfacePoint(const ON_3dPoint& pt, ON_2dPoint& uv, const BBNode* node) 
{
     plane_ray pr;
-    const ON_Surface *surf = node->m_face->SurfaceOf();
+    const ON_Surface *surf = node->get_face().SurfaceOf();
     double umin, umax;
     double vmin, vmax;
     surf->GetDomain(0, &umin, &umax);
@@ -878,7 +945,7 @@
        */
        TRACE("creating leaf: u(" << u.Min() << ", " << u.Max() <<
              ") v(" << v.Min() << ", " << v.Max() << ")");
-       node = new BBNode(m_ctree, ON_BoundingBox(ON_3dPoint(min), 
ON_3dPoint(max)), m_face, u, v, false, false);
+       node = new BBNode(m_ctree, ON_BoundingBox(ON_3dPoint(min), 
ON_3dPoint(max)), u, v, false, false);
        node->prepTrims();
 
     } else {
@@ -887,15 +954,14 @@
 
     node->m_estimate = estimate;
     node->m_normal = normal;
-    node->m_face = m_face;
     node->m_u = u;
     node->m_v = v;
     return node;
 }
 
 
-BBNode*
-initialBBox(const CurveTree* ctree, const ON_Surface* surf, const ON_BrepFace* 
face, const ON_Interval& u, const ON_Interval& v)
+HIDDEN BBNode*
+initialBBox(const CurveTree* ctree, const ON_Surface* surf, const ON_Interval& 
u, const ON_Interval& v)
 {
 #ifdef _OLD_SUBDIVISION_
     ON_BoundingBox bb = surf->BoundingBox();
@@ -905,7 +971,7 @@
        return NULL;
     }
 #endif
-    BBNode* node = new BBNode(ctree, bb, face, u, v, false, false);
+    BBNode* node = new BBNode(ctree, bb, u, v, false, false);
     ON_3dPoint estimate;
     ON_3dVector normal;
     if (!surface_EvNormal(surf,surf->Domain(0).Mid(), surf->Domain(1).Mid(), 
estimate, normal)) {
@@ -913,7 +979,6 @@
     }
     node->m_estimate = estimate;
     node->m_normal = normal;
-    node->m_face = face;
     node->m_u = u;
     node->m_v = v;
     return node;
@@ -1048,7 +1113,7 @@
 #ifdef _OLD_SUBDIVISION_
        int spanu_cnt = localsurf->SpanCount(0);
        int spanv_cnt = localsurf->SpanCount(1);
-       parent = initialBBox(m_ctree, localsurf, m_face, u, v);
+       parent = initialBBox(m_ctree, localsurf, u, v);
        if (spanu_cnt > 1) {
            double *spanu = new double[spanu_cnt+1];
            localsurf->GetSpanVector(0, spanu);
@@ -1082,7 +1147,7 @@
                do_v_split = 1;
            }
        }
-       parent = initialBBox(m_ctree, localsurf, m_face, u, v);
+       parent = initialBBox(m_ctree, localsurf, u, v);
 #endif
     }
     // Flatness
@@ -1090,7 +1155,7 @@
        bool isUFlat = isFlatU(frames);
        bool isVFlat = isFlatV(frames);
 
-       parent = (divDepth == 0) ? initialBBox(m_ctree, localsurf, m_face, u, 
v) : surfaceBBox(localsurf, false, frames, u, v, within_distance_tol);
+       parent = (divDepth == 0) ? initialBBox(m_ctree, localsurf, u, v) : 
surfaceBBox(localsurf, false, frames, u, v, within_distance_tol);
 
        if ((!isVFlat || (width/height > ratio)) && (!isUFlat || (height/width 
> ratio))) {
            do_both_splits = 1;

Index: brlcad/trunk/src/libged/polyclip.cpp
===================================================================
--- brlcad/trunk/src/libged/polyclip.cpp        2016-09-29 16:23:24 UTC (rev 
68933)
+++ brlcad/trunk/src/libged/polyclip.cpp        2016-09-30 03:29:52 UTC (rev 
68934)

Property changes on: brlcad/trunk/src/libged/polyclip.cpp
___________________________________________________________________
Modified: svn:mergeinfo
## -3,3 +3,4 ##
 /brlcad/branches/bullet/src/libged/polyclip.cpp:62518
 /brlcad/branches/gct/src/libged/polyclip.cpp:62423-62425
 /brlcad/branches/osg/src/libged/polyclip.cpp:62110-62113
+/brlcad/branches/prep-cache/src/libged/polyclip.cpp:68236-68933
\ No newline at end of property
Modified: brlcad/trunk/src/librt/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/librt/CMakeLists.txt       2016-09-29 16:23:24 UTC (rev 
68933)
+++ brlcad/trunk/src/librt/CMakeLists.txt       2016-09-30 03:29:52 UTC (rev 
68934)
@@ -33,6 +33,7 @@
   binunif/db5_bin.c
   bool.c
   bundle.c
+  cache.c
   cmd.c
   comb/comb.c
   comb/comb_brep.cpp

Copied: brlcad/trunk/src/librt/cache.c (from rev 68933, 
brlcad/branches/prep-cache/src/librt/cache.c)
===================================================================
--- brlcad/trunk/src/librt/cache.c                              (rev 0)
+++ brlcad/trunk/src/librt/cache.c      2016-09-30 03:29:52 UTC (rev 68934)
@@ -0,0 +1,342 @@
+/*                         C A C H E . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2016 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file cache.c
+ *
+ * Caching of prep data
+ *
+ */
+
+
+#include "common.h"
+
+#include "cache.h"
+
+#include "bu/cv.h"
+#include "bu/log.h"
+#include "bu/str.h"
+#include "bu/uuid.h"
+#include "pstdint.h"
+#include "rt/db_attr.h"
+#include "rt/db_io.h"
+#include "rt/func.h"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <zlib.h>
+
+
+static const char * const cache_mime_type = "brlcad/cache";
+
+
+struct rt_cache {
+    struct db_i *dbip;
+};
+
+
+HIDDEN void
+rt_cache_check(const struct rt_cache *cache)
+{
+    if (!cache)
+       bu_bomb("NULL rt_cache pointer");
+
+    RT_CK_DBI(cache->dbip);
+}
+
+
+HIDDEN void
+rt_cache_generate_name(char name[STATIC_ARRAY(37)], const struct soltab *stp)
+{
+    struct bu_external raw_external;
+    struct db5_raw_internal raw_internal;
+    uint8_t namespace_uuid[16];
+    uint8_t uuid[16];
+
+    RT_CK_SOLTAB(stp);
+
+    {
+       const uint8_t base_namespace_uuid[16] = {0x4a, 0x3e, 0x13, 0x3f, 0x1a, 
0xfc, 0x4d, 0x6c, 0x9a, 0xdd, 0x82, 0x9b, 0x7b, 0xb6, 0xc6, 0xc1};
+       char mat_buffer[SIZEOF_NETWORK_DOUBLE * ELEMENTS_PER_MAT];
+
+       bu_cv_htond((unsigned char *)mat_buffer,
+                   (unsigned char *)(stp->st_matp ? stp->st_matp : 
bn_mat_identity),
+                   ELEMENTS_PER_MAT);
+
+       if (5 != bu_uuid_create(namespace_uuid, sizeof(mat_buffer),
+                               (const uint8_t *)mat_buffer, 
base_namespace_uuid))
+           bu_bomb("bu_uuid_create() failed");
+    }
+
+    if (db_get_external(&raw_external, stp->st_dp, stp->st_rtip->rti_dbip))
+       bu_bomb("db_get_external() failed");
+
+    if (db5_get_raw_internal_ptr(&raw_internal, raw_external.ext_buf) == NULL)
+       bu_bomb("rt_db_external5_to_internal5() failed");
+
+    if (5 != bu_uuid_create(uuid, raw_internal.body.ext_nbytes,
+                           raw_internal.body.ext_buf, namespace_uuid))
+       bu_bomb("bu_uuid_create() failed");
+
+    if (bu_uuid_encode(uuid, (uint8_t *)name))
+       bu_bomb("bu_uuid_encode() failed");
+
+    bu_free_external(&raw_external);
+}
+
+
+struct rt_cache *
+rt_cache_open(void)
+{
+    const char * const path = "rt_cache.tmp";
+    const int create = !bu_file_exists(path, NULL);
+    struct rt_cache *result;
+
+    BU_GET(result, struct rt_cache);
+
+    result->dbip = create ? db_create(path, 5) : db_open(path, 
DB_OPEN_READWRITE);
+
+    if (!result->dbip || (!create && db_dirbuild(result->dbip))) {
+       db_close(result->dbip);
+       BU_PUT(result, struct rt_cache);
+       return NULL;
+    }
+
+    return result;
+}
+
+
+void
+rt_cache_close(struct rt_cache *cache)
+{
+    rt_cache_check(cache);
+
+    db_close(cache->dbip);
+    BU_PUT(cache, struct rt_cache);
+}
+
+
+HIDDEN void
+compress_external(struct bu_external *external)
+{
+    uint8_t *buffer;
+    size_t compressed_size;
+    BU_CK_EXTERNAL(external);
+
+    compressed_size = compressBound(external->ext_nbytes);
+    buffer = (uint8_t *)bu_malloc(compressed_size + SIZEOF_NETWORK_LONG, 
"buffer");
+
+    *(uint32_t *)buffer = htonl(external->ext_nbytes);
+
+    if (Z_OK != compress(buffer + SIZEOF_NETWORK_LONG, &compressed_size,
+                        external->ext_buf, external->ext_nbytes))
+       bu_bomb("compress() failed");
+
+    bu_free(external->ext_buf, "ext_buf");
+    external->ext_nbytes = compressed_size + SIZEOF_NETWORK_LONG;
+    external->ext_buf = buffer;
+}
+
+
+HIDDEN void
+uncompress_external(const struct bu_external *external,
+                   struct bu_external *dest)
+{
+    uint8_t *buffer;
+
+    BU_CK_EXTERNAL(external);
+
+    BU_EXTERNAL_INIT(dest);
+
+    dest->ext_nbytes = ntohl(*(uint32_t *)external->ext_buf);
+    buffer = (uint8_t *)bu_malloc(dest->ext_nbytes, "buffer");
+
+    if (Z_OK != uncompress(buffer, &dest->ext_nbytes,
+                          external->ext_buf + SIZEOF_NETWORK_LONG,
+                          external->ext_nbytes - SIZEOF_NETWORK_LONG))
+       bu_bomb("uncompress() failed");
+
+    dest->ext_buf = buffer;
+}
+
+
+HIDDEN int
+rt_cache_try_load(const struct rt_cache *cache,
+                 const struct directory *cache_dir, struct soltab *stp,
+                 const struct rt_db_internal *internal)
+{
+    struct bu_external data_external = BU_EXTERNAL_INIT_ZERO;
+    uint32_t version = UINT32_MAX;
+
+    rt_cache_check(cache);
+    RT_CK_DIR(cache_dir);
+    RT_CK_SOLTAB(stp);
+
+    if (stp->st_specific)
+       bu_bomb("already prepped");
+
+    if (cache_dir->d_major_type != DB5_MAJORTYPE_BINARY_MIME
+       || cache_dir->d_minor_type != 0)
+       bu_bomb("invalid object type");
+
+    {
+       struct bu_external raw_external;
+       struct db5_raw_internal raw_internal;
+
+       if (db_get_external(&raw_external, cache_dir, cache->dbip))
+           bu_bomb("db_get_external() failed");
+
+       if (db5_get_raw_internal_ptr(&raw_internal, raw_external.ext_buf) == 
NULL)
+           bu_bomb("rt_db_external5_to_internal5() failed");
+
+       {
+           struct bu_attribute_value_set attributes;
+           const char *version_str;
+
+           if (0 > db5_import_attributes(&attributes, 
&raw_internal.attributes))
+               bu_bomb("db5_import_attributes() failed");
+
+           if (bu_strcmp(cache_mime_type, bu_avs_get(&attributes, 
"mime_type")))
+               bu_bomb("invalid MIME type");
+
+           if (!(version_str = bu_avs_get(&attributes, "rt_cache::version")))
+               bu_bomb("missing version");
+
+           {
+               const char *endptr;
+
+               errno = 0;
+               version = strtol(version_str, (char **)&endptr, 10);
+
+               if ((version == 0 && errno) || endptr == version_str || *endptr)
+                   bu_bomb("invalid version");
+           }
+
+           bu_avs_free(&attributes);
+       }
+
+       uncompress_external(&raw_internal.body, &data_external);
+       bu_free_external(&raw_external);
+    }
+
+    if (rt_obj_prep_serialize(stp, internal, &data_external, &version)) {
+       bu_free_external(&data_external);
+       return 0;
+    }
+
+    bu_free_external(&data_external);
+    return 1;
+}
+
+
+HIDDEN void
+rt_cache_try_store(struct rt_cache *cache, struct directory *cache_dir,
+                  struct soltab *stp, const struct rt_db_internal *internal)
+{
+    struct bu_external attributes_external;
+    struct bu_external data_external = BU_EXTERNAL_INIT_ZERO;
+    uint32_t version = UINT32_MAX;
+
+    rt_cache_check(cache);
+    RT_CK_DIR(cache_dir);
+    RT_CK_SOLTAB(stp);
+
+    if (!stp->st_specific)
+       bu_bomb("not prepped");
+
+    cache_dir->d_major_type = DB5_MAJORTYPE_BINARY_MIME;
+    cache_dir->d_minor_type = 0;
+
+    if (rt_obj_prep_serialize(stp, internal, &data_external, &version)
+       || version == UINT32_MAX)
+       bu_bomb("rt_obj_prep_serialize() failed");
+
+    compress_external(&data_external);
+
+    {
+       struct bu_attribute_value_set attributes = BU_AVS_INIT_ZERO;
+       struct bu_vls version_vls = BU_VLS_INIT_ZERO;
+
+       bu_vls_sprintf(&version_vls, "%" PRINTF_INT32_MODIFIER "u", version);
+       bu_avs_add(&attributes, "mime_type", cache_mime_type);
+       bu_avs_add(&attributes, "rt_cache::version", bu_vls_addr(&version_vls));
+       db5_export_attributes(&attributes_external, &attributes);
+       bu_vls_free(&version_vls);
+       bu_avs_free(&attributes);
+    }
+
+    {
+       struct bu_external db_external;
+       db5_export_object3(&db_external, 0, cache_dir->d_namep, 0, 
&attributes_external,
+                          &data_external, cache_dir->d_major_type, 
cache_dir->d_minor_type,
+                          DB5_ZZZ_UNCOMPRESSED, DB5_ZZZ_UNCOMPRESSED);
+
+       if (db_put_external(&db_external, cache_dir, cache->dbip))
+           bu_bomb("db_put_external() failed");
+    }
+
+    bu_free_external(&attributes_external);
+    bu_free_external(&data_external);
+}
+
+
+int
+rt_cache_prep(struct rt_cache *cache, struct soltab *stp,
+             struct rt_db_internal *internal)
+{
+    char name[37];
+    struct directory *dir;
+
+    rt_cache_check(cache);
+    RT_CK_SOLTAB(stp);
+    RT_CK_DB_INTERNAL(internal);
+
+    rt_cache_generate_name(name, stp);
+    dir = db_lookup(cache->dbip, name, 0);
+
+    if (dir) {
+       if (!rt_cache_try_load(cache, dir, stp, internal))
+           bu_bomb("rt_cache_try_load() failed");
+    } else {
+       char type = 0;
+
+       if (rt_obj_prep(stp, internal, stp->st_rtip))
+           bu_bomb("rt_obj_prep() failed");
+
+       if (OBJ[stp->st_id].ft_prep_serialize) {
+           if (!(dir = db_diradd(cache->dbip, name, RT_DIR_PHONY_ADDR, 0, 
RT_DIR_NON_GEOM,
+                                 (void *)&type)))
+               bu_bomb("db_diradd() failed");
+
+           rt_cache_try_store(cache, dir, stp, internal);
+       }
+    }
+
+    return 1;
+}
+
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Copied: brlcad/trunk/src/librt/cache.h (from rev 68933, 
brlcad/branches/prep-cache/src/librt/cache.h)
===================================================================
--- brlcad/trunk/src/librt/cache.h                              (rev 0)
+++ brlcad/trunk/src/librt/cache.h      2016-09-30 03:29:52 UTC (rev 68934)
@@ -0,0 +1,64 @@
+/*                         C A C H E . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2016 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file cache.h
+ *
+ * Caching of prep data
+ *
+ */
+
+
+#ifndef LIBRT_CACHE_H
+#define LIBRT_CACHE_H
+
+
+#include "common.h"
+
+#include "rt/db_internal.h"
+#include "rt/soltab.h"
+
+
+__BEGIN_DECLS
+
+
+struct rt_cache;
+
+struct rt_cache *rt_cache_open(void);
+void rt_cache_close(struct rt_cache *cache);
+
+/* rt_cache_prep() is thread-safe */
+int rt_cache_prep(struct rt_cache *cache, struct soltab *stp,
+                 struct rt_db_internal *ip);
+
+
+__END_DECLS
+
+
+#endif
+
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Modified: brlcad/trunk/src/librt/primitives/brep/brep.cpp
===================================================================
--- brlcad/trunk/src/librt/primitives/brep/brep.cpp     2016-09-29 16:23:24 UTC 
(rev 68933)
+++ brlcad/trunk/src/librt/primitives/brep/brep.cpp     2016-09-30 03:29:52 UTC 
(rev 68934)
@@ -97,6 +97,7 @@
 struct rt_selection_set *rt_brep_find_selections(const struct rt_db_internal 
*ip, const struct rt_selection_query *query);
 int rt_brep_process_selection(struct rt_db_internal *ip, const struct 
rt_selection *selection, const struct rt_selection_operation *op);
 int rt_brep_valid(struct rt_db_internal *ip, struct bu_vls *log);
+int rt_brep_prep_serialize(struct soltab *stp, const struct rt_db_internal 
*ip, struct bu_external *external, uint32_t *version);
 #ifdef __cplusplus
 }
 #endif
@@ -1212,7 +1213,7 @@
 
     for (std::list<const BBNode*>::const_iterator i = inters.begin(); i != 
inters.end(); i++) {
        const BBNode* sbv = (*i);
-       const ON_BrepFace* f = sbv->m_face;
+       const ON_BrepFace* f = &sbv->get_face();
        const ON_Surface* surf = f->SurfaceOf();
        pt2d_t uv = {sbv->m_u.Mid(), sbv->m_v.Mid()};
        utah_brep_intersect(sbv, f, surf, uv, r, all_hits);
@@ -1623,7 +1624,7 @@
                if (out.hit == brep_hit::NEAR_MISS) bu_log("_NM_(%d)", 
out.face.m_face_index);
                if (out.direction == brep_hit::ENTERING) bu_log("+");
                if (out.direction == brep_hit::LEAVING) bu_log("-");
-               bu_log("<%d>", out.sbv->m_face->m_bRev);
+               bu_log("<%d>", out.sbv->get_face().m_bRev);
 
                bu_log(")");
            }
@@ -1762,9 +1763,9 @@
 
     }
 
-    for (size_t i = 0; i < node->m_children->size(); i++) {
+    for (size_t i = 0; i < node->get_children().size(); i++) {
        if (i < 1) {
-           std::vector<brlcad::BBNode*> &nodes = *node->m_children;
+           const std::vector<brlcad::BBNode*> &nodes = node->get_children();
            plot_bbnode(nodes[i], vhead, depth + 1, start, limit);
        }
     }
@@ -2124,7 +2125,7 @@
            return;
        }
     } else {
-           for (std::vector<BBNode*>::const_iterator childnode = 
node->m_children->begin(); childnode != node->m_children->end(); ++childnode) {
+           for (std::vector<BBNode*>::const_iterator childnode = 
node->get_children().begin(); childnode != node->get_children().end(); 
++childnode) {
                plot_BBNode(vhead, st, *childnode, isocurveres, gridres);
            }
     }
@@ -5030,6 +5031,83 @@
     return 0;
 }
 
+
+int
+rt_brep_prep_serialize(struct soltab *stp, const struct rt_db_internal *ip, 
struct bu_external *external, uint32_t *version)
+{
+    RT_CK_SOLTAB(stp);
+    RT_CK_DB_INTERNAL(ip);
+    BU_CK_EXTERNAL(external);
+
+    const uint32_t current_version = 0;
+
+    RT_CK_SOLTAB(stp);
+    BU_CK_EXTERNAL(external);
+
+    if (stp->st_specific) {
+       /* export to external */
+
+       const brep_specific &specific = *static_cast<brep_specific 
*>(stp->st_specific);
+
+       Serializer serializer;
+       serializer.write_uint32(specific.bvh->get_children().size());
+
+       for (std::vector<BBNode *>::const_iterator it = 
specific.bvh->get_children().begin(); it != specific.bvh->get_children().end(); 
++it) {
+           (*it)->m_ctree->serialize(serializer);
+           (*it)->serialize(serializer);
+       }
+
+       *version = current_version;
+       *external = serializer.take();
+       return 0;
+    } else {
+       /* load from external */
+
+       if (*version != current_version)
+           return 1;
+
+       brep_specific * const specific = brep_specific_new();
+       stp->st_specific = specific;
+       std::swap(specific->brep, static_cast<rt_brep_internal 
*>(ip->idb_ptr)->brep);
+       specific->bvh = new BBNode(specific->brep->BoundingBox());
+
+       Deserializer deserializer(*external);
+       const uint32_t num_children = deserializer.read_uint32();
+
+       for (uint32_t i = 0; i < num_children; ++i) {
+           const CurveTree * const ctree = new CurveTree(deserializer, 
*specific->brep->m_F.At(i));
+           specific->bvh->addChild(new BBNode(deserializer, *ctree));
+       }
+
+       specific->bvh->BuildBBox();
+
+       {
+           /* Once a proper SurfaceTree is built, finalize the bounding
+            * volumes.  This takes no time. */
+           specific->bvh->GetBBox(stp->st_min, stp->st_max);
+
+           // expand outer bounding box just a little bit
+           const struct bn_tol *tol = &stp->st_rtip->rti_tol;
+           point_t adjust;
+           VSETALL(adjust, tol->dist < SMALL_FASTF ? SMALL_FASTF : tol->dist);
+           VSUB2(stp->st_min, stp->st_min, adjust);
+           VADD2(stp->st_max, stp->st_max, adjust);
+
+           VADD2SCALE(stp->st_center, stp->st_min, stp->st_max, 0.5);
+           vect_t work;
+           VSUB2SCALE(work, stp->st_max, stp->st_min, 0.5);
+           fastf_t f = work[X];
+           V_MAX(f, work[Y]);
+           V_MAX(f, work[Z]);
+           stp->st_aradius = f;
+           stp->st_bradius = MAGNITUDE(work);
+       }
+
+       return 0;
+    }
+}
+
+
 /** @} */
 
 /*

Modified: brlcad/trunk/src/librt/primitives/brep/brep_debug.cpp
===================================================================
--- brlcad/trunk/src/librt/primitives/brep/brep_debug.cpp       2016-09-29 
16:23:24 UTC (rev 68933)
+++ brlcad/trunk/src/librt/primitives/brep/brep_debug.cpp       2016-09-30 
03:29:52 UTC (rev 68934)
@@ -283,7 +283,7 @@
     point_t a, b;
     ON_3dPoint p;
     const BRNode* trimBR = NULL;
-    const ON_BrepFace* f = bb->m_face;
+    const ON_BrepFace* f = &bb->get_face();
     const ON_Surface* surf = f->SurfaceOf();
     fastf_t uinc = (bb->m_u[1] - bb->m_u[0])/100.0;
     fastf_t vinc = (bb->m_v[1] - bb->m_v[0])/100.0;
@@ -2355,9 +2355,9 @@
            return;
        }
     } else {
-       if (!node->m_children->empty()) {
-           for (std::vector<BBNode*>::const_iterator childnode = 
node->m_children->begin(); childnode
-                    != node->m_children->end(); childnode++) {
+       if (!node->get_children().empty()) {
+           for (std::vector<BBNode*>::const_iterator childnode = 
node->get_children().begin(); childnode
+                    != node->get_children().end(); childnode++) {
                drawBBNode(st, vbp, *childnode);
            }
        }

Modified: brlcad/trunk/src/librt/primitives/obj_prep.c
===================================================================
--- brlcad/trunk/src/librt/primitives/obj_prep.c        2016-09-29 16:23:24 UTC 
(rev 68933)
+++ brlcad/trunk/src/librt/primitives/obj_prep.c        2016-09-30 03:29:52 UTC 
(rev 68934)
@@ -51,6 +51,32 @@
 }
 
 
+int rt_obj_prep_serialize(struct soltab *stp, const struct rt_db_internal *ip, 
struct bu_external *external, uint32_t *version)
+{
+    const struct rt_functab *ft;
+
+    if (!stp || !ip || !external || !version)
+       return -1;
+
+    RT_CK_SOLTAB(stp);
+    RT_CK_DB_INTERNAL(ip);
+    BU_CK_EXTERNAL(external);
+
+    if (stp->st_id < 0)
+       return -2;
+
+    ft = &OBJ[stp->st_id];
+
+    if (!ft)
+       return -3;
+
+    if (!ft->ft_prep_serialize)
+       return -4;
+
+    return ft->ft_prep_serialize(stp, ip, external, version);
+}
+
+
 /*
  * Local Variables:
  * mode: C

Modified: brlcad/trunk/src/librt/primitives/table.c
===================================================================
--- brlcad/trunk/src/librt/primitives/table.c   2016-09-29 16:23:24 UTC (rev 
68933)
+++ brlcad/trunk/src/librt/primitives/table.c   2016-09-30 03:29:52 UTC (rev 
68934)
@@ -77,7 +77,8 @@
     extern int rt_##name##_oriented_bbox(struct rt_arb_internal *bbox, struct 
rt_db_internal *ip, const fastf_t tol); \
     extern struct rt_selection_set *rt_##name##_find_selections(const struct 
rt_db_internal *ip, const struct rt_selection_query *query); \
     extern struct rt_selection *rt_##name##_evaluate_selection(const struct 
rt_db_internal *ip, int op, const struct rt_selection *a, const struct 
rt_selection *b); \
-    extern int rt_##name##_process_selection(struct rt_db_internal *ip, struct 
db_i *, const struct rt_selection *selection, const struct 
rt_selection_operation *op)
+    extern int rt_##name##_process_selection(struct rt_db_internal *ip, struct 
db_i *, const struct rt_selection *selection, const struct 
rt_selection_operation *op); \
+    extern int rt_##name##_prep_serialize(struct soltab *stp, const struct 
rt_db_internal *ip, struct bu_external *external, uint32_t *version)
 
 RT_DECLARE_INTERFACE(tor);
 RT_DECLARE_INTERFACE(tgc);
@@ -197,6 +198,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -242,6 +244,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -287,6 +290,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -332,6 +336,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -377,6 +382,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -422,6 +428,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -467,6 +474,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -512,6 +520,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -557,6 +566,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -602,6 +612,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -647,6 +658,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -692,6 +704,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -737,6 +750,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -782,6 +796,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -827,6 +842,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -872,6 +888,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -917,6 +934,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -962,6 +980,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1007,6 +1026,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1052,6 +1072,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1097,6 +1118,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1142,6 +1164,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1187,6 +1210,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1232,7 +1256,8 @@
        NULL,
        RTFUNCTAB_FUNC_FIND_SELECTIONS_CAST(rt_joint_find_selections),
        NULL,
-       RTFUNCTAB_FUNC_PROCESS_SELECTION_CAST(rt_joint_process_selection)
+       RTFUNCTAB_FUNC_PROCESS_SELECTION_CAST(rt_joint_process_selection),
+       NULL
 #if 0
        0, /* ft_use_rpp */
        NULL,/* prep */
@@ -1319,6 +1344,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1364,6 +1390,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1409,6 +1436,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1454,6 +1482,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1499,6 +1528,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1544,6 +1574,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1589,6 +1620,7 @@
        RTFUNCTAB_FUNC_ORIENTED_BBOX_CAST(rt_bot_oriented_bbox),
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1634,6 +1666,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1681,6 +1714,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1726,6 +1760,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1773,6 +1808,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1818,6 +1854,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1863,6 +1900,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1908,7 +1946,8 @@
        NULL,
        RTFUNCTAB_FUNC_FIND_SELECTIONS_CAST(rt_brep_find_selections),
        NULL,
-       RTFUNCTAB_FUNC_PROCESS_SELECTION_CAST(rt_brep_process_selection)
+       RTFUNCTAB_FUNC_PROCESS_SELECTION_CAST(rt_brep_process_selection),
+        RTFUNCTAB_FUNC_PREP_SERIALIZE_CAST(rt_brep_prep_serialize)
     },
 
     {
@@ -1953,6 +1992,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -1998,6 +2038,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2043,6 +2084,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2088,6 +2130,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2133,6 +2176,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2178,6 +2222,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2224,6 +2269,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     },
 
@@ -2269,6 +2315,7 @@
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
     }
 };

Modified: brlcad/trunk/src/librt/tree.c
===================================================================
--- brlcad/trunk/src/librt/tree.c       2016-09-29 16:23:24 UTC (rev 68933)
+++ brlcad/trunk/src/librt/tree.c       2016-09-30 03:29:52 UTC (rev 68934)
@@ -27,6 +27,7 @@
 #include "bio.h"
 
 
+#include "cache.h"
 #include "bu/parallel.h"
 #include "vmath.h"
 #include "bn.h"
@@ -122,6 +123,13 @@
 }
 
 
+struct rt_gettree_data
+{
+    struct bu_hash_tbl *tbl;
+    struct rt_cache *cache;
+};
+
+
 /**
  * This routine will be called by db_walk_tree() once all the solids
  * in this region have been visited.
@@ -140,7 +148,7 @@
     struct directory *dp = NULL;
     size_t shader_len=0;
     struct rt_i *rtip;
-    struct bu_hash_tbl *tbl = (struct bu_hash_tbl *)client_data;
+    struct bu_hash_tbl *tbl = ((struct rt_gettree_data *)client_data)->tbl;
     matp_t inv_mat;
     struct bu_attribute_value_set avs;
     struct bu_attribute_value_pair *avpp;
@@ -432,8 +440,9 @@
  * This routine must be prepared to run in parallel.
  */
 HIDDEN union tree *
-_rt_gettree_leaf(struct db_tree_state *tsp, const struct db_full_path *pathp, 
struct rt_db_internal *ip, void *UNUSED(client_data))
+_rt_gettree_leaf(struct db_tree_state *tsp, const struct db_full_path *pathp, 
struct rt_db_internal *ip, void *client_data)
 {
+    struct rt_gettree_data *data;
     struct soltab *stp;
     struct directory *dp;
     matp_t mat;
@@ -450,6 +459,12 @@
     RT_CK_RTI(rtip);
     RT_CK_RESOURCE(tsp->ts_resp);
     dp = DB_FULL_PATH_CUR_DIR(pathp);
+
+    data = (struct rt_gettree_data *)client_data;
+
+    if (!data)
+       bu_bomb("missing argument");
+
     if (!dp)
        return TREE_NULL;
 
@@ -506,11 +521,9 @@
      * that is OK, as long as idb_ptr is set to null.  Note that the
      * prep routine may have changed st_id.
      */
-    ret = -1;
-    if (stp->st_meth->ft_prep) {
-       ret = stp->st_meth->ft_prep(stp, ip, rtip);
-    }
-    if (ret != 0) {
+    ret = rt_cache_prep(data->cache, stp, ip);
+
+    if (ret != 1) {
        int hash;
        /* Error, solid no good */
        bu_log("_rt_gettree_leaf(%s):  prep failure\n", dp->d_namep);
@@ -722,6 +735,7 @@
     prev_sol_count = rtip->nsolids;
 
     {
+       struct rt_gettree_data data;
        struct db_tree_state tree_state;
 
        tree_state = rt_initial_tree_state;     /* struct copy */
@@ -757,12 +771,19 @@
            bu_avs_init_empty(&tree_state.ts_attrs);
        }
 
+       data.tbl = tbl;
+
+       if (!(data.cache = rt_cache_open()))
+           bu_bomb("rt_cache_open() failed");
+
        i = db_walk_tree(rtip->rti_dbip, argc, argv, ncpus,
                         &tree_state,
                         _rt_gettree_region_start,
                         _rt_gettree_region_end,
-                        _rt_gettree_leaf, (void *)tbl);
+                        _rt_gettree_leaf, (void *)&data);
        bu_avs_free(&tree_state.ts_attrs);
+
+       rt_cache_close(data.cache);
     }
 
     /* DEBUG:  Ensure that all region trees are valid */

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to