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: 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