Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

sps.C

Go to the documentation of this file.
00001 /*****************************************************************
00002  * sps.C
00003  *****************************************************************/
00004 // comments to be added
00005 #include "sps.H"
00006 #include <queue>
00007 
00008 static bool debug = Config::get_var_bool("DEBUG_SPS",false);
00009 
00010 // Recommended method to call for sampling points on a surface
00011 //
00012 // Input: mesh is the surface to be sampled
00013 //        height is the height of the octree you want to build (which means the resolution for sampling
00014 //           can only be controlled exponentially). Default to be 6.
00015 //        min_dist is a double between 0 and 1, proportional to the diagonal length of the smallest cells in
00016 //           the octree. (You probably want min_dist to be less than 0.5). Default is 0.35.
00017 //        regularity is a density parameter discussed in the paper: Stratified Point Sampling. The larger
00018 //           this parameter is, the more the samples will be squeezed toward the center of the octree node.
00019 //           Default is 20. Changing this would not effect the result much.
00020 //
00021 //  Output: a Bface_list and a list of barycentric coordinates
00022 void
00023 generate_samples(BMESHptr mesh, 
00024    Bface_list& flist, // faces
00025    ARRAY<Wvec>& blist, // barycentric coordinates
00026    int height, double min_dist, double regularity)
00027 {
00028    Bvert_list verts;
00029    OctreeNode* n = sps(mesh, height, regularity, min_dist, flist, blist);
00030    delete n;
00031 }
00032 
00033 // Another method to call
00034 //
00035 // min_spacing is the minimum spacing between samples
00036 void
00037 generate_samples(BMESHptr mesh, double min_spacing,
00038    Bface_list& flist, ARRAY<Wvec>& blist)
00039 {
00040    flist.clear(); blist.clear();
00041    int height = 6;
00042    double regularity = 20;
00043 
00044    clock_t start, end;
00045    double duration; 
00046 
00047    BBOX box = mesh->get_bb();
00048    OctreeNode* root = new OctreeNode(box.min(), box.max(), 1, NULL);
00049    if (height == 1) {
00050       root->set_leaf(true);
00051       root->set_disp(true);
00052    }
00053    root->intersects() = (mesh->faces());
00054    
00055    start = clock();
00056    root->build_octree(height);
00057    end = clock();   
00058    duration = (double)(end - start) / CLOCKS_PER_SEC;
00059    err_adv(debug, "step 1 time: %f", duration); 
00060    
00061    start = clock();
00062    visit(root, regularity, flist, blist);
00063    end = clock();
00064    duration = (double)(end - start) / CLOCKS_PER_SEC;
00065    err_adv(debug, "step 2 time: %f", duration);
00066 
00067    // remove bad samples
00068    start = clock();
00069    root->set_neibors();
00070    root->set_terms();
00071    remove_nodes(flist, blist, min_spacing, root->terms());
00072    end = clock();
00073    duration = (double)(end - start) / CLOCKS_PER_SEC;
00074    err_adv(debug, "step 3 time: %f", duration);   
00075    err_adv(debug, "no of points: %d", flist.num());
00076 
00077    delete root;
00078 }
00079 
00080 OctreeNode*
00081 sps(BMESHptr mesh, int height, double regularity, double min_dist,
00082    Bface_list& flist, ARRAY<Wvec>& blist) 
00083 {
00084    clock_t start, end;
00085    double duration; 
00086    flist.clear(); blist.clear();
00087 
00088    BBOX box = mesh->get_bb();
00089    OctreeNode* root = new OctreeNode(box.min(), box.max(), 1, NULL);
00090    if (height == 1) {
00091       root->set_leaf(true);
00092       root->set_disp(true);
00093    }
00094    root->intersects() = (mesh->faces());
00095    
00096 
00097 
00098    start = clock();
00099    root->build_octree(height);
00100    end = clock();   
00101   
00102    duration = (double)(end - start) / CLOCKS_PER_SEC;
00103    err_adv(debug, "step 1 time: %f", duration); 
00104   
00105    start = clock();
00106    visit(root, regularity, flist, blist);
00107    end = clock();
00108    duration = (double)(end - start) / CLOCKS_PER_SEC;
00109    err_adv(debug, "step 2 time: %f", duration);
00110 
00111    // remove bad samples
00112    start = clock();
00113    double dist = min_dist * box.dim().length() / (1<<(height-1));
00114 
00115    root->set_neibors();
00116 
00117    root->set_terms();
00118 
00119    remove_nodes(flist, blist, dist, root->terms());
00120    end = clock();
00121    duration = (double)(end - start) / CLOCKS_PER_SEC;
00122    err_adv(debug, "step 3 time: %f", duration);   
00123    err_adv(debug, "no of points: %d", flist.num());
00124 
00125    return root;
00126 }
00127 
00128 inline
00129 Wpt
00130 center (Wpt_list& pts, ARRAY<int>& N)
00131 {
00132    Wpt ret = Wpt(0);
00133    for (int i = 0; i < N.num(); i++) {
00134       ret += pts[N[i]];
00135    }
00136    return ret / N.num();
00137 }
00138 
00139 class Priority{
00140 public:
00141   
00142   bool operator< (const Priority& other) const { return _priority < other._priority;}; 
00143   int _index;
00144   double _priority;
00145   int _version;
00146 };
00147 
00148 inline Wpt_list
00149 get_pts(Bface_list& flist, ARRAY<Wvec>& blist)
00150 {
00151    assert(flist.num() == blist.num());
00152    Wpt_list pts;
00153    for (int i = 0; i < flist.num(); i++) {
00154       Wpt pt;
00155       flist[i]->bc2pos(blist[i], pt);
00156       pts += pt;
00157    }
00158    return pts;
00159 }
00160 
00161 void 
00162 remove_nodes(Bface_list& flist, ARRAY<Wvec>& blist, double min_dist, ARRAY<OctreeNode*>& t)
00163 {
00164    assert(flist.num() == blist.num());
00165    Wpt_list pts = get_pts(flist, blist);
00166    ARRAY< ARRAY<int> > N;
00167    ARRAY<bool> to_remove;
00168    for (int i = 0; i < pts.num(); i++) {
00169       N += ARRAY<int>();
00170       to_remove += false;
00171    }
00172 
00173    clock_t start;
00174 
00175    for (int i = 0; i < pts.num(); i++) {
00176       for (int j = 0; j < t[i]->neibors().num(); j++) {
00177          int index = t[i]->neibors()[j]->get_term_index();
00178          if (pts[i].dist(pts[index]) < min_dist) {
00179             N[i] += index;
00180             N[index] += i;
00181          }
00182       }
00183    }
00184 
00185    start = clock();
00186    priority_queue< Priority, vector<Priority> > queue;
00187    ARRAY<int> versions;
00188    for (int i = 0; i < pts.num(); i++) {
00189       if (!to_remove[i] && !N[i].empty()) {
00190          Priority p;
00191          p._priority = center(pts, N[i]).dist(pts[i]);
00192          p._index = i;
00193          p._version = 0;
00194          queue.push(p);
00195       }
00196       versions += 0;
00197    }
00198 
00199    while (!queue.empty()) {
00200       Priority p = queue.top();
00201       queue.pop();
00202       int r = p._index;
00203       if (p._version == versions[r]) {
00204          to_remove[r] = true;
00205          for (int i = 0; i < N[r].num(); i++) {
00206             N[N[r][i]] -= r;
00207             versions[N[r][i]]++;
00208             if (!N[N[r][i]].empty()) {
00209                Priority q;
00210                q._priority = center(pts, N[N[r][i]]).dist(pts[N[r][i]]);
00211                q._index = N[r][i];
00212                q._version = versions[N[r][i]];
00213                queue.push(q);
00214             }
00215          }
00216       }
00217    }
00218    versions.clear();
00219 
00220    Bface_list ftemp(flist);
00221    ARRAY<Wvec> btemp(blist);
00222    flist.clear();
00223    blist.clear();
00224    for (int i = 0; i < ftemp.num(); i++)
00225       if (!to_remove[i]) {
00226          flist += ftemp[i];
00227          blist += btemp[i];
00228       }
00229 }
00230 
00231 inline
00232 double
00233 distr_func (double r, double d) 
00234 {
00235    const double E = 2.71828183;
00236    return r * powf(E, -(float)r * (float)d);
00237 }
00238 
00239 /// An auxilliary function that produces a pseudo-random floating
00240 /// point number between 0 and 1
00241 inline
00242 float dorand() {
00243   return double(rand()) / (RAND_MAX);
00244 }
00245 
00246 inline
00247 int
00248 pick (ARRAY<QuadtreeNode*>& l)
00249 {
00250    int ret = -1;
00251    double total_w = 0.0;
00252    for (int i = 0; i < l.num(); i++) {
00253       total_w += l[i]->get_weight();
00254    }
00255    double r = dorand() * total_w;
00256    
00257    total_w = 0.0;
00258    for (int i = 0; i < l.num(); i++) {
00259       total_w += l[i]->get_weight();
00260       if (total_w >= r) {
00261          ret = i;
00262          break;
00263       }
00264    }
00265    return ret;
00266 }
00267 
00268 void
00269 assign_weights(ARRAY<QuadtreeNode*>& fs, double regularity, CWpt& pt)
00270 {
00271    double weight, d;
00272    QuadtreeNode* leaf;
00273    for (int i = 0; i < fs.num(); i++) {
00274       weight = 0.0;
00275       for (int j = 0; j < fs[i]->terms().num(); j++) {
00276          leaf = fs[i]->terms()[j];
00277          d = pt.dist(leaf->centroid());
00278          leaf->set_weight(distr_func(regularity, d) * leaf->area());
00279          weight += leaf->get_weight();
00280       }
00281       fs[i]->set_weight(weight);
00282    }
00283 }
00284 
00285 void 
00286 visit(OctreeNode* node,  
00287    double regularity, Bface_list& flist, ARRAY<Wvec>& blist)
00288 {
00289    if (node->get_leaf()) {
00290       if (node->get_disp()) {
00291          // subdivision
00292          ARRAY<QuadtreeNode*> fs;
00293          Bface_list temp;
00294          for (int i = 0; i < node->intersects().num(); i++) {
00295             Bface* f = node->intersects()[i];
00296             temp += f;
00297             fs += new QuadtreeNode(f->v1()->loc(), f->v2()->loc(), f->v3()->loc());
00298             fs.last()->build_quadtree(node, regularity);
00299             fs.last()->set_terms();
00300          }
00301 
00302          // assign weights
00303          assign_weights(fs, regularity, node->center());
00304          
00305          // pick a triangle
00306          int t = pick(fs);
00307          flist += temp[t];
00308 
00309          // pick a point
00310          int p = pick(fs[t]->terms());
00311          if (p != -1) {
00312             Wvec bc;
00313             temp[t]->project_barycentric(fs[t]->terms()[p]->urand_pick(), bc);
00314             blist += bc;
00315          }
00316 
00317          for (int i = 0; i < fs.num(); i++)
00318             delete fs[i];
00319          fs.clear();
00320       }
00321    } else {
00322       for (int i = 0; i < 8; i++)
00323          visit(node->get_children()[i], regularity, flist, blist);
00324    }
00325 }
00326 
00327 void
00328 OctreeNode::set_neibors()
00329 {
00330    OctreeNode* n;
00331    BBOX test_box = BBOX(min()-0.5*dim(), max()+0.5*dim());
00332 
00333    if ((!_leaf || _display) && _height != 1) {
00334          for (int i = 0; i < 8; i++) {
00335             n = _parent->get_children()[i];
00336             if (n != this && (!n->get_leaf() || n->get_disp())) {
00337                _neibors += n;
00338             }
00339          }
00340 
00341        _parent->neibors().num();
00342 
00343          for (int i = 0; i < _parent->neibors().num(); i++) {
00344             n = _parent->neibors()[i];
00345             if (!n->get_leaf()) {
00346                for (int j = 0; j < 8; j++) {
00347                   if (n->get_children()[j]->overlaps(test_box) &&
00348                      (!n->get_children()[j]->get_leaf() || 
00349                      n->get_children()[j]->get_disp())) {
00350                 //XXX - crashing here...
00351                      _neibors += n->get_children()[j];
00352                   }
00353                }
00354          }
00355          }
00356    
00357    }
00358 
00359    if (!_leaf) {
00360       for (int i = 0; i < 8; i++) {
00361          _children[i]->set_neibors();
00362       }
00363    }
00364 }
00365 
00366 void 
00367 OctreeNode::set_terms(ARRAY<OctreeNode*>& terms, int& count)
00368 {
00369    if (_leaf) {
00370       if (_display) {
00371          terms += this;
00372          _term_index = count;
00373          count++;
00374       }
00375    } else {
00376       for (int i = 0; i < 8; i++)
00377          _children[i]->set_terms(terms, count);
00378    }
00379 }
00380 
00381 void 
00382 OctreeNode::set_terms()
00383 {
00384    _terms.clear();
00385    int count = 0;
00386    set_terms(_terms, count);
00387 }
00388 
00389 void 
00390 QuadtreeNode::set_terms(ARRAY<QuadtreeNode*>& terms)
00391 {
00392    if (_leaf) {
00393       if (_in_cell) {
00394          terms += this;
00395       }
00396    } else {
00397       for (int i = 0; i < 4; i++)
00398          _children[i]->set_terms(terms);
00399    }
00400 }
00401 
00402 void 
00403 QuadtreeNode::set_terms()
00404 {
00405    _terms.clear();
00406    set_terms(_terms);
00407 }
00408 
00409 inline
00410 BBOX
00411 bface_bbox(QuadtreeNode* face) 
00412 {
00413    BBOX ret = BBOX();
00414    ret.update(face->v1());
00415    ret.update(face->v2());
00416    ret.update(face->v3());
00417    return ret;
00418 }
00419 
00420 inline
00421 BBOX
00422 bface_bbox(Bface* face) 
00423 {
00424    BBOX ret = BBOX();
00425    ret.update(face->v1()->loc());
00426    ret.update(face->v2()->loc());
00427    ret.update(face->v3()->loc());
00428    return ret;
00429 }
00430 
00431 void 
00432 OctreeNode::build_octree(int height) 
00433 {
00434 
00435    if (_leaf || _height == height) 
00436       return;
00437 
00438    int i, j;
00439    Wpt_list pts;
00440    points(pts);
00441 
00442    for (i = 0; i < 8; i++) {
00443       _children[i] = new OctreeNode((pts[0]+pts[i])/2, (pts[i]+pts[7])/2, 
00444          _height+1, this);
00445    }
00446 
00447    for (j = 0; j < _intersects.num(); j++) {
00448       Bface* f = _intersects[j];
00449 
00450       for (i = 0; i < 8; i++) {
00451          OctreeNode* n = _children[i];
00452          if (n->contains(f->v1()->loc()) && n->contains(f->v2()->loc())
00453             && n->contains(f->v3()->loc())) {
00454             n->intersects() += f;
00455             break;
00456          } else if (n->overlaps(bface_bbox(f))) {
00457             n->intersects() += f;
00458          }
00459       }
00460    }
00461 
00462    for (i = 0; i < 8; i++) {
00463       if (_height+1 == height) {
00464          _children[i]->set_leaf(true);
00465          _children[i]->set_disp(true);
00466       }
00467       if (_children[i]->intersects().empty()) {
00468          _children[i]->set_leaf(true);
00469          _children[i]->set_disp(false);
00470       }
00471       _children[i]->build_octree(height);
00472    }
00473 
00474 }
00475 
00476 void
00477 QuadtreeNode::subdivide(OctreeNode* o, double regularity)
00478 {
00479    // subdivide 
00480    Wpt v4 = (_v1+_v2)/2;
00481    Wpt v5 = (_v2+_v3)/2;
00482    Wpt v6 = (_v3+_v1)/2;
00483    _children[0] = new QuadtreeNode(_v1, v4, v6);
00484    _children[0]->build_quadtree(o, regularity);
00485    _children[1] = new QuadtreeNode(v4, _v2, v5);
00486    _children[1]->build_quadtree(o, regularity);
00487    _children[2] = new QuadtreeNode(v6, v5, _v3);
00488    _children[2]->build_quadtree(o, regularity);
00489    _children[3] = new QuadtreeNode(v4, v5, v6);
00490    _children[3]->build_quadtree(o, regularity);
00491 }
00492 
00493 void 
00494 QuadtreeNode::build_quadtree(OctreeNode* o, double regularity)
00495 {
00496    //const double THRED_RATIO = 0.3;
00497    const double THRED_EDGE = 0.3 * o->dim().length();
00498    
00499    if (!(o->contains(_v1) && o->contains(_v2))
00500       && o->contains(_v3)) {
00501       if (max(max(_v1.dist(_v2), _v2.dist(_v3)), _v3.dist(_v1))
00502          < THRED_EDGE || !o->overlaps(bface_bbox(this))) {
00503          _leaf = true;
00504          _in_cell = false;
00505          return;
00506       }
00507    }
00508 
00509    if (area() < o->get_area()/20) {
00510       _leaf = true;
00511       return;
00512    }
00513 
00514    //Wpt nearest = nearest_pt(o->center());
00515    //Wpt farthest = farthest_pt(o->center());
00516    //double smallest = distr_func(regularity, farthest.dist(o->center()));
00517    //double largest = distr_func(regularity, nearest.dist(o->center()));
00518    //double ratio = (largest - smallest) / smallest;
00519    //if (ratio < THRED_RATIO) {
00520    //   _leaf = true;
00521    //   return;
00522    //}
00523    subdivide(o, regularity);
00524 }
00525 
00526 Wpt 
00527 QuadtreeNode::nearest_pt(Wpt& p)
00528 {
00529    Wvec bc; 
00530    bool on;
00531    Bvert* v1 = new Bvert(_v1);
00532    Bvert* v2 = new Bvert(_v2);
00533    Bvert* v3 = new Bvert(_v3);
00534    Bface f(v1, v2, v3, new Bedge(v1, v2), new Bedge(v2, v3), new Bedge(v3, v1));
00535    return f.nearest_pt(p, bc, on);
00536 }
00537 
00538 Wpt 
00539 QuadtreeNode::farthest_pt(Wpt& p)
00540 {
00541    Wpt ret = _v1;
00542    double max_dist = ret.dist(p);
00543    if (_v2.dist(p) > max_dist) {
00544       ret = _v2;
00545       max_dist = ret.dist(p);
00546    }
00547    if (_v3.dist(p) > max_dist) {
00548       ret = _v3;
00549    }
00550    return ret;
00551 }
00552 
00553 Wpt 
00554 QuadtreeNode::urand_pick()
00555 {
00556    Wvec vec1 = _v2 - _v1;
00557    Wvec vec2 = _v3 - _v1;
00558    double d1 = dorand(), d2 = dorand();
00559    Wpt pt = _v1 + d1 * vec1 + d2 * vec2;
00560    if (!contains(pt, 0.1))
00561       pt = (_v2 + _v3) + (-pt);
00562    return pt;
00563 }
00564 
00565 // end of file sps.C

Generated on Mon Sep 18 11:39:33 2006 for jot by  doxygen 1.4.4