00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #if defined(_MSC_VER)
00025 #pragma once
00026 #endif
00027 
00028 #ifndef PBRT_CORE_OCTREE_H
00029 #define PBRT_CORE_OCTREE_H
00030 
00031 
00032 #include "pbrt.h"
00033 #include "geometry.h"
00034 
00035 
00036 template <typename NodeData> struct OctNode {
00037     OctNode() {
00038         for (int i = 0; i < 8; ++i)
00039             children[i] = NULL;
00040     }
00041     ~OctNode() {
00042         for (int i = 0; i < 8; ++i)
00043             delete children[i];
00044     }
00045     OctNode *children[8];
00046     vector<NodeData> data;
00047 };
00048 
00049 
00050 template <typename NodeData> class Octree {
00051 public:
00052     
00053     Octree(const BBox &b, int md = 16)
00054         : maxDepth(md), bound(b) { }
00055     void Add(const NodeData &dataItem, const BBox &dataBound) {
00056         addPrivate(&root, bound, dataItem, dataBound,
00057                    DistanceSquared(dataBound.pMin, dataBound.pMax));
00058     }
00059     template <typename LookupProc> void Lookup(const Point &p,
00060                                                LookupProc &process) {
00061         if (!bound.Inside(p)) return;
00062         lookupPrivate(&root, bound, p, process);
00063     }
00064 private:
00065     
00066     void addPrivate(OctNode<NodeData> *node, const BBox &nodeBound,
00067         const NodeData &dataItem, const BBox &dataBound, float diag2,
00068         int depth = 0);
00069     template <typename LookupProc> bool lookupPrivate(OctNode<NodeData> *node,
00070             const BBox &nodeBound, const Point &P, LookupProc &process);
00071 
00072     
00073     int maxDepth;
00074     BBox bound;
00075     OctNode<NodeData> root;
00076 };
00077 
00078 
00079 inline BBox octreeChildBound(int child, const BBox &nodeBound,
00080                              const Point &pMid) {
00081     BBox childBound;
00082     childBound.pMin.x = (child & 4) ? pMid.x : nodeBound.pMin.x;
00083     childBound.pMax.x = (child & 4) ? nodeBound.pMax.x : pMid.x;
00084     childBound.pMin.y = (child & 2) ? pMid.y : nodeBound.pMin.y;
00085     childBound.pMax.y = (child & 2) ? nodeBound.pMax.y : pMid.y;
00086     childBound.pMin.z = (child & 1) ? pMid.z : nodeBound.pMin.z;
00087     childBound.pMax.z = (child & 1) ? nodeBound.pMax.z : pMid.z;
00088     return childBound;
00089 }
00090 
00091 
00092 
00093 
00094 template <typename NodeData>
00095 void Octree<NodeData>::addPrivate(
00096         OctNode<NodeData> *node, const BBox &nodeBound,
00097         const NodeData &dataItem, const BBox &dataBound,
00098         float diag2, int depth) {
00099     
00100     if (depth == maxDepth ||
00101         DistanceSquared(nodeBound.pMin, nodeBound.pMax) < diag2) {
00102         node->data.push_back(dataItem);
00103         return;
00104     }
00105 
00106     
00107     Point pMid = .5 * nodeBound.pMin + .5 * nodeBound.pMax;
00108 
00109     
00110     bool x[2] = { dataBound.pMin.x <= pMid.x, dataBound.pMax.x > pMid.x };
00111     bool y[2] = { dataBound.pMin.y <= pMid.y, dataBound.pMax.y > pMid.y };
00112     bool z[2] = { dataBound.pMin.z <= pMid.z, dataBound.pMax.z > pMid.z };
00113     bool over[8] = { x[0] & y[0] & z[0], x[0] & y[0] & z[1],
00114                      x[0] & y[1] & z[0], x[0] & y[1] & z[1],
00115                      x[1] & y[0] & z[0], x[1] & y[0] & z[1],
00116                      x[1] & y[1] & z[0], x[1] & y[1] & z[1] };
00117     for (int child = 0; child < 8; ++child) {
00118         if (!over[child]) continue;
00119         
00120         if (!node->children[child])
00121             node->children[child] = new OctNode<NodeData>;
00122         BBox childBound = octreeChildBound(child, nodeBound, pMid);
00123         addPrivate(node->children[child], childBound,
00124                    dataItem, dataBound, diag2, depth+1);
00125     }
00126 }
00127 
00128 
00129 template <typename NodeData> template <typename LookupProc>
00130 bool Octree<NodeData>::lookupPrivate(OctNode<NodeData> *node,
00131         const BBox &nodeBound, const Point &p, LookupProc &process) {
00132     for (uint32_t i = 0; i < node->data.size(); ++i)
00133         if (!process(node->data[i]))
00134             return false;
00135     
00136     Point pMid = .5f * nodeBound.pMin + .5f * nodeBound.pMax;
00137     int child = (p.x > pMid.x ? 4 : 0) + (p.y > pMid.y ? 2 : 0) +
00138                 (p.z > pMid.z ? 1 : 0);
00139     if (!node->children[child])
00140         return true;
00141     BBox childBound = octreeChildBound(child, nodeBound, pMid);
00142     return lookupPrivate(node->children[child], childBound, p, process);
00143 }
00144 
00145 
00146 
00147 #endif // PBRT_CORE_OCTREE_H