OpenMesh
|
00001 /*===========================================================================*\ 00002 * * 00003 * OpenMesh * 00004 * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * 00005 * www.openmesh.org * 00006 * * 00007 *---------------------------------------------------------------------------* 00008 * This file is part of OpenMesh. * 00009 * * 00010 * OpenMesh is free software: you can redistribute it and/or modify * 00011 * it under the terms of the GNU Lesser General Public License as * 00012 * published by the Free Software Foundation, either version 3 of * 00013 * the License, or (at your option) any later version with the * 00014 * following exceptions: * 00015 * * 00016 * If other files instantiate templates or use macros * 00017 * or inline functions from this file, or you compile this file and * 00018 * link it with other files to produce an executable, this file does * 00019 * not by itself cause the resulting executable to be covered by the * 00020 * GNU Lesser General Public License. This exception does not however * 00021 * invalidate any other reasons why the executable file might be * 00022 * covered by the GNU Lesser General Public License. * 00023 * * 00024 * OpenMesh is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU Lesser General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU LesserGeneral Public * 00030 * License along with OpenMesh. If not, * 00031 * see <http://www.gnu.org/licenses/>. * 00032 * * 00033 \*===========================================================================*/ 00034 00035 /*===========================================================================*\ 00036 * * 00037 * $Revision: 362 $ * 00038 * $Date: 2011-01-26 10:21:12 +0100 (Mi, 26 Jan 2011) $ * 00039 * * 00040 \*===========================================================================*/ 00041 00046 //============================================================================= 00047 // 00048 // CLASS LoopT 00049 // 00050 //============================================================================= 00051 00052 #ifndef OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH 00053 #define OPENMESH_SUBDIVIDER_UNIFORM_LOOPT_HH 00054 00055 00056 //== INCLUDES ================================================================= 00057 00058 #include <OpenMesh/Core/System/config.hh> 00059 #include <OpenMesh/Tools/Subdivider/Uniform/SubdividerT.hh> 00060 #include <OpenMesh/Core/Utils/vector_cast.hh> 00061 // -------------------- STL 00062 #include <vector> 00063 #if defined(OM_CC_MIPS) 00064 # include <math.h> 00065 #else 00066 # include <cmath> 00067 #endif 00068 00069 00070 //== NAMESPACE ================================================================ 00071 00072 namespace OpenMesh { // BEGIN_NS_OPENMESH 00073 namespace Subdivider { // BEGIN_NS_DECIMATER 00074 namespace Uniform { // BEGIN_NS_DECIMATER 00075 00076 00077 //== CLASS DEFINITION ========================================================= 00078 00087 template <typename MeshType, typename RealType = float> 00088 class LoopT : public SubdividerT<MeshType, RealType> 00089 { 00090 public: 00091 00092 typedef RealType real_t; 00093 typedef MeshType mesh_t; 00094 typedef SubdividerT< mesh_t, real_t > parent_t; 00095 00096 typedef std::pair< real_t, real_t > weight_t; 00097 typedef std::vector< std::pair<real_t,real_t> > weights_t; 00098 00099 public: 00100 00101 00102 LoopT(void) : parent_t(), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) 00103 { init_weights(); } 00104 00105 00106 LoopT( mesh_t& _m ) : parent_t(_m), _1over8( 1.0/8.0 ), _3over8( 3.0/8.0 ) 00107 { init_weights(); } 00108 00109 00110 ~LoopT() {} 00111 00112 00113 public: 00114 00115 00116 const char *name() const { return "Uniform Loop"; } 00117 00118 00120 void init_weights(size_t _max_valence=50) 00121 { 00122 weights_.resize(_max_valence); 00123 std::generate(weights_.begin(), weights_.end(), compute_weight()); 00124 } 00125 00126 00127 protected: 00128 00129 00130 bool prepare( mesh_t& _m ) 00131 { 00132 _m.add_property( vp_pos_ ); 00133 _m.add_property( ep_pos_ ); 00134 return true; 00135 } 00136 00137 00138 bool cleanup( mesh_t& _m ) 00139 { 00140 _m.remove_property( vp_pos_ ); 00141 _m.remove_property( ep_pos_ ); 00142 return true; 00143 } 00144 00145 00146 bool subdivide( mesh_t& _m, size_t _n) 00147 { 00148 typename mesh_t::FaceIter fit, f_end; 00149 typename mesh_t::EdgeIter eit, e_end; 00150 typename mesh_t::VertexIter vit; 00151 00152 // Do _n subdivisions 00153 for (size_t i=0; i < _n; ++i) 00154 { 00155 // compute new positions for old vertices 00156 for ( vit = _m.vertices_begin(); 00157 vit != _m.vertices_end(); ++vit) 00158 smooth( _m, vit.handle() ); 00159 00160 00161 // Compute position for new vertices and store them in the edge property 00162 for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) 00163 compute_midpoint( _m, eit.handle() ); 00164 00165 00166 // Split each edge at midpoint and store precomputed positions (stored in 00167 // edge property ep_pos_) in the vertex property vp_pos_; 00168 00169 // Attention! Creating new edges, hence make sure the loop ends correctly. 00170 e_end = _m.edges_end(); 00171 for (eit=_m.edges_begin(); eit != e_end; ++eit) 00172 split_edge(_m, eit.handle() ); 00173 00174 00175 // Commit changes in topology and reconsitute consistency 00176 00177 // Attention! Creating new faces, hence make sure the loop ends correctly. 00178 f_end = _m.faces_end(); 00179 for (fit = _m.faces_begin(); fit != f_end; ++fit) 00180 split_face(_m, fit.handle() ); 00181 00182 00183 // Commit changes in geometry 00184 for ( vit = _m.vertices_begin(); 00185 vit != _m.vertices_end(); ++vit) 00186 _m.set_point(vit, _m.property( vp_pos_, vit ) ); 00187 00188 #if defined(_DEBUG) || defined(DEBUG) 00189 // Now we have an consistent mesh! 00190 assert( OpenMesh::Utils::MeshCheckerT<mesh_t>(_m).check() ); 00191 #endif 00192 } 00193 00194 return true; 00195 } 00196 00197 private: 00198 00201 struct compute_weight 00202 { 00203 compute_weight() : valence(-1) { } 00204 weight_t operator() (void) 00205 { 00206 #if !defined(OM_CC_MIPS) 00207 using std::cos; 00208 #endif 00209 // 1 00210 // alpha(n) = ---- * (40 - ( 3 + 2 cos( 2 Pi / n ) )² ) 00211 // 64 00212 00213 if (++valence) 00214 { 00215 double inv_v = 1.0/double(valence); 00216 double t = (3.0 + 2.0 * cos( 2.0 * M_PI * inv_v) ); 00217 double alpha = (40.0 - t * t)/64.0; 00218 00219 return weight_t( 1.0-alpha, inv_v*alpha); 00220 } 00221 return weight_t(0.0, 0.0); 00222 } 00223 int valence; 00224 }; 00225 00226 private: // topological modifiers 00227 00228 void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh) 00229 { 00230 typename mesh_t::HalfedgeHandle 00231 heh1(_m.halfedge_handle(_fh)), 00232 heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))), 00233 heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2))); 00234 00235 // Cutting off every corner of the 6_gon 00236 corner_cutting( _m, heh1 ); 00237 corner_cutting( _m, heh2 ); 00238 corner_cutting( _m, heh3 ); 00239 } 00240 00241 00242 void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he) 00243 { 00244 // Define Halfedge Handles 00245 typename mesh_t::HalfedgeHandle 00246 heh1(_he), 00247 heh5(heh1), 00248 heh6(_m.next_halfedge_handle(heh1)); 00249 00250 // Cycle around the polygon to find correct Halfedge 00251 for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1; 00252 heh5 = _m.next_halfedge_handle(heh5)) 00253 {} 00254 00255 typename mesh_t::VertexHandle 00256 vh1 = _m.to_vertex_handle(heh1), 00257 vh2 = _m.to_vertex_handle(heh5); 00258 00259 typename mesh_t::HalfedgeHandle 00260 heh2(_m.next_halfedge_handle(heh5)), 00261 heh3(_m.new_edge( vh1, vh2)), 00262 heh4(_m.opposite_halfedge_handle(heh3)); 00263 00264 /* Intermediate result 00265 * 00266 * * 00267 * 5 /|\ 00268 * /_ \ 00269 * vh2> * * 00270 * /|\3 |\ 00271 * /_ \|4 \ 00272 * *----\*----\* 00273 * 1 ^ 6 00274 * vh1 (adjust_outgoing halfedge!) 00275 */ 00276 00277 // Old and new Face 00278 typename mesh_t::FaceHandle fh_old(_m.face_handle(heh6)); 00279 typename mesh_t::FaceHandle fh_new(_m.new_face()); 00280 00281 00282 // Re-Set Handles around old Face 00283 _m.set_next_halfedge_handle(heh4, heh6); 00284 _m.set_next_halfedge_handle(heh5, heh4); 00285 00286 _m.set_face_handle(heh4, fh_old); 00287 _m.set_face_handle(heh5, fh_old); 00288 _m.set_face_handle(heh6, fh_old); 00289 _m.set_halfedge_handle(fh_old, heh4); 00290 00291 // Re-Set Handles around new Face 00292 _m.set_next_halfedge_handle(heh1, heh3); 00293 _m.set_next_halfedge_handle(heh3, heh2); 00294 00295 _m.set_face_handle(heh1, fh_new); 00296 _m.set_face_handle(heh2, fh_new); 00297 _m.set_face_handle(heh3, fh_new); 00298 00299 _m.set_halfedge_handle(fh_new, heh1); 00300 } 00301 00302 00303 void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) 00304 { 00305 typename mesh_t::HalfedgeHandle 00306 heh = _m.halfedge_handle(_eh, 0), 00307 opp_heh = _m.halfedge_handle(_eh, 1); 00308 00309 typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh; 00310 typename mesh_t::VertexHandle vh; 00311 typename mesh_t::VertexHandle vh1(_m.to_vertex_handle(heh)); 00312 typename mesh_t::Point zero(0,0,0); 00313 00314 // new vertex 00315 vh = _m.new_vertex( zero ); 00316 00317 // memorize position, will be set later 00318 _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh ); 00319 00320 00321 // Re-link mesh entities 00322 if (_m.is_boundary(_eh)) 00323 { 00324 for (t_heh = heh; 00325 _m.next_halfedge_handle(t_heh) != opp_heh; 00326 t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) 00327 {} 00328 } 00329 else 00330 { 00331 for (t_heh = _m.next_halfedge_handle(opp_heh); 00332 _m.next_halfedge_handle(t_heh) != opp_heh; 00333 t_heh = _m.next_halfedge_handle(t_heh) ) 00334 {} 00335 } 00336 00337 new_heh = _m.new_edge(vh, vh1); 00338 opp_new_heh = _m.opposite_halfedge_handle(new_heh); 00339 _m.set_vertex_handle( heh, vh ); 00340 00341 _m.set_next_halfedge_handle(t_heh, opp_new_heh); 00342 _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); 00343 _m.set_next_halfedge_handle(heh, new_heh); 00344 _m.set_next_halfedge_handle(opp_new_heh, opp_heh); 00345 00346 if (_m.face_handle(opp_heh).is_valid()) 00347 { 00348 _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); 00349 _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); 00350 } 00351 00352 _m.set_face_handle( new_heh, _m.face_handle(heh) ); 00353 _m.set_halfedge_handle( vh, new_heh); 00354 _m.set_halfedge_handle( _m.face_handle(heh), heh ); 00355 _m.set_halfedge_handle( vh1, opp_new_heh ); 00356 00357 // Never forget this, when playing with the topology 00358 _m.adjust_outgoing_halfedge( vh ); 00359 _m.adjust_outgoing_halfedge( vh1 ); 00360 } 00361 00362 private: // geometry helper 00363 00364 void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) 00365 { 00366 #define V( X ) vector_cast< typename mesh_t::Normal >( X ) 00367 typename mesh_t::HalfedgeHandle heh, opp_heh; 00368 00369 heh = _m.halfedge_handle( _eh, 0); 00370 opp_heh = _m.halfedge_handle( _eh, 1); 00371 00372 typename mesh_t::Point 00373 pos(_m.point(_m.to_vertex_handle(heh))); 00374 00375 pos += V( _m.point(_m.to_vertex_handle(opp_heh)) ); 00376 00377 // boundary edge: just average vertex positions 00378 if (_m.is_boundary(_eh) ) 00379 { 00380 pos *= 0.5; 00381 } 00382 else // inner edge: add neighbouring Vertices to sum 00383 { 00384 pos *= real_t(3.0); 00385 pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)))); 00386 pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)))); 00387 pos *= _1over8; 00388 } 00389 _m.property( ep_pos_, _eh ) = pos; 00390 #undef V 00391 } 00392 00393 00394 void smooth(mesh_t& _m, const typename mesh_t::VertexHandle& _vh) 00395 { 00396 typename mesh_t::Point pos(0.0,0.0,0.0); 00397 00398 if (_m.is_boundary(_vh)) // if boundary: Point 1-6-1 00399 { 00400 typename mesh_t::HalfedgeHandle heh, prev_heh; 00401 heh = _m.halfedge_handle( _vh ); 00402 00403 if ( heh.is_valid() ) 00404 { 00405 assert( _m.is_boundary( _m.edge_handle( heh ) ) ); 00406 00407 prev_heh = _m.prev_halfedge_handle( heh ); 00408 00409 typename mesh_t::VertexHandle 00410 to_vh = _m.to_vertex_handle( heh ), 00411 from_vh = _m.from_vertex_handle( prev_heh ); 00412 00413 // ( v_l + 6 v + v_r ) / 8 00414 pos = _m.point( _vh ); 00415 pos *= real_t(6.0); 00416 pos += vector_cast< typename mesh_t::Normal >( _m.point( to_vh ) ); 00417 pos += vector_cast< typename mesh_t::Normal >( _m.point( from_vh ) ); 00418 pos *= _1over8; 00419 00420 } 00421 else 00422 return; 00423 } 00424 else // inner vertex: (1-a) * p + a/n * Sum q, q in one-ring of p 00425 { 00426 typedef typename mesh_t::Normal Vec; 00427 typename mesh_t::VertexVertexIter vvit; 00428 size_t valence(0); 00429 00430 // Calculate Valence and sum up neighbour points 00431 for (vvit=_m.vv_iter(_vh); vvit; ++vvit) { 00432 ++valence; 00433 pos += vector_cast< Vec >( _m.point(vvit) ); 00434 } 00435 pos *= weights_[valence].second; // alpha(n)/n * Sum q, q in one-ring of p 00436 pos += weights_[valence].first 00437 * vector_cast<Vec>(_m.point(_vh)); // + (1-a)*p 00438 } 00439 00440 _m.property( vp_pos_, _vh ) = pos; 00441 } 00442 00443 private: // data 00444 00445 OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_; 00446 OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_; 00447 00448 weights_t weights_; 00449 00450 const real_t _1over8; 00451 const real_t _3over8; 00452 00453 }; 00454 00455 00456 //============================================================================= 00457 } // END_NS_UNIFORM 00458 } // END_NS_SUBDIVIDER 00459 } // END_NS_OPENMESH 00460 //============================================================================= 00461 #endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined 00462 //=============================================================================