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: 362 $                                                         *
00038  *   $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $                   *
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 
00159   bool subdivide( MeshType& _m, size_t _n )
00160   {
00161     typename MeshType::VertexIter       vit;
00162     typename MeshType::VertexVertexIter vvit;
00163     typename MeshType::EdgeIter         eit;
00164     typename MeshType::FaceIter         fit;
00165     typename MeshType::FaceVertexIter   fvit;
00166     typename MeshType::VertexHandle     vh;
00167     typename MeshType::HalfedgeHandle   heh;
00168     typename MeshType::Point            pos(0,0,0), zero(0,0,0);
00169     size_t                            &gen = _m.property( mp_gen_ );
00170 
00171     for (size_t l=0; l<_n; ++l)
00172     {
00173       // tag existing edges
00174       for (eit=_m.edges_begin(); eit != _m.edges_end();++eit)
00175       {
00176         _m.status( eit ).set_tagged( true );
00177         if ( (gen%2) && _m.is_boundary(eit) )
00178           compute_new_boundary_points( _m, eit ); // *) creates new vertices
00179       }
00180 
00181       // do relaxation of old vertices, but store new pos in property vp_pos_
00182 
00183       for (vit=_m.vertices_begin(); vit!=_m.vertices_end(); ++vit)
00184       {
00185         if ( _m.is_boundary(vit) )
00186         {
00187           if ( gen%2 )
00188           {
00189             heh  = _m.halfedge_handle(vit);
00190             if (heh.is_valid()) // skip isolated newly inserted vertices *)
00191             {
00192               typename OpenMesh::HalfedgeHandle 
00193                 prev_heh = _m.prev_halfedge_handle(heh);
00194 
00195               assert( _m.is_boundary(heh     ) );
00196               assert( _m.is_boundary(prev_heh) );
00197             
00198               pos  = _m.point(_m.to_vertex_handle(heh));
00199               pos += _m.point(_m.from_vertex_handle(prev_heh));
00200               pos *= real_t(4.0);
00201 
00202               pos += real_t(19.0) * _m.point( vit );
00203               pos *= _1over27;
00204 
00205               _m.property( vp_pos_, vit ) = pos;
00206             }
00207           }
00208           else
00209             _m.property( vp_pos_, vit ) = _m.point( vit );
00210         }
00211         else
00212         {
00213           size_t valence=0;
00214 
00215           pos = zero;
00216           for ( vvit = _m.vv_iter(vit); vvit; ++vvit)
00217           {
00218             pos += _m.point( vvit );
00219             ++valence;
00220           }
00221           pos *= weights_[ valence ].second;
00222           pos += weights_[ valence ].first * _m.point(vit);
00223           _m.property( vp_pos_, vit ) =  pos;
00224         }
00225       }   
00226 
00227       // insert new vertices, but store pos in vp_pos_
00228       typename MeshType::FaceIter fend = _m.faces_end();
00229       for (fit = _m.faces_begin();fit != fend; ++fit)
00230       {
00231         if ( (gen%2) && _m.is_boundary(fit))
00232         {
00233           boundary_split( _m, fit );
00234         }
00235         else
00236         {
00237           fvit = _m.fv_iter( fit );        
00238           pos  = _m.point(  fvit);
00239           pos += _m.point(++fvit);
00240           pos += _m.point(++fvit);
00241           pos *= _1over3;
00242           vh   = _m.add_vertex( zero );
00243           _m.property( vp_pos_, vh ) = pos;
00244           _m.split( fit, vh );
00245         }
00246       }
00247 
00248       // commit new positions (now iterating over all vertices)
00249       for (vit=_m.vertices_begin();vit != _m.vertices_end(); ++vit)
00250         _m.set_point(vit, _m.property( vp_pos_, vit ) );
00251       
00252       // flip old edges
00253       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00254         if ( _m.status( eit ).tagged() && !_m.is_boundary( eit ) )
00255           _m.flip(eit);
00256 
00257       // Now we have an consistent mesh!
00258       ASSERT_CONSISTENCY( MeshType, _m );
00259 
00260       // increase generation by one
00261       ++gen;
00262     }
00263     return true;
00264   }
00265 
00266 private:
00267 
00270   struct compute_weight 
00271   {
00272     compute_weight() : valence(-1) { }    
00273     weight_t operator() (void) 
00274     { 
00275 #if !defined(OM_CC_MIPS)
00276       using std::cos;
00277 #endif
00278       if (++valence)
00279       {
00280         real_t alpha = (4.0-2.0*cos(2.0*M_PI / (double)valence))/9.0;
00281         return weight_t( real_t(1)-alpha, alpha/real_t(valence) );
00282       }
00283       return weight_t(0.0, 0.0);
00284     }    
00285     int valence;
00286   };
00287 
00288 private:
00289 
00290   // Pre-compute location of new boundary points for odd generations
00291   // and store them in the edge property ep_nv_;
00292   void compute_new_boundary_points( MeshType& _m, 
00293                                     const typename MeshType::EdgeHandle& _eh)
00294   {
00295     assert( _m.is_boundary(_eh) );
00296 
00297     typename MeshType::HalfedgeHandle heh;
00298     typename MeshType::VertexHandle   vh1, vh2, vh3, vh4, vhl, vhr;
00299     typename MeshType::Point          zero(0,0,0), P1, P2, P3, P4;
00300 
00301     /*
00302     //       *---------*---------*
00303     //      / \       / \       / \
00304     //     /   \     /   \     /   \
00305     //    /     \   /     \   /     \
00306     //   /       \ /       \ /       \
00307     //  *---------*--#---#--*---------*
00308     //                
00309     //  ^         ^  ^   ^  ^         ^
00310     //  P1        P2 pl  pr P3        P4
00311     */
00312     // get halfedge pointing from P3 to P2 (outer boundary halfedge)
00313 
00314     heh = _m.halfedge_handle(_eh, 
00315                              _m.is_boundary(_m.halfedge_handle(_eh,1)));
00316     
00317     assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) );
00318     assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) );
00319 
00320     vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) );
00321     vh2 = _m.to_vertex_handle( heh );
00322     vh3 = _m.from_vertex_handle( heh );
00323     vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh ));
00324     
00325     P1  = _m.point(vh1);
00326     P2  = _m.point(vh2);
00327     P3  = _m.point(vh3);
00328     P4  = _m.point(vh4);
00329     
00330     vhl = _m.add_vertex(zero);
00331     vhr = _m.add_vertex(zero);
00332  
00333     _m.property(vp_pos_, vhl ) = (P1 + real_t(16.0f) * P2 + real_t(10.0f) * P3) * _1over27;
00334     _m.property(vp_pos_, vhr ) = ( real_t(10.0f) * P2 + real_t(16.0f) * P3 + P4) * _1over27;
00335     _m.property(ep_nv_, _eh).first  = vhl;
00336     _m.property(ep_nv_, _eh).second = vhr; 
00337   }
00338 
00339 
00340   void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh )
00341   {
00342     assert( _m.is_boundary(_fh) );
00343 
00344     typename MeshType::VertexHandle     vhl, vhr;
00345     typename MeshType::FaceEdgeIter     fe_it;
00346     typename MeshType::HalfedgeHandle   heh;
00347 
00348     // find boundary edge
00349     for( fe_it=_m.fe_iter( _fh ); fe_it && !_m.is_boundary( fe_it ); ++fe_it ) {};
00350 
00351     // use precomputed, already inserted but not linked vertices
00352     vhl = _m.property(ep_nv_, fe_it).first;
00353     vhr = _m.property(ep_nv_, fe_it).second;
00354 
00355     /*
00356     //       *---------*---------*
00357     //      / \       / \       / \
00358     //     /   \     /   \     /   \
00359     //    /     \   /     \   /     \
00360     //   /       \ /       \ /       \
00361     //  *---------*--#---#--*---------*
00362     //                
00363     //  ^         ^  ^   ^  ^         ^
00364     //  P1        P2 pl  pr P3        P4
00365     */
00366     // get halfedge pointing from P2 to P3 (inner boundary halfedge)
00367 
00368     heh = _m.halfedge_handle(fe_it, 
00369                              _m.is_boundary(_m.halfedge_handle(fe_it,0)));
00370 
00371     typename MeshType::HalfedgeHandle pl_P3;
00372 
00373     // split P2->P3 (heh) in P2->pl (heh) and pl->P3
00374     boundary_split( _m, heh, vhl );         // split edge
00375     pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle
00376     boundary_split( _m, heh );              // split face
00377 
00378     // split pl->P3 in pl->pr and pr->P3
00379     boundary_split( _m, pl_P3, vhr );
00380     boundary_split( _m, pl_P3 );
00381 
00382     assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() );
00383     assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() );
00384   }
00385 
00386   void boundary_split(MeshType& _m, 
00387                       const typename MeshType::HalfedgeHandle& _heh,
00388                       const typename MeshType::VertexHandle& _vh)
00389   {
00390     assert( _m.is_boundary( _m.edge_handle(_heh) ) );
00391 
00392     typename MeshType::HalfedgeHandle 
00393       heh(_heh),
00394       opp_heh( _m.opposite_halfedge_handle(_heh) ),
00395       new_heh, opp_new_heh;
00396     typename MeshType::VertexHandle   to_vh(_m.to_vertex_handle(heh));
00397     typename MeshType::HalfedgeHandle t_heh;
00398     
00399     /*
00400      *            P5
00401      *             *
00402      *            /|\
00403      *           /   \
00404      *          /     \
00405      *         /       \
00406      *        /         \
00407      *       /_ heh  new \
00408      *      *-----\*-----\*\-----*
00409      *             ^      ^ t_heh
00410      *            _vh     to_vh
00411      *
00412      *     P1     P2     P3     P4
00413      */
00414     // Re-Setting Handles
00415     
00416     // find halfedge point from P4 to P3
00417     for(t_heh = heh; 
00418         _m.next_halfedge_handle(t_heh) != opp_heh; 
00419         t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00420     {}
00421     
00422     assert( _m.is_boundary( t_heh ) );
00423 
00424     new_heh     = _m.new_edge( _vh, to_vh );
00425     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00426 
00427     // update halfedge connectivity
00428 
00429     _m.set_next_halfedge_handle(t_heh,   opp_new_heh); // P4-P3 -> P3-P2
00430     // P2-P3 -> P3-P5
00431     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh));    
00432     _m.set_next_halfedge_handle(heh,         new_heh); // P1-P2 -> P2-P3
00433     _m.set_next_halfedge_handle(opp_new_heh, opp_heh); // P3-P2 -> P2-P1
00434 
00435     // both opposite halfedges point to same face
00436     _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00437 
00438     // let heh finally point to new inserted vertex
00439     _m.set_vertex_handle(heh, _vh); 
00440 
00441     // let heh and new_heh point to same face
00442     _m.set_face_handle(new_heh, _m.face_handle(heh));
00443 
00444     // let opp_new_heh be the new outgoing halfedge for to_vh 
00445     // (replaces for opp_heh)
00446     _m.set_halfedge_handle( to_vh, opp_new_heh );
00447 
00448     // let opp_heh be the outgoing halfedge for _vh
00449     _m.set_halfedge_handle( _vh, opp_heh );
00450   }
00451 
00452   void boundary_split( MeshType& _m, 
00453                        const typename MeshType::HalfedgeHandle& _heh)
00454   {
00455     assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) );
00456 
00457     typename MeshType::HalfedgeHandle 
00458       heh(_heh),
00459       n_heh(_m.next_halfedge_handle(heh));
00460 
00461     typename MeshType::VertexHandle   
00462       to_vh(_m.to_vertex_handle(heh));
00463 
00464     typename MeshType::HalfedgeHandle 
00465       heh2(_m.new_edge(to_vh,
00466                        _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))),
00467       heh3(_m.opposite_halfedge_handle(heh2));
00468 
00469     typename MeshType::FaceHandle
00470       new_fh(_m.new_face()),
00471       fh(_m.face_handle(heh));
00472     
00473     // Relink (half)edges    
00474 
00475 #define set_next_heh set_next_halfedge_handle
00476 #define next_heh next_halfedge_handle
00477 
00478     _m.set_face_handle(heh,  new_fh);
00479     _m.set_face_handle(heh2, new_fh);
00480     _m.set_next_heh(heh2, _m.next_heh(_m.next_heh(n_heh)));
00481     _m.set_next_heh(heh,  heh2);
00482     _m.set_face_handle( _m.next_heh(heh2), new_fh);
00483 
00484     // _m.set_face_handle( _m.next_heh(_m.next_heh(heh2)), new_fh);
00485 
00486     _m.set_next_heh(heh3,                           n_heh);
00487     _m.set_next_heh(_m.next_halfedge_handle(n_heh), heh3);
00488     _m.set_face_handle(heh3,  fh);
00489     // _m.set_face_handle(n_heh, fh);
00490 
00491     _m.set_halfedge_handle(    fh, n_heh);
00492     _m.set_halfedge_handle(new_fh, heh);
00493 
00494 #undef set_next_halfedge_handle
00495 #undef next_halfedge_handle
00496 
00497   }
00498 
00499 private:
00500 
00501   weights_t     weights_;
00502   OpenMesh::VPropHandleT< typename MeshType::Point >                    vp_pos_;
00503   OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle,
00504                                      typename MeshType::VertexHandle> > ep_nv_;
00505   OpenMesh::MPropHandleT< size_t >                                      mp_gen_;
00506 
00507   const real_t _1over3;
00508   const real_t _1over27;
00509 };
00510 
00511 
00512 //=============================================================================
00513 } // END_NS_UNIFORM
00514 } // END_NS_SUBDIVIDER
00515 } // END_NS_OPENMESH
00516 //=============================================================================
00517 #endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00518 //=============================================================================