mirror of https://github.com/CGAL/cgal
Fixed various bugs in the handling of boundaries
This commit is contained in:
parent
2ed5292c1e
commit
7fdc391f75
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<class Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
class Polyhedron_vertex_is_border_map : public put_get_helper<bool, Polyhedron_vertex_is_border_map<Gt, I, HDS, A> >
|
||||
{
|
||||
private:
|
||||
|
||||
typedef CGAL::Polyhedron_3<Gt,I,HDS,A> Polyhedron ;
|
||||
|
||||
public:
|
||||
|
||||
typedef readable_property_map_tag category;
|
||||
typedef bool value_type;
|
||||
typedef bool reference;
|
||||
typedef typename graph_traits<Polyhedron const>::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 Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
class Polyhedron_vertex_point_map : public put_get_helper< typename Gt::Point_3&, Polyhedron_vertex_point_map<Gt, I, HDS, A> >
|
||||
{
|
||||
|
|
@ -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<class Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
inline
|
||||
|
|
@ -144,6 +178,14 @@ Polyhedron_edge_is_border_map<Gt,I,HDS,A> get(edge_is_border_t, CGAL::Polyhedron
|
|||
return m;
|
||||
}
|
||||
|
||||
template<class Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
inline
|
||||
Polyhedron_vertex_is_border_map<Gt,I,HDS,A> get(vertex_is_border_t, CGAL::Polyhedron_3<Gt,I,HDS,A> const& p)
|
||||
{
|
||||
Polyhedron_vertex_is_border_map<Gt,I,HDS,A> m(p);
|
||||
return m;
|
||||
}
|
||||
|
||||
template<class Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
inline
|
||||
Polyhedron_vertex_point_map<Gt,I,HDS,A> get(vertex_point_t, CGAL::Polyhedron_3<Gt,I,HDS,A>& p)
|
||||
|
|
@ -185,6 +227,17 @@ struct Polyhedron_property_map<edge_is_border_t>
|
|||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Polyhedron_property_map<vertex_is_border_t>
|
||||
{
|
||||
template<class Gt, class I, CGAL_HDS_PARAM_, class A>
|
||||
struct bind_
|
||||
{
|
||||
typedef Polyhedron_vertex_is_border_map<Gt,I,HDS,A> type;
|
||||
typedef Polyhedron_vertex_is_border_map<Gt,I,HDS,A> const_type;
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Polyhedron_property_map<vertex_point_t>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<class DS_>
|
||||
struct Collapse_triangulation_edge
|
||||
{
|
||||
typedef DS_ DS ;
|
||||
|
||||
typedef typename boost::graph_traits<DS>::edge_descriptor edge_descriptor ;
|
||||
typedef typename boost::graph_traits<DS>::edge_descriptor edge_descriptor ;
|
||||
typedef typename boost::graph_traits<DS>::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 ;
|
||||
}
|
||||
|
||||
} ;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
#ifndef CGAL_SURFACE_MESH_SIMPLIFICATION_LINDSTROM_TURK_CORE_H
|
||||
#define CGAL_SURFACE_MESH_SIMPLIFICATION_LINDSTROM_TURK_CORE_H 1
|
||||
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <vector>
|
||||
|
||||
#include <CGAL/Surface_mesh_simplification/TSMS_common.h>
|
||||
#include <CGAL/Surface_mesh_simplification/Policies/LindstromTurk_collapse_data.h>
|
||||
|
||||
|
|
@ -48,6 +49,10 @@ public:
|
|||
typedef typename Collapse_data::edge_descriptor edge_descriptor ;
|
||||
typedef typename Collapse_data::Params Params ;
|
||||
|
||||
typedef boost::graph_traits<TSM> GraphTraits ;
|
||||
|
||||
typedef typename GraphTraits::in_edge_iterator in_edge_iterator ;
|
||||
|
||||
typedef typename Surface_geometric_traits<TSM>::Kernel Kernel ;
|
||||
|
||||
typedef typename Kernel::Point_3 Point ;
|
||||
|
|
@ -88,23 +93,16 @@ private :
|
|||
|
||||
typedef std::vector<Triangle> Triangles ;
|
||||
typedef std::vector<vertex_descriptor> Link ;
|
||||
|
||||
struct Boundary
|
||||
typedef std::vector<edge_descriptor> 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<Boundary> OptionalBoundary ;
|
||||
typedef std::vector<BoundaryEdge> 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 ;
|
||||
|
|
|
|||
|
|
@ -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<CD>::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<CD>::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<CD>::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<CD>::compute( Collapse_data& rData )
|
|||
<< "\nBoundary cost: " << lBdryCost
|
||||
<< "\nVolume cost: " << lVolumeCost
|
||||
<< "\nShape cost: " << lShapeCost
|
||||
<< "\nTOTAL COST: " << lTotalCost
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -212,52 +194,58 @@ void LindstromTurkCore<CD>::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<class CD>
|
||||
typename LindstromTurkCore<CD>::OptionalBoundary LindstromTurkCore<CD>::Extract_boundary()
|
||||
void LindstromTurkCore<CD>::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<class CD>
|
||||
void LindstromTurkCore<CD>::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<class CD>
|
||||
void LindstromTurkCore<CD>::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<CD>::Triangle LindstromTurkCore<CD>::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<CD>::Triangle LindstromTurkCore<CD>::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<CD>::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<CD>::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<CD>::Extract_triangles_and_link( Triangles& rTriangles, L
|
|||
}
|
||||
|
||||
template<class CD>
|
||||
void LindstromTurkCore<CD>::Add_boundary_preservation_constrians( Boundary const& aBdry )
|
||||
void LindstromTurkCore<CD>::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<class CD>
|
||||
|
|
@ -407,19 +411,16 @@ void LindstromTurkCore<CD>::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<class CD>
|
||||
void LindstromTurkCore<CD>::Add_boundary_and_volume_optimization_constrians( OptionalBoundary const& aBdry, Triangles const& aTriangles )
|
||||
void LindstromTurkCore<CD>::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<CD>::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<CD>::Add_boundary_and_volume_optimization_constrians( Opt
|
|||
template<class CD>
|
||||
void LindstromTurkCore<CD>::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<CD>::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<class CD>
|
||||
typename LindstromTurkCore<CD>::FT
|
||||
LindstromTurkCore<CD>::Compute_boundary_cost( Vector const& v, Boundary const& aBdry )
|
||||
LindstromTurkCore<CD>::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<class CD>
|
||||
|
|
@ -632,11 +653,10 @@ void LindstromTurkCore<CD>::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<class V>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -48,6 +48,16 @@ VertexPairCollapse<M,D,C,V,S,I>::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<class M,class D,class C,class V,class S, class I>
|
||||
|
|
@ -55,26 +65,14 @@ int VertexPairCollapse<M,D,C,V,S,I>::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<M,D,C,V,S,I>::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<M,D,C,V,S,I>::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<M,D,C,V,S,I>::Collapse( vertex_pair_ptr aPair )
|
|||
}
|
||||
|
||||
template<class M,class D,class C,class V,class S, class I>
|
||||
void VertexPairCollapse<M,D,C,V,S,I>::Update_neighbors( vertex_pair_ptr aCollapsingPair )
|
||||
void VertexPairCollapse<M,D,C,V,S,I>::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_ptr> 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<M,D,C,V,S,I>::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
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<selectedenvironment>default</selectedenvironment>
|
||||
<environments>
|
||||
<default>
|
||||
<envvar value="-g" name="EXTRA_FLAGS" />
|
||||
<envvar value="-O2" name="EXTRA_FLAGS" />
|
||||
</default>
|
||||
</environments>
|
||||
</make>
|
||||
|
|
|
|||
|
|
@ -36,9 +36,9 @@
|
|||
#include <CGAL/Constrained_triangulation_2.h>
|
||||
|
||||
//#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 )
|
||||
|
|
|
|||
Loading…
Reference in New Issue