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: 525 $ * 00038 * $Date: 2012-01-23 15:42:13 +0100 (Mo, 23 Jan 2012) $ * 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, const bool _update_points = true) 00147 { 00148 00150 00151 typename mesh_t::FaceIter fit, f_end; 00152 typename mesh_t::EdgeIter eit, e_end; 00153 typename mesh_t::VertexIter vit; 00154 00155 // Do _n subdivisions 00156 for (size_t i=0; i < _n; ++i) 00157 { 00158 00159 if(_update_points) { 00160 // compute new positions for old vertices 00161 for (vit = _m.vertices_begin(); vit != _m.vertices_end(); ++vit) { 00162 smooth(_m, vit.handle()); 00163 } 00164 } 00165 00166 // Compute position for new vertices and store them in the edge property 00167 for (eit=_m.edges_begin(); eit != _m.edges_end(); ++eit) 00168 compute_midpoint( _m, eit.handle() ); 00169 00170 // Split each edge at midpoint and store precomputed positions (stored in 00171 // edge property ep_pos_) in the vertex property vp_pos_; 00172 00173 // Attention! Creating new edges, hence make sure the loop ends correctly. 00174 e_end = _m.edges_end(); 00175 for (eit=_m.edges_begin(); eit != e_end; ++eit) 00176 split_edge(_m, eit.handle() ); 00177 00178 00179 // Commit changes in topology and reconsitute consistency 00180 00181 // Attention! Creating new faces, hence make sure the loop ends correctly. 00182 f_end = _m.faces_end(); 00183 for (fit = _m.faces_begin(); fit != f_end; ++fit) 00184 split_face(_m, fit.handle() ); 00185 00186 if(_update_points) { 00187 // Commit changes in geometry 00188 for ( vit = _m.vertices_begin(); 00189 vit != _m.vertices_end(); ++vit) { 00190 _m.set_point(vit, _m.property( vp_pos_, vit ) ); 00191 } 00192 } 00193 00194 00195 #if defined(_DEBUG) || defined(DEBUG) 00196 // Now we have an consistent mesh! 00197 assert( OpenMesh::Utils::MeshCheckerT<mesh_t>(_m).check() ); 00198 #endif 00199 } 00200 00201 return true; 00202 } 00203 00204 private: 00205 00208 struct compute_weight 00209 { 00210 compute_weight() : valence(-1) { } 00211 weight_t operator() (void) 00212 { 00213 #if !defined(OM_CC_MIPS) 00214 using std::cos; 00215 #endif 00216 // 1 00217 // alpha(n) = ---- * (40 - ( 3 + 2 cos( 2 Pi / n ) )� ) 00218 // 64 00219 00220 if (++valence) 00221 { 00222 double inv_v = 1.0/double(valence); 00223 double t = (3.0 + 2.0 * cos( 2.0 * M_PI * inv_v) ); 00224 double alpha = (40.0 - t * t)/64.0; 00225 00226 return weight_t( 1.0-alpha, inv_v*alpha); 00227 } 00228 return weight_t(0.0, 0.0); 00229 } 00230 int valence; 00231 }; 00232 00233 private: // topological modifiers 00234 00235 void split_face(mesh_t& _m, const typename mesh_t::FaceHandle& _fh) 00236 { 00237 typename mesh_t::HalfedgeHandle 00238 heh1(_m.halfedge_handle(_fh)), 00239 heh2(_m.next_halfedge_handle(_m.next_halfedge_handle(heh1))), 00240 heh3(_m.next_halfedge_handle(_m.next_halfedge_handle(heh2))); 00241 00242 // Cutting off every corner of the 6_gon 00243 corner_cutting( _m, heh1 ); 00244 corner_cutting( _m, heh2 ); 00245 corner_cutting( _m, heh3 ); 00246 } 00247 00248 00249 void corner_cutting(mesh_t& _m, const typename mesh_t::HalfedgeHandle& _he) 00250 { 00251 // Define Halfedge Handles 00252 typename mesh_t::HalfedgeHandle 00253 heh1(_he), 00254 heh5(heh1), 00255 heh6(_m.next_halfedge_handle(heh1)); 00256 00257 // Cycle around the polygon to find correct Halfedge 00258 for (; _m.next_halfedge_handle(_m.next_halfedge_handle(heh5)) != heh1; 00259 heh5 = _m.next_halfedge_handle(heh5)) 00260 {} 00261 00262 typename mesh_t::VertexHandle 00263 vh1 = _m.to_vertex_handle(heh1), 00264 vh2 = _m.to_vertex_handle(heh5); 00265 00266 typename mesh_t::HalfedgeHandle 00267 heh2(_m.next_halfedge_handle(heh5)), 00268 heh3(_m.new_edge( vh1, vh2)), 00269 heh4(_m.opposite_halfedge_handle(heh3)); 00270 00271 /* Intermediate result 00272 * 00273 * * 00274 * 5 /|\ 00275 * /_ \ 00276 * vh2> * * 00277 * /|\3 |\ 00278 * /_ \|4 \ 00279 * *----\*----\* 00280 * 1 ^ 6 00281 * vh1 (adjust_outgoing halfedge!) 00282 */ 00283 00284 // Old and new Face 00285 typename mesh_t::FaceHandle fh_old(_m.face_handle(heh6)); 00286 typename mesh_t::FaceHandle fh_new(_m.new_face()); 00287 00288 00289 // Re-Set Handles around old Face 00290 _m.set_next_halfedge_handle(heh4, heh6); 00291 _m.set_next_halfedge_handle(heh5, heh4); 00292 00293 _m.set_face_handle(heh4, fh_old); 00294 _m.set_face_handle(heh5, fh_old); 00295 _m.set_face_handle(heh6, fh_old); 00296 _m.set_halfedge_handle(fh_old, heh4); 00297 00298 // Re-Set Handles around new Face 00299 _m.set_next_halfedge_handle(heh1, heh3); 00300 _m.set_next_halfedge_handle(heh3, heh2); 00301 00302 _m.set_face_handle(heh1, fh_new); 00303 _m.set_face_handle(heh2, fh_new); 00304 _m.set_face_handle(heh3, fh_new); 00305 00306 _m.set_halfedge_handle(fh_new, heh1); 00307 } 00308 00309 00310 void split_edge(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) 00311 { 00312 typename mesh_t::HalfedgeHandle 00313 heh = _m.halfedge_handle(_eh, 0), 00314 opp_heh = _m.halfedge_handle(_eh, 1); 00315 00316 typename mesh_t::HalfedgeHandle new_heh, opp_new_heh, t_heh; 00317 typename mesh_t::VertexHandle vh; 00318 typename mesh_t::VertexHandle vh1(_m.to_vertex_handle(heh)); 00319 typename mesh_t::Point midP(_m.point(_m.to_vertex_handle(heh))); 00320 midP += _m.point(_m.to_vertex_handle(opp_heh)); 00321 midP *= 0.5; 00322 00323 // new vertex 00324 vh = _m.new_vertex( midP ); 00325 00326 // memorize position, will be set later 00327 _m.property( vp_pos_, vh ) = _m.property( ep_pos_, _eh ); 00328 00329 00330 // Re-link mesh entities 00331 if (_m.is_boundary(_eh)) 00332 { 00333 for (t_heh = heh; 00334 _m.next_halfedge_handle(t_heh) != opp_heh; 00335 t_heh = _m.opposite_halfedge_handle(_m.next_halfedge_handle(t_heh))) 00336 {} 00337 } 00338 else 00339 { 00340 for (t_heh = _m.next_halfedge_handle(opp_heh); 00341 _m.next_halfedge_handle(t_heh) != opp_heh; 00342 t_heh = _m.next_halfedge_handle(t_heh) ) 00343 {} 00344 } 00345 00346 new_heh = _m.new_edge(vh, vh1); 00347 opp_new_heh = _m.opposite_halfedge_handle(new_heh); 00348 _m.set_vertex_handle( heh, vh ); 00349 00350 _m.set_next_halfedge_handle(t_heh, opp_new_heh); 00351 _m.set_next_halfedge_handle(new_heh, _m.next_halfedge_handle(heh)); 00352 _m.set_next_halfedge_handle(heh, new_heh); 00353 _m.set_next_halfedge_handle(opp_new_heh, opp_heh); 00354 00355 if (_m.face_handle(opp_heh).is_valid()) 00356 { 00357 _m.set_face_handle(opp_new_heh, _m.face_handle(opp_heh)); 00358 _m.set_halfedge_handle(_m.face_handle(opp_new_heh), opp_new_heh); 00359 } 00360 00361 _m.set_face_handle( new_heh, _m.face_handle(heh) ); 00362 _m.set_halfedge_handle( vh, new_heh); 00363 _m.set_halfedge_handle( _m.face_handle(heh), heh ); 00364 _m.set_halfedge_handle( vh1, opp_new_heh ); 00365 00366 // Never forget this, when playing with the topology 00367 _m.adjust_outgoing_halfedge( vh ); 00368 _m.adjust_outgoing_halfedge( vh1 ); 00369 } 00370 00371 private: // geometry helper 00372 00373 void compute_midpoint(mesh_t& _m, const typename mesh_t::EdgeHandle& _eh) 00374 { 00375 #define V( X ) vector_cast< typename mesh_t::Normal >( X ) 00376 typename mesh_t::HalfedgeHandle heh, opp_heh; 00377 00378 heh = _m.halfedge_handle( _eh, 0); 00379 opp_heh = _m.halfedge_handle( _eh, 1); 00380 00381 typename mesh_t::Point 00382 pos(_m.point(_m.to_vertex_handle(heh))); 00383 00384 pos += V( _m.point(_m.to_vertex_handle(opp_heh)) ); 00385 00386 // boundary edge: just average vertex positions 00387 if (_m.is_boundary(_eh) ) 00388 { 00389 pos *= 0.5; 00390 } 00391 else // inner edge: add neighbouring Vertices to sum 00392 { 00393 pos *= real_t(3.0); 00394 pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(heh)))); 00395 pos += V(_m.point(_m.to_vertex_handle(_m.next_halfedge_handle(opp_heh)))); 00396 pos *= _1over8; 00397 } 00398 _m.property( ep_pos_, _eh ) = pos; 00399 #undef V 00400 } 00401 00402 void smooth(mesh_t& _m, const typename mesh_t::VertexHandle& _vh) 00403 { 00404 typename mesh_t::Point pos(0.0,0.0,0.0); 00405 00406 if (_m.is_boundary(_vh) ) // if boundary: Point 1-6-1 00407 { 00408 typename mesh_t::HalfedgeHandle heh, prev_heh; 00409 heh = _m.halfedge_handle( _vh ); 00410 00411 if ( heh.is_valid() ) 00412 { 00413 assert( _m.is_boundary( _m.edge_handle( heh ) ) ); 00414 00415 prev_heh = _m.prev_halfedge_handle( heh ); 00416 00417 typename mesh_t::VertexHandle 00418 to_vh = _m.to_vertex_handle( heh ), 00419 from_vh = _m.from_vertex_handle( prev_heh ); 00420 00421 // ( v_l + 6 v + v_r ) / 8 00422 pos = _m.point( _vh ); 00423 pos *= real_t(6.0); 00424 pos += vector_cast< typename mesh_t::Normal >( _m.point( to_vh ) ); 00425 pos += vector_cast< typename mesh_t::Normal >( _m.point( from_vh ) ); 00426 pos *= _1over8; 00427 00428 } 00429 else 00430 return; 00431 } 00432 else // inner vertex: (1-a) * p + a/n * Sum q, q in one-ring of p 00433 { 00434 typedef typename mesh_t::Normal Vec; 00435 typename mesh_t::VertexVertexIter vvit; 00436 size_t valence(0); 00437 00438 // Calculate Valence and sum up neighbour points 00439 for (vvit=_m.vv_iter(_vh); vvit; ++vvit) { 00440 ++valence; 00441 pos += vector_cast< Vec >( _m.point(vvit) ); 00442 } 00443 pos *= weights_[valence].second; // alpha(n)/n * Sum q, q in one-ring of p 00444 pos += weights_[valence].first 00445 * vector_cast<Vec>(_m.point(_vh)); // + (1-a)*p 00446 } 00447 00448 _m.property( vp_pos_, _vh ) = pos; 00449 } 00450 00451 private: // data 00452 00453 OpenMesh::VPropHandleT< typename mesh_t::Point > vp_pos_; 00454 OpenMesh::EPropHandleT< typename mesh_t::Point > ep_pos_; 00455 00456 weights_t weights_; 00457 00458 const real_t _1over8; 00459 const real_t _3over8; 00460 00461 }; 00462 00463 00464 //============================================================================= 00465 } // END_NS_UNIFORM 00466 } // END_NS_SUBDIVIDER 00467 } // END_NS_OPENMESH 00468 //============================================================================= 00469 #endif // OPENMESH_SUBDIVIDER_UNIFORM_COMPOSITELOOPT_HH defined 00470 //=============================================================================