From 7fdc391f75f928e15fe4d52907c43ae3cda2cc1b Mon Sep 17 00:00:00 2001 From: Fernando Cacciola Date: Thu, 17 Aug 2006 17:29:20 +0000 Subject: [PATCH] Fixed various bugs in the handling of boundaries --- Surface_mesh_simplification/changes.txt | 3 +- .../include/CGAL/Polyhedron_BGL_properties.h | 57 +++- .../Collapse_operator.h | 166 ++++++++---- .../Policies/Detail/Lindstrom_Turk_core.h | 44 ++-- .../Detail/Lindstrom_Turk_core_impl.h | 208 ++++++++------- .../Surface_mesh_simplification/TSMS_common.h | 7 +- .../Vertex_pair_collapse.h | 12 +- .../Vertex_pair_collapse_impl.h | 246 ++++++++++-------- .../LT_edge_collapse_test.kdevelop | 2 +- .../edge_collapse_test.cpp | 4 +- 10 files changed, 469 insertions(+), 280 deletions(-) diff --git a/Surface_mesh_simplification/changes.txt b/Surface_mesh_simplification/changes.txt index 597d5024fef..5535937f730 100644 --- a/Surface_mesh_simplification/changes.txt +++ b/Surface_mesh_simplification/changes.txt @@ -1,6 +1,7 @@ +17 August 2006 Fernando Cacciola + - Fixed various bugs in the handling of boundaries 20 June 2006 Fernando Cacciola - Bug fixes - - Vertex-evetns replaced by Speudo-split events . 31 March 2006 Fernando Cacciola - Start diff --git a/Surface_mesh_simplification/include/CGAL/Polyhedron_BGL_properties.h b/Surface_mesh_simplification/include/CGAL/Polyhedron_BGL_properties.h index 8224dfe8bc5..8eaee1ec9b0 100644 --- a/Surface_mesh_simplification/include/CGAL/Polyhedron_BGL_properties.h +++ b/Surface_mesh_simplification/include/CGAL/Polyhedron_BGL_properties.h @@ -75,6 +75,39 @@ public: } }; +template +class Polyhedron_vertex_is_border_map : public put_get_helper > +{ +private: + + typedef CGAL::Polyhedron_3 Polyhedron ; + +public: + + typedef readable_property_map_tag category; + typedef bool value_type; + typedef bool reference; + typedef typename graph_traits::vertex_descriptor key_type; + + Polyhedron_vertex_is_border_map( Polyhedron const& p_) {} + + reference operator[](key_type const& v) const + { + typedef typename Polyhedron::Halfedge_around_vertex_const_circulator Halfedge_around_vertex_const_circulator ; + Halfedge_around_vertex_const_circulator cb = v->vertex_begin(); + Halfedge_around_vertex_const_circulator c = cb ; + do + { + if ( c->is_border() || c->opposite()->is_border() ) + return true ; + ++ c ; + } + while ( c != cb ) ; + + return false ; + } +}; + template class Polyhedron_vertex_point_map : public put_get_helper< typename Gt::Point_3&, Polyhedron_vertex_point_map > { @@ -125,8 +158,9 @@ public: } }; -struct edge_is_border_t {} ; -struct vertex_point_t {} ; +struct edge_is_border_t {} ; +struct vertex_is_border_t {} ; +struct vertex_point_t {} ; template inline @@ -144,6 +178,14 @@ Polyhedron_edge_is_border_map get(edge_is_border_t, CGAL::Polyhedron return m; } +template +inline +Polyhedron_vertex_is_border_map get(vertex_is_border_t, CGAL::Polyhedron_3 const& p) +{ + Polyhedron_vertex_is_border_map m(p); + return m; +} + template inline Polyhedron_vertex_point_map get(vertex_point_t, CGAL::Polyhedron_3& p) @@ -185,6 +227,17 @@ struct Polyhedron_property_map }; }; +template <> +struct Polyhedron_property_map +{ + template + struct bind_ + { + typedef Polyhedron_vertex_is_border_map type; + typedef Polyhedron_vertex_is_border_map const_type; + }; +}; + template <> struct Polyhedron_property_map { diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Collapse_operator.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Collapse_operator.h index 4948ce41755..76fa992fb25 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Collapse_operator.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Collapse_operator.h @@ -27,79 +27,141 @@ namespace Triangulated_surface_mesh { namespace Simplification // // collapse_triangulation_edge euler operator (topological operation only). // -// This operator removes from a triangulation 'aDS' 2 facets, 1 vertex and 3 edges, as follows: +// This operator collapses the edge p-q replacing it with one single vertex connected to the link of p-q. // -// Consider 2 vertices 'p', 'q', 't' and 'b', such that the edge 'p-q' is shared by two facets -// 'p-q-t' and 'q-p-b', called top and bottom facets resp. (their orientation is unimportant) +// The net effect of the operator is equivalent to removing one of the vertices and re-triangulating the resulting hole. // -// Consider additional vertices 'l' and 'r' such that -// 'p-t-l' and 'q-r-t' are the other 2 facets adjacent to the top facet, called the top-left and top-right facets, resp., -// and -// 'l-b-p' and 'b-r-q' are the other 2 facets adjacent to the bottom facet, called the bottom-left and bottom-right facets, resp. +// The actual collapse operation only removes up to 2 faces, 3 edges and 1 vertex, as follows. // -// In such a triangulated path there is a cycle of vertices around 'p' and 'q' called the "link" of the edge 'p-q'. -// In the minimal case, the link is the unordered cycle of vertices: l-b-r-t. It could also be that 'l' and 'r' are really a -// sequence of vertices instead of just 1 vertex. -// As the link has at least 4 vertices there are at least 6 facets inside the link: -// bottom-left (l-b-p) -// bottom (q-p-b) -// bottom-right (q-b-r) -// top-right (q-r-t) -// top (p-q-t) -// top-left (l-p-t) -// (the vertices are enumerated in an arbiraty order as that is unimportant here) +// The top face, p-q-t, to the left of p->q, if any, is removed. +// The bottom face, q-p-b, to the left of q->p (right of p->q), if any, is removed. +// +// If there is a top-left face, that is, if the edge p->t is NOT a border edge, the top face is removed by joining it +// with the top-left face (this creates a 4 sided face: p-q-t-l). +// If p->t IS a border edge then the top face is simply erased. +// +// If there is a bottom-right face, that is, if the edge q->b is NOT a border edge, the bottom face is removed by joining it +// with the bottom-right face (this creates a 4 sided face: q-p-b-r) +// If q->b IS a border edge then the bottom face is simply erased. +// +// If there is a top face edge p->t is removed. +// If there is a bottom face edge q->b is removed. // -// The operator is passed 3 DIRECTED edges: 'p-q', 'p-t' and 'q-b' as proceeds with the following 3 steps: +// One of the vertices (p or q) is removed. +// If there is no top-left face so the top face is directly erased AND there is no bottom face, +// that face erasure automatically removes vertex p. Likewise, if there is no bottom-right face +// so the bottom face is directly erased AND there is no top face, that erasure automatically +// removes vertex q. +// Directly erasing the top/bottom faces when the opposite face exists does not removes any vertex +// automatically, in which case vertex p is removed by joining p->q // -// (1) Merges the top facet with the top-left facet keeping the top-left facet; that is, -// removes the top-facet 'q-p-t', the edge 'p-t' and -// redefines the top-left facet to be 'l-p-q-t' instead of 'l-p-t'. +// NOTES: // -// (2) Merges the bottom facet with the bottom-right facet keeping the bottom-right facet; that is, -// removes the botton-facet 'q-p-t', the edge 'q-b' and -// redefines the bottom-right facet to be 'r-q-p-b' instead of 'r-q-b'. +// This operator can only be called by collapsable edges (which satisfy the link condition), hence, +// there must exist at least the top face or a bottom face, and, if there is no top-left face there is a top-right face +// and likewise, if there is no bottom-right face there is a bottom-left face. (IOW vertices t/b must have degree >=3 +// unless the top/bottom faces do not exists) // -// (3) Joins the vertices 'p' and 'q' keeping the vertex 'q'; that is -// removes the edge 'p-q' and the vertex 'p' redefining the top-left facet to be 'l-q-t' instead of 'l-p-q-t' -// and the bottom-right facet to be 'r-q-b' instead of 'r-q-p-b' +// The operator doesn't join the top face with the top-left face and the bottom-face with the bottom-left face +// (or both to the right) because if the top-left and bottom-left (or both right) faces are themselve adjacent, +// the first joint would introduce a degree 2 vertex. +// That is why the operator alternates left and right to join the top and bottom faces. // -// The net result is a valid triangulation but the intermediate results from steps 1 and 2 are not as the top-left -// and bottom-right facets are temporarily 4-sided until 'p' and 'q' is joint. +// PARAMETERS: +// pq : the edge to collapse +// pt : the edge shared between the top face and the top-left face (if any). If there is no top face this parameter is a null handle. +// qb : the edge shared between the bottom face and the bottom-right face. If there is no bottom face this parameter is a null handle. // -// The operator merges the bottom facets with the bottom-right facet instead of the bottom-left facet becasue in the -// minimal link case (that is, just 'l-b-r-t'), the top-left and bottom-left facets are adjacent, so merging one of -// them prevents the other to be merged becuase doing so would introduce degree-2 vertex (which is illegal in most DS) -// -// The operator is required to erase from the aDS the following: vertex 'p', edges 'pq', 'pt' and 'qb', and -// facets 'pqt' and 'qpb'. It is also required NOT to erase anything else. -// -// The code in this primary template simply forwards the operations to the DS. -// Thus, the DS must support the join_facet(edge) and join_vertex(edge) operations. If not, an specialization is required. +// RETURN VALUE: A handle to the vertex that IS NOT removed. // template struct Collapse_triangulation_edge { typedef DS_ DS ; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor ; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor ; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor ; - void operator() ( edge_descriptor const& pq - , edge_descriptor const& pt - , edge_descriptor const& qb - , DS& aDS - ) const + vertex_descriptor operator() ( edge_descriptor const& pq + , edge_descriptor const& pt + , edge_descriptor const& qb + , DS& aDS + ) const { - CGAL_precondition( pt->vertex()->vertex_degree() >= 3 || qb->vertex()->vertex_degree() >= 3 ) ; - - if ( pt->vertex()->vertex_degree() >= 3 ) - aDS.join_facet (pt); + edge_descriptor null ; - if ( qb->vertex()->vertex_degree() >= 3 ) - aDS.join_facet (qb); + bool lTopFaceExists = pt != null ; + bool lBottomFaceExists = qb != null ; + bool lTopLeftFaceExists = lTopFaceExists && !pt->is_border() ; + bool lBottomRightFaceExists = lBottomFaceExists && !qb->is_border() ; - aDS.join_vertex(pq); + CGAL_precondition( !lTopFaceExists || (lTopFaceExists && ( pt->vertex()->vertex_degree() > 2 ) ) ) ; + CGAL_precondition( !lBottomFaceExists || (lBottomFaceExists && ( qb->vertex()->vertex_degree() > 2 ) ) ) ; + + vertex_descriptor q = pq->vertex(); + vertex_descriptor p = pq->opposite()->vertex(); + + CGAL_TSMS_TRACE(3, "Collapsing p-q E" << pq->ID << " (V" << p->ID << "->V" << q->ID << ")" ) ; + + bool lP_Erased = false, lQ_Erased = false ; + + if ( lTopFaceExists ) + { + CGAL_precondition( !pt->opposite()->is_border() ) ; // p-q-t is a face of the mesh + if ( lTopLeftFaceExists ) + { + CGAL_TSMS_TRACE(3, "Removing p-t E" << pt->ID << " (V" << p->ID << "->V" << pt->vertex()->ID << ") by joining top-left face" ) ; + + aDS.join_facet (pt); + } + else + { + CGAL_TSMS_TRACE(3, "Removing p-t E" << pt->ID << " (V" << p->ID << "->V" << pt->vertex()->ID << ") by erasing top face" ) ; + + aDS.erase_facet(pt->opposite()); + + if ( !lBottomFaceExists ) + { + CGAL_TSMS_TRACE(3, "Bottom face doesn't exist so vertex P already removed" ) ; + lP_Erased = true ; + } + } + } + + if ( lBottomFaceExists ) + { + CGAL_precondition( !qb->opposite()->is_border() ) ; // p-q-b is a face of the mesh + if ( lBottomRightFaceExists ) + { + CGAL_TSMS_TRACE(3, "Removing q-b E" << qb->ID << " (V" << q->ID << "->V" << qb->vertex()->ID << ") by joining bottom-right face" ) ; + aDS.join_facet (qb); + } + else + { + CGAL_TSMS_TRACE(3, "Removing q-b E" << qb->ID << " (V" << q->ID << "->V" << qb->vertex()->ID << ") by erasing bottom face" ) ; + + aDS.erase_facet(qb->opposite()); + + if ( !lTopFaceExists ) + { + CGAL_TSMS_TRACE(3, "Top face doesn't exist so vertex Q already removed" ) ; + lQ_Erased = true ; + } + } + } + + CGAL_assertion( !lP_Erased || !lQ_Erased ) ; + + if ( !lP_Erased && !lQ_Erased ) + { + CGAL_TSMS_TRACE(3, "Removing vertex P by joining pQ" ) ; + aDS.join_vertex(pq); + lP_Erased = true ; + } CGAL_expensive_postcondition(aDS.is_valid()); + + return lP_Erased ? q : p ; } } ; diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core.h index a4060a93ee0..bd7be108078 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core.h @@ -18,7 +18,8 @@ #ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_LINDSTROM_TURK_CORE_H #define CGAL_SURFACE_MESH_SIMPLIFICATION_LINDSTROM_TURK_CORE_H 1 -#include +#include + #include #include @@ -48,6 +49,10 @@ public: typedef typename Collapse_data::edge_descriptor edge_descriptor ; typedef typename Collapse_data::Params Params ; + typedef boost::graph_traits GraphTraits ; + + typedef typename GraphTraits::in_edge_iterator in_edge_iterator ; + typedef typename Surface_geometric_traits::Kernel Kernel ; typedef typename Kernel::Point_3 Point ; @@ -88,23 +93,16 @@ private : typedef std::vector Triangles ; typedef std::vector Link ; - - struct Boundary + typedef std::vector edge_descriptor_vector ; + + struct BoundaryEdge { - Boundary ( Vector const& op_ - , Vector const& opN_ - , Vector const& pq_ - , Vector const& pqN_ - , Vector const& qr_ - , Vector const& qrN_ - ) - : - op(op_), opN(opN_), pq(pq_), pqN(pqN_), qr(qr_), qrN(qrN_) - {} - - Vector op, opN, pq, pqN, qr, qrN ; + BoundaryEdge ( Point s_, Point t_, Vector const& v_, Vector const& n_ ) : s(s_), t(t_), v(v_), n(n_) {} + + Point s, t ; + Vector v, n ; } ; - typedef optional OptionalBoundary ; + typedef std::vector BoundaryEdges ; class Constrians { @@ -129,12 +127,12 @@ private : private : - void Add_boundary_preservation_constrians( Boundary const& aBdry ) ; + void Add_boundary_preservation_constrians( BoundaryEdges const& aBdry ) ; void Add_volume_preservation_constrians( Triangles const& aTriangles ); - void Add_boundary_and_volume_optimization_constrians( OptionalBoundary const& aBdry, Triangles const& aTriangles ) ; + void Add_boundary_and_volume_optimization_constrians( BoundaryEdges const& aBdry, Triangles const& aTriangles ) ; void Add_shape_optimization_constrians( Link const& aLink ) ; - FT Compute_boundary_cost( Vector const& v, Boundary const& aBdry ) ; + FT Compute_boundary_cost( Vector const& v, BoundaryEdges const& aBdry ) ; FT Compute_volume_cost ( Vector const& v, Triangles const& aTriangles ) ; FT Compute_shape_cost ( Point const& p, Link const& aLink ) ; @@ -195,8 +193,14 @@ private : void Extract_triangles_and_link( Triangles& rTriangles, Link& rLink ); - OptionalBoundary Extract_boundary() ; + void Extract_boundary_edge ( edge_descriptor edge, BoundaryEdges& rBdry ) ; + void Extract_boundary_edges( vertex_descriptor const& v + , edge_descriptor_vector& rCollected + , BoundaryEdges& rBdry + ) ; + void Extract_boundary_edges( BoundaryEdges& rBdry ) ; + private: Params const& mParams ; diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core_impl.h index 3b23effbdec..1cc1e75701e 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core_impl.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_core_impl.h @@ -20,19 +20,6 @@ CGAL_BEGIN_NAMESPACE -struct G -{ - ~G() - { - std::cout << "PFixed=" << PFixed << " QFixed=" << QFixed << " Boundary=" << Boundary << std::endl ; - } - - int PFixed ; - int QFixed ; - int Boundary ; -} ; -G g ; - // // Implementation of the strategy from: // @@ -94,11 +81,9 @@ void LindstromTurkCore::compute( Collapse_data& rData ) CGAL_TSMS_LT_TRACE(3,"Link: " << s ); #endif - // If the collapsing edge is a boundary edge, the "local boundary" is cached in a Boundary object. - OptionalBoundary lBdry ; + BoundaryEdges lBdry ; - if ( is_undirected_edge_a_border(mP_Q) ) - lBdry = Extract_boundary(); + Extract_boundary_edges(lBdry); Point const& lP = get_point(mP) ; Point const& lQ = get_point(mQ) ; @@ -138,8 +123,8 @@ void LindstromTurkCore::compute( Collapse_data& rData ) // // A constrian (Ai,bi) must be alpha-compatible with the previously added constrians (see Paper); if it's not, is discarded. // - if ( lBdry) - Add_boundary_preservation_constrians(*lBdry); + if ( lBdry.size() > 0 ) + Add_boundary_preservation_constrians(lBdry); if ( mConstrians.n < 3 ) Add_volume_preservation_constrians(lTriangles); @@ -181,13 +166,9 @@ void LindstromTurkCore::compute( Collapse_data& rData ) CGAL_TSMS_LT_TRACE(1,"Squared edge length: " << lSquaredLength ) ; - FT lBdryCost = 0; - if ( lBdry ) - lBdryCost = Compute_boundary_cost(*lOptionalV,*lBdry); - - FT lVolumeCost = Compute_volume_cost(*lOptionalV,lTriangles); - - FT lShapeCost = Compute_shape_cost(*lOptionalP,lLink); + FT lBdryCost = Compute_boundary_cost(*lOptionalV,lBdry); + FT lVolumeCost = Compute_volume_cost (*lOptionalV,lTriangles); + FT lShapeCost = Compute_shape_cost (*lOptionalP,lLink); FT lTotalCost = mParams.VolumeWeight * lVolumeCost + mParams.BoundaryWeight * lBdryCost * lSquaredLength @@ -201,6 +182,7 @@ void LindstromTurkCore::compute( Collapse_data& rData ) << "\nBoundary cost: " << lBdryCost << "\nVolume cost: " << lVolumeCost << "\nShape cost: " << lShapeCost + << "\nTOTAL COST: " << lTotalCost ); } @@ -212,52 +194,58 @@ void LindstromTurkCore::compute( Collapse_data& rData ) rData = Collapse_data(mP,mQ,mIsPFixed,mIsQFixed,mP_Q,mSurface,lOptionalCost,lOptionalP) ; } + // // Caches the "local boundary", that is, the sequence of 3 border edges: o->p, p->q, q->e // template -typename LindstromTurkCore::OptionalBoundary LindstromTurkCore::Extract_boundary() +void LindstromTurkCore::Extract_boundary_edge( edge_descriptor edge, BoundaryEdges& rBdry ) { - // Since p_q is a boundary edge, one of the previous edges (ccw or cw) is the previous boundary edge - // Likewise, one of the next edges (ccw or cw) is the next boundary edge. - edge_descriptor p_pt = next_edge_ccw(mP_Q,mSurface); - edge_descriptor p_pb = next_edge_cw (mP_Q,mSurface); - edge_descriptor q_qt = next_edge_cw (mQ_P,mSurface); - edge_descriptor q_qb = next_edge_ccw(mQ_P,mSurface); + edge_descriptor face_edge = is_border(edge) ? opposite_edge(edge,mSurface) : edge ; + + vertex_descriptor sv = source(face_edge,mSurface); + vertex_descriptor tv = target(face_edge,mSurface); - edge_descriptor border_1 = mP_Q; - edge_descriptor border_0 = is_undirected_edge_a_border(p_pt) ? p_pt : p_pb ; - edge_descriptor border_2 = is_undirected_edge_a_border(q_qt) ? q_qt : q_qb ; + Point const& sp = get_point(sv); + Point const& tp = get_point(tv); - CGAL_assertion(is_undirected_edge_a_border(border_0)); - CGAL_assertion(is_undirected_edge_a_border(border_2)); + Vector v = tp - sp ; + Vector n = Point_cross_product(tp,sp) ; + + CGAL_TSMS_LT_TRACE(3,"Boundary edge. S:" << xyz_to_string(sp) << " T:" << xyz_to_string(tp) + << " V:" << xyz_to_string(v) << " N:" << xyz_to_string(n) + ) ; + + rBdry.push_back( BoundaryEdge(sp,tp,v,n) ) ; + +} - // opposite(border0)->border1->border2 is the local boundary - - vertex_descriptor ov = target(border_0,mSurface); - vertex_descriptor rv = target(border_2,mSurface); - - // o->p->q->r is the local boundary - - Point const& o = get_point(ov); - Point const& p = get_point(mP); - Point const& q = get_point(mQ); - Point const& r = get_point(rv); - - // - // The "Boundary" object caches the boundary as displacement vectors since the code uses that. - // - - Vector op = p - o ; - Vector opN = Point_cross_product(p,o); - - Vector pq = q - p ; - Vector pqN = Point_cross_product(q,p); - - Vector qr = r - q ; - Vector qrN = Point_cross_product(r,q); - - return OptionalBoundary(Boundary(op,opN,pq,pqN,qr,qrN)) ; +template +void LindstromTurkCore::Extract_boundary_edges( vertex_descriptor const& v + , edge_descriptor_vector& rCollected + , BoundaryEdges& rBdry + ) +{ + in_edge_iterator eb, ee ; + for ( tie(eb,ee) = in_edges(v,mSurface) ; eb != ee ; ++ eb ) + { + edge_descriptor edge = *eb ; + + if ( is_undirected_edge_a_border(edge) && std::find(rCollected.begin(),rCollected.end(),edge) == rCollected.end() ) + { + Extract_boundary_edge(edge,rBdry); + rCollected.push_back(edge); + rCollected.push_back(opposite_edge(edge,mSurface)); + } + } +} + +template +void LindstromTurkCore::Extract_boundary_edges( BoundaryEdges& rBdry ) +{ + edge_descriptor_vector lCollected ; + Extract_boundary_edges(mP,lCollected,rBdry); + Extract_boundary_edges(mQ,lCollected,rBdry); } // @@ -269,8 +257,6 @@ typename LindstromTurkCore::Triangle LindstromTurkCore::Get_triangle( ve , vertex_descriptor const& v2 ) { - CGAL_TSMS_LT_TRACE(3,"Extracting triangle v" << v0->ID << "->v" << v1->ID << "->v" << v2->ID ); - Point const& p0 = get_point(v0); Point const& p1 = get_point(v1); Point const& p2 = get_point(v2); @@ -282,6 +268,10 @@ typename LindstromTurkCore::Triangle LindstromTurkCore::Get_triangle( ve FT lNormalL = Point_cross_product(p0,p1) * (p2-ORIGIN); + CGAL_TSMS_LT_TRACE(3,"Extracting triangle v" << v0->ID << "->v" << v1->ID << "->v" << v2->ID + << " N:" << xyz_to_string(lNormalV) << " L:" << lNormalL + ); + return Triangle(lNormalV,lNormalL); } @@ -360,7 +350,11 @@ void LindstromTurkCore::Extract_triangles_and_link( Triangles& rTriangles, L e02 = next_edge_ccw(mQ_P,mSurface); - v1 = target(e02,mSurface); // This was added to the link while circulating around mP + v1 = target(e02,mSurface); + + // This could have been added to the link while circulating around mP + if ( v1 != mP && std::find(rLink.begin(),rLink.end(),v1) == rLink.end() ) + rLink.push_back(v1) ; e02 = next_edge_ccw(e02,mSurface); @@ -369,7 +363,7 @@ void LindstromTurkCore::Extract_triangles_and_link( Triangles& rTriangles, L vertex_descriptor v2 = target(e02,mSurface); // Any of the vertices found around mP can be reached again around mQ, but we can't duplicate them here. - if ( std::find(rLink.begin(),rLink.end(),v2) == rLink.end() ) + if ( v2 != mP && std::find(rLink.begin(),rLink.end(),v2) == rLink.end() ) rLink.push_back(v2) ; Extract_triangle(v0,v1,v2,e02,rTriangles); @@ -383,18 +377,28 @@ void LindstromTurkCore::Extract_triangles_and_link( Triangles& rTriangles, L } template -void LindstromTurkCore::Add_boundary_preservation_constrians( Boundary const& aBdry ) +void LindstromTurkCore::Add_boundary_preservation_constrians( BoundaryEdges const& aBdry ) { - CGAL_TSMS_LT_TRACE(2,"Adding boundary preservation constrians. "); - Vector e1 = aBdry.op + aBdry.pq + aBdry.qr ; - Vector e3 = aBdry.opN + aBdry.pqN + aBdry.qrN ; - - Matrix H = LT_product(e1); + if ( aBdry.size() > 0 ) + { + Vector e1 = NULL_VECTOR ; + Vector e2 = NULL_VECTOR ; + + for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) + { + e1 = e1 + it->v ; + e2 = e2 + it->n ; + } - Vector c = cross_product(e1,e3); - - mConstrians.Add_from_gradient(H,c); + CGAL_TSMS_LT_TRACE(2,"Adding boundary preservation constrians. SumV=" << xyz_to_string(e1) << " SumN=" << xyz_to_string(e2) ); + + Matrix H = LT_product(e1); + + Vector c = cross_product(e1,e2); + + mConstrians.Add_from_gradient(H,c); + } } template @@ -407,19 +411,16 @@ void LindstromTurkCore::Add_volume_preservation_constrians( Triangles const& for( typename Triangles::const_iterator it = aTriangles.begin(), eit = aTriangles.end() ; it != eit ; ++it ) { - CGAL_TSMS_LT_TRACE(2,"V:" << xyz_to_string(it->NormalV) << ", L:" << it->NormalL); - lSumV = lSumV + it->NormalV ; lSumL = lSumL + it->NormalL ; } - mConstrians.Add_if_alpha_compatible(lSumV,lSumL); } template -void LindstromTurkCore::Add_boundary_and_volume_optimization_constrians( OptionalBoundary const& aBdry, Triangles const& aTriangles ) +void LindstromTurkCore::Add_boundary_and_volume_optimization_constrians( BoundaryEdges const& aBdry, Triangles const& aTriangles ) { CGAL_TSMS_LT_TRACE(2,"Adding boundary and volume optimization constrians. "); @@ -438,26 +439,40 @@ void LindstromTurkCore::Add_boundary_and_volume_optimization_constrians( Opt c = c - ( lTri.NormalL * lTri.NormalV ) ; } + CGAL_TSMS_LT_TRACE(3,"Hv:" << matrix_to_string(H) << "\n cv:" << xyz_to_string(c) ) ; - if ( aBdry ) + + if ( aBdry.size() > 0 ) { // // Boundary optimization // - Matrix Hb = LT_product(aBdry->op) + LT_product(aBdry->pq) + LT_product(aBdry->qr) ; + Matrix Hb = NULL_MATRIX ; + Vector cb = NULL_VECTOR ; - Vector cb = cross_product(aBdry->op,aBdry->opN) + cross_product(aBdry->pq,aBdry->pqN) + cross_product(aBdry->qr,aBdry->qrN); + for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) + { + Matrix H = LT_product(it->v); + Vector c = cross_product(it->v,it->n); + + Hb += H ; + cb = cb + c ; + } + + CGAL_TSMS_LT_TRACE(3,"Hb:" << matrix_to_string(Hb) << "\n cb:" << xyz_to_string(cb) ) ; // // Weighted average // - FT lBoundaryWeight = ( FT(9) * mParams.BoundaryWeight * squared_distance ( get_point(mP), get_point(mQ) ) ) / FT(10) ; + FT lScaledBoundaryWeight = FT(9) * mParams.BoundaryWeight * squared_distance ( get_point(mP), get_point(mQ) ) ; H *= mParams.VolumeWeight ; c = c * mParams.VolumeWeight ; - H += lBoundaryWeight * Hb ; - c = c + ( lBoundaryWeight * cb ) ; + H += lScaledBoundaryWeight * Hb ; + c = c + ( lScaledBoundaryWeight * cb ) ; + + CGAL_TSMS_LT_TRACE(3,"VolW=" << mParams.VolumeWeight << " BdryW=" << mParams.BoundaryWeight << " ScaledBdryW=" << lScaledBoundaryWeight ) ; } @@ -467,8 +482,6 @@ void LindstromTurkCore::Add_boundary_and_volume_optimization_constrians( Opt template void LindstromTurkCore::Add_shape_optimization_constrians( Link const& aLink ) { - CGAL_TSMS_LT_TRACE(2,"Add shape optimization constrians. "); - FT s(aLink.size()); Matrix H (s,0,0 @@ -481,15 +494,23 @@ void LindstromTurkCore::Add_shape_optimization_constrians( Link const& aLink for( typename Link::const_iterator it = aLink.begin(), eit = aLink.end() ; it != eit ; ++it ) c = c + (ORIGIN - get_point(*it)) ; + CGAL_TSMS_LT_TRACE(2,"Adding shape optimization constrians: Shape vector: " << xyz_to_string(c) ); + mConstrians.Add_from_gradient(H,c); } template typename LindstromTurkCore::FT -LindstromTurkCore::Compute_boundary_cost( Vector const& v, Boundary const& aBdry ) +LindstromTurkCore::Compute_boundary_cost( Vector const& v, BoundaryEdges const& aBdry ) { FT rCost(0); - return rCost ; + for ( typename BoundaryEdges::const_iterator it = aBdry.begin() ; it != aBdry.end() ; ++ it ) + { + Vector u = (it->t - ORIGIN ) - v ; + Vector c = cross_product(it->v,u); + rCost += c*c; + } + return rCost / FT(4) ; } template @@ -632,11 +653,10 @@ void LindstromTurkCore::Constrians::Add_if_alpha_compatible( Vector const& A break ; } ++ n ; + + CGAL_TSMS_LT_TRACE(1,"Constrains.A:" << matrix_to_string(A) << "\nConstrains.b:" << xyz_to_string(b) ) ; } } - - CGAL_TSMS_LT_TRACE(1,"Constrains.A:" << matrix_to_string(A) << "\nConstrains.b:" << xyz_to_string(b) ) ; - } template diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/TSMS_common.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/TSMS_common.h index 7bccc79399c..60bdf6a5ce5 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/TSMS_common.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/TSMS_common.h @@ -50,6 +50,7 @@ using boost::in_edges ; using boost::source ; using boost::target ; using boost::edge_is_border_t ; +using boost::vertex_is_border_t ; using boost::vertex_point_t ; using boost::cgal_tsms_is_vertex_fixed_t ; using boost::cgal_tsms_edge_cached_pointer_t ; @@ -146,14 +147,16 @@ CGAL_END_NAMESPACE #endif #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE -# define CGAL_TSMS_LT_TRACE(l,m) if ( l <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE ) CGAL_TSMS_TRACE_IMPL(m) +# define CGAL_TSMS_LT_TRACE(l,m) if ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE ) CGAL_TSMS_TRACE_IMPL(m) #else # define CGAL_TSMS_LT_TRACE(l,m) #endif #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE -# define CGAL_TSMS_TRACE(l,m) if ( l <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE ) CGAL_TSMS_TRACE_IMPL(m) +# define CGAL_TSMS_TRACE_IF(c,l,m) if ( (c) && ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE) ) CGAL_TSMS_TRACE_IMPL(m) +# define CGAL_TSMS_TRACE(l,m) if ( (l) <= CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE ) CGAL_TSMS_TRACE_IMPL(m) #else +# define CGAL_TSMS_TRACE_IF(c,l,m) # define CGAL_TSMS_TRACE(l,m) #endif diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse.h index 9e3e4f4a2e7..51a3d25de40 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse.h @@ -242,7 +242,7 @@ private: void Loop(); bool Is_collapsable( vertex_descriptor const& p, vertex_descriptor const& q, edge_descriptor const& p_q ) ; void Collapse( vertex_pair_ptr aPair ) ; - void Update_neighbors( vertex_pair_ptr aCollapsingPair ) ; + void Update_neighbors( vertex_descriptor aRemovedV, vertex_descriptor aKeptV, bool aIsKeptVFixed ) ; vertex_pair_ptr get_pair ( edge_descriptor const& e ) { @@ -304,10 +304,16 @@ private: return get(is_vertex_fixed,mSurface,v) ; } + bool is_border ( vertex_descriptor const& v ) const + { + vertex_is_border_t is_border_vertex_property ; + return get(is_border_vertex_property,mSurface,v) ; + } + bool is_border ( edge_descriptor const& edge ) const { - edge_is_border_t is_border_property ; - return get(is_border_property,mSurface,edge) ; + edge_is_border_t is_border_edge_property ; + return get(is_border_edge_property,mSurface,edge) ; } bool is_undirected_edge_a_border ( edge_descriptor const& edge ) const diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse_impl.h index fa94a58d73e..2d91873f220 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse_impl.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Vertex_pair_collapse_impl.h @@ -48,6 +48,16 @@ VertexPairCollapse::VertexPairCollapse( TSM& CGAL_TSMS_TRACE(0,"VertexPairCollapse of TSM with " << num_undirected_edges(aSurface) << " edges" ); CGAL_TSMS_DEBUG_CODE ( mStep = 0 ; ) + +#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE + vertex_iterator vb, ve ; + for ( tie(vb,ve) = vertices(mSurface) ; vb != ve ; ++ vb ) + CGAL_TSMS_TRACE(2,"V" << (*vb)->ID << xyz_to_string((*vb)->point()) ) ; + + undirected_edge_iterator eb, ee ; + for ( tie(eb,ee) = undirected_edges(mSurface); eb!=ee; ++eb ) + CGAL_TSMS_TRACE(2,"E" << (*eb)->ID << " (V" << source((*eb),mSurface)->ID << "-V" << target((*eb),mSurface)->ID << ")" ) ; +#endif } template @@ -55,26 +65,14 @@ int VertexPairCollapse::run() { if ( Visitor ) Visitor->OnStarted(mSurface); - - if ( num_vertices(mSurface) > 4 ) - { - // First collect all candidate edges in a PQ - Collect(); - - // Then proceed to collapse each edge in turn - Loop(); + + // First collect all candidate edges in a PQ + Collect(); - CGAL_TSMS_TRACE(0,"Finished: " << (mInitialPairCount - mCurrentPairCount) << " pairs removed." ) ; - } - else - { - if ( Visitor ) - Visitor->OnThetrahedronReached(mSurface); - - mInitialPairCount = mCurrentPairCount = num_undirected_edges(mSurface) ; - - CGAL_TSMS_TRACE(0,"A thetrahedron cannot be simplified any further."); - } + // Then proceed to collapse each edge in turn + Loop(); + + CGAL_TSMS_TRACE(0,"Finished: " << (mInitialPairCount - mCurrentPairCount) << " pairs removed." ) ; int r = (int)(mInitialPairCount - mCurrentPairCount) ; @@ -235,11 +233,15 @@ bool VertexPairCollapse::Is_collapsable( vertex_descriptor const& p { bool rR = true ; -std::cout << "testing collapsabilty of p_q=V" << p->ID << "->V" << q->ID << std::endl ; -std::cout << "is p_q border:" << is_border(p_q) << std::endl ; -std::cout << "is q_q border:" << is_border(opposite_edge(p_q,mSurface)) << std::endl ; - - std::size_t min = is_undirected_edge_a_border(p_q) ? 3 : 4 ; + CGAL_TSMS_TRACE(3,"Testing collapsabilty of p_q=V" << p->ID << "(%" << p->vertex_degree() << ")" + << "->V" << q->ID << "(%" << q->vertex_degree() << ")" + ); + + CGAL_TSMS_TRACE(4, "is p_q border:" << is_border(p_q) ); + CGAL_TSMS_TRACE(4, "is q_q border:" << is_border(opposite_edge(p_q,mSurface)) ) ; + + bool is_boundary = is_undirected_edge_a_border(p_q) ; + std::size_t min = is_boundary ? 3 : 4 ; if ( num_vertices(mSurface) > min ) { out_edge_iterator eb1, ee1 ; @@ -250,8 +252,8 @@ std::cout << "is q_q border:" << is_border(opposite_edge(p_q,mSurface)) << std:: vertex_descriptor t = target(next_edge(p_q,mSurface),mSurface); vertex_descriptor b = target(next_edge(q_p,mSurface),mSurface); -std::cout << " t=V" << t->ID << std::endl ; -std::cout << " b=V" << b->ID << std::endl ; + CGAL_TSMS_TRACE(4," t=V" << t->ID << "(%" << t->vertex_degree() << ")" ); + CGAL_TSMS_TRACE(4," b=V" << b->ID << "(%" << b->vertex_degree() << ")" ); // The following loop checks the link condition for p_q. // Specifically, that every vertex 'k' adjacent to both 'p and 'q' is a face of the mesh. @@ -270,7 +272,6 @@ std::cout << " b=V" << b->ID << std::endl ; if ( target(k_l,mSurface) == q ) { -std::cout << " k=V" << k->ID << std::endl ; // 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. @@ -286,14 +287,34 @@ std::cout << " k=V" << k->ID << std::endl ; || ( b == k && !is_border(q_p) ) ; if ( !is_face ) + { + CGAL_TSMS_TRACE(3," k=V" << k->ID << " IS NOT in a face with p-q. NON-COLLAPSABLE edge." ) ; rR = false ; + } + else + { + CGAL_TSMS_TRACE(4," k=V" << k->ID << " is in a face with p-q") ; + } } } } } } - else rR = false ; + else + { + rR = false ; + CGAL_TSMS_TRACE(3," Surface is irreducible. NON-COLLAPSABLE edge." ) ; + } + if ( rR && !is_boundary ) + { + if ( is_border(p) && is_border(q) ) + { + rR = false ; + CGAL_TSMS_TRACE(3," both p and q are boundary vertices but p-q is not. NON-COLLAPSABLE edge." ) ; + } + } + return rR ; } @@ -313,71 +334,94 @@ void VertexPairCollapse::Collapse( vertex_pair_ptr aPair ) if ( lNewVertexPoint ) { CGAL_TSMS_TRACE(2,"New vertex point: " << xyz_to_string(*lNewVertexPoint) ) ; + + -- mCurrentPairCount ; - // The actual collapse of edge PQ merges the top and bottom facets with its left and right adjacents resp, then - // joins P and Q. - edge_descriptor lEdgePQ = aPair->edge(); - edge_descriptor lEdgeQP = opposite_edge(lEdgePQ,mSurface); - //edge_descriptor lEdgePT = next_edge_ccw(lEdgePQ,mSurface); - edge_descriptor lEdgePT = opposite_edge(prev_edge(lEdgePQ,mSurface),mSurface); + // The collapse of P-Q removes the top and bottom facets, if any. + // Edges P-T and P-Q, which are in the top and bottom facets (if they exist), are used by the collapse operator to remove them. - edge_descriptor lEdgeQB = opposite_edge(prev_edge(lEdgeQP,mSurface),mSurface); + // Edges P-T and P-Q are defined only if the top/bottom facets exists + + edge_descriptor lEdgePT, lEdgeQB ; + + if ( !is_border(lEdgePQ) ) // Exists top facet + lEdgePT = opposite_edge(prev_edge(lEdgePQ,mSurface),mSurface); + + if ( !is_border(lEdgeQP) ) // Exists bottom facet + lEdgeQB = opposite_edge(prev_edge(lEdgeQP,mSurface),mSurface); CGAL_TSMS_TRACE(3,"EdgePQ E" << lEdgePQ->ID - << "(V" << lEdgePQ->vertex()->ID << "->V" << lEdgePQ->opposite()->vertex()->ID - << ") EdgeQP E" << lEdgePQ->opposite()->ID - ) ; - CGAL_TSMS_TRACE(3,"EdgePT E" << lEdgePT->ID - << "(V" << lEdgePT->vertex()->ID << "->V" << lEdgePT->opposite()->vertex()->ID - << ") EdgeTP E" << lEdgePT->opposite()->ID - ) ; - CGAL_TSMS_TRACE(3,"EdgeQB E" << lEdgeQB->ID - << "(V" << lEdgeQB->vertex()->ID << "->V" << lEdgeQB->opposite()->vertex()->ID - << ") EdgeBQ E" << lEdgeQB->opposite()->ID + << "(V" << lEdgePQ->vertex()->ID << "->V" << lEdgePQ->opposite()->vertex()->ID + << ") EdgeQP E" << lEdgePQ->opposite()->ID ) ; + - // The collapse will also remove QB so it must be pop off the PQ as well - vertex_pair_ptr lPairQB = get_pair(lEdgeQB) ; - vertex_pair_ptr lPairPT = get_pair(lEdgePT) ; + // If the top/bottom facets exists, they are removed and the edges P-T and Q-B along with them. + // In that case their corresponding pairs must be pop off the queue - if ( lPairPT->is_in_PQ() ) + if ( handle_assigned(lEdgePT) ) { - CGAL_TSMS_TRACE(2,"Removing VP" << lPairPT->id() << " from PQ" ) ; - remove_from_PQ(lPairPT) ; - } - if ( lPairQB->is_in_PQ() ) - { - CGAL_TSMS_TRACE(2,"Removing VP" << lPairQB->id() << " from PQ") ; - remove_from_PQ(lPairQB) ; + CGAL_TSMS_TRACE(3,"EdgePT E" << lEdgePT->ID + << "(V" << lEdgePT->vertex()->ID << "->V" << lEdgePT->opposite()->vertex()->ID + << ") EdgeTP E" << lEdgePT->opposite()->ID + ) ; + vertex_pair_ptr lPairPT = get_pair(lEdgePT) ; + + if ( lPairPT->is_in_PQ() ) + { + CGAL_TSMS_TRACE(2,"Removing VP" << lPairPT->id() << " from PQ" ) ; + remove_from_PQ(lPairPT) ; + -- mCurrentPairCount ; + } } - CGAL_TSMS_TRACE(1,"Removing from surface V" << lP->ID - << " E" << lEdgePQ->ID << "(PQ=V" << lP->ID << "->V" << lQ->ID << ")" - << " E" << lEdgePT->ID << "(PT=V" << lP->ID << "->V" << target(lEdgePT,mSurface)->ID << ")" - << " E" << lEdgeQB->ID << "(QB=V" << lQ->ID << "->V" << target(lEdgeQB,mSurface)->ID << ")" - ); + if ( handle_assigned(lEdgeQB) ) + { + CGAL_TSMS_TRACE(3,"EdgeQB E" << lEdgeQB->ID + << "(V" << lEdgeQB->vertex()->ID << "->V" << lEdgeQB->opposite()->vertex()->ID + << ") EdgeBQ E" << lEdgeQB->opposite()->ID + ) ; + vertex_pair_ptr lPairQB = get_pair(lEdgeQB) ; + if ( lPairQB->is_in_PQ() ) + { + CGAL_TSMS_TRACE(2,"Removing VP" << lPairQB->id() << " from PQ") ; + remove_from_PQ(lPairQB) ; + -- mCurrentPairCount ; + } + } if ( Visitor ) Visitor->OnCollapsed(mSurface,lP,lEdgePQ,lEdgePT,lEdgeQB); - // + CGAL_TSMS_TRACE(1,"Removing:\n P-Q: E" << lEdgePQ->ID << "(V" << lP->ID << "->V" << lQ->ID << ")" ); + CGAL_TSMS_TRACE_IF(handle_assigned(lEdgePT),1," P-T: E" << lEdgePT->ID << "(V" << lP->ID << "->V" << target(lEdgePT,mSurface)->ID << ")" ) ; + CGAL_TSMS_TRACE_IF(handle_assigned(lEdgeQB),1," Q-B: E" << lEdgeQB->ID << "(V" << lQ->ID << "->V" << target(lEdgeQB,mSurface)->ID << ")" ) ; + // Perform the actuall collapse. // This is an external function. - // It's REQUIRED to remove ONLY vertex P and edges PQ,PT and QB, keeping all other edges and - // to relink all directed edges incident to P with Q. - // The algorithm is based on the stability of the remaining edges. - Collapse_triangulation_edge(lEdgePQ,lEdgePT,lEdgeQB,mSurface); + // It's REQUIRED to remove ONLY 1 vertex (P or Q) and edges PQ,PT and QB (PT and QB are removed if they are not null). + // All other edges must be kept. + // All directed edges incident to vertex removed are relink to the vertex kept. + vertex_descriptor lKeptV = Collapse_triangulation_edge(lEdgePQ,lEdgePT,lEdgeQB,mSurface); - // Reset the point of placement of Q (the vertex that "replaces" the collapsed edge) + vertex_descriptor lRemovedV = ( lKeptV == lP ? lQ : lP ) ; + + CGAL_TSMS_TRACE(1,"V" << lKeptV->ID << " kept." ) ; + +#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE + out_edge_iterator eb1, ee1 ; + for ( tie(eb1,ee1) = out_edges(lKeptV,mSurface) ; eb1 != ee1 ; ++ eb1 ) + CGAL_TSMS_TRACE(2," E" << (*eb1)->ID << " V" << lKeptV->ID << "->V" << target(*eb1,mSurface)->ID ) ; +#endif + + // Reset the point of placement of the kept vertex. vertex_point_t vertex_point ; - put(vertex_point,mSurface,lQ,*lNewVertexPoint) ; + put(vertex_point,mSurface,lKeptV,*lNewVertexPoint) ; - Update_neighbors(aPair); - - mCurrentPairCount -= 3 ; + Update_neighbors(lRemovedV,lKeptV, ( lKeptV == lP ? aPair->is_p_fixed() : aPair->is_q_fixed() ) ) ; } else { @@ -388,66 +432,67 @@ void VertexPairCollapse::Collapse( vertex_pair_ptr aPair ) } template -void VertexPairCollapse::Update_neighbors( vertex_pair_ptr aCollapsingPair ) +void VertexPairCollapse::Update_neighbors( vertex_descriptor aRemovedV + , vertex_descriptor aKeptV + , bool aIsKeptVFixed + ) { CGAL_TSMS_TRACE(3,"Updating cost of neighboring edges..." ) ; - // - // (A) Collect all pairs to update its cost: all those around each vertex adjacent to q + // (A) Collect all pairs to update its cost: all those around each vertex adjacent to the vertex kept // typedef std::set vertex_pair_set ; vertex_pair_set lToUpdate ; - - // (A.1) Loop around all vertices adjacent to q + // (A.1) Loop around all vertices adjacent to the vertex kept in_edge_iterator eb1, ee1 ; - for ( tie(eb1,ee1) = in_edges(aCollapsingPair->q(),mSurface) ; eb1 != ee1 ; ++ eb1 ) + for ( tie(eb1,ee1) = in_edges(aKeptV,mSurface) ; eb1 != ee1 ; ++ eb1 ) { edge_descriptor edge1 = *eb1 ; - vertex_descriptor adj_q = source(edge1,mSurface); + vertex_descriptor adj_k = source(edge1,mSurface); // (A.2) Loop around all edges incident on each adjacent vertex in_edge_iterator eb2, ee2 ; - for ( tie(eb2,ee2) = in_edges(adj_q,mSurface) ; eb2 != ee2 ; ++ eb2 ) + for ( tie(eb2,ee2) = in_edges(adj_k,mSurface) ; eb2 != ee2 ; ++ eb2 ) { edge_descriptor edge2 = *eb2 ; vertex_pair_ptr lPair = get_pair(edge2); - if ( lPair->p() == aCollapsingPair->p() ) + if ( lPair->p() == aRemovedV ) { - CGAL_TSMS_TRACE(4,"Replacing lPair->p() with V" << aCollapsingPair->q()->id() << "(Q)" ) ; + CGAL_TSMS_TRACE(4,"Replacing lPair->p() with V" << aKeptV->id() << "(Q)" ) ; - CGAL_assertion( aCollapsingPair->q() != lPair->q() ) ; + CGAL_assertion( aKeptV != lPair->q() ) ; - lPair->data().set(aCollapsingPair->q() - ,lPair ->q() - ,aCollapsingPair->is_q_fixed() - ,lPair ->is_q_fixed() - ,source(edge2,mSurface) == aCollapsingPair->q() ? edge2 : opposite_edge(edge2,mSurface) + lPair->data().set(aKeptV + ,lPair->q() + ,aIsKeptVFixed + ,lPair->is_q_fixed() + ,source(edge2,mSurface) == aKeptV ? edge2 : opposite_edge(edge2,mSurface) ,mSurface ); } - else if ( lPair->q() == aCollapsingPair->p() ) + else if ( lPair->q() == aRemovedV ) { - CGAL_TSMS_TRACE(4,"Replacing lPair->q() with V" << aCollapsingPair->q()->id() << " (Q)" ) ; + CGAL_TSMS_TRACE(4,"Replacing lPair->q() with V" << aKeptV->id() << " (Q)" ) ; - CGAL_assertion( aCollapsingPair->q() != lPair->p() ) ; + CGAL_assertion( aKeptV != lPair->p() ) ; - lPair->data().set(lPair ->p() - ,aCollapsingPair->q() - ,lPair ->is_p_fixed() - ,aCollapsingPair->is_q_fixed() - ,target(edge2,mSurface) == aCollapsingPair->q() ? edge2 : opposite_edge(edge2,mSurface) + lPair->data().set(lPair->p() + ,aKeptV + ,lPair->is_p_fixed() + ,aIsKeptVFixed + ,target(edge2,mSurface) == aKeptV ? edge2 : opposite_edge(edge2,mSurface) ,mSurface ); } - CGAL_TSMS_TRACE(4,"Inedge around V" << adj_q->ID << " E" << edge2->ID << " Opposite E" << edge2->opposite()->ID + CGAL_TSMS_TRACE(4,"Inedge around V" << adj_k->ID << " E" << edge2->ID << " Opposite E" << edge2->opposite()->ID << " V" << edge2->opposite()->vertex()->ID << "->V" << edge2->vertex()->ID << "\nPair:" << *lPair ) ; @@ -471,16 +516,11 @@ void VertexPairCollapse::Update_neighbors( vertex_pair_ptr aCollaps { vertex_pair_ptr lPair = *it ; - //bool lIsPFixed = lPair->p() == aCollapsingPair->q() ? true : lPair->is_p_fixed() ; - //bool lIsQFixed = lPair->q() == aCollapsingPair->q() ? true : lPair->is_q_fixed() ; - bool lIsPFixed = lPair->is_p_fixed() ; - bool lIsQFixed = lPair->is_q_fixed() ; - Set_collapse_data(lPair->data() ,lPair->p() ,lPair->q() - ,lIsPFixed - ,lIsQFixed + ,lPair->is_p_fixed() + ,lPair->is_q_fixed() ,lPair->edge() ,lPair->surface() ,mParamsToSetCollapseData diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.kdevelop b/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.kdevelop index e3fc5b83d01..f36e05f5f3c 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.kdevelop +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.kdevelop @@ -32,7 +32,7 @@ default - + diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_test.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_test.cpp index a95385eb55d..de20a9262c6 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_test.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/edge_collapse_test.cpp @@ -36,9 +36,9 @@ #include //#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE 4 -#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 1 +//#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 4 -//#define STATS +#define STATS //#define AUDIT void Surface_simplification_external_trace( std::string s )