OpenMesh
OpenMesh/Tools/Subdivider/Uniform/Sqrt3InterpolatingSubdividerLabsikGreinerT.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 InterpolatingSqrt3LGT
00054 //
00055 //=============================================================================
00056 
00057 #ifndef OPENMESH_SUBDIVIDER_UNIFORM_INTERP_SQRT3T_LABSIK_GREINER_HH
00058 #define OPENMESH_SUBDIVIDER_UNIFORM_INTERP_SQRT3T_LABSIK_GREINER_HH
00059 
00060 
00061 //== INCLUDES =================================================================
00062 
00063 #include <OpenMesh/Core/Mesh/Handles.hh>
00064 #include <OpenMesh/Core/System/config.hh>
00065 #include <OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh>
00066 
00067 #if defined(_DEBUG) || defined(DEBUG)
00068 // Makes life lot easier, when playing/messing around with low-level topology
00069 // changing methods of OpenMesh
00070 #  include <OpenMesh/Tools/Utils/MeshCheckerT.hh>
00071 #  define ASSERT_CONSISTENCY( T, m ) \
00072      assert(OpenMesh::Utils::MeshCheckerT<T>(m).check())
00073 #else
00074 #  define ASSERT_CONSISTENCY( T, m )
00075 #endif
00076 // -------------------- STL
00077 #include <vector>
00078 #if defined(OM_CC_MIPS)
00079 #  include <math.h>
00080 #else
00081 #  include <cmath>
00082 #endif
00083 
00084 //#define MIRROR_TRIANGLES
00085 //#define MIN_NORM
00086 
00087 //== NAMESPACE ================================================================
00088 
00089 namespace OpenMesh   { // BEGIN_NS_OPENMESH
00090 namespace Subdivider { // BEGIN_NS_DECIMATER
00091 namespace Uniform    { // BEGIN_NS_UNIFORM
00092 
00093 
00094 //== CLASS DEFINITION =========================================================
00095 
00096 
00105 template <typename MeshType, typename RealType = float>
00106 class InterpolatingSqrt3LGT : public SubdividerT< MeshType, RealType >
00107 {
00108 public:
00109 
00110   typedef RealType                                real_t;
00111   typedef MeshType                                mesh_t;
00112   typedef SubdividerT< mesh_t, real_t >           parent_t;
00113 
00114   typedef std::vector< std::vector<real_t> >      weights_t;
00115 
00116 public:
00117 
00118 
00119   InterpolatingSqrt3LGT(void) : parent_t()
00120   { init_weights(); }
00121 
00122   InterpolatingSqrt3LGT(MeshType &_m) : parent_t(_m)
00123   { init_weights(); }
00124 
00125   virtual ~InterpolatingSqrt3LGT() {}
00126 
00127 
00128 public:
00129 
00130 
00131   const char *name() const { return "Uniform Interpolating Sqrt3"; }
00132 
00134   void init_weights(size_t _max_valence=50)
00135   {
00136     weights_.resize(_max_valence);
00137 
00138     weights_[3].resize(4);
00139     weights_[3][0] = +4.0/27;
00140     weights_[3][1] = -5.0/27;
00141     weights_[3][2] = +4.0/27;
00142     weights_[3][3] = +8.0/9;
00143 
00144     weights_[4].resize(5);
00145     weights_[4][0] = +2.0/9;
00146     weights_[4][1] = -1.0/9;
00147     weights_[4][2] = -1.0/9;
00148     weights_[4][3] = +2.0/9;
00149     weights_[4][4] = +7.0/9 ;
00150 
00151     for(unsigned int K=5; K<_max_valence; ++K)
00152     {
00153         weights_[K].resize(K+1);
00154         double aH = 2.0*cos(M_PI/K)/3.0;
00155         weights_[K][K] = 1.0 - aH*aH;
00156         for(unsigned int i=0; i<K; ++i)
00157         {
00158             weights_[K][i] = (aH*aH + 2.0*aH*cos(2.0*i*M_PI/K + M_PI/K) + 2.0*aH*aH*cos(4.0*i*M_PI/K + 2.0*M_PI/K))/K;
00159         }
00160     }
00161 
00162     //just to be sure:
00163     weights_[6].resize(0);
00164 
00165   }
00166 
00167 
00168 protected:
00169 
00170 
00171   bool prepare( MeshType& _m )
00172   {
00173     _m.request_edge_status();
00174     _m.add_property( fp_pos_ );
00175     _m.add_property( ep_nv_ );
00176     _m.add_property( mp_gen_ );
00177     _m.property( mp_gen_ ) = 0;
00178 
00179     return _m.has_edge_status() 
00180       &&   ep_nv_.is_valid() && mp_gen_.is_valid();
00181   }
00182 
00183 
00184   bool cleanup( MeshType& _m )
00185   {
00186     _m.release_edge_status();
00187     _m.remove_property( fp_pos_ );
00188     _m.remove_property( ep_nv_ );
00189     _m.remove_property( mp_gen_ );
00190     return true;
00191   }
00192 
00193 
00194   bool subdivide( MeshType& _m, size_t _n , const bool _update_points = true)
00195   {
00196 
00198 
00199     typename MeshType::VertexIter       vit;
00200     typename MeshType::VertexVertexIter vvit;
00201     typename MeshType::EdgeIter         eit;
00202     typename MeshType::FaceIter         fit;
00203     typename MeshType::FaceVertexIter   fvit;
00204     typename MeshType::FaceHalfedgeIter fheit;
00205     typename MeshType::VertexHandle     vh;
00206     typename MeshType::HalfedgeHandle   heh;
00207     typename MeshType::Point            pos(0,0,0), zero(0,0,0);
00208     size_t                              &gen = _m.property( mp_gen_ );
00209 
00210     for (size_t l=0; l<_n; ++l)
00211     {
00212       // tag existing edges
00213       for (eit=_m.edges_begin(); eit != _m.edges_end();++eit)
00214       {
00215         _m.status( eit ).set_tagged( true );
00216         if ( (gen%2) && _m.is_boundary(eit) )
00217           compute_new_boundary_points( _m, eit ); // *) creates new vertices
00218       }
00219 
00220       // insert new vertices, and store pos in vp_pos_
00221       typename MeshType::FaceIter fend = _m.faces_end();
00222       for (fit = _m.faces_begin();fit != fend; ++fit)
00223       {
00224         if (_m.is_boundary(fit))
00225         {
00226             if(gen%2)
00227                 _m.property(fp_pos_, fit.handle()).invalidate();
00228             else
00229             {
00230                 //find the interior boundary halfedge
00231                 for( heh = _m.halfedge_handle(fit.handle()); !_m.is_boundary( _m.opposite_halfedge_handle(heh) ); heh = _m.next_halfedge_handle(heh) )
00232                   ;
00233                 assert(_m.is_boundary( _m.opposite_halfedge_handle(heh) ));
00234                 pos = zero;
00235                 //check for two boundaries case:
00236                 if( _m.is_boundary(_m.next_halfedge_handle(heh)) || _m.is_boundary(_m.prev_halfedge_handle(heh)) )
00237                 {
00238                     if(_m.is_boundary(_m.prev_halfedge_handle(heh)))
00239                         heh = _m.prev_halfedge_handle(heh); //ensure that the boundary halfedges are heh and heh->next
00240                     //check for three boundaries case:
00241                     if(_m.is_boundary(_m.next_halfedge_handle(_m.next_halfedge_handle(heh))))
00242                     {
00243                         //three boundaries, use COG of triangle
00244                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00245                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00246                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00247                     }
00248                     else
00249                     {
00250 #ifdef MIRROR_TRIANGLES
00251                         //two boundaries, mirror two triangles
00252                         pos += real_t(2.0/9) * _m.point(_m.to_vertex_handle(heh));
00253                         pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00254                         pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00255                         pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))));
00256 #else
00257                         pos += real_t(7.0/24) * _m.point(_m.to_vertex_handle(heh));
00258                         pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00259                         pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00260                         pos += real_t(-1.0/24) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))));
00261 #endif
00262                     }
00263                 }
00264                 else
00265                 {
00266                     vh = _m.to_vertex_handle(_m.next_halfedge_handle(heh));
00267                     //check last vertex regularity
00268                     if((_m.valence(vh) == 6) || _m.is_boundary(vh))
00269                     {
00270 #ifdef MIRROR_TRIANGLES
00271                         //use regular rule and mirror one triangle
00272                         pos += real_t(5.0/9) * _m.point(vh);
00273                         pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(heh));
00274                         pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00275                         pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh)))));
00276                         pos += real_t(-1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))));
00277 #else
00278 #ifdef MIN_NORM
00279                         pos += real_t(1.0/9) * _m.point(vh);
00280                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00281                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00282                         pos += real_t(1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh)))));
00283                         pos += real_t(1.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))));
00284 #else
00285                         pos += real_t(1.0/2) * _m.point(vh);
00286                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00287                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00288                         pos += real_t(-1.0/12) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.next_halfedge_handle(heh)))));
00289                         pos += real_t(-1.0/12) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(_m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)))));
00290 #endif
00291 #endif
00292                     }
00293                     else
00294                     {
00295                         //irregular setting, use usual irregular rule
00296                         unsigned int K = _m.valence(vh);
00297                         pos += weights_[K][K]*_m.point(vh);
00298                         heh = _m.opposite_halfedge_handle( _m.next_halfedge_handle(heh) );
00299                         for(unsigned int i = 0; i<K; ++i, heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)) )
00300                         {
00301                             pos += weights_[K][i]*_m.point(_m.to_vertex_handle(heh));
00302                         }
00303                     }
00304                 }
00305                 vh   = _m.add_vertex( pos );
00306                 _m.property(fp_pos_, fit.handle()) = vh;
00307             }
00308         }
00309         else
00310         {
00311             pos = zero;
00312             int nOrdinary = 0;
00313             
00314             //check number of extraordinary vertices
00315             for(fvit = _m.fv_iter( fit ); fvit; ++fvit)
00316                 if( (_m.valence(fvit.handle())) == 6 || _m.is_boundary(fvit.handle()) )
00317                     ++nOrdinary;
00318 
00319             if(nOrdinary==3)
00320             {
00321                 for(fheit = _m.fh_iter( fit ); fheit; ++fheit)
00322                 {
00323                     //one ring vertex has weight 32/81
00324                     heh = fheit.handle();
00325                     assert(_m.to_vertex_handle(heh).is_valid());
00326                     pos += real_t(32.0/81) * _m.point(_m.to_vertex_handle(heh));
00327                     //tip vertex has weight -1/81
00328                     heh = _m.opposite_halfedge_handle(heh);
00329                     assert(heh.is_valid());
00330                     assert(_m.next_halfedge_handle(heh).is_valid());
00331                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00332                     pos -= real_t(1.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00333                     //outer vertices have weight -2/81
00334                     heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00335                     assert(heh.is_valid());
00336                     assert(_m.next_halfedge_handle(heh).is_valid());
00337                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00338                     pos -= real_t(2.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00339                     heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00340                     assert(heh.is_valid());
00341                     assert(_m.next_halfedge_handle(heh).is_valid());
00342                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00343                     pos -= real_t(2.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00344                 }
00345             }
00346             else
00347             {
00348                 //only use irregular vertices:
00349                 for(fheit = _m.fh_iter( fit ); fheit; ++fheit)
00350                 {
00351                     vh = _m.to_vertex_handle(fheit);
00352                     if( (_m.valence(vh) != 6) && (!_m.is_boundary(vh)) )
00353                     {
00354                         unsigned int K = _m.valence(vh);
00355                         pos += weights_[K][K]*_m.point(vh);
00356                         heh = _m.opposite_halfedge_handle( fheit.handle() );
00357                         for(unsigned int i = 0; i<K; ++i, heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)) )
00358                         {
00359                             pos += weights_[K][i]*_m.point(_m.to_vertex_handle(heh));
00360                         }
00361                     }
00362                 }
00363                 pos *= real_t(1.0/(3-nOrdinary));
00364             }
00365 
00366             vh   = _m.add_vertex( pos );
00367             _m.property(fp_pos_, fit.handle()) = vh;
00368         }
00369       }
00370 
00371       //split faces
00372       for (fit = _m.faces_begin();fit != fend; ++fit)
00373       {
00374         if ( _m.is_boundary(fit) && (gen%2))
00375         {
00376                 boundary_split( _m, fit );
00377         }
00378         else
00379         {
00380             assert(_m.property(fp_pos_, fit.handle()).is_valid());
00381             _m.split( fit, _m.property(fp_pos_, fit.handle()) );
00382         }
00383       }
00384 
00385       // flip old edges
00386       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00387         if ( _m.status( eit ).tagged() && !_m.is_boundary( eit ) )
00388           _m.flip(eit);
00389 
00390       // Now we have an consistent mesh!
00391       ASSERT_CONSISTENCY( MeshType, _m );
00392 
00393       // increase generation by one
00394       ++gen;
00395     }
00396     return true;
00397   }
00398 
00399 private:
00400 
00401   // Pre-compute location of new boundary points for odd generations
00402   // and store them in the edge property ep_nv_;
00403   void compute_new_boundary_points( MeshType& _m, 
00404                                     const typename MeshType::EdgeHandle& _eh)
00405   {
00406     assert( _m.is_boundary(_eh) );
00407 
00408     typename MeshType::HalfedgeHandle heh;
00409     typename MeshType::VertexHandle   vh1, vh2, vh3, vh4, vhl, vhr;
00410     typename MeshType::Point          zero(0,0,0), P1, P2, P3, P4;
00411 
00412     /*
00413     //       *---------*---------*
00414     //      / \       / \       / \
00415     //     /   \     /   \     /   \
00416     //    /     \   /     \   /     \
00417     //   /       \ /       \ /       \
00418     //  *---------*--#---#--*---------*
00419     //                
00420     //  ^         ^  ^   ^  ^         ^
00421     //  P1        P2 pl  pr P3        P4
00422     */
00423     // get halfedge pointing from P3 to P2 (outer boundary halfedge)
00424 
00425     heh = _m.halfedge_handle(_eh, 
00426                              _m.is_boundary(_m.halfedge_handle(_eh,1)));
00427     
00428     assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) );
00429     assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) );
00430 
00431     vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) );
00432     vh2 = _m.to_vertex_handle( heh );
00433     vh3 = _m.from_vertex_handle( heh );
00434     vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh ));
00435     
00436     P1  = _m.point(vh1);
00437     P2  = _m.point(vh2);
00438     P3  = _m.point(vh3);
00439     P4  = _m.point(vh4);
00440 
00441     vhl = _m.add_vertex(real_t(-5.0/81)*P1 + real_t(20.0/27)*P2 + real_t(10.0/27)*P3 + real_t(-4.0/81)*P4);
00442     vhr = _m.add_vertex(real_t(-5.0/81)*P4 + real_t(20.0/27)*P3 + real_t(10.0/27)*P2 + real_t(-4.0/81)*P1);
00443 
00444     _m.property(ep_nv_, _eh).first  = vhl;
00445     _m.property(ep_nv_, _eh).second = vhr; 
00446   }
00447 
00448 
00449   void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh )
00450   {
00451     assert( _m.is_boundary(_fh) );
00452 
00453     typename MeshType::VertexHandle     vhl, vhr;
00454     typename MeshType::FaceEdgeIter     fe_it;
00455     typename MeshType::HalfedgeHandle   heh;
00456 
00457     // find boundary edge
00458     for( fe_it=_m.fe_iter( _fh ); fe_it && !_m.is_boundary( fe_it ); ++fe_it ) {};
00459 
00460     // use precomputed, already inserted but not linked vertices
00461     vhl = _m.property(ep_nv_, fe_it).first;
00462     vhr = _m.property(ep_nv_, fe_it).second;
00463 
00464     /*
00465     //       *---------*---------*
00466     //      / \       / \       / \
00467     //     /   \     /   \     /   \
00468     //    /     \   /     \   /     \
00469     //   /       \ /       \ /       \
00470     //  *---------*--#---#--*---------*
00471     //                
00472     //  ^         ^  ^   ^  ^         ^
00473     //  P1        P2 pl  pr P3        P4
00474     */
00475     // get halfedge pointing from P2 to P3 (inner boundary halfedge)
00476 
00477     heh = _m.halfedge_handle(fe_it, 
00478                              _m.is_boundary(_m.halfedge_handle(fe_it,0)));
00479 
00480     typename MeshType::HalfedgeHandle pl_P3;
00481 
00482     // split P2->P3 (heh) in P2->pl (heh) and pl->P3
00483     boundary_split( _m, heh, vhl );         // split edge
00484     pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle
00485     boundary_split( _m, heh );              // split face
00486 
00487     // split pl->P3 in pl->pr and pr->P3
00488     boundary_split( _m, pl_P3, vhr );
00489     boundary_split( _m, pl_P3 );
00490 
00491     assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() );
00492     assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() );
00493   }
00494 
00495   void boundary_split(MeshType& _m, 
00496                       const typename MeshType::HalfedgeHandle& _heh,
00497                       const typename MeshType::VertexHandle& _vh)
00498   {
00499     assert( _m.is_boundary( _m.edge_handle(_heh) ) );
00500 
00501     typename MeshType::HalfedgeHandle 
00502       heh(_heh),
00503       opp_heh( _m.opposite_halfedge_handle(_heh) ),
00504       new_heh, opp_new_heh;
00505     typename MeshType::VertexHandle   to_vh(_m.to_vertex_handle(heh));
00506     typename MeshType::HalfedgeHandle t_heh;
00507     
00508     /*
00509      *            P5
00510      *             *
00511      *            /|\
00512      *           /   \
00513      *          /     \
00514      *         /       \
00515      *        /         \
00516      *       /_ heh  new \
00517      *      *-----\*-----\*\-----*
00518      *             ^      ^ t_heh
00519      *            _vh     to_vh
00520      *
00521      *     P1     P2     P3     P4
00522      */
00523     // Re-Setting Handles
00524     
00525     // find halfedge point from P4 to P3
00526     for(t_heh = heh; 
00527         _m.next_halfedge_handle(t_heh) != opp_heh; 
00528         t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00529     {}
00530     
00531     assert( _m.is_boundary( t_heh ) );
00532 
00533     new_heh     = _m.new_edge( _vh, to_vh );
00534     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00535 
00536     // update halfedge connectivity
00537     _m.set_next_halfedge_handle(t_heh,   opp_new_heh);                  // P4-P3 -> P3-P2
00538     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); // P2-P3 -> P3-P5   
00539     _m.set_next_halfedge_handle(heh,         new_heh);                  // P1-P2 -> P2-P3
00540     _m.set_next_halfedge_handle(opp_new_heh, opp_heh);                  // P3-P2 -> P2-P1
00541 
00542     // both opposite halfedges point to same face
00543     _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00544 
00545     // let heh finally point to new inserted vertex
00546     _m.set_vertex_handle(heh, _vh); 
00547 
00548     // let heh and new_heh point to same face
00549     _m.set_face_handle(new_heh, _m.face_handle(heh));
00550 
00551     // let opp_new_heh be the new outgoing halfedge for to_vh 
00552     // (replaces for opp_heh)
00553     _m.set_halfedge_handle( to_vh, opp_new_heh );
00554 
00555     // let opp_heh be the outgoing halfedge for _vh
00556     _m.set_halfedge_handle( _vh, opp_heh );
00557   }
00558 
00559   void boundary_split( MeshType& _m, 
00560                        const typename MeshType::HalfedgeHandle& _heh)
00561   {
00562     assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) );
00563 
00564     typename MeshType::HalfedgeHandle 
00565       heh(_heh),
00566       n_heh(_m.next_halfedge_handle(heh));
00567 
00568     typename MeshType::VertexHandle   
00569       to_vh(_m.to_vertex_handle(heh));
00570 
00571     typename MeshType::HalfedgeHandle 
00572       heh2(_m.new_edge(to_vh,
00573                        _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))),
00574       heh3(_m.opposite_halfedge_handle(heh2));
00575 
00576     typename MeshType::FaceHandle
00577       new_fh(_m.new_face()),
00578       fh(_m.face_handle(heh));
00579     
00580     // Relink (half)edges    
00581     _m.set_face_handle(heh,  new_fh);
00582     _m.set_face_handle(heh2, new_fh);
00583     _m.set_next_halfedge_handle(heh2, _m.next_halfedge_handle(_m.next_halfedge_handle(n_heh)));
00584     _m.set_next_halfedge_handle(heh,  heh2);
00585     _m.set_face_handle( _m.next_halfedge_handle(heh2), new_fh);
00586 
00587     _m.set_next_halfedge_handle(heh3,                           n_heh);
00588     _m.set_next_halfedge_handle(_m.next_halfedge_handle(n_heh), heh3);
00589     _m.set_face_handle(heh3,  fh);
00590 
00591     _m.set_halfedge_handle(    fh, n_heh);
00592     _m.set_halfedge_handle(new_fh, heh);
00593 
00594 
00595   }
00596 
00597 private:
00598 
00599   weights_t     weights_;
00600   OpenMesh::FPropHandleT< typename MeshType::VertexHandle >             fp_pos_;
00601   OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle,
00602                                      typename MeshType::VertexHandle> > ep_nv_;
00603   OpenMesh::MPropHandleT< size_t >                                      mp_gen_;
00604 };
00605 
00606 
00607 //=============================================================================
00608 } // END_NS_UNIFORM
00609 } // END_NS_SUBDIVIDER
00610 } // END_NS_OPENMESH
00611 //=============================================================================
00612 #endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00613 //=============================================================================