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

lvert.C

Go to the documentation of this file.
00001 /**********************************************************************
00002  * lvert.C
00003  **********************************************************************/
00004 #include "std/config.H"
00005 #include "mesh/mi.H"
00006 #include "mesh/lmesh.H"
00007 
00008 using namespace mlib;
00009 
00010 double 
00011 loop_alpha(int n)
00012 {
00013    // do_warren means use a weight of 5/8 at each vertex instead of the
00014    // more complex computation proposed by Loop:
00015    static bool do_warren = Config::get_var_bool("DO_WARREN",false);
00016    if (do_warren)
00017       return 5.0/3*n;
00018 
00019    // Function alpha (which depends on a vertex's degree), from
00020    // section 2.1 of Hoppe et al. Siggraph 94 (see subdiv_calc.H).
00021    //
00022    // This was supposed to go in subdiv_calc.H but the sun compiler
00023    // has been taking prissiness to an extreme.
00024    //
00025    // return values are cached for vertex degrees up to 31
00026 
00027    static double _alpha[] = {
00028       1,         1,         1.282051,  2.333333,
00029       4.258065,  6.891565, 10.000000, 13.397789,
00030       16.957691, 20.598919, 24.272687, 27.950704,
00031       31.617293, 35.264345, 38.888210, 42.487807,
00032       46.063495, 49.616397, 53.148004, 56.659946,
00033       60.153856, 63.631303, 67.093752, 70.542553,
00034       73.978934, 77.404006, 80.818773, 84.224136,
00035       87.620905, 91.009809, 94.391503, 97.766576
00036    };
00037    if (n<2) {
00038       err_msg("loop_alpha: bad index %d", n);
00039       return 1;
00040    } else if (n >= 32) {
00041       // actual formula encoded in _alpha table:
00042       double b = 5.0/8.0 - sqr(3.0 + 2.0*cos(2*M_PI/n))/64.0;
00043       return n*(1-b)/b;
00044    } else {
00045       return _alpha[n];
00046    }
00047 }
00048 
00049 Lvert::~Lvert()
00050 {
00051   if (is_edge(_parent)) {
00052     ((Ledge*)_parent)->subdiv_vert_deleted();
00053   } else if (is_vert(_parent)) {
00054     ((Lvert*)_parent)->subdiv_vert_deleted();
00055   } 
00056    // subdiv vert must die with us
00057    delete_subdiv_vert();
00058 
00059    // one other thing... we have to repeat code here that's
00060    // from the Bvert destructor, since it will trigger
00061    // callbacks that come back this way, calling Lvert
00062    // methods, which won't be available once the Lvert
00063    // destructor is finished:
00064 
00065    // if the vertex dies, it takes neighboring edges and
00066    // faces with it:
00067    if (_mesh) {
00068       while (degree() > 0)
00069          _mesh->remove_edge(_adj.last());
00070    }
00071 }
00072 
00073 void    
00074 Lvert::subdiv_vert_deleted() 
00075 { 
00076   // not for public use, to be called by the child
00077   _subdiv_vertex = 0; 
00078 
00079   clear_bit(SUBDIV_LOC_VALID_BIT);
00080   clear_bit(SUBDIV_COLOR_VALID_BIT);
00081   clear_bit(SUBDIV_CORNER_VALID_BIT);
00082 }
00083 
00084 Bsimplex* 
00085 Lvert::ctrl_element() const 
00086 {
00087    if (!_parent)
00088       return (Bsimplex*)this;
00089    if (is_vert(_parent))
00090       return ((Lvert*)_parent)->ctrl_element();
00091    if (is_edge(_parent))
00092       return ((Ledge*)_parent)->ctrl_element();
00093    if (is_face(_parent))
00094       return ((Lface*)_parent)->control_face();
00095    return 0; // should never happen
00096 }
00097 
00098 Lvert* 
00099 Lvert::subdiv_vert(int level)
00100 {
00101    // Return subdiv vertex at given level down,
00102    // relative to this:
00103 
00104    if (level < 0)
00105       return 0;
00106    if (level == 0)
00107       return this;
00108    return _subdiv_vertex ? _subdiv_vertex->subdiv_vert(level-1) : 0;
00109 }
00110 
00111 Lvert* 
00112 Lvert::parent_vert(int rel_level) const 
00113 { 
00114    // Get parent vert (it it exists) at the given relative
00115    // level up from this vert
00116 
00117    Lvert* v = (Lvert*)this; 
00118    for (int i=0; v && i<rel_level; i++) {
00119       Bsimplex* p = v->parent();
00120       if (!is_vert(p))
00121          return 0;
00122       v = (Lvert*)p;
00123    }
00124 
00125    return v;
00126 }
00127 
00128 Lvert* 
00129 Lvert::cur_subdiv_vert()
00130 {
00131    // Return subdiv vertex at current subdiv level of the mesh:
00132 
00133    return _mesh ? subdiv_vert(_mesh->rel_cur_level()) : 0;
00134 }
00135 
00136 /*****************************************************************
00137  * managing the subdivision vertex
00138  *****************************************************************/
00139 Lvert*       
00140 Lvert::allocate_subdiv_vert()
00141 {
00142    // Make this lightweight, so you can call
00143    // it when you're not sure if you need to:
00144    if (is_set(SUBDIV_ALLOCATED_BIT))
00145       return _subdiv_vertex;
00146    set_bit(SUBDIV_ALLOCATED_BIT);
00147 
00148    assert(!_subdiv_vertex);
00149 
00150    LMESH* submesh = lmesh()->subdiv_mesh();
00151    assert(submesh);
00152    _subdiv_vertex = (Lvert*)submesh->add_vertex(_loc);   assert(_subdiv_vertex);
00153 
00154    _subdiv_vertex->set_parent(this);
00155 
00156    // Notify observers:
00157    if (_data_list)
00158       _data_list->notify_subdiv_gen();
00159 
00160    return _subdiv_vertex;
00161 }
00162 
00163 void
00164 Lvert::set_subdiv_vert(Lvert* subv)
00165 {
00166    if (is_set(SUBDIV_ALLOCATED_BIT)) {
00167       err_msg("Lvert::set_subdiv_vert: already set");
00168       return;
00169    }
00170    assert(!_subdiv_vertex);
00171 
00172    set_bit(SUBDIV_ALLOCATED_BIT);
00173    _subdiv_vertex = subv;
00174    if (subv) {
00175       assert(!subv->parent());
00176       assert(lmesh()->subdiv_mesh() == subv->mesh());
00177       subv->set_parent(this);
00178    }
00179 
00180    // Notify observers:
00181    if (_data_list)
00182       _data_list->notify_subdiv_gen();
00183 }
00184 
00185 void               
00186 Lvert::delete_subdiv_vert()
00187 {
00188    // Make this lightweight, so you can call
00189    // it when you're not sure if you need to:
00190    if (!is_set(SUBDIV_ALLOCATED_BIT))
00191       return;
00192    clear_bit(SUBDIV_ALLOCATED_BIT);
00193 
00194    if (_subdiv_vertex) {
00195       _subdiv_vertex->mesh()->remove_vertex(_subdiv_vertex);
00196       mark_dirty();
00197    }
00198 }
00199 
00200 Lvert*
00201 Lvert::update_subdivision()
00202 {
00203    // make sure subdiv vertex is allocated
00204    allocate_subdiv_vert();
00205    if (!_subdiv_vertex) {
00206      // this vertex generated a child at one time, but someone else
00207      // removed it at the next level down
00208       return 0;
00209    }
00210 
00211    // keep track of color, position, and corner separately
00212    // since any one can be changed independently
00213 
00214    // propagate variable sharpness corner:
00215    if (is_clear(SUBDIV_CORNER_VALID_BIT)) {
00216       set_bit(SUBDIV_CORNER_VALID_BIT);
00217       _subdiv_vertex->set_corner((_corner > 0) ? _corner - 1 : 0);
00218    }
00219 
00220    // calculate subdiv color (if needed):
00221    if (is_clear(SUBDIV_COLOR_VALID_BIT)) {
00222       set_bit(SUBDIV_COLOR_VALID_BIT);
00223       if (has_color())
00224          _subdiv_vertex->set_color(lmesh()->subdiv_color(this));
00225    }
00226 
00227    // calculate subdiv loc:
00228    if (is_clear(SUBDIV_LOC_VALID_BIT)) {
00229       set_bit(SUBDIV_LOC_VALID_BIT);
00230 
00231       // Assign subdiv loc, but defer to observers:
00232       if (!(_data_list && _data_list->handle_subdiv_calc())) {
00233         if (corner_value() > 0) 
00234           _subdiv_vertex->set_loc(loc());
00235         else
00236           _subdiv_vertex->set_subdiv_base_loc(lmesh()->subdiv_loc(this));
00237       }
00238    }
00239 
00240    // return
00241    return _subdiv_vertex;
00242 }
00243 
00244 void
00245 Lvert::set_offset(double d)
00246 {
00247    if (!_parent) {
00248       err_msg("Lvert::set_offset: error: called on control vert");
00249    } else if (_offset != d) {
00250       _offset = d;
00251       set_loc(detail_loc_from_parent());
00252    }
00253 }
00254 
00255 Wpt 
00256 Lvert::smooth_loc_from_parent() const
00257 {
00258    // Return the smooth subdiv location (without the "detail")
00259    // that would be assigned to this vertex using the SubdivCalc
00260    // of the parent LMESH:
00261 
00262    if (!_parent)
00263       return loc();
00264    assert(lmesh() && lmesh()->parent_mesh());
00265    if (is_vert(_parent))
00266       return lmesh()->parent_mesh()->subdiv_loc((Lvert*)_parent);
00267    if (is_edge(_parent))
00268       return lmesh()->parent_mesh()->subdiv_loc((Ledge*)_parent);
00269    assert(0);
00270    return Wpt::Origin();
00271 }
00272 
00273 Wpt 
00274 Lvert::detail_loc_from_parent() const
00275 {
00276    // Return smooth_loc_from_parent() + added "detail" offset:
00277 
00278    assert(_parent);
00279 
00280    return smooth_loc_from_parent() + get_norm(_parent)*_offset;
00281 }
00282 
00283 void 
00284 Lvert::set_subdiv_base_loc(CWpt& base_loc)
00285 {
00286    // Protected method called by the parent of this vertex
00287    // to set the smooth subdiv location.
00288    //
00289    // The given value base_loc is the smooth subdiv location
00290    // computed from the parent level; this vertex should now set
00291    // its location = base_loc + n*offset, where n is the normal
00292    // from the parent and offset is the subdiv offset ("detail").
00293 
00294    if (_offset == 0 || !_parent) {
00295       set_loc(base_loc);
00296    } else {
00297       set_loc(base_loc + get_norm(_parent)*_offset);
00298    }
00299 }
00300 
00301 void 
00302 Lvert::fit_subdiv_offset(CWpt& detail_loc)
00303 {
00304    // Compute and store the offset needed to approximate the
00305    // given location via the smooth subdiv loc + detail offset.
00306 
00307    if (!_parent) {
00308       set_loc(detail_loc);
00309    } else {
00310       set_offset( (detail_loc - smooth_loc_from_parent()) * get_norm(_parent) );
00311    }
00312 }
00313 
00314 Wpt&
00315 Lvert::limit_loc(Wpt& ret) const
00316 {
00317    return (ret = lmesh()->limit_loc(this));
00318 }
00319 
00320 Wvec&
00321 Lvert::loop_normal(Wvec& ret) const
00322 {
00323    return (ret = LoopLoc().limit_normal(this));
00324 }
00325 
00326 CWpt&
00327 Lvert::displaced_loc(LocCalc* c)
00328 {
00329    static double a = Config::get_var_dbl("VOL_PRESERVE_ALPHA", 0.5,true);
00330 
00331    if (!is_set(DISPLACED_LOC_VALID)) {
00332       // It's the scaled Laplacian added to the base location
00333       _displaced_loc = interp(c->subdiv_val(this), _loc, 1 + a);
00334       set_bit(DISPLACED_LOC_VALID);
00335    }
00336    return _displaced_loc;
00337 }
00338 
00339 void
00340 Lvert::mark_dirty(int bit)
00341 {
00342    if (!is_set(DEAD_BIT)) {
00343       clear_bit(bit);
00344       lmesh()->add_dirty_vert(this);
00345    }
00346 }
00347 
00348 void
00349 Lvert::crease_changed()
00350 {
00351    Bvert::crease_changed();
00352 
00353    mask_changed();
00354 }
00355 
00356 void 
00357 Lvert::degree_changed()
00358 {
00359    Bvert::degree_changed();
00360 
00361    mask_changed();
00362 }
00363 
00364 void 
00365 Lvert::mask_changed()
00366 {
00367    clear_bit(MASK_VALID_BIT);
00368    subdiv_loc_changed();
00369    subdiv_color_changed();
00370 
00371    // Edge masks depend on vertex masks.
00372    //
00373    // In the loop below, if we try to upcast an
00374    // adjacent Bedge* to Ledge* when the Bedge
00375    // constructor is not finished, the upcast is
00376    // invalid, causing a seg fault.  The following
00377    // 'if' statement is a work-around:
00378    for (int k = 0; k < degree(); k++) {
00379       if (e(k)->is_set(Ledge::MASK_VALID_BIT))
00380          le(k)->mask_changed();
00381    }
00382 }
00383 
00384 void 
00385 Lvert::geometry_changed()
00386 { 
00387    subdiv_loc_changed(); 
00388    Bvert::geometry_changed(); 
00389 }
00390 
00391 void 
00392 Lvert::normal_changed()
00393 {
00394    subdiv_loc_changed();
00395    Bvert::normal_changed();
00396 }
00397 
00398 void 
00399 Lvert::color_changed()
00400 {
00401    subdiv_color_changed();
00402    Bvert::color_changed();
00403 
00404    for (int k = 0; k < degree(); k++)
00405       le(k)->color_changed();
00406 }
00407 
00408 void  
00409 Lvert::set_corner(unsigned short c) 
00410 {
00411    if (_corner != c) {
00412       _corner = c;                              // set the new value
00413       clear_bit(SUBDIV_CORNER_VALID_BIT);       // subdiv vert is now invalid
00414       mask_changed();                           // recompute mask
00415    }
00416 }
00417 
00418 void
00419 Lvert::set_mask()
00420 {
00421    set_bit(MASK_VALID_BIT);
00422 
00423    static Bedge_list pedges;
00424    get_manifold_edges(pedges);
00425 
00426    // vertex can be explicitly set to be a "corner."  i.e., it is not
00427    // smoothed in subdivision. also applies to isolated vertices, or
00428    // vertices adjacent to just one edge.
00429    if (_corner || pedges.num() < 2) {
00430       _mask = CORNER_VERTEX;
00431       return;
00432    }
00433 
00434    // deal with the polyline case first --
00435    // a polyline edge is one w/ no adjacent faces.
00436    // polyline degree is number of such edges
00437    // connected to this vertex.
00438    int s = pedges.num_satisfy(PolylineEdgeFilter());
00439    if (s > 0) {
00440       _mask = ((s == 2) ? REGULAR_CREASE_VERTEX : CORNER_VERTEX);
00441       return;
00442    }
00443 
00444    // normal case (vertex is part of a surface).
00445    // count adjacent crease or border edges:
00446    for (int k=0; k<pedges.num(); k++)
00447       if (pedges[k]->is_crease() || pedges[k]->is_border())
00448          s++;
00449 
00450    // set mask value
00451    _mask = ((s == 0) ? SMOOTH_VERTEX             :      // no creases
00452             (s == 1) ? DART_VERTEX               :      // just one
00453             (s == 2) ? REGULAR_CREASE_VERTEX     :      // two
00454             CORNER_VERTEX);                             // wow! a whole bunch
00455 }       
00456  
00457 // end of file lvert.C

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