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 )
00195   {
00196     typename MeshType::VertexIter       vit;
00197     typename MeshType::VertexVertexIter vvit;
00198     typename MeshType::EdgeIter         eit;
00199     typename MeshType::FaceIter         fit;
00200     typename MeshType::FaceVertexIter   fvit;
00201     typename MeshType::FaceHalfedgeIter fheit;
00202     typename MeshType::VertexHandle     vh;
00203     typename MeshType::HalfedgeHandle   heh;
00204     typename MeshType::Point            pos(0,0,0), zero(0,0,0);
00205     size_t                              &gen = _m.property( mp_gen_ );
00206 
00207     for (size_t l=0; l<_n; ++l)
00208     {
00209       // tag existing edges
00210       for (eit=_m.edges_begin(); eit != _m.edges_end();++eit)
00211       {
00212         _m.status( eit ).set_tagged( true );
00213         if ( (gen%2) && _m.is_boundary(eit) )
00214           compute_new_boundary_points( _m, eit ); // *) creates new vertices
00215       }
00216 
00217       // insert new vertices, and store pos in vp_pos_
00218       typename MeshType::FaceIter fend = _m.faces_end();
00219       for (fit = _m.faces_begin();fit != fend; ++fit)
00220       {
00221         if (_m.is_boundary(fit))
00222         {
00223             if(gen%2)
00224                 _m.property(fp_pos_, fit.handle()).invalidate();
00225             else
00226             {
00227                 //find the interior boundary halfedge
00228                 for( heh = _m.halfedge_handle(fit.handle()); !_m.is_boundary( _m.opposite_halfedge_handle(heh) ); heh = _m.next_halfedge_handle(heh) )
00229                   ;
00230                 assert(_m.is_boundary( _m.opposite_halfedge_handle(heh) ));
00231                 pos = zero;
00232                 //check for two boundaries case:
00233                 if( _m.is_boundary(_m.next_halfedge_handle(heh)) || _m.is_boundary(_m.prev_halfedge_handle(heh)) )
00234                 {
00235                     if(_m.is_boundary(_m.prev_halfedge_handle(heh)))
00236                         heh = _m.prev_halfedge_handle(heh); //ensure that the boundary halfedges are heh and heh->next
00237                     //check for three boundaries case:
00238                     if(_m.is_boundary(_m.next_halfedge_handle(_m.next_halfedge_handle(heh))))
00239                     {
00240                         //three boundaries, use COG of triangle
00241                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00242                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00243                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00244                     }
00245                     else
00246                     {
00247 #ifdef MIRROR_TRIANGLES
00248                         //two boundaries, mirror two triangles
00249                         pos += real_t(2.0/9) * _m.point(_m.to_vertex_handle(heh));
00250                         pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00251                         pos += real_t(4.0/9) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00252                         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)))));
00253 #else
00254                         pos += real_t(7.0/24) * _m.point(_m.to_vertex_handle(heh));
00255                         pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00256                         pos += real_t(3.0/8) * _m.point(_m.to_vertex_handle(_m.prev_halfedge_handle(heh)));
00257                         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)))));
00258 #endif
00259                     }
00260                 }
00261                 else
00262                 {
00263                     vh = _m.to_vertex_handle(_m.next_halfedge_handle(heh));
00264                     //check last vertex regularity
00265                     if((_m.valence(vh) == 6) || _m.is_boundary(vh))
00266                     {
00267 #ifdef MIRROR_TRIANGLES
00268                         //use regular rule and mirror one triangle
00269                         pos += real_t(5.0/9) * _m.point(vh);
00270                         pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(heh));
00271                         pos += real_t(3.0/9) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00272                         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)))));
00273                         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)))));
00274 #else
00275 #ifdef MIN_NORM
00276                         pos += real_t(1.0/9) * _m.point(vh);
00277                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00278                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00279                         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)))));
00280                         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)))));
00281 #else
00282                         pos += real_t(1.0/2) * _m.point(vh);
00283                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(heh));
00284                         pos += real_t(1.0/3) * _m.point(_m.to_vertex_handle(_m.opposite_halfedge_handle(heh)));
00285                         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)))));
00286                         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)))));
00287 #endif
00288 #endif
00289                     }
00290                     else
00291                     {
00292                         //irregular setting, use usual irregular rule
00293                         unsigned int K = _m.valence(vh);
00294                         pos += weights_[K][K]*_m.point(vh);
00295                         heh = _m.opposite_halfedge_handle( _m.next_halfedge_handle(heh) );
00296                         for(unsigned int i = 0; i<K; ++i, heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)) )
00297                         {
00298                             pos += weights_[K][i]*_m.point(_m.to_vertex_handle(heh));
00299                         }
00300                     }
00301                 }
00302                 vh   = _m.add_vertex( pos );
00303                 _m.property(fp_pos_, fit.handle()) = vh;
00304             }
00305         }
00306         else
00307         {
00308             pos = zero;
00309             int nOrdinary = 0;
00310             
00311             //check number of extraordinary vertices
00312             for(fvit = _m.fv_iter( fit ); fvit; ++fvit)
00313                 if( (_m.valence(fvit.handle())) == 6 || _m.is_boundary(fvit.handle()) )
00314                     ++nOrdinary;
00315 
00316             if(nOrdinary==3)
00317             {
00318                 for(fheit = _m.fh_iter( fit ); fheit; ++fheit)
00319                 {
00320                     //one ring vertex has weight 32/81
00321                     heh = fheit.handle();
00322                     assert(_m.to_vertex_handle(heh).is_valid());
00323                     pos += real_t(32.0/81) * _m.point(_m.to_vertex_handle(heh));
00324                     //tip vertex has weight -1/81
00325                     heh = _m.opposite_halfedge_handle(heh);
00326                     assert(heh.is_valid());
00327                     assert(_m.next_halfedge_handle(heh).is_valid());
00328                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00329                     pos -= real_t(1.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00330                     //outer vertices have weight -2/81
00331                     heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00332                     assert(heh.is_valid());
00333                     assert(_m.next_halfedge_handle(heh).is_valid());
00334                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00335                     pos -= real_t(2.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00336                     heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh));
00337                     assert(heh.is_valid());
00338                     assert(_m.next_halfedge_handle(heh).is_valid());
00339                     assert(_m.to_vertex_handle(_m.next_halfedge_handle(heh)).is_valid());
00340                     pos -= real_t(2.0/81) * _m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)));
00341                 }
00342             }
00343             else
00344             {
00345                 //only use irregular vertices:
00346                 for(fheit = _m.fh_iter( fit ); fheit; ++fheit)
00347                 {
00348                     vh = _m.to_vertex_handle(fheit);
00349                     if( (_m.valence(vh) != 6) && (!_m.is_boundary(vh)) )
00350                     {
00351                         unsigned int K = _m.valence(vh);
00352                         pos += weights_[K][K]*_m.point(vh);
00353                         heh = _m.opposite_halfedge_handle( fheit.handle() );
00354                         for(unsigned int i = 0; i<K; ++i, heh = _m.opposite_halfedge_handle(_m.prev_halfedge_handle(heh)) )
00355                         {
00356                             pos += weights_[K][i]*_m.point(_m.to_vertex_handle(heh));
00357                         }
00358                     }
00359                 }
00360                 pos *= real_t(1.0/(3-nOrdinary));
00361             }
00362 
00363             vh   = _m.add_vertex( pos );
00364             _m.property(fp_pos_, fit.handle()) = vh;
00365         }
00366       }
00367 
00368       //split faces
00369       for (fit = _m.faces_begin();fit != fend; ++fit)
00370       {
00371         if ( _m.is_boundary(fit) && (gen%2))
00372         {
00373                 boundary_split( _m, fit );
00374         }
00375         else
00376         {
00377             assert(_m.property(fp_pos_, fit.handle()).is_valid());
00378             _m.split( fit, _m.property(fp_pos_, fit.handle()) );
00379         }
00380       }
00381 
00382       // flip old edges
00383       for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit)
00384         if ( _m.status( eit ).tagged() && !_m.is_boundary( eit ) )
00385           _m.flip(eit);
00386 
00387       // Now we have an consistent mesh!
00388       ASSERT_CONSISTENCY( MeshType, _m );
00389 
00390       // increase generation by one
00391       ++gen;
00392     }
00393     return true;
00394   }
00395 
00396 private:
00397 
00398   // Pre-compute location of new boundary points for odd generations
00399   // and store them in the edge property ep_nv_;
00400   void compute_new_boundary_points( MeshType& _m, 
00401                                     const typename MeshType::EdgeHandle& _eh)
00402   {
00403     assert( _m.is_boundary(_eh) );
00404 
00405     typename MeshType::HalfedgeHandle heh;
00406     typename MeshType::VertexHandle   vh1, vh2, vh3, vh4, vhl, vhr;
00407     typename MeshType::Point          zero(0,0,0), P1, P2, P3, P4;
00408 
00409     /*
00410     //       *---------*---------*
00411     //      / \       / \       / \
00412     //     /   \     /   \     /   \
00413     //    /     \   /     \   /     \
00414     //   /       \ /       \ /       \
00415     //  *---------*--#---#--*---------*
00416     //                
00417     //  ^         ^  ^   ^  ^         ^
00418     //  P1        P2 pl  pr P3        P4
00419     */
00420     // get halfedge pointing from P3 to P2 (outer boundary halfedge)
00421 
00422     heh = _m.halfedge_handle(_eh, 
00423                              _m.is_boundary(_m.halfedge_handle(_eh,1)));
00424     
00425     assert( _m.is_boundary( _m.next_halfedge_handle( heh ) ) );
00426     assert( _m.is_boundary( _m.prev_halfedge_handle( heh ) ) );
00427 
00428     vh1 = _m.to_vertex_handle( _m.next_halfedge_handle( heh ) );
00429     vh2 = _m.to_vertex_handle( heh );
00430     vh3 = _m.from_vertex_handle( heh );
00431     vh4 = _m.from_vertex_handle( _m.prev_halfedge_handle( heh ));
00432     
00433     P1  = _m.point(vh1);
00434     P2  = _m.point(vh2);
00435     P3  = _m.point(vh3);
00436     P4  = _m.point(vh4);
00437 
00438     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);
00439     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);
00440 
00441     _m.property(ep_nv_, _eh).first  = vhl;
00442     _m.property(ep_nv_, _eh).second = vhr; 
00443   }
00444 
00445 
00446   void boundary_split( MeshType& _m, const typename MeshType::FaceHandle& _fh )
00447   {
00448     assert( _m.is_boundary(_fh) );
00449 
00450     typename MeshType::VertexHandle     vhl, vhr;
00451     typename MeshType::FaceEdgeIter     fe_it;
00452     typename MeshType::HalfedgeHandle   heh;
00453 
00454     // find boundary edge
00455     for( fe_it=_m.fe_iter( _fh ); fe_it && !_m.is_boundary( fe_it ); ++fe_it ) {};
00456 
00457     // use precomputed, already inserted but not linked vertices
00458     vhl = _m.property(ep_nv_, fe_it).first;
00459     vhr = _m.property(ep_nv_, fe_it).second;
00460 
00461     /*
00462     //       *---------*---------*
00463     //      / \       / \       / \
00464     //     /   \     /   \     /   \
00465     //    /     \   /     \   /     \
00466     //   /       \ /       \ /       \
00467     //  *---------*--#---#--*---------*
00468     //                
00469     //  ^         ^  ^   ^  ^         ^
00470     //  P1        P2 pl  pr P3        P4
00471     */
00472     // get halfedge pointing from P2 to P3 (inner boundary halfedge)
00473 
00474     heh = _m.halfedge_handle(fe_it, 
00475                              _m.is_boundary(_m.halfedge_handle(fe_it,0)));
00476 
00477     typename MeshType::HalfedgeHandle pl_P3;
00478 
00479     // split P2->P3 (heh) in P2->pl (heh) and pl->P3
00480     boundary_split( _m, heh, vhl );         // split edge
00481     pl_P3 = _m.next_halfedge_handle( heh ); // store next halfedge handle
00482     boundary_split( _m, heh );              // split face
00483 
00484     // split pl->P3 in pl->pr and pr->P3
00485     boundary_split( _m, pl_P3, vhr );
00486     boundary_split( _m, pl_P3 );
00487 
00488     assert( _m.is_boundary( vhl ) && _m.halfedge_handle(vhl).is_valid() );
00489     assert( _m.is_boundary( vhr ) && _m.halfedge_handle(vhr).is_valid() );
00490   }
00491 
00492   void boundary_split(MeshType& _m, 
00493                       const typename MeshType::HalfedgeHandle& _heh,
00494                       const typename MeshType::VertexHandle& _vh)
00495   {
00496     assert( _m.is_boundary( _m.edge_handle(_heh) ) );
00497 
00498     typename MeshType::HalfedgeHandle 
00499       heh(_heh),
00500       opp_heh( _m.opposite_halfedge_handle(_heh) ),
00501       new_heh, opp_new_heh;
00502     typename MeshType::VertexHandle   to_vh(_m.to_vertex_handle(heh));
00503     typename MeshType::HalfedgeHandle t_heh;
00504     
00505     /*
00506      *            P5
00507      *             *
00508      *            /|\
00509      *           /   \
00510      *          /     \
00511      *         /       \
00512      *        /         \
00513      *       /_ heh  new \
00514      *      *-----\*-----\*\-----*
00515      *             ^      ^ t_heh
00516      *            _vh     to_vh
00517      *
00518      *     P1     P2     P3     P4
00519      */
00520     // Re-Setting Handles
00521     
00522     // find halfedge point from P4 to P3
00523     for(t_heh = heh; 
00524         _m.next_halfedge_handle(t_heh) != opp_heh; 
00525         t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh)))
00526     {}
00527     
00528     assert( _m.is_boundary( t_heh ) );
00529 
00530     new_heh     = _m.new_edge( _vh, to_vh );
00531     opp_new_heh = _m.opposite_halfedge_handle(new_heh);
00532 
00533     // update halfedge connectivity
00534     _m.set_next_halfedge_handle(t_heh,   opp_new_heh);                  // P4-P3 -> P3-P2
00535     _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); // P2-P3 -> P3-P5   
00536     _m.set_next_halfedge_handle(heh,         new_heh);                  // P1-P2 -> P2-P3
00537     _m.set_next_halfedge_handle(opp_new_heh, opp_heh);                  // P3-P2 -> P2-P1
00538 
00539     // both opposite halfedges point to same face
00540     _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh));
00541 
00542     // let heh finally point to new inserted vertex
00543     _m.set_vertex_handle(heh, _vh); 
00544 
00545     // let heh and new_heh point to same face
00546     _m.set_face_handle(new_heh, _m.face_handle(heh));
00547 
00548     // let opp_new_heh be the new outgoing halfedge for to_vh 
00549     // (replaces for opp_heh)
00550     _m.set_halfedge_handle( to_vh, opp_new_heh );
00551 
00552     // let opp_heh be the outgoing halfedge for _vh
00553     _m.set_halfedge_handle( _vh, opp_heh );
00554   }
00555 
00556   void boundary_split( MeshType& _m, 
00557                        const typename MeshType::HalfedgeHandle& _heh)
00558   {
00559     assert( _m.is_boundary( _m.opposite_halfedge_handle( _heh ) ) );
00560 
00561     typename MeshType::HalfedgeHandle 
00562       heh(_heh),
00563       n_heh(_m.next_halfedge_handle(heh));
00564 
00565     typename MeshType::VertexHandle   
00566       to_vh(_m.to_vertex_handle(heh));
00567 
00568     typename MeshType::HalfedgeHandle 
00569       heh2(_m.new_edge(to_vh,
00570                        _m.to_vertex_handle(_m.next_halfedge_handle(n_heh)))),
00571       heh3(_m.opposite_halfedge_handle(heh2));
00572 
00573     typename MeshType::FaceHandle
00574       new_fh(_m.new_face()),
00575       fh(_m.face_handle(heh));
00576     
00577     // Relink (half)edges    
00578     _m.set_face_handle(heh,  new_fh);
00579     _m.set_face_handle(heh2, new_fh);
00580     _m.set_next_halfedge_handle(heh2, _m.next_halfedge_handle(_m.next_halfedge_handle(n_heh)));
00581     _m.set_next_halfedge_handle(heh,  heh2);
00582     _m.set_face_handle( _m.next_halfedge_handle(heh2), new_fh);
00583 
00584     _m.set_next_halfedge_handle(heh3,                           n_heh);
00585     _m.set_next_halfedge_handle(_m.next_halfedge_handle(n_heh), heh3);
00586     _m.set_face_handle(heh3,  fh);
00587 
00588     _m.set_halfedge_handle(    fh, n_heh);
00589     _m.set_halfedge_handle(new_fh, heh);
00590 
00591 
00592   }
00593 
00594 private:
00595 
00596   weights_t     weights_;
00597   OpenMesh::FPropHandleT< typename MeshType::VertexHandle >             fp_pos_;
00598   OpenMesh::EPropHandleT< std::pair< typename MeshType::VertexHandle,
00599                                      typename MeshType::VertexHandle> > ep_nv_;
00600   OpenMesh::MPropHandleT< size_t >                                      mp_gen_;
00601 };
00602 
00603 
00604 //=============================================================================
00605 } // END_NS_UNIFORM
00606 } // END_NS_SUBDIVIDER
00607 } // END_NS_OPENMESH
00608 //=============================================================================
00609 #endif // OPENMESH_SUBDIVIDER_UNIFORM_SQRT3T_HH
00610 //=============================================================================