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

subdiv_calc.H

Go to the documentation of this file.
00001 /*****************************************************************
00002  * subdiv_calc.H
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  * SubdivCalc:
00012  *
00013  *      Calculate subdivision values (e.g. position, color,
00014  *      uv-coords, etc) according to some scheme. LoopCalc,
00015  *      below, uses the scheme of Charles Loop. It's
00016  *      templated to work on different types, e.g. Wpts for
00017  *      computing subdivison postions, COLORs for computing
00018  *      subdivision colors, etc. In those examples, the
00019  *      calculations are identical, only the types are
00020  *      different. 
00021  *****************************************************************/
00022 #define CSubdivCalc const SubdivCalc
00023 template <class T>
00024 class SubdivCalc {
00025  public:
00026    //******** MANAGERS ********
00027    SubdivCalc(): _boss(0) {}
00028    virtual ~SubdivCalc() {}
00029 
00030    void set_boss(SubdivCalc<T> * boss) { _boss=boss; }
00031 
00032    //******** VALUE ACCESSORS ********
00033 
00034    // This method tells how to get the "value" out of a vertex.
00035    // Normally subclasses override it. But they can optionally
00036    // not over-ride it as long as they provide a "boss"
00037    // SubdivCalc that does over-ride it. Used in the hybrid
00038    // scheme, below, which is the boss of a LoopCalc and a
00039    // CatmullClarkCalc, calling on each as needed:
00040    virtual T get_val(CBvert* v)    const {
00041       assert(_boss);
00042       return _boss->get_val(v);
00043    }
00044 
00045    // override for types that need initialization, eg double
00046    virtual void clear(T&) const { }
00047 
00048    //******** DEBUG HELPER ********
00049 
00050    // Used mainly for debugging, to identify the type of scheme
00051    // in cerr statements:
00052    virtual str_ptr name() const {
00053       // XXX - can't use static variables ...
00054       // The Sun compiler asks that you bear with it.
00055       return str_ptr("SubdivCalc");
00056    }
00057 
00058    //******** SUBDIVISION CALCULATION ********
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    //******** DUPLICATING ********
00065 
00066    virtual SubdivCalc<T> *dup() const { return 0; }
00067 
00068  protected:
00069    SubdivCalc<T> * _boss;
00070 };
00071 
00072 /*****************************************************************
00073  * SimpleCalc:
00074  *
00075  *      Calculates subdivision values using simple averaging at
00076  *      edges, interpolating at vertices.
00077  *****************************************************************/
00078 template <class T>
00079 class SimpleCalc : public SubdivCalc<T> {
00080  public:
00081 
00082    //******** SubdivCalc VIRTUAL METHODS ********
00083    virtual str_ptr name() const {
00084       // XXX - can't use static variables ...
00085       // The Sun compiler asks that you bear with it.
00086       return str_ptr("Simple subdivision");
00087    }
00088 
00089    //******** SUBDIVISION CALCULATION ********
00090 
00091    // Interpolate at vertices:
00092    virtual T subdiv_val(CBvert* v) const { return get_val(v); }
00093 
00094    // Take midpoint average at edges:
00095    virtual T subdiv_val(CBedge* e) const {
00096       assert(e);
00097       if (e->is_weak()) {
00098 
00099          // The edge is a quad diagonal.
00100          // For quad diagonals we actually average the 4 quad points:
00101 
00102          Bface* f1 = e->f1();
00103          Bface* f2 = e->f2();
00104 
00105          // Many assumptions should hold:
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    // Interpolate at vertices:
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  * LoopCalc:
00129  *
00130  *      Calculates subdivision values using the scheme of
00131  *      Charles Loop, with special rules for creases as
00132  *      described in:
00133  *
00134  *        Hugues Hoppe, Tony DeRose, Tom Duchamp, Mark Halstead,
00135  *        Hubert Jin, John McDonald, Jean Schweitzer, and Werner
00136  *        Stuetzle. Piecewise Smooth Surface Reconstruction,
00137  *        Proceedings of SIGGRAPH 94, Computer Graphics
00138  *        Proceedings, Annual Conference Series, pp. 295-302
00139  *        (July 1994, Orlando, Florida). ACM Press. Edited by
00140  *        Andrew Glassner. ISBN 0-89791-667-0.
00141  *****************************************************************/
00142 template <class T>
00143 class LoopCalc : public SubdivCalc<T> {
00144  public:
00145 
00146    //******** SubdivCalc VIRTUAL METHODS ********
00147    virtual str_ptr name() const {
00148       // XXX - can't use static variables ...
00149       // The Sun compiler asks that you bear with it.
00150       return str_ptr("Loop subdivision");
00151    }
00152 
00153    virtual T centroid(CLvert* v) const {
00154 
00155       // Return average of neighboring vertices for use in computing
00156       // subdivision values. Here "neighbors" are those determined by
00157       // the masks in the Hoppe paper, above.
00158 
00159       switch (v->subdiv_mask()) {
00160        case Lvert::SMOOTH_VERTEX:
00161        case Lvert::DART_VERTEX:
00162        {
00163           // regular centroid -- average of all neighboring verts
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           // average of neighboring crease/border/polyline verts
00177           //
00178           // XXX - there should be exactly 2 qualified neighbors.
00179           //       should we simplify the code to rely on that?
00180           //       ... naaah.
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; // weight for incoming value
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          // if that's really the mask, we don't need the
00199          // centroid. i.e. this won't get called. return the value at
00200          // the vertex anyway.
00201          return get_val(v);
00202       }
00203    }
00204 
00205    // helpers
00206    T smooth_subdiv_val(CLvert* v) const {
00207       // Compute subdivision value for a vertex whose mask is
00208       // SMOOTH_VERTEX or DART_VERTEX
00209 
00210       // from Figure 3 in Hoppe et al. Siggraph 94 (see above).
00211 
00212       int    n = v->p_degree(); // its degree
00213       double a = loop_alpha(n); // "alpha" from Hoppe94 above
00214       double w = a / (a + n);   // weight for the vertex
00215       return interp(centroid(v), get_val(v), w);
00216    }
00217 
00218    T crease_subdiv_val(CLvert* v) const {
00219       // Compute subdivision value for a crease vertex
00220 
00221       // From figure 4 in Hoppe et al., Siggraph 94 (see above).
00222 
00223       return interp(centroid(v), get_val(v), 0.75);
00224    }
00225 
00226    T smooth_limit_val (CLvert* v) const {
00227       // Compute the limit value using the smooth limit mask.
00228 
00229       // From figure 2 in Hoppe et al., Siggraph 94 (see above).
00230 
00231       // XXX - should cache omega in lookup table:
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 //       double omega = 3 * n / (5.0 - sqr(3.0 + 2.0*cos(2*M_PI/n))/8.0);
00238 //       double w = omega / (omega + n);
00239       return interp(centroid(v), get_val(v), w);
00240    }
00241 
00242    T crease_limit_val (CLvert* v) const {
00243       // Compute limit value for a crease vertex
00244 
00245       // From figure 4 in Hoppe et al., Siggraph 94 (see above).
00246 
00247       return interp(centroid(v), get_val(v), 2.0/3);
00248    }
00249 
00250    //******** SUBDIVISION CALCULATION ********
00251    virtual T subdiv_val(CBvert* bv) const {
00252       // XXX - don't call with a non-Lvert
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       // XXX - don't call with a non-Ledge
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          // we're skipping the whole regular / non-regular thing
00278          // because this seems to work fine:
00279          return (get_val(e->v1()) + get_val(e->v2()))/2.0;
00280       }
00281    }
00282 
00283    virtual T limit_val (CBvert* bv) const {
00284       // XXX - don't call with a non-Lvert
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  * LoopLoc: Calculates subdivision positions using Loop scheme.
00303  *****************************************************************/
00304 class LoopLoc : public LoopCalc<Wpt> {
00305  public:
00306    //******** VALUE ACCESSORS ********
00307    virtual Wpt get_val(CBvert* v)   const { return v->loc(); }
00308 
00309    //******** SUBDIVISION CALCULATION ********
00310    Wvec limit_normal(CBvert* v) const {
00311       // Compute limit normal following Hoppe et al., SIGGRAPH 94.
00312       //
00313       // XXX - doesn't handle creases, just borders.
00314       //       for creases, the input arguments would have to specify
00315       //       which side to take the normal from.
00316 
00317       assert(v);
00318 
00319       // need adjacent faces to proceed:
00320       if (v->face_degree(BfaceFilter()) == 0)
00321          return Wvec::null();
00322 
00323       // until ordering CCW is fixed for non-manifold surfaces,
00324       // we'll assert the surface is manifold here:
00325       assert(v->is_manifold());
00326 
00327       // get neighbors in CCW order:
00328       Bvert_list nbrs = v->get_ccw_nbrs();
00329       assert(nbrs.num() == v->degree());
00330       
00331       Wpt t1, t2; // tangent "vectors" 
00332       int n = nbrs.num();
00333       int bd = v->border_degree();
00334       if (bd == 0) {
00335          // no borders: simple case
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          // t1: along the border:
00343          t1 = nbrs.first()->loc() + (-1 * nbrs.last()->loc());
00344          // t2 goes across the border:
00345          if (n == 4) {
00346             // regular case
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          // number of border edges not 0 or 2: error
00366          assert(0);
00367       }
00368       return (cross(t1 - Wpt::Origin(), t2 - Wpt::Origin())).normalized();
00369    }
00370 
00371    //******** DUPLICATING ********
00372    virtual SubdivCalc<Wpt> *dup() const { return new LoopLoc(); }
00373 };
00374 
00375 /*****************************************************************
00376  * LoopColor: Calculates subdivision colors using Loop scheme.
00377  *****************************************************************/
00378 class LoopColor : public LoopCalc<COLOR> {
00379  public:
00380    //******** VALUE ACCESSORS ********
00381    virtual COLOR get_val(CBvert* v) const { return v->color(); }
00382 
00383    //******** DUPLICATING ********
00384    virtual SubdivCalc<COLOR> *dup() const { return new LoopColor(); }
00385 };
00386 
00387 /*****************************************************************
00388  * CatmullClarkCalc:
00389  *
00390  *      Calculates subdivision values using the Catmull-Clark
00391  *      scheme. Based on:
00392  *
00393  *        Tony DeRose and Michael Kass and Tien Truong.
00394  *        Subdivision Surfaces in Character Animation,
00395  *        Proceedings of SIGGRAPH 98, Computer Graphics
00396  *        Proceedings, Annual Conference Series, pp. 85-94 
00397  *        (July 1998, Orlando, Florida). Addison Wesley. 
00398  *        Edited by Michael Cohen.  ISBN 0-89791-999-8.
00399  *
00400  *      The BMESH class is based on triangles (Bfaces) and
00401  *      doesn't have an explicit notion of quads or polygons
00402  *      with more than 4 sides. To work around that, an edge
00403  *      (Bedge) can be labelled "weak," which means it is
00404  *      considered to be the internal diagonal edge of a
00405  *      quad, defined by the 2 adjacent Bfaces.
00406  *
00407  *      XXX - These rules should work for meshes consisting of
00408  *      quads and triangles (possible bugs aside). However,
00409  *      meshes at this time do refinement by splitting all
00410  *      triangles 1-to-4, which means that for now Catmull-Clark
00411  *      rules should only be applied to meshes consisting
00412  *      entirely of "quads."
00413  *****************************************************************/
00414 template <class T>
00415 class CatmullClarkCalc : public SubdivCalc<T> {
00416  public:
00417 
00418    //******** SubdivCalc VIRTUAL METHODS ********
00419    virtual str_ptr name() const {
00420       // XXX - can't use static variables ...
00421       // The Sun compiler asks that you bear with it.
00422       return str_ptr("Catmull-Clark subdivision");
00423    }
00424 
00425    T vcentroid(CBvert* v) const {
00426       // "vert centroid" - average of neighboring vertices,
00427       // not counting those connected by weak edges.
00428       // At non-manifold parts of the mesh, take neighbors
00429       // just from the primary level.
00430       T ret;
00431       clear(ret);
00432       Bedge_list adj;    // adjacent edges from primary level
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             // weight for incoming value:
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       // "face centroid" - if the face is half of a quad,
00446       // returns the average of the 4 vertex values at the
00447       // corners of the quad. otherwise returns the average
00448       // of the 3 vertex values of the face.
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       // returns average of the face centroids in the given list
00456       // (usually from the 1-ring of a given vertex)
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       // value used in catmull-clark computation for
00469       // "smooth" case - average of:
00470       //   (1) vertex centroid and
00471       //   (2) average of the neighboring face centroids
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       // value used in catmull-clark computation for a
00480       // "crease" vertex. returns average of neighboring
00481       // crease/border/polyline verts.
00482       //
00483       // should only have 2 qualifying neighbors
00484       T ret;
00485       int count = 0;
00486       Bedge_list adj;    // adjacent edges from primary level
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             // weight for incoming value:
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       // catmull-clark rule for smooth vertex
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); // vertex weight
00512       return interp(smooth_centroid(v), get_val(v), w);
00513    }
00514    T crease_subdiv_val(CBvert* v) const {
00515       // catmull-clark rule for crease vertex
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          // this is really the face rule
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    //******** SUBDIVISION CALCULATION ********
00536    virtual T subdiv_val(CBvert* v) const {
00537       // count number of creases/borders
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       // XXX - not implemented yet
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    //******** VALUE ACCESSORS ********
00570    virtual Wpt get_val(CBvert* v)   const { return v->loc(); }
00571 
00572    //******** DUPLICATING ********
00573    virtual SubdivCalc<Wpt> *dup() const { return new CatmullClarkLoc(); }
00574 };
00575 
00576 /*****************************************************************
00577  * HybridCalc:
00578  *
00579  *   Scheme that is a hybrid of the Loop scheme and the
00580  *   Catmull-Clark scheme. In regions of triangles it uses the
00581  *   Loop masks. In regions of quads it uses the Catmull-clark
00582  *   masks. Along the border between the two types of regions it
00583  *   uses specialized "hybrid" masks.
00584  *****************************************************************/
00585 template <class T>
00586 class HybridCalc : public SubdivCalc<T> {
00587  protected:
00588    LoopCalc<T>          _loop_calc;  // Computes Loop scheme
00589    CatmullClarkCalc<T>  _cc_calc;    // Computes Catmull-clark scheme
00590 
00591  public:
00592 
00593    //******** MANAGERS ********
00594    HybridCalc<T>() {
00595       _loop_calc.set_boss(this);
00596       _cc_calc.set_boss(this);
00597    }
00598 
00599    //******** HELPER FUNCTIONS ********
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; // from edges whose "num quads" is 2
00610       Bvert_list q; // vertices that lie opposite this one in a quad
00611       Bvert_list r; // from edges whose "num quads" is 1
00612       Bvert_list t; // from edges whose "num quads" is 0
00613 
00614       // Load up p and r lists
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       // Get the q list
00630       v->get_q_nbrs(q);
00631 
00632       // Define weighting to use for each vertex type:
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    //******** SubdivCalc VIRTUAL METHODS ********
00646    virtual str_ptr name() const {
00647       // XXX - can't use static variables ...
00648       // The Sun compiler asks that you bear with it.
00649       return str_ptr("Hybrid subdivision");
00650    }
00651 
00652    //******** SUBDIVISION CALCULATION ********
00653    virtual T subdiv_val(CBvert* v) const {
00654       if (v->p_degree() < 2)
00655          return get_val(v);
00656 
00657       // count number of creases/borders
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           // no quads
00668           if (v->num_quads()==0)
00669              return(_loop_calc.subdiv_val(v));
00670 
00671           // all quads
00672           else if (v->num_tris()==0)
00673              return(_cc_calc.subdiv_val(v));
00674 
00675           // mix
00676           else {
00677 
00678              // "degree" of vertex
00679              double n = v->num_tris()+(3/2.0)*v->num_quads();
00680 
00681              // k used in cc calculation
00682              double k = (2/3.0)*n;
00683 
00684              // used for loop calculation
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);  // All Loop
00707        case 2:  return (_cc_calc.subdiv_val(e));  // All Catmull-Clark
00708        default: {
00709           //
00710           //       Hybrid case
00711           //
00712           //            3_________ 0.5       
00713           //           /|         |          
00714           //         /  |         |          
00715           //       /    |         |          
00716           //   1 /      | e       | e2       
00717           //     \  tri |         |         
00718           //       \    |   quad  |          
00719           //         \  |         |          
00720           //           \|_________|
00721           //            3          0.5
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       // XXX - not implemented yet -- go with Loop calculation
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    //******** VALUE ACCESSORS ********
00746    virtual Wpt get_val(CBvert* v)   const { return v->loc(); }
00747 
00748    //******** DUPLICATING ********
00749    virtual SubdivCalc<Wpt> *dup() const { return new HybridLoc(); }
00750 };
00751 
00752 typedef SubdivCalc<Wpt>   SubdivLocCalc;
00753 typedef SubdivCalc<COLOR> SubdivColorCalc;
00754 
00755 /*****************************************************************
00756  * VolPreserve:
00757  *
00758  *      Does subdivision via any given scheme (its base class),
00759  *      with a correction to control the change in volume at each
00760  *      refinement.
00761  *****************************************************************/
00762 template <class C>
00763 class VolPreserve : public C {
00764  public:
00765    //******** MANAGERS ********
00766    VolPreserve() : _base_calc(new C) {}
00767 
00768    //******** VALUE ACCESSORS ********
00769    virtual Wpt get_val(CBvert* v)   const {
00770       return ((Lvert*)v)->displaced_loc(_base_calc);
00771    }
00772 
00773    //******** DEBUG HELPER ********
00774 
00775    // Used mainly for debugging, to identify the type of scheme
00776    // in cerr statements:
00777    virtual str_ptr name() const {
00778       return C::name() + str_ptr(", with volume preservation");
00779    }
00780 
00781    //******** DUPLICATING ********
00782    virtual SubdivCalc<Wpt> *dup() const { return new VolPreserve<C>(); }
00783 
00784  protected:
00785    C*   _base_calc; // instance of plain base class
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 // end of file subdiv_calc.H

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