00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef SHEEP_MATH_OCTREE_H
00024 #define SHEEP_MATH_OCTREE_H
00025
00026 #include "common/misc/minmax.h"
00027 #include "aabb3.h"
00028 #include "point3.h"
00029 #include "real.h"
00030 #include "vector3.h"
00031
00032 #include <cassert>
00033 #include <vector>
00034
00035 namespace sheep {
00036
00037 inline
00038 unsigned int choose_next(Real x, Real y, Real z,
00039 unsigned int a, unsigned int b, unsigned int c)
00040 {
00041 if(x < y) {
00042 if(x < z) return a;
00043 else return c;
00044 } else {
00045 if(y < z) return b;
00046 else return c;
00047 }
00048 }
00049
00050 template<typename Item>
00051 struct OctreeNode {
00052 AABB3 m_voxel;
00053 Point3 m_center;
00054
00055 bool m_is_leaf;
00056 OctreeNode *m_children[8];
00057
00058 typedef std::vector<Item> ItemVector;
00059 typedef typename ItemVector::const_iterator ItemVectorConstIt;
00060
00061 ItemVector m_items;
00062
00063 OctreeNode();
00064 OctreeNode(const AABB3 &voxel);
00065 ~OctreeNode();
00066
00067 template<typename ItemVoxelIntersector>
00068 void Subdivide(
00069 int pop_threshold,
00070 int remaining_subdiv,
00071 ItemVoxelIntersector &intersector)
00072 {
00073 assert(pop_threshold > 0);
00074 assert(remaining_subdiv > 0);
00075
00076 if(m_items.size() <= static_cast<typename ItemVector::size_type>(pop_threshold))
00077 return;
00078
00079 m_is_leaf = false;
00080
00081 m_children[0] = new OctreeNode<Item>(
00082 AABB3(m_voxel.m_min, m_center));
00083
00084 m_children[1] = new OctreeNode<Item>(
00085 AABB3(
00086 Point3(m_voxel.m_min.m_x, m_voxel.m_min.m_y, m_center.m_z),
00087 Point3(m_center.m_x, m_center.m_y, m_voxel.m_max.m_z)));
00088
00089 m_children[2] = new OctreeNode<Item>(
00090 AABB3(
00091 Point3(m_voxel.m_min.m_x, m_center.m_y, m_voxel.m_min.m_z),
00092 Point3(m_center.m_x, m_voxel.m_max.m_y, m_center.m_z)));
00093
00094 m_children[3] = new OctreeNode<Item>(
00095 AABB3(
00096 Point3(m_voxel.m_min.m_x, m_center.m_y, m_center.m_z),
00097 Point3(m_center.m_x, m_voxel.m_max.m_y, m_voxel.m_max.m_z)));
00098
00099 m_children[4] = new OctreeNode<Item>(
00100 AABB3(
00101 Point3(m_center.m_x, m_voxel.m_min.m_y, m_voxel.m_min.m_z),
00102 Point3(m_voxel.m_max.m_x, m_center.m_y, m_center.m_z)));
00103
00104 m_children[5] = new OctreeNode<Item>(
00105 AABB3(
00106 Point3(m_center.m_x, m_voxel.m_min.m_y, m_center.m_z),
00107 Point3(m_voxel.m_max.m_x, m_center.m_y, m_voxel.m_max.m_z)));
00108
00109 m_children[6] = new OctreeNode<Item>(
00110 AABB3(
00111 Point3(m_center.m_x, m_center.m_y, m_voxel.m_min.m_z),
00112 Point3(m_voxel.m_max.m_x, m_voxel.m_max.m_y, m_center.m_z)));
00113
00114 m_children[7] = new OctreeNode<Item>(
00115 AABB3(m_center, m_voxel.m_max));
00116
00117 for(ItemVectorConstIt i = m_items.begin(), e = m_items.end(); i != e; ++i) {
00118 const Item &item = *i;
00119
00120 for(int j = 0; j < 8; ++j) {
00121 if(intersector.Intersect(item, m_children[j]->m_voxel))
00122 m_children[j]->m_items.push_back(item);
00123 }
00124 }
00125
00126 m_items.clear();
00127
00128 if(--remaining_subdiv == 0)
00129 return;
00130
00131 for(int i = 0; i < 8; ++i)
00132 m_children[i]->Subdivide(pop_threshold, remaining_subdiv, intersector);
00133 }
00134
00135 template<typename Visitor>
00136 bool Trace(
00137 const Point3 &origin,
00138 Real tx0, Real ty0, Real tz0,
00139 Real tx1, Real ty1, Real tz1,
00140 unsigned int a,
00141 unsigned int b,
00142 Visitor &visitor) const
00143 {
00144
00145 if(tx1 < 0.0 || ty1 < 0.0 || tz1 < 0.0)
00146 return false;
00147
00148
00149 if(m_is_leaf) {
00150 Real t0 = max<Real>(tx0, ty0, tz0);
00151 Real t1 = min<Real>(tx1, ty1, tz1);
00152
00153 return visitor.Trace(this, t0, t1);
00154 }
00155
00156
00157
00158 const Real &x0 = m_voxel.m_min.m_x;
00159 const Real &y0 = m_voxel.m_min.m_y;
00160 const Real &z0 = m_voxel.m_min.m_z;
00161 const Real &x1 = m_voxel.m_max.m_x;
00162 const Real &y1 = m_voxel.m_max.m_y;
00163 const Real &z1 = m_voxel.m_max.m_z;
00164
00165 const Real INF = 1e9;
00166
00167 Real txm, tym, tzm;
00168
00169 switch(b) {
00170 case 0:
00171 txm = 0.5 * (tx0 + tx1);
00172 tym = 0.5 * (ty0 + ty1);
00173 tzm = 0.5 * (tz0 + tz1);
00174 break;
00175 case 1:
00176 txm = 0.5 * (tx0 + tx1);
00177 tym = 0.5 * (ty0 + ty1);
00178 tzm = origin.m_z < 0.5 * (z0 + z1) ? +INF : -INF;
00179 break;
00180 case 2:
00181 txm = 0.5 * (tx0 + tx1);
00182 tym = origin.m_y < 0.5 * (y0 + y1) ? +INF : -INF;
00183 tzm = 0.5 * (tz0 + tz1);
00184 break;
00185 case 3:
00186 txm = 0.5 * (tx0 + tx1);
00187 tym = origin.m_y < 0.5 * (y0 + y1) ? +INF : -INF;
00188 tzm = origin.m_z < 0.5 * (z0 + z1) ? +INF : -INF;
00189 break;
00190 case 4:
00191 txm = origin.m_x < 0.5 * (x0 + x1) ? +INF : -INF;
00192 tym = 0.5 * (ty0 + ty1);
00193 tzm = 0.5 * (tz0 + tz1);
00194 break;
00195 case 5:
00196 txm = origin.m_x < 0.5 * (x0 + x1) ? +INF : -INF;
00197 tym = 0.5 * (ty0 + ty1);
00198 tzm = origin.m_z < 0.5 * (z0 + z1) ? +INF : -INF;
00199 break;
00200 case 6:
00201 txm = origin.m_x < 0.5 * (x0 + x1) ? +INF : -INF;
00202 tym = origin.m_y < 0.5 * (y0 + y1) ? +INF : -INF;
00203 tzm = 0.5 * (tz0 + tz1);
00204 break;
00205 case 7:
00206 txm = origin.m_x < 0.5 * (x0 + x1) ? +INF : -INF;
00207 tym = origin.m_y < 0.5 * (y0 + y1) ? +INF : -INF;
00208 tzm = origin.m_z < 0.5 * (z0 + z1) ? +INF : -INF;
00209 break;
00210 default:
00211 assert(!"Internal failure.");
00212 }
00213
00214 unsigned int current_octant = 0;
00215
00216 if(tx0 > ty0) {
00217 if(tx0 > tz0) {
00218
00219 if(tym < tx0) current_octant |= 2;
00220 if(tzm < tx0) current_octant |= 1;
00221 } else {
00222
00223 if(txm < tz0) current_octant |= 4;
00224 if(tym < tz0) current_octant |= 2;
00225 }
00226 } else {
00227 if(ty0 > tz0) {
00228
00229 if(txm < ty0) current_octant |= 4;
00230 if(tzm < ty0) current_octant |= 1;
00231 } else {
00232
00233 if(txm < tz0) current_octant |= 4;
00234 if(tym < tz0) current_octant |= 2;
00235 }
00236 }
00237
00238
00239 const unsigned int END = 8;
00240
00241 while(true) {
00242 switch(current_octant) {
00243 case 0:
00244 if(m_children[a]->Trace(origin, tx0, ty0, tz0, txm, tym, tzm, a, b, visitor))
00245 return true;
00246 current_octant = choose_next(txm, tym, tzm, 4, 2, 1);
00247 break;
00248 case 1:
00249 if(m_children[1 ^ a]->Trace(origin, tx0, ty0, tzm, txm, tym, tz1, a, b, visitor))
00250 return true;
00251 current_octant = choose_next(txm, tym, tz1, 5, 3, END);
00252 break;
00253 case 2:
00254 if(m_children[2 ^ a]->Trace(origin, tx0, tym, tz0, txm, ty1, tzm, a, b, visitor))
00255 return true;
00256 current_octant = choose_next(txm, ty1, tzm, 6, END, 3);
00257 break;
00258 case 3:
00259 if(m_children[3 ^ a]->Trace(origin, tx0, tym, tzm, txm, ty1, tz1, a, b, visitor))
00260 return true;
00261 current_octant = choose_next(txm, ty1, tz1, 7, END, END);
00262 break;
00263 case 4:
00264 if(m_children[4 ^ a]->Trace(origin, txm, ty0, tz0, tx1, tym, tzm, a, b, visitor))
00265 return true;
00266 current_octant = choose_next(tx1, tym, tzm, END, 6, 5);
00267 break;
00268 case 5:
00269 if(m_children[5 ^ a]->Trace(origin, txm, ty0, tzm, tx1, tym, tz1, a, b, visitor))
00270 return true;
00271 current_octant = choose_next(tx1, tym, tz1, END, 7, END);
00272 break;
00273 case 6:
00274 if(m_children[6 ^ a]->Trace(origin, txm, tym, tz0, tx1, ty1, tzm, a, b, visitor))
00275 return true;
00276 current_octant = choose_next(tx1, ty1, tzm, END, END, 7);
00277 break;
00278 case 7:
00279 if(m_children[7 ^ a]->Trace(origin, txm, tym, tzm, tx1, ty1, tz1, a, b, visitor))
00280 return true;
00281 case END:
00282 return false;
00283 }
00284 }
00285 }
00286
00287 template<typename Visitor>
00288 void Visit(Visitor &visitor) const {
00289 visitor.Visit(this);
00290
00291 if(!m_is_leaf) {
00292 for(int i = 0; i < 8; ++i)
00293 m_children[i]->Visit(visitor);
00294 }
00295 }
00296 };
00297
00298 template<typename Item>
00299 class Octree {
00300 public:
00301 Octree();
00302 ~Octree();
00303
00304 void Insert(const Item &item, const AABB3 &aabb);
00305
00306 template<typename ItemBoxIntersector>
00307 void Subdivide(int pop_threshold, int max_subdiv, ItemBoxIntersector &intersector) {
00308 assert(m_root);
00309 assert(pop_threshold > 0);
00310 assert(max_subdiv >= 0);
00311
00312 if(max_subdiv > 0) {
00313 m_root->m_center = m_root->m_voxel.GetCenter();
00314 m_root->Subdivide(pop_threshold, max_subdiv, intersector);
00315 }
00316 }
00317
00318 const AABB3 &GetAABB() const;
00319
00320
00321 template<typename Visitor>
00322 void Hit(const Point3 &point, Visitor &visitor) const {
00323 assert(m_root);
00324
00325 Real x = point.m_x;
00326 Real y = point.m_y;
00327 Real z = point.m_z;
00328
00329 const Point3 &box_min = m_root->m_voxel.m_min;
00330 const Point3 &box_max = m_root->m_voxel.m_max;
00331
00332 if( x < box_min.m_x || x > box_max.m_x ||
00333 y < box_min.m_y || y > box_max.m_y ||
00334 z < box_min.m_z || z > box_max.m_z)
00335 return;
00336
00337 OctreeNode<Item> *node = m_root;
00338
00339 while(!node->m_is_leaf) {
00340 unsigned int octant = 0;
00341
00342 if(x >= node->m_center.m_x) octant |= 4;
00343 if(y >= node->m_center.m_y) octant |= 2;
00344 if(z >= node->m_center.m_z) octant |= 1;
00345
00346 node = node->m_children[octant];
00347 }
00348
00349 visitor.Hit(node);
00350 }
00351
00352
00353
00354
00355
00356 template<typename Visitor>
00357 void Trace(Point3 origin, Vector3 direction, Visitor &visitor) const {
00358 assert(m_root);
00359
00360 const Point3 &box_min = m_root->m_voxel.m_min;
00361 const Point3 &box_max = m_root->m_voxel.m_max;
00362
00363 const Real EPSILON = 1e-9;
00364
00365 unsigned int a = 0;
00366 unsigned int b = 0;
00367
00368 if(direction.m_x == 0.0) {
00369 direction.m_x = EPSILON;
00370 b |= 4;
00371 } else if(direction.m_x < 0.0) {
00372 origin.m_x = (box_min.m_x + box_max.m_x) - origin.m_x;
00373 direction.m_x = -direction.m_x;
00374 a |= 4;
00375 }
00376
00377 if(direction.m_y == 0.0) {
00378 direction.m_y = EPSILON;
00379 b |= 2;
00380 } else if(direction.m_y < 0.0) {
00381 origin.m_y = (box_min.m_y + box_max.m_y) - origin.m_y;
00382 direction.m_y = -direction.m_y;
00383 a |= 2;
00384 }
00385
00386 if(direction.m_z == 0.0) {
00387 direction.m_z = EPSILON;
00388 b |= 1;
00389 } else if(direction.m_z < 0.0) {
00390 origin.m_z = (box_min.m_z + box_max.m_z) - origin.m_z;
00391 direction.m_z = -direction.m_z;
00392 a |= 1;
00393 }
00394
00395 assert(
00396 direction.m_x != 0.0 &&
00397 direction.m_y != 0.0 &&
00398 direction.m_z != 0.0);
00399
00400 Real tx0 = (box_min.m_x - origin.m_x) / direction.m_x;
00401 Real tx1 = (box_max.m_x - origin.m_x) / direction.m_x;
00402 Real ty0 = (box_min.m_y - origin.m_y) / direction.m_y;
00403 Real ty1 = (box_max.m_y - origin.m_y) / direction.m_y;
00404 Real tz0 = (box_min.m_z - origin.m_z) / direction.m_z;
00405 Real tz1 = (box_max.m_z - origin.m_z) / direction.m_z;
00406
00407 if(max(tx0, ty0, tz0) < min(tx1, ty1, tz1))
00408 m_root->Trace(origin, tx0, ty0, tz0, tx1, ty1, tz1, a, b, visitor);
00409 }
00410
00411
00412 template<typename Visitor>
00413 void Visit(Visitor &visitor) const {
00414 assert(m_root);
00415 m_root->Visit(visitor);
00416 }
00417
00418 private:
00419 OctreeNode<Item> *m_root;
00420 };
00421
00422 #include "octree.inl"
00423
00424 }
00425
00426 #endif // !SHEEP_MATH_OCTREE_H