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