📄 edge_collapse_impl.h
字号:
// Copyright (c) 2006 Fernando Luis Cacciola Carballal. All rights reserved.//// This file is part of CGAL (www.cgal.org); you may redistribute it under// the terms of the Q Public License version 1.0.// See the file LICENSE.QPL distributed with CGAL.//// Licensees holding a valid commercial license may use this file in// accordance with the commercial license agreement provided with the software.//// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.//// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.3-branch/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Detail/Edge_collapse_impl.h $// $Id: Edge_collapse_impl.h 37267 2007-03-19 14:40:37Z fcacciola $//// Author(s) : Fernando Cacciola <fernando_cacciola@ciudad.com.ar>//#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_COLLAPSE_IMPL_H#define CGAL_SURFACE_MESH_SIMPLIFICATION_DETAIL_EDGE_COLLAPSE_IMPL_HCGAL_BEGIN_NAMESPACEnamespace Surface_mesh_simplification {template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::EdgeCollapse( ECM& aSurface , ShouldStop const& aShould_stop , VertexIndexMap const& aVertex_index_map , EdgeIndexMap const& aEdge_index_map , EdgeIsBorderMap const& aEdge_is_border_map , GetCost const& aGet_cost , GetPlacement const& aGet_placement , VisitorT* aVisitor ) : mSurface (aSurface) ,Should_stop (aShould_stop) ,Vertex_index_map (aVertex_index_map) ,Edge_index_map (aEdge_index_map) ,Edge_is_border_map (aEdge_is_border_map) ,Get_cost (aGet_cost) ,Get_placement (aGet_placement) ,Visitor (aVisitor) { CGAL_ECMS_TRACE(0,"EdgeCollapse of ECM with " << (num_edges(aSurface)/2) << " edges" ); CGAL_ECMS_DEBUG_CODE ( mStep = 0 ; ) #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE vertex_iterator vb, ve ; for ( tie(vb,ve) = vertices(mSurface) ; vb != ve ; ++ vb ) CGAL_ECMS_TRACE(2, vertex_to_string(*vb) ) ; undirected_edge_iterator eb, ee ; for ( tie(eb,ee) = undirected_edges(mSurface); eb!=ee; ++eb ) CGAL_ECMS_TRACE(2, edge_to_string(*eb) ) ;#endif}template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>int EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::run(){ CGAL_SURF_SIMPL_TEST_assertion( mSurface.is_valid() && mSurface.is_pure_triangle() ) ; if ( Visitor ) Visitor->OnStarted(mSurface); // First collect all candidate edges in a PQ Collect(); // Then proceed to collapse each edge in turn Loop(); CGAL_ECMS_TRACE(0,"Finished: " << (mInitialEdgeCount - mCurrentEdgeCount) << " edges removed." ) ; int r = (int)(mInitialEdgeCount - mCurrentEdgeCount) ; if ( Visitor ) Visitor->OnFinished(mSurface); return r ;}template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Collect(){ CGAL_ECMS_TRACE(0,"Collecting edges..."); // // Loop over all the _undirected_ edges in the surface putting them in the PQ // Equal_3 equal_points = Kernel().equal_3_object(); size_type lSize = num_edges(mSurface) / 2 ; CGAL_SURF_SIMPL_TEST_assertion( ( lSize * 2 ) == mSurface.size_of_halfedges() ) ; mInitialEdgeCount = mCurrentEdgeCount = lSize; mEdgeDataArray.reset( new Edge_data[lSize] ) ; mPQ.reset( new PQ (lSize, Compare_cost(this), Undirected_edge_id(this) ) ) ; std::size_t id = 0 ; CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lInserted = 0 ) ; CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lNotInserted = 0 ) ; undirected_edge_iterator eb, ee ; for ( tie(eb,ee) = undirected_edges(mSurface); eb!=ee; ++eb ) { edge_descriptor lEdge = *eb ; CGAL_assertion( get_directed_edge_id(lEdge) == id ) ; CGAL_assertion( get_directed_edge_id(opposite_edge(lEdge,mSurface)) == id+1 ) ; Profile const& lProfile = create_profile(lEdge); if ( !equal_points(lProfile.p0(),lProfile.p1()) ) { Edge_data& lData = get_data(lEdge); lData.cost() = get_cost(lProfile) ; insert_in_PQ(lEdge,lData); if ( Visitor ) Visitor->OnCollected(lProfile ,lData.cost() #ifdef CGAL_TESTING_SURFACE_MESH_SIMPLIFICATION_USING_EXTENDED_VISITOR ,get_placement(lProfile) #endif ); CGAL_SURF_SIMPL_TEST_assertion_code ( ++ lInserted ) ; } else { CGAL_SURF_SIMPL_TEST_assertion_code ( ++ lNotInserted ) ; } CGAL_ECMS_TRACE(2,edge_to_string(lEdge)); id += 2 ; } CGAL_SURF_SIMPL_TEST_assertion ( lInserted + lNotInserted == mInitialEdgeCount ) ; CGAL_ECMS_TRACE(0,"Initial edge count: " << mInitialEdgeCount ) ;}template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>void EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Loop(){ CGAL_ECMS_TRACE(0,"Collapsing edges...") ; CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lLoop_watchdog = 0 ) ; CGAL_SURF_SIMPL_TEST_assertion_code ( size_type lNonCollapsableCount = 0 ) ; // // Pops and processes each edge from the PQ // optional<edge_descriptor> lEdge ; while ( (lEdge = pop_from_PQ()) ) { CGAL_SURF_SIMPL_TEST_assertion ( lLoop_watchdog ++ < mInitialEdgeCount ) ; CGAL_ECMS_TRACE(3,"Poped " << edge_to_string(*lEdge) ) ; Profile const& lProfile = create_profile(*lEdge); Cost_type lCost = get_data(*lEdge).cost(); if ( Visitor ) Visitor->OnSelected(lProfile,lCost,mInitialEdgeCount,mCurrentEdgeCount); if ( lCost ) { if ( Should_stop(*lCost,lProfile,mInitialEdgeCount,mCurrentEdgeCount) ) { if ( Visitor ) Visitor->OnStopConditionReached(lProfile); CGAL_ECMS_TRACE(0,"Stop condition reached with InitialEdgeCount=" << mInitialEdgeCount << " CurrentEdgeCount=" << mCurrentEdgeCount << " Current Edge: " << edge_to_string(*lEdge) ); break ; } if ( Is_collapsable(lProfile) ) { Collapse(lProfile); } else { CGAL_SURF_SIMPL_TEST_assertion_code ( lNonCollapsableCount++ ) ; if ( Visitor ) Visitor->OnNonCollapsable(lProfile); CGAL_ECMS_TRACE(1,edge_to_string(*lEdge) << " NOT Collapsable" ); } } else { CGAL_ECMS_TRACE(1,edge_to_string(*lEdge) << " uncomputable cost." ); } } CGAL_SURF_SIMPL_TEST_assertion ( mCurrentEdgeCount = mSurface.size_of_halfedges() * 2 ) ;}template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::is_border( const_vertex_descriptor const& aV ) const{ bool rR = false ; const_in_edge_iterator eb, ee ; for ( tie(eb,ee) = in_edges(aV,mSurface) ; eb != ee ; ++ eb ) { const_edge_descriptor lEdge = *eb ; if ( is_undirected_edge_a_border(lEdge) ) { rR = true ; break ; } } return rR ; }// Some edges are NOT collapsable: doing so would break the topological consistency of the mesh.// This function returns true if a edge 'p->q' can be collapsed.//// An edge p->q can be collapsed iff it satisfies the "link condition"// (as described in the "Mesh Optimization" article of Hoppe et al (1993))//// The link conidition is as follows: for every vertex 'k' adjacent to both 'p and 'q',// "p,k,q" is a facet of the mesh.//template<class M,class SP, class VIM,class EIM,class EBM, class CF,class PF,class V>bool EdgeCollapse<M,SP,VIM,EIM,EBM,CF,PF,V>::Is_collapsable( Profile const& aProfile ){ bool rR = true ; CGAL_ECMS_TRACE(3,"Testing collapsabilty of p_q=V" << aProfile.v0()->id() << "(%" << aProfile.v0()->vertex_degree() << ")" << "->V" << aProfile.v1()->id() << "(%" << aProfile.v1()->vertex_degree() << ")" ); CGAL_ECMS_TRACE(4, "is p_q border:" << aProfile.is_v0_v1_a_border() ); CGAL_ECMS_TRACE(4, "is q_q border:" << aProfile.is_v1_v0_a_border() ); out_edge_iterator eb1, ee1 ; out_edge_iterator eb2, ee2 ; CGAL_ECMS_TRACE(4," t=V" << aProfile.vL()->ID << "(%" << aProfile.vL()->vertex_degree() << ")" ); CGAL_ECMS_TRACE(4," b=V" << aProfile.vR()->ID << "(%" << aProfile.vR()->vertex_degree() << ")" ); // The following loop checks the link condition for v0_v1. // Specifically, that for every vertex 'k' adjacent to both 'p and 'q', 'pkq' is a face of the mesh. // for ( tie(eb1,ee1) = out_edges(aProfile.v0(),mSurface) ; rR && eb1 != ee1 ; ++ eb1 ) { edge_descriptor v0_k = *eb1 ; if ( v0_k != aProfile.v0_v1() ) { vertex_descriptor k = target(v0_k,mSurface); for ( tie(eb2,ee2) = out_edges(k,mSurface) ; rR && eb2 != ee2 ; ++ eb2 ) { edge_descriptor k_v1 = *eb2 ; if ( target(k_v1,mSurface) == aProfile.v1() ) { // At this point we know p-q-k are connected and we need to determine if this triangle is a face of the mesh. // // Since the mesh is known to be triangular there are at most two faces sharing the edge p-q. // // If p->q is NOT a border edge, the top face is p->q->t where t is target(next(p->q)) // If q->p is NOT a border edge, the bottom face is q->p->b where b is target(next(q->p)) // // If k is either t or b then p-q-k *might* be a face of the mesh. It won't be if k==t but p->q is border // or k==b but q->b is a border (because in that case even though there exists triangles p->q->t (or q->p->b) // they are holes, not faces) // bool lIsFace = ( aProfile.vL() == k && aProfile.left_face_exists () ) || ( aProfile.vR() == k && aProfile.right_face_exists() ) ; CGAL_SURF_SIMPL_TEST_assertion_code ( if ( lIsFace ) { // Is k_v1 the halfedge bounding the face 'k-v1-v0'? if ( !k_v1->is_border() && k_v1->next()->vertex() == aProfile.v0() ) { CGAL_SURF_SIMPL_TEST_assertion( !k_v1->is_border() ) ; CGAL_SURF_SIMPL_TEST_assertion( k_v1 ->vertex() == aProfile.v1() ) ; CGAL_SURF_SIMPL_TEST_assertion( k_v1->next() ->vertex() == aProfile.v0() ) ; CGAL_SURF_SIMPL_TEST_assertion( k_v1->next()->next()->vertex() == k ) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -