KDtritree.cc
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:5k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. //############################################################
  2. // KDtritree.cc
  3. // Kari Pulli
  4. // 11/19/98
  5. //############################################################
  6. #include "KDtritree.h"
  7. #include "Bbox.h"
  8. #include "Median.h"
  9. static Median<float> med;
  10. static int
  11. mediansort(KDsphere *data, int n,
  12.    int dim, float med)
  13. {
  14.   // move values <= med to left, the rest to right
  15.   int left = 0, right = n-1;
  16.   while (1) {
  17.     while (data[left].ctr[dim] <= med && right > left) left++;
  18.     while (data[right].ctr[dim] > med && right > left) right--;
  19.     KDsphere tmp = data[left];  // swap
  20.     data[left] = data[right]; data[right] = tmp;
  21.     if (left == right) {
  22.       if (data[right].ctr[dim] <= med) right++;
  23.       break;
  24.     }
  25.     left++;
  26.   }
  27.   return right;
  28. }
  29. void
  30. KDtritree::collapse_spheres(void)
  31. {
  32.   float cdist = dist(child[0]->ctr, child[1]->ctr);
  33.   
  34.   if (cdist + child[0]->radius < child[1]->radius) {
  35.     ctr    = child[1]->ctr;
  36.     radius = child[1]->radius;
  37.   } else if (cdist + child[1]->radius < child[0]->radius) {
  38.     ctr    = child[0]->ctr;
  39.     radius = child[0]->radius;
  40.   } else {
  41.     // OK, find the new bounding sphere
  42.     radius  = 0.5 * (cdist + child[0]->radius + child[1]->radius);
  43.     float t = (radius - child[0]->radius) / cdist;
  44.     ctr.lerp(t, child[0]->ctr, child[1]->ctr);
  45.   }    
  46. }
  47. KDtritree::KDtritree(const Pnt3 *pts, const int *triinds, 
  48.      KDsphere *spheres, int n, int first)
  49. {
  50.   int i;
  51.   if (n > 1) {
  52.     // find the dimension of maximum range (of sphere centers)
  53.     Bbox bbox;
  54.     for (i=0; i<n; i++) bbox.add(spheres[i].ctr);
  55.     Pnt3 diag = bbox.max(); diag -= bbox.min();
  56.     if (diag[2] > diag[1] && diag[2] > diag[0]) ind = 2;
  57.     else ind = diag[1] > diag[0];
  58.     
  59.     if (diag.norm2() == 0.0) {
  60.       /*
  61.       // all the spheres have same center?
  62.       cerr << "KDtritree Warning: several triangles with the "
  63.    << "same center?!?" << endl;
  64.       SHOW(diag);
  65.       SHOW(n);
  66.       for (i=0; i<n; i++) {
  67. SHOW(spheres[i].ctr);
  68. SHOW(spheres[i].radius);
  69.       }
  70.       */
  71.       n = 1;
  72.     }
  73.   }
  74.   if (n > 1) {
  75. #define DATA(i) spheres[i].ctr[ind]
  76.     // find the median within that dimension
  77.     med.clear();
  78.     for (i=0; i<n; i++) med += DATA(i);
  79.     split = med.find();
  80.     int right = mediansort(spheres, n, ind, split);
  81.     if (right == n) {
  82.       // the median is also the largest, need new "median"
  83.       // find the next largest item for that
  84.       float nm = -9.e33;
  85.       for (i=0; i<n; i++) {
  86. if (DATA(i) != split && DATA(i) > nm) nm = DATA(i);
  87.       }
  88.       right = mediansort(spheres, n, ind, (split=nm));
  89.     }
  90.     assert(right != 0 && right != n);
  91. #undef DATA
  92.     // recurse
  93.     child[0] = new KDtritree(pts, triinds, spheres, right, 0);
  94.     child[1] = new KDtritree(pts, triinds, &spheres[right], n-right, 0);
  95.     collapse_spheres();
  96.   } else {
  97.     // leaf, store data here
  98.     ind      = spheres->ind;
  99.     ctr      = spheres->ctr;
  100.     radius   = spheres->radius;
  101.     child[0] = child[1] = NULL;
  102.   }
  103.   if (first) med.zap(); // release memory after the tree's done
  104. }
  105. KDtritree::~KDtritree(void)
  106. {
  107.   delete child[0];
  108.   delete child[1];
  109. }
  110. void
  111. KDtritree::_search(const Pnt3 *pts, const int *inds, 
  112.    const Pnt3 &p, Pnt3 &cp, float &d2) const
  113. {
  114.   if (child[0] == NULL) { 
  115.     // terminal node, check the triangle and return
  116.     closer_on_tri(p, cp, pts[inds[ind]],
  117.   pts[inds[ind+1]], 
  118.   pts[inds[ind+2]], d2);
  119.     return;
  120.   }
  121.   assert(child[1]);
  122.   if (p[ind] <= split) {
  123.     // can the left subtree contain anything interesting?
  124.     if (spheres_intersect(p, child[0]->ctr, d2, child[0]->radius))
  125.       child[0]->_search(pts, inds, p, cp, d2);
  126.     // can the right subtree contain anything interesting?
  127.     if (spheres_intersect(p, child[1]->ctr, d2, child[1]->radius))
  128.       child[1]->_search(pts, inds, p, cp, d2);
  129.   } else {
  130.     // can the right subtree contain anything interesting?
  131.     if (spheres_intersect(p, child[1]->ctr, d2, child[1]->radius))
  132.       child[1]->_search(pts, inds, p, cp, d2);
  133.     // can the left subtree contain anything interesting?
  134.     if (spheres_intersect(p, child[0]->ctr, d2, child[0]->radius))
  135.       child[0]->_search(pts, inds, p, cp, d2);
  136.   }
  137. }
  138. KDtritree *
  139. create_KDtritree(const Pnt3 *pts, const int *inds, int n)
  140. {
  141.   assert(n%3==0);
  142.   // first, create as many spheres as there are triangles
  143.   int ns = n/3;
  144.   KDsphere *spheres = new KDsphere[ns];
  145.   for (int i=0; i<ns; i++) {
  146.     int ti = i*3;
  147.     spheres[i].radius = 
  148.       spheres[i].ctr.smallest_circle(pts[inds[ti]],
  149.      pts[inds[ti+1]],
  150.      pts[inds[ti+2]]);
  151.     spheres[i].ind = ti;
  152.     //SHOW(spheres[i].radius);
  153.     //SHOW(spheres[i].ctr);
  154.   }
  155.   KDtritree *ret = new KDtritree(pts, inds, spheres, ns, 1);
  156.   delete[] spheres;
  157.   return ret;
  158. }