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