OpenMesh
OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.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: 410 $                                                        *
00038 *   $Date: 2010-06-17 12:45:58 +0200 (Do, 17. Jun 2010) $                   *
00039 *                                                                           *
00040 \*==========================================================================*/
00041 
00051 //=============================================================================
00052 //
00053 //  CLASS ModifiedButterflyT
00054 //
00055 //=============================================================================
00056 
00057 
00058 #ifndef SP_MODIFIED_BUTTERFLY_H
00059 #define SP_MODIFIED_BUTTERFLY_H
00060 
00061 #include <OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh>
00062 #include <OpenMesh/Core/Utils/vector_cast.hh>
00063 #include <OpenMesh/Core/Utils/Property.hh>
00064 // -------------------- STL
00065 #include <vector>
00066 #if defined(OM_CC_MIPS)
00067 #  include <math.h>
00068 #else
00069 #  include <cmath>
00070 #endif
00071 
00072 
00073 //== NAMESPACE ================================================================
00074 
00075 namespace OpenMesh   { // BEGIN_NS_OPENMESH
00076 namespace Subdivider { // BEGIN_NS_DECIMATER
00077 namespace Uniform    { // BEGIN_NS_UNIFORM
00078 
00079 
00080 //== CLASS DEFINITION =========================================================
00081 
00082 
00091 template <typename MeshType, typename RealType = float>
00092 class ModifiedButterflyT : public SubdividerT<MeshType, RealType>
00093 {
00094 public:
00095 
00096   typedef RealType                                real_t;
00097   typedef MeshType                                mesh_t;
00098   typedef SubdividerT< mesh_t, real_t >           parent_t;
00099 
00100   typedef std::vector< std::vector<real_t> >      weights_t;
00101   typedef std::vector<real_t>                     weight_t;
00102 
00103 public:
00104 
00105 
00106   ModifiedButterflyT() : parent_t()
00107   { init_weights(); }
00108 
00109 
00110   ModifiedButterflyT( mesh_t& _m) : parent_t(_m)
00111   { init_weights(); }
00112 
00113 
00114   ~ModifiedButterflyT() {}
00115 
00116 
00117 public:
00118 
00119 
00120   const char *name() const { return "Uniform Spectral"; }
00121 
00122 
00124   void init_weights(size_t _max_valence=20)
00125   {
00126     weights.resize(_max_valence);
00127 
00128     //special case: K==3, K==4
00129     weights[3].resize(4);
00130     weights[3][0] = real_t(5.0)/12;
00131     weights[3][1] = real_t(-1.0)/12;
00132     weights[3][2] = real_t(-1.0)/12;
00133     weights[3][3] = real_t(3.0)/4;
00134 
00135     weights[4].resize(5);
00136     weights[4][0] = real_t(3.0)/8;
00137     weights[4][1] = 0;
00138     weights[4][2] = real_t(-1.0)/8;
00139     weights[4][3] = 0;
00140     weights[4][4] = real_t(3.0)/4;
00141 
00142     for(unsigned int K = 5; K<_max_valence; ++K)
00143     {
00144         weights[K].resize(K+1);
00145         // s(j) = ( 1/4 + cos(2*pi*j/K) + 1/2 * cos(4*pi*j/K) )/K
00146         real_t   invK  = 1.0/real_t(K);
00147         real_t sum = 0;
00148         for(unsigned int j=0; j<K; ++j)
00149         {
00150             weights[K][j] = (0.25 + cos(2.0*M_PI*j*invK) + 0.5*cos(4.0*M_PI*j*invK))*invK;
00151             sum += weights[K][j];
00152         }
00153         weights[K][K] = (real_t)1.0 - sum;
00154     }
00155   }
00156 
00157 
00158 protected:
00159 
00160 
00161   bool prepare( mesh_t& _m )
00162   {
00163     _m.add_property( vp_pos_ );
00164     _m.add_property( ep_pos_ );
00165     return true;
00166   }
00167 
00168 
00169   bool cleanup( mesh_t& _m )
00170   {
00171     _m.remove_property( vp_pos_ );
00172     _m.remove_property( ep_pos_ );
00173     return true;
00174   }
00175 
00176 
00177   bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true)
00178   {
00179 
00181 
00182     typename mesh_t::FaceIter   fit, f_end;
00183     typename mesh_t::EdgeIter   eit, e_end;
00184     typename mesh_t::VertexIter vit;
00185 
00186     // Do _n subdivisions
00187     for (size_t i=0; i < _n; ++i)
00188     {
00189 
00190       // This is an interpolating scheme, old vertices remain the same.
00191       typename mesh_t::VertexIter initialVerticesEnd = _m.vertices_end();
00192       for ( vit  = _m.vertices_begin(); vit != initialVerticesEnd; ++vit)
00193         _m.property( vp_pos_, vit.handle() ) = _m.point(vit.handle());
00194 
00195       // Compute position for new vertices and store them in the edge property
00196       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00197         compute_midpoint( _m, eit.handle() );
00198 
00199 
00200       // Split each edge at midpoint and store precomputed positions (stored in
00201       // edge property ep_pos_) in the vertex property vp_pos_;
00202 
00203       // Attention! Creating new edges, hence make sure the loop ends correctly.
00204       e_end = _m.edges_end();
00205       for (eit=_m.edges_begin(); eit != e_end; ++eit)
00206         split_edge(_m, eit.handle() );
00207 
00208 
00209       // Commit changes in topology and reconsitute consistency
00210 
00211       // Attention! Creating new faces, hence make sure the loop ends correctly.
00212       f_end   = _m.faces_end();
00213       for (fit = _m.faces_begin(); fit != f_end; ++fit)
00214         split_face(_m, fit.handle() );
00215 
00216 
00217       // Commit changes in geometry
00218       for ( vit  = /*initialVerticesEnd;*/_m.vertices_begin();
00219             vit != _m.vertices_end(); ++vit)
00220         _m.set_point(vit, _m.property( vp_pos_, vit ) );
00221 
00222 #if defined(_DEBUG) || defined(DEBUG)
00223       // Now we have an consistent mesh!
00224       assert( OpenMesh::Utils::MeshCheckerT<mesh_t>(_m).check() );
00225 #endif
00226     }
00227 
00228     return true;
00229   }
00230 
00231 private: // topological modifiers
00232 
00233   void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh)
00234   {
00235     typename mesh_t::HalfedgeHandle
00236       heh1(_m.halfedge_handle(_fh)),
00237       heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))),
00238       heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2)));
00239 
00240     // Cutting off every corner of the 6_gon
00241     corner_cutting( _m, heh1 );
00242     corner_cutting( _m, heh2 );
00243     corner_cutting( _m, heh3 );
00244   }
00245 
00246 
00247   void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he)
00248   {
00249     // Define Halfedge Handles
00250     typename mesh_t::HalfedgeHandle
00251       heh1(_he),
00252       heh5(heh1),
00253       heh6(_m.next_halfedge_handle(heh1));
00254 
00255     // Cycle around the polygon to find correct Halfedge
00256     for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1;
00257          heh5 = _m.next_halfedge_handle(heh5))
00258     {}
00259 
00260     typename mesh_t::VertexHandle
00261       vh1 = _m.to_vertex_handle(heh1),
00262       vh2 = _m.to_vertex_handle(heh5);
00263 
00264     typename mesh_t::HalfedgeHandle
00265       heh2(_m.next_halfedge_handle(heh5)),
00266       heh3(_m.new_edge( vh1, vh2)),
00267       heh4(_m.opposite_halfedge_handle(heh3));
00268 
00269     /* Intermediate result
00270      *
00271      *            *
00272      *         5 /|\
00273      *          /_  \
00274      *    vh2> *     *
00275      *        /|\3   |\
00276      *       /_  \|4   \
00277      *      *----\*----\*
00278      *          1 ^   6
00279      *            vh1 (adjust_outgoing halfedge!)
00280      */
00281 
00282     // Old and new Face
00283     typename mesh_t::FaceHandle     fh_old(_m.face_handle(heh6));
00284     typename mesh_t::FaceHandle     fh_new(_m.new_face());
00285 
00286 
00287     // Re-Set Handles around old Face
00288     _m.set_next_halfedge_handle(heh4, heh6);
00289     _m.set_next_halfedge_handle(heh5, heh4);
00290 
00291     _m.set_face_handle(heh4, fh_old);
00292     _m.set_face_handle(heh5, fh_old);
00293     _m.set_face_handle(heh6, fh_old);
00294     _m.set_halfedge_handle(fh_old, heh4);
00295 
00296     // Re-Set Handles around new Face
00297     _m.set_next_halfedge_handle(heh1, heh3);
00298     _m.set_next_halfedge_handle(heh3, heh2);
00299 
00300     _m.set_face_handle(heh1, fh_new);
00301     _m.set_face_handle(heh2, fh_new);
00302     _m.set_face_handle(heh3, fh_new);
00303 
00304     _m.set_halfedge_handle(fh_new, heh1);
00305   }
00306 
00307 
00308   void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh)
00309   {
00310     typename mesh_t::HalfedgeHandle
00311       heh     = _m.halfedge_handle(_eh, 0),
00312       opp_heh = _m.halfedge_handle(_eh, 1);
00313 
00314     typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh;
00315     typename mesh_t::VertexHandle   vh;
00316     typename mesh_t::VertexHandle   vh1(_m.to_vertex_handle(heh));
00317     typename mesh_t::Point          zero(0,0,0);
00318 
00319     // new vertex
00320     vh                = _m.new_vertex( zero );
00321 
00322     // memorize position, will be set later
00323     _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh );
00324 
00325 
00326     // Re-link mesh entities
00327     if (_m.is_boundary(_eh))
00328     {
00329       for (t_heh = heh;
00330            _m.next_halfedge_handle(t_heh) != opp_heh;
00331            t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00332       {}
00333     }
00334     else
00335     {
00336       for (t_heh = _m.next_halfedge_handle(opp_heh);
00337            _m.next_halfedge_handle(t_heh) != opp_heh;
00338            t_heh = _m.next_halfedge_handle(t_heh) )
00339       {}
00340     }
00341 
00342     new_heh     = _m.new_edge(vh, vh1);
00343     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00344     _m.set_vertex_handle( heh, vh );
00345 
00346     _m.set_next_halfedge_handle(t_heh, opp_new_heh);
00347     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh));
00348     _m.set_next_halfedge_handle(heh, new_heh);
00349     _m.set_next_halfedge_handle(opp_new_heh, opp_heh);
00350 
00351     if (_m.face_handle(opp_heh).is_valid())
00352     {
00353       _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00354       _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh);
00355     }
00356 
00357     _m.set_face_handle( new_heh, _m.face_handle(heh) );
00358     _m.set_halfedge_handle( vh, new_heh);
00359     _m.set_halfedge_handle( _m.face_handle(heh), heh );
00360     _m.set_halfedge_handle( vh1, opp_new_heh );
00361 
00362     // Never forget this, when playing with the topology
00363     _m.adjust_outgoing_halfedge( vh );
00364     _m.adjust_outgoing_halfedge( vh1 );
00365   }
00366 
00367 private: // geometry helper
00368 
00369   void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh)
00370   {
00371     typename mesh_t::HalfedgeHandle heh, opp_heh;
00372 
00373     heh      = _m.halfedge_handle( _eh, 0);
00374     opp_heh  = _m.halfedge_handle( _eh, 1);
00375 
00376     typename mesh_t::Point pos(0,0,0);
00377 
00378     typename mesh_t::VertexHandle a_0(_m.to_vertex_handle(heh));
00379     typename mesh_t::VertexHandle a_1(_m.to_vertex_handle(opp_heh));
00380 
00381     // boundary edge: 4-point scheme
00382     if (_m.is_boundary(_eh) )
00383     {
00384         pos = _m.point(a_0);
00385         pos += _m.point(a_1);
00386         pos *= 9.0/16;
00387         typename mesh_t::Point tpos;
00388         if(_m.is_boundary(heh))
00389         {
00390             tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00391             tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))));
00392         }
00393         else
00394         {
00395             assert(_m.is_boundary(opp_heh));
00396             tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)));
00397             tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh))));
00398         }
00399         tpos *= -1.0/16;
00400         pos += tpos;
00401     }
00402     else
00403     {
00404         int valence_a_0 = _m.valence(a_0);
00405         int valence_a_1 = _m.valence(a_1);
00406         assert(valence_a_0>2);
00407         assert(valence_a_1>2);
00408 
00409         if( (valence_a_0==6 && valence_a_1==6) || (_m.is_boundary(a_0) && valence_a_1==6) || (_m.is_boundary(a_1) && valence_a_0==6) || (_m.is_boundary(a_0) && _m.is_boundary(a_1)) )// use 8-point scheme
00410         {
00411             real_t alpha    = real_t(1.0/2);
00412             real_t beta     = real_t(1.0/8);
00413             real_t gamma    = real_t(-1.0/16);
00414 
00415             //get points
00416             typename mesh_t::VertexHandle b_0, b_1, c_0, c_1, c_2, c_3;
00417             typename mesh_t::HalfedgeHandle t_he;
00418 
00419             t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(heh));
00420             b_0 = _m.to_vertex_handle(t_he);
00421             if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he)))
00422             {
00423                 t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he));
00424                 c_0 = _m.to_vertex_handle(t_he);
00425             }
00426 
00427             t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00428             b_1 = _m.to_vertex_handle(t_he);
00429             if(!_m.is_boundary(t_he))
00430             {
00431                 t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he));
00432                 c_1 = _m.to_vertex_handle(t_he);
00433             }
00434 
00435             t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(opp_heh));
00436             assert(b_1.idx()==_m.to_vertex_handle(t_he).idx());
00437             if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he)))
00438             {
00439                 t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he));
00440                 c_2 = _m.to_vertex_handle(t_he);
00441             }
00442 
00443             t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh));
00444             assert(b_0==_m.to_vertex_handle(t_he));
00445             if(!_m.is_boundary(t_he))
00446             {
00447                 t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he));
00448                 c_3 = _m.to_vertex_handle(t_he);
00449             }
00450 
00451             //compute position.
00452             //a0,a1,b0,b1 must exist.
00453             assert(a_0.is_valid());
00454             assert(a_1.is_valid());
00455             assert(b_0.is_valid());
00456             assert(b_1.is_valid());
00457             //The other vertices may be created from symmetry is they are on the other side of the boundary.
00458 
00459             pos = _m.point(a_0);
00460             pos += _m.point(a_1);
00461             pos *= alpha;
00462 
00463             typename mesh_t::Point tpos ( _m.point(b_0) );
00464             tpos += _m.point(b_1);
00465             tpos *= beta;
00466             pos += tpos;
00467 
00468             typename mesh_t::Point pc_0, pc_1, pc_2, pc_3;
00469             if(c_0.is_valid())
00470                 pc_0 = _m.point(c_0);
00471             else //create the point by symmetry
00472             {
00473                     pc_0 = _m.point(a_1) + _m.point(b_0) - _m.point(a_0);
00474             }
00475             if(c_1.is_valid())
00476                 pc_1 = _m.point(c_1);
00477             else //create the point by symmetry
00478             {
00479                     pc_1 = _m.point(a_1) + _m.point(b_1) - _m.point(a_0);
00480             }
00481             if(c_2.is_valid())
00482                 pc_2 = _m.point(c_2);
00483             else //create the point by symmetry
00484             {
00485                     pc_2 = _m.point(a_0) + _m.point(b_1) - _m.point(a_1);
00486             }
00487             if(c_3.is_valid())
00488                 pc_3 = _m.point(c_3);
00489             else //create the point by symmetry
00490             {
00491                     pc_3 = _m.point(a_0) + _m.point(b_0) - _m.point(a_1);
00492             }
00493             tpos = pc_0;
00494             tpos += pc_1;
00495             tpos += pc_2;
00496             tpos += pc_3;
00497             tpos *= gamma;
00498             pos += tpos;
00499         }
00500         else //at least one endpoint is [irregular and not in boundary]
00501         {
00502             double normFactor = 0.0;
00503 
00504             if(valence_a_0!=6 && !_m.is_boundary(a_0))
00505             {
00506                 assert((int)weights[valence_a_0].size()==valence_a_0+1);
00507                 typename mesh_t::HalfedgeHandle t_he = opp_heh;
00508                 for(int i = 0; i < valence_a_0 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i)
00509                 {
00510                     pos += weights[valence_a_0][i] * _m.point(_m.to_vertex_handle(t_he));
00511                 }
00512                 assert(t_he==opp_heh);
00513 
00514                 //add irregular vertex:
00515                 pos += weights[valence_a_0][valence_a_0] * _m.point(a_0);
00516                 ++normFactor;
00517             }
00518 
00519             if(valence_a_1!=6  && !_m.is_boundary(a_1))
00520             {
00521                 assert((int)weights[valence_a_1].size()==valence_a_1+1);
00522                 typename mesh_t::HalfedgeHandle t_he = heh;
00523                 for(int i = 0; i < valence_a_1 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i)
00524                 {
00525                     pos += weights[valence_a_1][i] * _m.point(_m.to_vertex_handle(t_he));
00526                 }
00527                 assert(t_he==heh);
00528                 //add irregular vertex:
00529                 pos += weights[valence_a_1][valence_a_1] * _m.point(a_1);
00530                 ++normFactor;
00531             }
00532 
00533             assert(normFactor>0.1); //normFactor should be 1 or 2
00534 
00535             //if both vertices are irregular, average positions:
00536             pos /= normFactor;
00537         }
00538     }
00539     _m.property( ep_pos_, _eh ) = pos;
00540   }
00541 
00542 private: // data
00543 
00544   OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_;
00545   OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_;
00546 
00547   weights_t     weights;
00548 
00549 };
00550 
00551 } // END_NS_UNIFORM
00552 } // END_NS_SUBDIVIDER
00553 } // END_NS_OPENMESH
00554 #endif
00555 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines