OpenMesh
OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh
Go to the documentation of this file.
00001 /*===========================================================================*\
00002  *                                                                           *
00003  *                               OpenMesh                                    *
00004  *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
00005  *                           www.openmesh.org                                *
00006  *                                                                           *
00007  *---------------------------------------------------------------------------* 
00008  *  This file is part of OpenMesh.                                           *
00009  *                                                                           *
00010  *  OpenMesh is free software: you can redistribute it and/or modify         * 
00011  *  it under the terms of the GNU Lesser General Public License as           *
00012  *  published by the Free Software Foundation, either version 3 of           *
00013  *  the License, or (at your option) any later version with the              *
00014  *  following exceptions:                                                    *
00015  *                                                                           *
00016  *  If other files instantiate templates or use macros                       *
00017  *  or inline functions from this file, or you compile this file and         *
00018  *  link it with other files to produce an executable, this file does        *
00019  *  not by itself cause the resulting executable to be covered by the        *
00020  *  GNU Lesser General Public License. This exception does not however       *
00021  *  invalidate any other reasons why the executable file might be            *
00022  *  covered by the GNU Lesser General Public License.                        *
00023  *                                                                           *
00024  *  OpenMesh is distributed in the hope that it will be useful,              *
00025  *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
00026  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
00027  *  GNU Lesser General Public License for more details.                      *
00028  *                                                                           *
00029  *  You should have received a copy of the GNU LesserGeneral Public          *
00030  *  License along with OpenMesh.  If not,                                    *
00031  *  see <http://www.gnu.org/licenses/>.                                      *
00032  *                                                                           *
00033 \*===========================================================================*/ 
00034 
00035 /*===========================================================================*\
00036  *                                                                           *             
00037  *   $Revision: 520 $                                                         *
00038  *   $Date: 2012-01-20 15:29:31 +0100 (Fr, 20 Jan 2012) $                   *
00039  *                                                                           *
00040 \*===========================================================================*/
00041 
00046 //=============================================================================
00047 //
00048 //  CLASS Sqrt3T
00049 //
00050 //=============================================================================
00051 
00052 #ifndef OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00053 #define OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00054 
00055 
00056 //== INCLUDES =================================================================
00057 
00058 #include <OpenMesh/Core/Mesh/Handles.hh>
00059 #include <OpenMesh/Core/System/config.hh>
00060 #include <OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh>
00061 #if defined(_DEBUG) || defined(DEBUG)
00062 // Makes life lot easier, when playing/messing around with low-level topology
00063 // changing methods of OpenMesh
00064 #  include <OpenMesh/Tools/Utils/MeshCheckerT.hh>
00065 #  define ASSERT_CONSISTENCY( T, m ) \
00066      assert(OpenMesh::Utils::MeshCheckerT<T>(m).check())
00067 #else
00068 #  define ASSERT_CONSISTENCY( T, m )
00069 #endif
00070 // -------------------- STL
00071 #include <vector>
00072 #if defined(OM_CC_MIPS)
00073 #  include <math.h>
00074 #else
00075 #  include <cmath>
00076 #endif
00077 
00078 
00079 //== NAMESPACE ================================================================
00080 
00081 namespace OpenMesh   { // BEGIN_NS_OPENMESH
00082 namespace Subdivider { // BEGIN_NS_DECIMATER
00083 namespace Uniform    { // BEGIN_NS_DECIMATER
00084 
00085 
00086 //== CLASS DEFINITION =========================================================
00087 
00088 
00095 template <typename MeshType, typename RealType = float>
00096 class Sqrt3T : public SubdividerT< MeshType, RealType >
00097 {
00098 public:
00099 
00100   typedef RealType                                real_t;
00101   typedef MeshType                                mesh_t;
00102   typedef SubdividerT< mesh_t, real_t >           parent_t;
00103 
00104   typedef std::pair< real_t, real_t >             weight_t;
00105   typedef std::vector< std::pair<real_t,real_t> > weights_t;
00106 
00107 public:
00108 
00109 
00110   Sqrt3T(void) : parent_t(), _1over3( 1.0/3.0 ), _1over27( 1.0/27.0 )
00111   { init_weights(); }
00112 
00113   Sqrt3T(MeshType &_m) : parent_t(_m), _1over3( 1.0/3.0 ), _1over27( 1.0/27.0 )
00114   { init_weights(); }
00115 
00116   virtual ~Sqrt3T() {}
00117 
00118 
00119 public:
00120 
00121 
00122   const char *name() const { return "Uniform Sqrt3"; }
00123 
00124   
00126   void init_weights(size_t _max_valence=50)
00127   {
00128     weights_.resize(_max_valence);
00129     std::generate(weights_.begin(), weights_.end(), compute_weight());
00130   }
00131 
00132 
00133 protected:
00134 
00135 
00136   bool prepare( MeshType& _m )
00137   {
00138     _m.request_edge_status();
00139     _m.add_property( vp_pos_ );
00140     _m.add_property( ep_nv_ );
00141     _m.add_property( mp_gen_ );
00142     _m.property( mp_gen_ ) = 0;
00143 
00144     return _m.has_edge_status() && vp_pos_.is_valid() 
00145       &&   ep_nv_.is_valid() && mp_gen_.is_valid();
00146   }
00147 
00148 
00149   bool cleanup( MeshType& _m )
00150   {
00151     _m.release_edge_status();
00152     _m.remove_property( vp_pos_ );
00153     _m.remove_property( ep_nv_ );
00154     _m.remove_property( mp_gen_ );
00155     return true;
00156   }
00157 
00158   bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true)
00159   {
00160 
00162 
00163     typename MeshType::VertexIter       vit;
00164     typename MeshType::VertexVertexIter vvit;
00165     typename MeshType::EdgeIter         eit;
00166     typename MeshType::FaceIter         fit;
00167     typename MeshType::FaceVertexIter   fvit;
00168     typename MeshType::VertexHandle     vh;
00169     typename MeshType::HalfedgeHandle   heh;
00170     typename MeshType::Point            pos(0,0,0), zero(0,0,0);
00171     size_t                            &gen = _m.property( mp_gen_ );
00172 
00173     for (size_t l=0; l<_n; ++l)
00174     {
00175       // tag existing edges
00176       for (eit=_m.edges_begin(); eit != _m.edges_end();++eit)
00177       {
00178         _m.status( eit ).set_tagged( true );
00179         if ( (gen%2) && _m.is_boundary(eit) )
00180           compute_new_boundary_points( _m, eit ); // *) creates new vertices
00181       }
00182 
00183       // do relaxation of old vertices, but store new pos in property vp_pos_
00184 
00185       for (vit=_m.vertices_begin(); vit!=_m.vertices_end(); ++vit)
00186       {
00187         if ( _m.is_boundary(vit) )
00188         {
00189           if ( gen%2 )
00190           {
00191             heh  = _m.halfedge_handle(vit);
00192             if (heh.is_valid()) // skip isolated newly inserted vertices *)
00193             {
00194               typename OpenMesh::HalfedgeHandle 
00195                 prev_heh = _m.prev_halfedge_handle(heh);
00196 
00197               assert( _m.is_boundary(heh     ) );
00198               assert( _m.is_boundary(prev_heh) );
00199             
00200               pos  = _m.point(_m.to_vertex_handle(heh));
00201               pos += _m.point(_m.from_vertex_handle(prev_heh));
00202               pos *= real_t(4.0);
00203 
00204               pos += real_t(19.0) * _m.point( vit );
00205               pos *= _1over27;
00206 
00207               _m.property( vp_pos_, vit ) = pos;
00208             }
00209           }
00210           else
00211             _m.property( vp_pos_, vit ) = _m.point( vit );
00212         }
00213         else
00214         {
00215           size_t valence=0;
00216 
00217           pos = zero;
00218           for ( vvit = _m.vv_iter(vit); vvit; ++vvit)
00219           {
00220             pos += _m.point( vvit );
00221             ++valence;
00222           }
00223           pos *= weights_[ valence ].second;
00224           pos += weights_[ valence ].first * _m.point(vit);
00225           _m.property( vp_pos_, vit ) =  pos;
00226         }
00227       }   
00228 
00229       // insert new vertices, but store pos in vp_pos_
00230       typename MeshType::FaceIter fend = _m.faces_end();
00231       for (fit = _m.faces_begin();fit != fend; ++fit)
00232       {
00233         if ( (gen%2) && _m.is_boundary(fit))
00234         {
00235           boundary_split( _m, fit );
00236         }
00237         else
00238         {
00239           fvit = _m.fv_iter( fit );        
00240           pos  = _m.point(  fvit);
00241           pos += _m.point(++fvit);
00242           pos += _m.point(++fvit);
00243           pos *= _1over3;
00244           vh   = _m.add_vertex( zero );
00245           _m.property( vp_pos_, vh ) = pos;
00246           _m.split( fit, vh );
00247         }
00248       }
00249 
00250       // commit new positions (now iterating over all vertices)
00251       for (vit=_m.vertices_begin();vit != _m.vertices_end(); ++vit)
00252         _m.set_point(vit, _m.property( vp_pos_, vit ) );
00253       
00254       // flip old edges
00255       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00256         if ( _m.status( eit ).tagged() && !_m.is_boundary( eit ) )
00257           _m.flip(eit);
00258 
00259       // Now we have an consistent mesh!
00260       ASSERT_CONSISTENCY( MeshType, _m );
00261 
00262       // increase generation by one
00263       ++gen;
00264     }
00265     return true;
00266   }
00267 
00268 private:
00269 
00272   struct compute_weight 
00273   {
00274     compute_weight() : valence(-1) { }    
00275     weight_t operator() (void) 
00276     { 
00277 #if !defined(OM_CC_MIPS)
00278       using std::cos;
00279 #endif
00280       if (++valence)
00281       {
00282         real_t alpha = (4.0-2.0*cos(2.0*M_PI / (double)valence))/9.0;
00283         return weight_t( real_t(1)-alpha, alpha/real_t(valence) );
00284       }
00285       return weight_t(0.0, 0.0);
00286     }    
00287     int valence;
00288   };
00289 
00290 private:
00291 
00292   // Pre-compute location of new boundary points for odd generations
00293   // and store them in the edge property ep_nv_;
00294   void compute_new_boundary_points( MeshType& _m, 
00295                                     const typename MeshType::EdgeHandle& _eh)
00296   {
00297     assert( _m.is_boundary(_eh) );
00298 
00299     typename MeshType::HalfedgeHandle heh;
00300     typename MeshType::VertexHandle   vh1, vh2, vh3, vh4, vhl, vhr;
00301     typename MeshType::Point          zero(0,0,0), P1, P2, P3, P4;
00302 
00303     /*
00304     //       *---------*---------*
00305     //      / \       / \       / \
00306     //     /   \     /   \     /   \
00307     //    /     \   /     \   /     \
00308     //   /       \ /       \ /       \
00309     //  *---------*--#---#--*---------*
00310     //                
00311     //  ^         ^  ^   ^  ^         ^
00312     //  P1        P2 pl  pr P3        P4
00313     */
00314     // get halfedge pointing from P3 to P2 (outer boundary halfedge)
00315 
00316     heh = _m.halfedge_handle(_eh, 
00317                              _m.is_boundary(_m.halfedge_handle(_eh,1)));
00318     
00319     assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) );
00320     assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) );
00321 
00322     vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) );
00323     vh2 = _m.to_vertex_handle( heh );
00324     vh3 = _m.from_vertex_handle( heh );
00325     vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh ));
00326     
00327     P1  = _m.point(vh1);
00328     P2  = _m.point(vh2);
00329     P3  = _m.point(vh3);
00330     P4  = _m.point(vh4);
00331     
00332     vhl = _m.add_vertex(zero);
00333     vhr = _m.add_vertex(zero);
00334  
00335     _m.property(vp_pos_, vhl ) = (P1 + real_t(16.0f) * P2 + real_t(10.0f) * P3) * _1over27;
00336     _m.property(vp_pos_, vhr ) = ( real_t(10.0f) * P2 + real_t(16.0f) * P3 + P4) * _1over27;
00337     _m.property(ep_nv_, _eh).first  = vhl;
00338     _m.property(ep_nv_, _eh).second = vhr; 
00339   }
00340 
00341 
00342   void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh )
00343   {
00344     assert( _m.is_boundary(_fh) );
00345 
00346     typename MeshType::VertexHandle     vhl, vhr;
00347     typename MeshType::FaceEdgeIter     fe_it;
00348     typename MeshType::HalfedgeHandle   heh;
00349 
00350     // find boundary edge
00351     for( fe_it=_m.fe_iter( _fh ); fe_it && !_m.is_boundary( fe_it ); ++fe_it ) {};
00352 
00353     // use precomputed, already inserted but not linked vertices
00354     vhl = _m.property(ep_nv_, fe_it).first;
00355     vhr = _m.property(ep_nv_, fe_it).second;
00356 
00357     /*
00358     //       *---------*---------*
00359     //      / \       / \       / \
00360     //     /   \     /   \     /   \
00361     //    /     \   /     \   /     \
00362     //   /       \ /       \ /       \
00363     //  *---------*--#---#--*---------*
00364     //                
00365     //  ^         ^  ^   ^  ^         ^
00366     //  P1        P2 pl  pr P3        P4
00367     */
00368     // get halfedge pointing from P2 to P3 (inner boundary halfedge)
00369 
00370     heh = _m.halfedge_handle(fe_it, 
00371                              _m.is_boundary(_m.halfedge_handle(fe_it,0)));
00372 
00373     typename MeshType::HalfedgeHandle pl_P3;
00374 
00375     // split P2->P3 (heh) in P2->pl (heh) and pl->P3
00376     boundary_split( _m, heh, vhl );         // split edge
00377     pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle
00378     boundary_split( _m, heh );              // split face
00379 
00380     // split pl->P3 in pl->pr and pr->P3
00381     boundary_split( _m, pl_P3, vhr );
00382     boundary_split( _m, pl_P3 );
00383 
00384     assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() );
00385     assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() );
00386   }
00387 
00388   void boundary_split(MeshType& _m, 
00389                       const typename MeshType::HalfedgeHandle& _heh,
00390                       const typename MeshType::VertexHandle& _vh)
00391   {
00392     assert( _m.is_boundary( _m.edge_handle(_heh) ) );
00393 
00394     typename MeshType::HalfedgeHandle 
00395       heh(_heh),
00396       opp_heh( _m.opposite_halfedge_handle(_heh) ),
00397       new_heh, opp_new_heh;
00398     typename MeshType::VertexHandle   to_vh(_m.to_vertex_handle(heh));
00399     typename MeshType::HalfedgeHandle t_heh;
00400     
00401     /*
00402      *            P5
00403      *             *
00404      *            /|\
00405      *           /   \
00406      *          /     \
00407      *         /       \
00408      *        /         \
00409      *       /_ heh  new \
00410      *      *-----\*-----\*\-----*
00411      *             ^      ^ t_heh
00412      *            _vh     to_vh
00413      *
00414      *     P1     P2     P3     P4
00415      */
00416     // Re-Setting Handles
00417     
00418     // find halfedge point from P4 to P3
00419     for(t_heh = heh; 
00420         _m.next_halfedge_handle(t_heh) != opp_heh; 
00421         t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00422     {}
00423     
00424     assert( _m.is_boundary( t_heh ) );
00425 
00426     new_heh     = _m.new_edge( _vh, to_vh );
00427     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00428 
00429     // update halfedge connectivity
00430 
00431     _m.set_next_halfedge_handle(t_heh,   opp_new_heh); // P4-P3 -> P3-P2
00432     // P2-P3 -> P3-P5
00433     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh));    
00434     _m.set_next_halfedge_handle(heh,         new_heh); // P1-P2 -> P2-P3
00435     _m.set_next_halfedge_handle(opp_new_heh, opp_heh); // P3-P2 -> P2-P1
00436 
00437     // both opposite halfedges point to same face
00438     _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00439 
00440     // let heh finally point to new inserted vertex
00441     _m.set_vertex_handle(heh, _vh); 
00442 
00443     // let heh and new_heh point to same face
00444     _m.set_face_handle(new_heh, _m.face_handle(heh));
00445 
00446     // let opp_new_heh be the new outgoing halfedge for to_vh 
00447     // (replaces for opp_heh)
00448     _m.set_halfedge_handle( to_vh, opp_new_heh );
00449 
00450     // let opp_heh be the outgoing halfedge for _vh
00451     _m.set_halfedge_handle( _vh, opp_heh );
00452   }
00453 
00454   void boundary_split( MeshType& _m, 
00455                        const typename MeshType::HalfedgeHandle& _heh)
00456   {
00457     assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) );
00458 
00459     typename MeshType::HalfedgeHandle 
00460       heh(_heh),
00461       n_heh(_m.next_halfedge_handle(heh));
00462 
00463     typename MeshType::VertexHandle   
00464       to_vh(_m.to_vertex_handle(heh));
00465 
00466     typename MeshType::HalfedgeHandle 
00467       heh2(_m.new_edge(to_vh,
00468                        _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))),
00469       heh3(_m.opposite_halfedge_handle(heh2));
00470 
00471     typename MeshType::FaceHandle
00472       new_fh(_m.new_face()),
00473       fh(_m.face_handle(heh));
00474     
00475     // Relink (half)edges    
00476 
00477 #define set_next_heh set_next_halfedge_handle
00478 #define next_heh next_halfedge_handle
00479 
00480     _m.set_face_handle(heh,  new_fh);
00481     _m.set_face_handle(heh2, new_fh);
00482     _m.set_next_heh(heh2, _m.next_heh(_m.next_heh(n_heh)));
00483     _m.set_next_heh(heh,  heh2);
00484     _m.set_face_handle( _m.next_heh(heh2), new_fh);
00485 
00486     // _m.set_face_handle( _m.next_heh(_m.next_heh(heh2)), new_fh);
00487 
00488     _m.set_next_heh(heh3,                           n_heh);
00489     _m.set_next_heh(_m.next_halfedge_handle(n_heh), heh3);
00490     _m.set_face_handle(heh3,  fh);
00491     // _m.set_face_handle(n_heh, fh);
00492 
00493     _m.set_halfedge_handle(    fh, n_heh);
00494     _m.set_halfedge_handle(new_fh, heh);
00495 
00496 #undef set_next_halfedge_handle
00497 #undef next_halfedge_handle
00498 
00499   }
00500 
00501 private:
00502 
00503   weights_t     weights_;
00504   OpenMesh::VPropHandleT< typename MeshType::Point >                    vp_pos_;
00505   OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle,
00506                                      typename MeshType::VertexHandle> > ep_nv_;
00507   OpenMesh::MPropHandleT< size_t >                                      mp_gen_;
00508 
00509   const real_t _1over3;
00510   const real_t _1over27;
00511 };
00512 
00513 
00514 //=============================================================================
00515 } // END_NS_UNIFORM
00516 } // END_NS_SUBDIVIDER
00517 } // END_NS_OPENMESH
00518 //=============================================================================
00519 #endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00520 //=============================================================================