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( mesh_t& _m, size_t _n)
00178   {
00179     typename mesh_t::FaceIter   fit, f_end;
00180     typename mesh_t::EdgeIter   eit, e_end;
00181     typename mesh_t::VertexIter vit;
00182 
00183     // Do _n subdivisions
00184     for (size_t i=0; i < _n; ++i)
00185     {
00186 
00187       // This is an interpolating scheme, old vertices remain the same.
00188       typename mesh_t::VertexIter initialVerticesEnd = _m.vertices_end();
00189       for ( vit  = _m.vertices_begin(); vit != initialVerticesEnd; ++vit)
00190         _m.property( vp_pos_, vit.handle() ) = _m.point(vit.handle());
00191 
00192       // Compute position for new vertices and store them in the edge property
00193       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00194         compute_midpoint( _m, eit.handle() );
00195 
00196 
00197       // Split each edge at midpoint and store precomputed positions (stored in
00198       // edge property ep_pos_) in the vertex property vp_pos_;
00199 
00200       // Attention! Creating new edges, hence make sure the loop ends correctly.
00201       e_end = _m.edges_end();
00202       for (eit=_m.edges_begin(); eit != e_end; ++eit)
00203         split_edge(_m, eit.handle() );
00204 
00205 
00206       // Commit changes in topology and reconsitute consistency
00207 
00208       // Attention! Creating new faces, hence make sure the loop ends correctly.
00209       f_end   = _m.faces_end();
00210       for (fit = _m.faces_begin(); fit != f_end; ++fit)
00211         split_face(_m, fit.handle() );
00212 
00213 
00214       // Commit changes in geometry
00215       for ( vit  = /*initialVerticesEnd;*/_m.vertices_begin();
00216             vit != _m.vertices_end(); ++vit)
00217         _m.set_point(vit, _m.property( vp_pos_, vit ) );
00218 
00219 #if defined(_DEBUG) || defined(DEBUG)
00220       // Now we have an consistent mesh!
00221       assert( OpenMesh::Utils::MeshCheckerT<mesh_t>(_m).check() );
00222 #endif
00223     }
00224 
00225     return true;
00226   }
00227 
00228 private: // topological modifiers
00229 
00230   void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh)
00231   {
00232     typename mesh_t::HalfedgeHandle
00233       heh1(_m.halfedge_handle(_fh)),
00234       heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))),
00235       heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2)));
00236 
00237     // Cutting off every corner of the 6_gon
00238     corner_cutting( _m, heh1 );
00239     corner_cutting( _m, heh2 );
00240     corner_cutting( _m, heh3 );
00241   }
00242 
00243 
00244   void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he)
00245   {
00246     // Define Halfedge Handles
00247     typename mesh_t::HalfedgeHandle
00248       heh1(_he),
00249       heh5(heh1),
00250       heh6(_m.next_halfedge_handle(heh1));
00251 
00252     // Cycle around the polygon to find correct Halfedge
00253     for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1;
00254          heh5 = _m.next_halfedge_handle(heh5))
00255     {}
00256 
00257     typename mesh_t::VertexHandle
00258       vh1 = _m.to_vertex_handle(heh1),
00259       vh2 = _m.to_vertex_handle(heh5);
00260 
00261     typename mesh_t::HalfedgeHandle
00262       heh2(_m.next_halfedge_handle(heh5)),
00263       heh3(_m.new_edge( vh1, vh2)),
00264       heh4(_m.opposite_halfedge_handle(heh3));
00265 
00266     /* Intermediate result
00267      *
00268      *            *
00269      *         5 /|\
00270      *          /_  \
00271      *    vh2> *     *
00272      *        /|\3   |\
00273      *       /_  \|4   \
00274      *      *----\*----\*
00275      *          1 ^   6
00276      *            vh1 (adjust_outgoing halfedge!)
00277      */
00278 
00279     // Old and new Face
00280     typename mesh_t::FaceHandle     fh_old(_m.face_handle(heh6));
00281     typename mesh_t::FaceHandle     fh_new(_m.new_face());
00282 
00283 
00284     // Re-Set Handles around old Face
00285     _m.set_next_halfedge_handle(heh4, heh6);
00286     _m.set_next_halfedge_handle(heh5, heh4);
00287 
00288     _m.set_face_handle(heh4, fh_old);
00289     _m.set_face_handle(heh5, fh_old);
00290     _m.set_face_handle(heh6, fh_old);
00291     _m.set_halfedge_handle(fh_old, heh4);
00292 
00293     // Re-Set Handles around new Face
00294     _m.set_next_halfedge_handle(heh1, heh3);
00295     _m.set_next_halfedge_handle(heh3, heh2);
00296 
00297     _m.set_face_handle(heh1, fh_new);
00298     _m.set_face_handle(heh2, fh_new);
00299     _m.set_face_handle(heh3, fh_new);
00300 
00301     _m.set_halfedge_handle(fh_new, heh1);
00302   }
00303 
00304 
00305   void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh)
00306   {
00307     typename mesh_t::HalfedgeHandle
00308       heh     = _m.halfedge_handle(_eh, 0),
00309       opp_heh = _m.halfedge_handle(_eh, 1);
00310 
00311     typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh;
00312     typename mesh_t::VertexHandle   vh;
00313     typename mesh_t::VertexHandle   vh1(_m.to_vertex_handle(heh));
00314     typename mesh_t::Point          zero(0,0,0);
00315 
00316     // new vertex
00317     vh                = _m.new_vertex( zero );
00318 
00319     // memorize position, will be set later
00320     _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh );
00321 
00322 
00323     // Re-link mesh entities
00324     if (_m.is_boundary(_eh))
00325     {
00326       for (t_heh = heh;
00327            _m.next_halfedge_handle(t_heh) != opp_heh;
00328            t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00329       {}
00330     }
00331     else
00332     {
00333       for (t_heh = _m.next_halfedge_handle(opp_heh);
00334            _m.next_halfedge_handle(t_heh) != opp_heh;
00335            t_heh = _m.next_halfedge_handle(t_heh) )
00336       {}
00337     }
00338 
00339     new_heh     = _m.new_edge(vh, vh1);
00340     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00341     _m.set_vertex_handle( heh, vh );
00342 
00343     _m.set_next_halfedge_handle(t_heh, opp_new_heh);
00344     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh));
00345     _m.set_next_halfedge_handle(heh, new_heh);
00346     _m.set_next_halfedge_handle(opp_new_heh, opp_heh);
00347 
00348     if (_m.face_handle(opp_heh).is_valid())
00349     {
00350       _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00351       _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh);
00352     }
00353 
00354     _m.set_face_handle( new_heh, _m.face_handle(heh) );
00355     _m.set_halfedge_handle( vh, new_heh);
00356     _m.set_halfedge_handle( _m.face_handle(heh), heh );
00357     _m.set_halfedge_handle( vh1, opp_new_heh );
00358 
00359     // Never forget this, when playing with the topology
00360     _m.adjust_outgoing_halfedge( vh );
00361     _m.adjust_outgoing_halfedge( vh1 );
00362   }
00363 
00364 private: // geometry helper
00365 
00366   void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh)
00367   {
00368     typename mesh_t::HalfedgeHandle heh, opp_heh;
00369 
00370     heh      = _m.halfedge_handle( _eh, 0);
00371     opp_heh  = _m.halfedge_handle( _eh, 1);
00372 
00373     typename mesh_t::Point pos(0,0,0);
00374 
00375     typename mesh_t::VertexHandle a_0(_m.to_vertex_handle(heh));
00376     typename mesh_t::VertexHandle a_1(_m.to_vertex_handle(opp_heh));
00377 
00378     // boundary edge: 4-point scheme
00379     if (_m.is_boundary(_eh) )
00380     {
00381         pos = _m.point(a_0);
00382         pos += _m.point(a_1);
00383         pos *= 9.0/16;
00384         typename mesh_t::Point tpos;
00385         if(_m.is_boundary(heh))
00386         {
00387             tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00388             tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh))));
00389         }
00390         else
00391         {
00392             assert(_m.is_boundary(opp_heh));
00393             tpos = _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)));
00394             tpos += _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh))));
00395         }
00396         tpos *= -1.0/16;
00397         pos += tpos;
00398     }
00399     else
00400     {
00401         int valence_a_0 = _m.valence(a_0);
00402         int valence_a_1 = _m.valence(a_1);
00403         assert(valence_a_0>2);
00404         assert(valence_a_1>2);
00405 
00406         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
00407         {
00408             real_t alpha    = real_t(1.0/2);
00409             real_t beta     = real_t(1.0/8);
00410             real_t gamma    = real_t(-1.0/16);
00411 
00412             //get points
00413             typename mesh_t::VertexHandle b_0, b_1, c_0, c_1, c_2, c_3;
00414             typename mesh_t::HalfedgeHandle t_he;
00415 
00416             t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(heh));
00417             b_0 = _m.to_vertex_handle(t_he);
00418             if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he)))
00419             {
00420                 t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he));
00421                 c_0 = _m.to_vertex_handle(t_he);
00422             }
00423 
00424             t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00425             b_1 = _m.to_vertex_handle(t_he);
00426             if(!_m.is_boundary(t_he))
00427             {
00428                 t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he));
00429                 c_1 = _m.to_vertex_handle(t_he);
00430             }
00431 
00432             t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(opp_heh));
00433             assert(b_1.idx()==_m.to_vertex_handle(t_he).idx());
00434             if(!_m.is_boundary(_m.opposite_halfedge_handle(t_he)))
00435             {
00436                 t_he = _m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he));
00437                 c_2 = _m.to_vertex_handle(t_he);
00438             }
00439 
00440             t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(opp_heh));
00441             assert(b_0==_m.to_vertex_handle(t_he));
00442             if(!_m.is_boundary(t_he))
00443             {
00444                 t_he = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(t_he));
00445                 c_3 = _m.to_vertex_handle(t_he);
00446             }
00447 
00448             //compute position.
00449             //a0,a1,b0,b1 must exist.
00450             assert(a_0.is_valid());
00451             assert(a_1.is_valid());
00452             assert(b_0.is_valid());
00453             assert(b_1.is_valid());
00454             //The other vertices may be created from symmetry is they are on the other side of the boundary.
00455 
00456             pos = _m.point(a_0);
00457             pos += _m.point(a_1);
00458             pos *= alpha;
00459 
00460             typename mesh_t::Point tpos ( _m.point(b_0) );
00461             tpos += _m.point(b_1);
00462             tpos *= beta;
00463             pos += tpos;
00464 
00465             typename mesh_t::Point pc_0, pc_1, pc_2, pc_3;
00466             if(c_0.is_valid())
00467                 pc_0 = _m.point(c_0);
00468             else //create the point by symmetry
00469             {
00470                     pc_0 = _m.point(a_1) + _m.point(b_0) - _m.point(a_0);
00471             }
00472             if(c_1.is_valid())
00473                 pc_1 = _m.point(c_1);
00474             else //create the point by symmetry
00475             {
00476                     pc_1 = _m.point(a_1) + _m.point(b_1) - _m.point(a_0);
00477             }
00478             if(c_2.is_valid())
00479                 pc_2 = _m.point(c_2);
00480             else //create the point by symmetry
00481             {
00482                     pc_2 = _m.point(a_0) + _m.point(b_1) - _m.point(a_1);
00483             }
00484             if(c_3.is_valid())
00485                 pc_3 = _m.point(c_3);
00486             else //create the point by symmetry
00487             {
00488                     pc_3 = _m.point(a_0) + _m.point(b_0) - _m.point(a_1);
00489             }
00490             tpos = pc_0;
00491             tpos += pc_1;
00492             tpos += pc_2;
00493             tpos += pc_3;
00494             tpos *= gamma;
00495             pos += tpos;
00496         }
00497         else //at least one endpoint is [irregular and not in boundary]
00498         {
00499             double normFactor = 0.0;
00500 
00501             if(valence_a_0!=6 && !_m.is_boundary(a_0))
00502             {
00503                 assert((int)weights[valence_a_0].size()==valence_a_0+1);
00504                 typename mesh_t::HalfedgeHandle t_he = opp_heh;
00505                 for(int i = 0; i < valence_a_0 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i)
00506                 {
00507                     pos += weights[valence_a_0][i] * _m.point(_m.to_vertex_handle(t_he));
00508                 }
00509                 assert(t_he==opp_heh);
00510 
00511                 //add irregular vertex:
00512                 pos += weights[valence_a_0][valence_a_0] * _m.point(a_0);
00513                 ++normFactor;
00514             }
00515 
00516             if(valence_a_1!=6  && !_m.is_boundary(a_1))
00517             {
00518                 assert((int)weights[valence_a_1].size()==valence_a_1+1);
00519                 typename mesh_t::HalfedgeHandle t_he = heh;
00520                 for(int i = 0; i < valence_a_1 ; t_he=_m.next_halfedge_handle(_m.opposite_halfedge_handle(t_he)), ++i)
00521                 {
00522                     pos += weights[valence_a_1][i] * _m.point(_m.to_vertex_handle(t_he));
00523                 }
00524                 assert(t_he==heh);
00525                 //add irregular vertex:
00526                 pos += weights[valence_a_1][valence_a_1] * _m.point(a_1);
00527                 ++normFactor;
00528             }
00529 
00530             assert(normFactor>0.1); //normFactor should be 1 or 2
00531 
00532             //if both vertices are irregular, average positions:
00533             pos /= normFactor;
00534         }
00535     }
00536     _m.property( ep_pos_, _eh ) = pos;
00537   }
00538 
00539 private: // data
00540 
00541   OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_;
00542   OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_;
00543 
00544   weights_t     weights;
00545 
00546 };
00547 
00548 } // END_NS_UNIFORM
00549 } // END_NS_SUBDIVIDER
00550 } // END_NS_OPENMESH
00551 #endif
00552