00001
00002
00003
00004 #ifndef SUBDIV_CALC_H_IS_INCLUDED
00005 #define SUBDIV_CALC_H_IS_INCLUDED
00006
00007 #include "bfilters.H"
00008 #include "lvert.H"
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #define CSubdivCalc const SubdivCalc
00023 template <class T>
00024 class SubdivCalc {
00025 public:
00026
00027 SubdivCalc(): _boss(0) {}
00028 virtual ~SubdivCalc() {}
00029
00030 void set_boss(SubdivCalc<T> * boss) { _boss=boss; }
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 virtual T get_val(CBvert* v) const {
00041 assert(_boss);
00042 return _boss->get_val(v);
00043 }
00044
00045
00046 virtual void clear(T&) const { }
00047
00048
00049
00050
00051
00052 virtual str_ptr name() const {
00053
00054
00055 return str_ptr("SubdivCalc");
00056 }
00057
00058
00059
00060 virtual T subdiv_val(CBvert*) const = 0;
00061 virtual T subdiv_val(CBedge*) const = 0;
00062 virtual T limit_val (CBvert*) const = 0;
00063
00064
00065
00066 virtual SubdivCalc<T> *dup() const { return 0; }
00067
00068 protected:
00069 SubdivCalc<T> * _boss;
00070 };
00071
00072
00073
00074
00075
00076
00077
00078 template <class T>
00079 class SimpleCalc : public SubdivCalc<T> {
00080 public:
00081
00082
00083 virtual str_ptr name() const {
00084
00085
00086 return str_ptr("Simple subdivision");
00087 }
00088
00089
00090
00091
00092 virtual T subdiv_val(CBvert* v) const { return get_val(v); }
00093
00094
00095 virtual T subdiv_val(CBedge* e) const {
00096 assert(e);
00097 if (e->is_weak()) {
00098
00099
00100
00101
00102 Bface* f1 = e->f1();
00103 Bface* f2 = e->f2();
00104
00105
00106 assert(f1 && f1->is_quad() &&
00107 f2 && f2->is_quad() && f1->quad_partner() == f2);
00108
00109 return (
00110 get_val(f1->v1()) +
00111 get_val(f1->v2()) +
00112 get_val(f1->v3()) +
00113 get_val(f1->quad_vert()))/4.0;
00114
00115 } else {
00116 return (get_val(e->v1()) + get_val(e->v2()))/2.0;
00117 }
00118 }
00119
00120
00121 virtual T limit_val (CBvert* v) const { return get_val(v); }
00122
00123 using SubdivCalc<T>::get_val;
00124 };
00125
00126 extern double loop_alpha(int n);
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 template <class T>
00143 class LoopCalc : public SubdivCalc<T> {
00144 public:
00145
00146
00147 virtual str_ptr name() const {
00148
00149
00150 return str_ptr("Loop subdivision");
00151 }
00152
00153 virtual T centroid(CLvert* v) const {
00154
00155
00156
00157
00158
00159 switch (v->subdiv_mask()) {
00160 case Lvert::SMOOTH_VERTEX:
00161 case Lvert::DART_VERTEX:
00162 {
00163
00164 T ret;
00165 clear(ret);
00166 Bvert_list nbrs;
00167 v->get_p_nbrs(nbrs);
00168 int n = nbrs.num();
00169 for (int k=0; k<n; k++)
00170 ret = (ret + get_val(nbrs[k]));
00171 return ret/n;
00172 }
00173 case Lvert::REGULAR_CREASE_VERTEX:
00174 case Lvert::NON_REGULAR_CREASE_VERTEX:
00175 {
00176
00177
00178
00179
00180
00181 T ret;
00182 clear(ret);
00183 int count = 0;
00184 Bvert_list nbrs;
00185 v->get_p_nbrs(nbrs);
00186 for (int k=0; k<nbrs.num(); k++) {
00187 Bedge* e = v->e(k);
00188 if (e->is_crease() || e->is_border() || e->is_polyline()) {
00189 double w = 1.0 / ++count;
00190 ret = interp(ret, get_val(v->nbr(k)), w);
00191 }
00192 }
00193 return ret;
00194 }
00195 case Lvert::CORNER_VERTEX:
00196 case Lvert::CUSP_VERTEX:
00197 default:
00198
00199
00200
00201 return get_val(v);
00202 }
00203 }
00204
00205
00206 T smooth_subdiv_val(CLvert* v) const {
00207
00208
00209
00210
00211
00212 int n = v->p_degree();
00213 double a = loop_alpha(n);
00214 double w = a / (a + n);
00215 return interp(centroid(v), get_val(v), w);
00216 }
00217
00218 T crease_subdiv_val(CLvert* v) const {
00219
00220
00221
00222
00223 return interp(centroid(v), get_val(v), 0.75);
00224 }
00225
00226 T smooth_limit_val (CLvert* v) const {
00227
00228
00229
00230
00231
00232
00233 int n = v->p_degree();
00234 double a = 5.0/8 - sqr(3 + 2*cos(TWO_PI/n))/64;
00235 double o = 3*n/(8*a);
00236 double w = o / (o + n);
00237
00238
00239 return interp(centroid(v), get_val(v), w);
00240 }
00241
00242 T crease_limit_val (CLvert* v) const {
00243
00244
00245
00246
00247 return interp(centroid(v), get_val(v), 2.0/3);
00248 }
00249
00250
00251 virtual T subdiv_val(CBvert* bv) const {
00252
00253 CLvert* v = (CLvert*)bv;
00254 switch (v->subdiv_mask()) {
00255 case Lvert::SMOOTH_VERTEX:
00256 case Lvert::DART_VERTEX:
00257 return smooth_subdiv_val(v);
00258 case Lvert::REGULAR_CREASE_VERTEX:
00259 case Lvert::NON_REGULAR_CREASE_VERTEX:
00260 return crease_subdiv_val(v);
00261 default:
00262 return get_val(v);
00263 }
00264 }
00265
00266 virtual T subdiv_val(CBedge* e) const {
00267
00268 switch (((CLedge*)e)->subdiv_mask()) {
00269 case Ledge::REGULAR_SMOOTH_EDGE:
00270 return (
00271 (get_val(e->v1()) + get_val(e->v2()))*3.0 +
00272 get_val(e->opposite_vert1()) +
00273 get_val(e->opposite_vert2())
00274 )/8.0;
00275 case Ledge::REGULAR_CREASE_EDGE:
00276 default:
00277
00278
00279 return (get_val(e->v1()) + get_val(e->v2()))/2.0;
00280 }
00281 }
00282
00283 virtual T limit_val (CBvert* bv) const {
00284
00285 CLvert* v = (CLvert*)bv;
00286 switch (v->subdiv_mask()) {
00287 case Lvert::SMOOTH_VERTEX:
00288 case Lvert::DART_VERTEX:
00289 return smooth_limit_val(v);
00290 case Lvert::REGULAR_CREASE_VERTEX:
00291 case Lvert::NON_REGULAR_CREASE_VERTEX:
00292 return crease_limit_val(v);
00293 default:
00294 return get_val(v);
00295 }
00296 }
00297
00298 using SubdivCalc<T>::get_val;
00299 };
00300
00301
00302
00303
00304 class LoopLoc : public LoopCalc<Wpt> {
00305 public:
00306
00307 virtual Wpt get_val(CBvert* v) const { return v->loc(); }
00308
00309
00310 Wvec limit_normal(CBvert* v) const {
00311
00312
00313
00314
00315
00316
00317 assert(v);
00318
00319
00320 if (v->face_degree(BfaceFilter()) == 0)
00321 return Wvec::null();
00322
00323
00324
00325 assert(v->is_manifold());
00326
00327
00328 Bvert_list nbrs = v->get_ccw_nbrs();
00329 assert(nbrs.num() == v->degree());
00330
00331 Wpt t1, t2;
00332 int n = nbrs.num();
00333 int bd = v->border_degree();
00334 if (bd == 0) {
00335
00336 for (int k=0; k<n; k++) {
00337 double theta = TWO_PI * k / n;
00338 t1 += nbrs[k]->loc() * cos(theta);
00339 t2 += nbrs[k]->loc() * sin(theta);
00340 }
00341 } else if (bd == 2) {
00342
00343 t1 = nbrs.first()->loc() + (-1 * nbrs.last()->loc());
00344
00345 if (n == 4) {
00346
00347 t2 = ( v->loc()*(-2) +
00348 nbrs[0]->loc()*(-1) +
00349 nbrs[1]->loc()*( 2) +
00350 nbrs[2]->loc()*( 2) +
00351 nbrs[3]->loc()*(-1));
00352 } else if (n == 2) {
00353 t2 = nbrs.first()->loc() + nbrs.last()->loc() + (-2 * v->loc());
00354 } else if (n == 3) {
00355 t2 = nbrs[1]->loc() + (-1 * v->loc());
00356 } else {
00357 double theta = M_PI/(n - 1);
00358 double c = 2*cos(theta) - 2;
00359 t2 = (nbrs.first()->loc() + nbrs.last()->loc())*sin(theta);
00360 for (int i=1; i<n-1; i++) {
00361 t2 += c*sin(i*theta)*nbrs[i]->loc();
00362 }
00363 }
00364 } else {
00365
00366 assert(0);
00367 }
00368 return (cross(t1 - Wpt::Origin(), t2 - Wpt::Origin())).normalized();
00369 }
00370
00371
00372 virtual SubdivCalc<Wpt> *dup() const { return new LoopLoc(); }
00373 };
00374
00375
00376
00377
00378 class LoopColor : public LoopCalc<COLOR> {
00379 public:
00380
00381 virtual COLOR get_val(CBvert* v) const { return v->color(); }
00382
00383
00384 virtual SubdivCalc<COLOR> *dup() const { return new LoopColor(); }
00385 };
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 template <class T>
00415 class CatmullClarkCalc : public SubdivCalc<T> {
00416 public:
00417
00418
00419 virtual str_ptr name() const {
00420
00421
00422 return str_ptr("Catmull-Clark subdivision");
00423 }
00424
00425 T vcentroid(CBvert* v) const {
00426
00427
00428
00429
00430 T ret;
00431 clear(ret);
00432 Bedge_list adj;
00433 v->get_manifold_edges(adj);
00434 int count = 0;
00435 for (int k=0; k<adj.num(); k++) {
00436 if (adj[k]->is_strong()) {
00437
00438 double w = 1.0 / ++count;
00439 ret = interp(ret, get_val(adj[k]->other_vertex(v)), w);
00440 }
00441 }
00442 return ret;
00443 }
00444 T fcentroid(CBface* f) const {
00445
00446
00447
00448
00449 T ret = (get_val(f->v1()) + get_val(f->v2()) + get_val(f->v3()))/3.0;
00450 if (f->is_quad() && f->quad_vert())
00451 ret = (ret*0.75) + (get_val(f->quad_vert())*0.25);
00452 return ret;
00453 }
00454 T fcentroids(CARRAY<Bface*>& faces) const {
00455
00456
00457 T ret;
00458 clear(ret);
00459 if (faces.empty()) {
00460 err_msg("CatmullClarkCalc::fcentroids: error: empty face list");
00461 return ret;
00462 }
00463 for (int k=0; k<faces.num(); k++)
00464 ret = ret + fcentroid(faces[k]);
00465 return ret / faces.num();
00466 }
00467 T smooth_centroid(CBvert* v) const {
00468
00469
00470
00471
00472
00473 Bface_list faces;
00474 v->get_quad_faces(faces);
00475
00476 return (vcentroid(v) + fcentroids(faces))*0.5;
00477 }
00478 T crease_centroid(CBvert* v) const {
00479
00480
00481
00482
00483
00484 T ret;
00485 int count = 0;
00486 Bedge_list adj;
00487 v->get_manifold_edges(adj);
00488 for (int k=0; k<adj.num(); k++) {
00489 if (v->e(k)->is_strong_poly_crease()) {
00490
00491 double w = 1.0 / ++count;
00492 ret = interp(ret, get_val(v->nbr(k)), w);
00493 }
00494 }
00495 if (count != 2) {
00496 cerr << "CatmullClarkCalc::crease_centroid: "
00497 << "bad number of neighbors ("
00498 << count
00499 << ")" << endl;
00500 }
00501 return ret;
00502 }
00503
00504 T smooth_subdiv_val(CBvert* v) const {
00505
00506 int n = 0;
00507 if (v->is_manifold())
00508 n = v->degree(StrongEdgeFilter());
00509 else
00510 n = v->get_manifold_edges().filter(StrongEdgeFilter()).num();
00511 double w = (n-2)/double(n);
00512 return interp(smooth_centroid(v), get_val(v), w);
00513 }
00514 T crease_subdiv_val(CBvert* v) const {
00515
00516 return get_val(v)*0.75 + crease_centroid(v)*0.25;
00517 }
00518 T smooth_subdiv_val(CBedge* e) const {
00519 if (e->is_weak()) {
00520
00521 return fcentroid(e->f1());
00522 } else {
00523 return (
00524 get_val(e->v1()) +
00525 get_val(e->v2()) +
00526 fcentroid(e->f1()) +
00527 fcentroid(e->f2())
00528 )/4.0;
00529 }
00530 }
00531 T crease_subdiv_val(CBedge* e) const {
00532 return (get_val(e->v1()) + get_val(e->v2()))*0.5;
00533 }
00534
00535
00536 virtual T subdiv_val(CBvert* v) const {
00537
00538 int n = 0;
00539 if (v->is_manifold())
00540 n = v->degree(StrongPolyCreaseEdgeFilter());
00541 else
00542 n = v->get_manifold_edges().filter(StrongPolyCreaseEdgeFilter()).num();
00543 switch (n) {
00544 case 0:
00545 case 1:
00546 return smooth_subdiv_val(v);
00547 case 2:
00548 return crease_subdiv_val(v);
00549 default:
00550 return get_val(v);
00551 }
00552 }
00553
00554 virtual T subdiv_val(CBedge* e) const {
00555 return e->is_poly_crease() ? crease_subdiv_val(e) : smooth_subdiv_val(e);
00556 }
00557
00558 virtual T limit_val (CBvert*) const {
00559
00560 assert(0);
00561 return T();
00562 }
00563
00564 using SubdivCalc<T>::get_val;
00565 };
00566
00567 class CatmullClarkLoc : public CatmullClarkCalc<Wpt> {
00568 public:
00569
00570 virtual Wpt get_val(CBvert* v) const { return v->loc(); }
00571
00572
00573 virtual SubdivCalc<Wpt> *dup() const { return new CatmullClarkLoc(); }
00574 };
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585 template <class T>
00586 class HybridCalc : public SubdivCalc<T> {
00587 protected:
00588 LoopCalc<T> _loop_calc;
00589 CatmullClarkCalc<T> _cc_calc;
00590
00591 public:
00592
00593
00594 HybridCalc<T>() {
00595 _loop_calc.set_boss(this);
00596 _cc_calc.set_boss(this);
00597 }
00598
00599
00600 T sum(CBvert_list & p) const {
00601 T ret;
00602 clear(ret);
00603 for (int i=0; i<p.num(); i++)
00604 ret = ret + get_val(p[i]);
00605 return ret;
00606 }
00607
00608 virtual T hybrid_centroid(CBvert* v) const {
00609 Bvert_list p;
00610 Bvert_list q;
00611 Bvert_list r;
00612 Bvert_list t;
00613
00614
00615 Bedge_list e = v->get_manifold_edges();
00616 for (int i=0; i<e.num(); i++) {
00617 if (e[i]->is_strong()) {
00618 switch (e[i]->num_quads()) {
00619 case 1:
00620 r += e[i]->other_vertex(v);
00621 brcase 2:
00622 p += e[i]->other_vertex(v);
00623 brdefault:
00624 t += e[i]->other_vertex(v);
00625 }
00626 }
00627 }
00628
00629
00630 v->get_q_nbrs(q);
00631
00632
00633 double alpha = 6;
00634 double beta = 1;
00635 double gamma = 5;
00636 double delta = 4;
00637
00638 double net_weight =
00639 alpha*p.num() + beta*q.num() + gamma*r.num() + delta*t.num();
00640
00641 return (sum(p)*alpha + sum(q)*beta + sum(r)*gamma + sum(t)*delta) /
00642 net_weight;
00643 }
00644
00645
00646 virtual str_ptr name() const {
00647
00648
00649 return str_ptr("Hybrid subdivision");
00650 }
00651
00652
00653 virtual T subdiv_val(CBvert* v) const {
00654 if (v->p_degree() < 2)
00655 return get_val(v);
00656
00657
00658 int n = 0;
00659 if (v->is_manifold())
00660 n = v->degree(StrongPolyCreaseEdgeFilter());
00661 else
00662 n = v->get_manifold_edges().filter(StrongPolyCreaseEdgeFilter()).num();
00663 switch (n) {
00664 case 0:
00665 case 1: {
00666
00667
00668 if (v->num_quads()==0)
00669 return(_loop_calc.subdiv_val(v));
00670
00671
00672 else if (v->num_tris()==0)
00673 return(_cc_calc.subdiv_val(v));
00674
00675
00676 else {
00677
00678
00679 double n = v->num_tris()+(3/2.0)*v->num_quads();
00680
00681
00682 double k = (2/3.0)*n;
00683
00684
00685 double b = 5.0/8.0 - sqr(3.0 + 2.0*cos(2*M_PI/n))/64.0;
00686
00687 double loop_weight = 1-b;
00688 double cc_weight= 1 - ( 7 / (4*k) );
00689 double scaling=v->num_tris()/n;
00690 double w = loop_weight*scaling + cc_weight*(1-scaling);
00691
00692 return interp(hybrid_centroid(v), get_val(v), w);
00693 }
00694 }
00695 brcase 2:
00696 return _loop_calc.crease_subdiv_val((Lvert*)v);
00697 brdefault:
00698 return get_val(v);
00699 }
00700 }
00701
00702 virtual T subdiv_val(CBedge* e) const {
00703 if (e->is_poly_crease())
00704 return _loop_calc.subdiv_val(e);
00705 switch (e->num_quads()) {
00706 case 0: return _loop_calc.subdiv_val(e);
00707 case 2: return (_cc_calc.subdiv_val(e));
00708 default: {
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 CBface* quad = e->f1()->is_quad() ? e->f1() : e->f2();
00724 CBface* tri = e->other_face(quad);
00725 CBedge* e2 = quad->opposite_quad_edge(e);
00726 return (
00727 0.5*(get_val(e2->v1()) + get_val(e2->v2())) +
00728 3.0*(get_val(e->v1()) + get_val(e->v2())) +
00729 get_val(tri->other_vertex(e))
00730 )/8.0;
00731 }
00732 }
00733 }
00734
00735 virtual T limit_val (CBvert* v) const {
00736
00737 return _loop_calc.limit_val(v);
00738 }
00739
00740 using SubdivCalc<T>::get_val;
00741 };
00742
00743 class HybridLoc : public HybridCalc<Wpt> {
00744 public:
00745
00746 virtual Wpt get_val(CBvert* v) const { return v->loc(); }
00747
00748
00749 virtual SubdivCalc<Wpt> *dup() const { return new HybridLoc(); }
00750 };
00751
00752 typedef SubdivCalc<Wpt> SubdivLocCalc;
00753 typedef SubdivCalc<COLOR> SubdivColorCalc;
00754
00755
00756
00757
00758
00759
00760
00761
00762 template <class C>
00763 class VolPreserve : public C {
00764 public:
00765
00766 VolPreserve() : _base_calc(new C) {}
00767
00768
00769 virtual Wpt get_val(CBvert* v) const {
00770 return ((Lvert*)v)->displaced_loc(_base_calc);
00771 }
00772
00773
00774
00775
00776
00777 virtual str_ptr name() const {
00778 return C::name() + str_ptr(", with volume preservation");
00779 }
00780
00781
00782 virtual SubdivCalc<Wpt> *dup() const { return new VolPreserve<C>(); }
00783
00784 protected:
00785 C* _base_calc;
00786 };
00787
00788 typedef VolPreserve<LoopLoc> LoopVolPreserve;
00789 typedef VolPreserve<CatmullClarkLoc> CCVolPreserve;
00790 typedef VolPreserve<HybridLoc> HybridVolPreserve;
00791
00792 #endif // SUBDIV_CALC_H_IS_INCLUDED
00793
00794