diff --git a/Surface_mesh_simplification/TODO b/Surface_mesh_simplification/TODO index 8b137891791..bb01bdad711 100644 --- a/Surface_mesh_simplification/TODO +++ b/Surface_mesh_simplification/TODO @@ -1 +1 @@ - +* Add a test driver that uses font outlines as test shapes. diff --git a/Surface_mesh_simplification/changes.txt b/Surface_mesh_simplification/changes.txt index f233711ff7f..597d5024fef 100644 --- a/Surface_mesh_simplification/changes.txt +++ b/Surface_mesh_simplification/changes.txt @@ -1,4 +1,6 @@ - +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/Cartesian/MatrixC33.h b/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h index 2a0ab2ee4e2..001012fcd22 100644 --- a/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h +++ b/Surface_mesh_simplification/include/CGAL/Cartesian/MatrixC33.h @@ -218,14 +218,34 @@ boost::optional< MatrixC33 > inverse_matrix ( MatrixC33 const& m ) { typedef typename R::RT RT ; - typedef boost::optional< MatrixC33 > result_type ; + typedef MatrixC33 Matrix ; + + typedef boost::optional result_type ; result_type rInverse ; RT det = m.determinant(); if ( ! CGAL_NTS is_zero(det) ) - rInverse = result_type( adjoint_matrix(m) / det ) ; + { + RT c00 = (m.r1().y()*m.r2().z() - m.r1().z()*m.r2().y()) / det; + RT c01 = (m.r2().y()*m.r0().z() - m.r0().y()*m.r2().z()) / det; + RT c02 = (m.r0().y()*m.r1().z() - m.r1().y()*m.r0().z()) / det; + + RT c10 = (m.r1().z()*m.r2().x() - m.r1().x()*m.r2().z()) / det; + RT c11 = (m.r0().x()*m.r2().z() - m.r2().x()*m.r0().z()) / det; + RT c12 = (m.r1().x()*m.r0().z() - m.r0().x()*m.r1().z()) / det; + + RT c20 = (m.r1().x()*m.r2().y() - m.r2().x()*m.r1().y()) / det; + RT c21 = (m.r2().x()*m.r0().y() - m.r0().x()*m.r2().y()) / det; + RT c22 = (m.r0().x()*m.r1().y() - m.r0().y()*m.r1().x()) / det; + + rInverse = result_type( Matrix(c00,c01,c02 + ,c10,c11,c12 + ,c20,c21,c22 + ) + ) ; + } return rInverse ; } diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk.h index e78108df2f0..d621123b1a9 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk.h @@ -21,7 +21,6 @@ #include #include #include -#include CGAL_BEGIN_NAMESPACE diff --git a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_impl.h b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_impl.h index 23992d12a1f..ad2a198bc38 100644 --- a/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_impl.h +++ b/Surface_mesh_simplification/include/CGAL/Surface_mesh_simplification/Policies/Detail/Lindstrom_Turk_impl.h @@ -54,10 +54,8 @@ LindstromTurkImpl::LindstromTurkImpl( Params const& aParams if ( !aIsPFixed || !aIsQFixed ) { - CGAL_TSMS_LT_TRACE(2,"Computing LT data for E" << mP_Q->ID << " (V" << mP->ID << "->V" << mQ->ID << ")" ); - // Volume preservation and optimization constrians are based on the normals to the triangles in the star of the collapsing egde // Triangle shape optimization constrians are based on the link of the collapsing edge (the cycle of vertices around the edge) Triangles lTriangles; @@ -68,7 +66,7 @@ LindstromTurkImpl::LindstromTurkImpl( Params const& aParams Extract_triangles_and_link(lTriangles,lLink); -#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE +#ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE std::ostringstream ss ; for( typename Link::const_iterator it = lLink.begin(), eit = lLink.end() ; it != eit ; ++it ) ss << "v" << (*it)->ID << " " ; @@ -161,6 +159,8 @@ LindstromTurkImpl::LindstromTurkImpl( Params const& aParams FT lSquaredLength = squared_distance(lP,lQ); + CGAL_TSMS_LT_TRACE(1,"Squared edge length: " << lSquaredLength ) ; + FT lBdryCost = 0; if ( lBdry ) lBdryCost = Compute_boundary_cost(*lOptionalV,*lBdry); @@ -169,18 +169,24 @@ LindstromTurkImpl::LindstromTurkImpl( Params const& aParams FT lShapeCost = Compute_shape_cost(*lOptionalP,lLink); - FT lTotalCost = mParams.BoundaryWeight * lBdryCost - + mParams.VolumeWeight * lVolumeCost * lSquaredLength + FT lTotalCost = mParams.VolumeWeight * lVolumeCost + + mParams.BoundaryWeight * lBdryCost * lSquaredLength + mParams.ShapeWeight * lShapeCost * lSquaredLength * lSquaredLength ; lOptionalCost = Optional_FT(lTotalCost); - CGAL_TSMS_LT_TRACE(1,"New vertex point: " << xyz_to_string(lV) << " cost: " << lTotalCost ); + CGAL_TSMS_LT_TRACE(1,"New vertex point: " << xyz_to_string(*lOptionalP) << "\nTotal cost: " << lTotalCost ); + + CGAL_TSMS_LT_TRACE(2,"\nSquared edge length: " << lSquaredLength + << "\nBoundary cost: " << lBdryCost + << "\nVolume cost: " << lVolumeCost + << "\nShape cost: " << lShapeCost + ); } } else - CGAL_TSMS_LT_TRACE(1,"The edge is fixed edge."); + CGAL_TSMS_LT_TRACE(1,"The edge is a fixed edge."); mResult = result_type( new Collapse_data(mP,mQ,aIsPFixed,aIsQFixed,mP_Q,mSurface,lOptionalCost,lOptionalP) ); @@ -317,8 +323,8 @@ void LindstromTurkImpl::Extract_triangles_and_link( Triangles& rTriangles, L if ( v2 != mQ ) { - CGAL_expensive_precondition(std::find(rLink.begin(),rLink.end(),v2) == rLink.end() ); - rLink.push_back(v2) ; + if ( std::find(rLink.begin(),rLink.end(),v2) == rLink.end() ) + rLink.push_back(v2) ; } Extract_triangle(v0,v1,v2,e02,rTriangles); @@ -360,6 +366,8 @@ void LindstromTurkImpl::Extract_triangles_and_link( Triangles& rTriangles, L template void LindstromTurkImpl::Add_boundary_preservation_constrians( Boundary 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 ; @@ -373,15 +381,20 @@ void LindstromTurkImpl::Add_boundary_preservation_constrians( Boundary const template void LindstromTurkImpl::Add_volume_preservation_constrians( Triangles const& aTriangles ) { + CGAL_TSMS_LT_TRACE(2,"Adding volume preservation constrians. " << aTriangles.size() << " triangles."); + Vector lSumV = NULL_VECTOR ; - FT lSumL(0) ; + FT lSumL(0) ; 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); } @@ -389,6 +402,8 @@ void LindstromTurkImpl::Add_volume_preservation_constrians( Triangles const& template void LindstromTurkImpl::Add_boundary_and_volume_optimization_constrians( OptionalBoundary const& aBdry, Triangles const& aTriangles ) { + CGAL_TSMS_LT_TRACE(2,"Adding boundary and volume optimization constrians. "); + Matrix H = NULL_MATRIX ; Vector c = NULL_VECTOR ; @@ -401,7 +416,7 @@ void LindstromTurkImpl::Add_boundary_and_volume_optimization_constrians( Opt H += direct_product(lTri.NormalV,lTri.NormalV) ; - c = c + ( lTri.NormalL * lTri.NormalV ) ; + c = c - ( lTri.NormalL * lTri.NormalV ) ; } @@ -433,6 +448,8 @@ void LindstromTurkImpl::Add_boundary_and_volume_optimization_constrians( Opt template void LindstromTurkImpl::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 @@ -487,6 +504,7 @@ LindstromTurkImpl::Compute_shape_cost( Point const& p, Link const& aLink ) return rCost ; } +/* template void LindstromTurkImpl::Constrians::Add_if_alpha_compatible( Vector const& Ai, FT const& bi ) { @@ -538,6 +556,67 @@ void LindstromTurkImpl::Constrians::Add_if_alpha_compatible( Vector const& A ++ n ; } } +} +*/ + +template +void LindstromTurkImpl::Constrians::Add_if_alpha_compatible( Vector const& Ai, FT const& bi ) +{ + double slai = to_double(Ai*Ai) ; + if ( slai > 0.0 ) + { + double l = CGAL_NTS sqrt(slai) ; + + Vector Ain = Ai / l ; + FT bin = bi / l ; + + bool lAddIt = true ; + + if ( n == 1 ) + { + FT d01 = A.r0() * Ai ; + + double sla0 = to_double(A.r0() * A.r0()) ; + double sd01 = to_double(d01 * d01) ; + + if ( sd01 > ( sla0 * slai * squared_cos_alpha() ) ) + lAddIt = false ; + } + else if ( n == 2 ) + { + Vector N = cross_product(A.r0(),A.r1()); + + FT dc012 = N * Ai ; + + double slc01 = to_double(N * N) ; + double sdc012 = to_double(dc012 * dc012); + + if ( sdc012 <= slc01 * slai * squared_sin_alpha() ) + lAddIt = false ; + } + + if ( lAddIt ) + { + switch ( n ) + { + case 0 : + A.r0() = Ain ; + b = Vector(bin,b.y(),b.z()); + break ; + case 1 : + A.r1() = Ain ; + b = Vector(b.x(),bin,b.z()); + break ; + case 2 : + A.r2() = Ain ; + b = Vector(b.x(),b.y(),bin); + break ; + } + ++ n ; + } + } + + CGAL_TSMS_LT_TRACE(1,"Constrains.A:" << matrix_to_string(A) << "\nConstrains.b:" << xyz_to_string(b) ) ; } 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 df80d6220c5..84e84c4fe90 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 @@ -28,6 +28,8 @@ #include #include +#include + namespace boost { @@ -102,6 +104,12 @@ inline std::string xyz_to_string( XYZ const& xyz ) return boost::str( boost::format("(%1%,%2%,%3%)") % xyz.x() % xyz.y() % xyz.z() ) ; } +template +inline std::string matrix_to_string( Matrix const& m ) +{ + return boost::str( boost::format("[%1%|%2%|%3%]") % xyz_to_string(m.r0()) % xyz_to_string(m.r1()) % xyz_to_string(m.r2()) ) ; +} + template inline std::string optional_to_string( boost::optional const& o ) { @@ -144,31 +152,14 @@ CGAL_END_NAMESPACE -#if defined(CGAL_SURFACE_SIMPLIFICATION_ENABLE_AUDIT) -#define CGAL_TSMS_ENABLE_AUDIT -#endif - -#ifdef CGAL_TSMS_ENABLE_AUDIT - -# include -# include -# include -# define CGAL_TSMS_AUDIT_IMPL(m) \ - { \ - std::ostringstream ss ; ss << m ; std::string s = ss.str(); \ - Surface_simplification_external_audit(s); \ - } -#endif - #ifdef CGAL_SURFACE_SIMPLIFICATION_ENABLE_AUDIT -# define CGAL_TSMS_AUDIT(m) CGAL_TSMS_AUDIT_IMPL(m) +# define CGAL_TSMS_AUDIT(p,q,e,c,v) CGAL_TSMS_audit(p,q,e,c,v) #else -# define CGAL_TSMS_AUDIT(m) +# define CGAL_TSMS_AUDIT(p,q,e,c,v) #endif #undef CGAL_TSMS_ENABLE_TRACE -#undef CGAL_TSMS_ENABLE_AUDIT #endif // CGAL_SURFACE_MESH_SIMPLIFICATION_TSMS_COMMON_H // // EOF // 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 f0b305a8be1..2f3a7b80b58 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 @@ -111,7 +111,7 @@ void VertexPairCollapse::Collect() set_pair(edge,lPair); insert_in_PQ(lPair); CGAL_TSMS_TRACE(3, (lPair->cost(),*lPair) << " accepted." ); - CGAL_TSMS_AUDIT("C-" << xyz_to_string(sp) << "->" << xyz_to_string(tp) << "-" << optional_to_string(lPair->cost()) ); + CGAL_TSMS_AUDIT(s,t,edge,lPair->cost(),Get_new_vertex_point(*lPair->data())); } } @@ -229,7 +229,6 @@ void VertexPairCollapse::Collapse( vertex_pair_ptr const& aPair ) if ( lNewVertexPoint ) { CGAL_TSMS_TRACE(2,"New vertex point: " << xyz_to_string(*lNewVertexPoint) ) ; - CGAL_TSMS_AUDIT("V-" << xyz_to_string(get_point(lP)) << "->" << xyz_to_string(get_point(lQ)) << "-" << xyz_to_string(*lNewVertexPoint) ); // The actual collapse of edge PQ merges the top and bottom facets with its left and right adjacents resp, then // joins P and Q. @@ -338,7 +337,6 @@ void VertexPairCollapse::Collapse( vertex_pair_ptr const& aPair ) else { CGAL_TSMS_TRACE(0,"Unable to calculate new vertex point. Pair " << aPair << " discarded without being removed" ) ; - CGAL_TSMS_AUDIT("V-" << xyz_to_string(get_point(lP)) << "->" << xyz_to_string(get_point(lQ)) << "-NONE" ); } } diff --git a/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.cpp b/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.cpp index 5db1b9abd37..ba4f3244ded 100644 --- a/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.cpp +++ b/Surface_mesh_simplification/test/Surface_mesh_simplification/LT_edge_collapse_test.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2002 Max Planck Institut fuer Informatik (Germany). +// // Copyright (c) 2002 Max Planck Institut fuer Informatik (Germany). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you may redistribute it under @@ -22,6 +22,7 @@ #include #include #include +#include #define CGAL_CHECK_EXPENSIVE @@ -33,19 +34,15 @@ #include #include -//#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 4 +//#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_LT_TRACE 4 +//#define CGAL_SURFACE_SIMPLIFICATION_ENABLE_TRACE 3 #define CGAL_SURFACE_SIMPLIFICATION_ENABLE_AUDIT -//#define CREATE_TESTCASE - void Surface_simplification_external_trace( std::string s ) { - std::cout << s << std::endl ; -} - -void Surface_simplification_external_audit( std::string s ) -{ - std::cout << s << std::endl ; + static std::ofstream lout("tsms_log.txt"); + lout << s << std::flush << std::endl ; + std::printf("%s\n",s.c_str()); } int exit_code = 0 ; @@ -58,39 +55,56 @@ int exit_code = 0 ; #include #include +using namespace std ; +using namespace boost ; +using namespace CGAL ; + +//typedef Simple_homogeneous Kernel; +typedef Simple_cartesian Kernel; +typedef Kernel::Vector_3 Vector; +typedef Kernel::Point_3 Point; template -struct My_vertex : public CGAL::HalfedgeDS_vertex_base +struct My_vertex : public HalfedgeDS_vertex_base { - typedef CGAL::HalfedgeDS_vertex_base Base ; + typedef HalfedgeDS_vertex_base Base ; My_vertex() : ID(-1), IsFixed(false) {} - My_vertex( typename Traits::Point_3 p ) : Base(p), ID(-1), IsFixed(false) {} - - int ID; + My_vertex( Point p ) : Base(p), ID(-1), IsFixed(false) {} + + int id() const { return ID ; } + + int ID; bool IsFixed ; } ; template -struct My_halfedge : public CGAL::HalfedgeDS_halfedge_base +struct My_halfedge : public HalfedgeDS_halfedge_base { - My_halfedge() : ID(-1) {} + My_halfedge() + : + ID(-1) + {} + int id() const { return ID ; } + int ID; }; template -struct My_face : public CGAL::HalfedgeDS_face_base +struct My_face : public HalfedgeDS_face_base { - typedef CGAL::HalfedgeDS_face_base Base ; + typedef HalfedgeDS_face_base Base ; My_face() : ID(-1) {} My_face( typename Traits::Plane_3 plane ) : Base(plane) {} + int id() const { return ID ; } + int ID; }; -struct My_items : public CGAL::Polyhedron_items_3 +struct My_items : public Polyhedron_items_3 { template < class Refs, class Traits> struct Vertex_wrapper { @@ -106,16 +120,14 @@ struct My_items : public CGAL::Polyhedron_items_3 }; }; -//typedef CGAL::Simple_homogeneous Kernel; -typedef CGAL::Simple_cartesian Kernel; -typedef Kernel::Vector_3 Vector; -typedef Kernel::Point_3 Point; -typedef CGAL::Polyhedron_3 Polyhedron; +typedef Polyhedron_3 Polyhedron; typedef Polyhedron::Vertex Vertex; typedef Polyhedron::Vertex_iterator Vertex_iterator; +typedef Polyhedron::Vertex_handle Vertex_handle; typedef Polyhedron::Vertex_const_handle Vertex_const_handle; typedef Polyhedron::Halfedge_handle Halfedge_handle; +typedef Polyhedron::Halfedge_const_handle Halfedge_const_handle; typedef Polyhedron::Edge_iterator Edge_iterator; typedef Polyhedron::Facet_iterator Facet_iterator; typedef Polyhedron::Halfedge_around_vertex_const_circulator HV_circulator; @@ -129,9 +141,177 @@ struct External_polyhedron_get_is_vertex_fixed bool operator() ( Polyhedron const&, Vertex_const_handle v ) const { return v->IsFixed; } } ; -CGAL_END_NAMESPACE +CGAL_END_NAMESPACE -using namespace std ; +double sCostMatchThreshold = 1e-2 ; +double sVertexMatchThreshold = 1e-2 ; + +struct Audit_data +{ + Audit_data( Point p, Point q ) : P(p), Q(q) {} + + Point P, Q ; + optional Cost ; + optional NewVertexPoint ; +} ; +typedef shared_ptr Audit_data_ptr ; +typedef vector Audit_data_vector ; + +Audit_data_vector sAuditData ; + +Audit_data_ptr lookup_audit ( Point p, Point q ) +{ + for ( Audit_data_vector::iterator it = sAuditData.begin() ; it != sAuditData.end() ; ++ it ) + { + Audit_data_ptr data = *it ; + if ( data->P == p && data->Q == q ) + return data ; + } + return Audit_data_ptr() ; +} + +Audit_data_ptr get_or_create_audit ( Point p, Point q ) +{ + Audit_data_ptr data = lookup_audit(p,q); + if ( !data ) + { + data = Audit_data_ptr(new Audit_data(p,q)); + sAuditData.push_back(data); + } + return data ; +} + +struct Audit_report +{ + Audit_report( int eid ) + : + HalfedgeID(eid) + , CostMatched(false) + , OrderMatched(false) + , NewVertexMatched(false) + {} + + + int HalfedgeID ; + Audit_data_ptr AuditData ; + optional Cost ; + optional NewVertexPoint ; + bool CostMatched ; + bool OrderMatched ; + bool NewVertexMatched ; +} ; + +typedef shared_ptr Audit_report_ptr ; + +typedef map Audit_report_map ; + +Audit_report_map sAuditReport ; + +typedef char_separator Separator ; +typedef tokenizer Tokenizer ; + +Point ParsePoint( vector tokens, int aIdx ) +{ + double x = atof(tokens[aIdx+0].c_str()); + double y = atof(tokens[aIdx+1].c_str()); + double z = atof(tokens[aIdx+2].c_str()); + + return Point(x,y,z); +} + +void ParseAuditLine( string s ) +{ + Tokenizer tk(s,Separator(",")); + vector tokens(tk.begin(),tk.end()); + if ( tokens.size() >= 7 ) + { + Point p = ParsePoint(tokens,0); + Point q = ParsePoint(tokens,3); + + Audit_data_ptr lData = get_or_create_audit(p,q); + + double cost = atof(tokens[6].c_str()) ; + + if ( cost != std::numeric_limits::max() ) + lData->Cost = cost ; + + if ( tokens.size() == 10 ) + lData->NewVertexPoint = ParsePoint(tokens,7); + } + else + cerr << "WARNING: Invalid audit line: [" << s << "]" << endl ; +} + + +void ParseAudit ( string name ) +{ + ifstream is(name.c_str()); + if ( is ) + { + while ( is ) + { + string line ; + getline(is,line); + if ( line.length() > 0 ) + ParseAuditLine(line); + } + } + else cerr << "Warning: Audit file " << name << " doesn't exist." << endl ; +} + +string to_string( optional const& c ) +{ + if ( c ) + return str( format("%1%") % (*c) ) ; + else return "NONE" ; +} + +string to_string( optional const& p ) +{ + if ( p ) + return str( format("(%1%,%2%,%3%)") % p->x() % p->y() % p->z() ) ; + else return "NONE" ; +} + +void CGAL_TSMS_audit( Vertex_handle const& p + , Vertex_handle const& q + , Halfedge_handle const& e + , optional const& cost + , optional const& newv + ) +{ + Audit_report_ptr lReport( new Audit_report(e->ID) ) ; + + lReport->Cost = cost ; + lReport->NewVertexPoint = newv ; + + Audit_data_ptr lData ; //= lookup_audit(p->point(),q->point()); + if ( lData ) + { + lReport->AuditData = lData ; + + if ( !!lData->Cost && !!cost ) + { + double d = fabs(*lData->Cost - *cost) ; + if ( d < sCostMatchThreshold ) + lReport->CostMatched = true ; + } + else if (!lData->Cost && !cost ) + lReport->CostMatched = true ; + + if ( !!lData->NewVertexPoint && !!newv ) + { + double d = std::sqrt(squared_distance(*lData->NewVertexPoint,*newv)); + + if ( d < sVertexMatchThreshold ) + lReport->NewVertexMatched = true ; + } + else if ( !lData->NewVertexPoint && !newv ) + lReport->NewVertexMatched = true ; + } + + sAuditReport.insert( make_pair(e->ID,lReport) ) ; +} // This is here only to allow a breakpoint to be placed so I can trace back the problem. void error_handler ( char const* what, char const* expr, char const* file, int line, char const* msg ) @@ -146,16 +326,27 @@ void error_handler ( char const* what, char const* expr, char const* file, int l using namespace CGAL::Triangulated_surface_mesh::Simplification ; -void Test ( char const* testcase ) +char const* matched_alpha ( bool matched ) { - ifstream in(testcase); - if ( in ) + return matched ? "matched" : "UNMATCHED" ; +} + +bool Test ( string name ) +{ + bool rSucceeded = false ; + + string off_name = name+string(".off"); + string audit_name = name+string(".audit"); + string result_name = name+string(".out.off"); + + ifstream off_is(off_name.c_str()); + if ( off_is ) { Polyhedron lP; - in >> lP ; + off_is >> lP ; - cout << "Testing Lindstrom Turk simplification of suracewith " << (lP.size_of_halfedges()/2) << " edges..." << endl ; + cout << "Testing Lindstrom Turk simplification of surace with " << (lP.size_of_halfedges()/2) << " edges..." << endl ; cout << setprecision(19) ; @@ -170,8 +361,12 @@ void Test ( char const* testcase ) int lFacetID = 0 ; for ( Polyhedron::Facet_iterator fi = lP.facets_begin(); fi != lP.facets_end() ; ++ fi ) fi->ID = lFacetID ++ ; - - + + sAuditData.clear(); + //ParseAudit(audit_name); + + cout << "Audit data loaded." << endl ; + typedef LindstromTurk_collapse_data Collapse_data ; Construct_LindstromTurk_collapse_data Construct_collapse_data ; @@ -181,56 +376,81 @@ void Test ( char const* testcase ) Collapse_data::Params lParams; + sAuditReport.clear(); int r = vertex_pair_collapse(lP,Construct_collapse_data,&lParams,Get_cost,Get_vertex_point,Should_stop); - + + ofstream off_out(result_name.c_str(),ios::trunc); + off_out << lP ; + cout << "Finished...\n" << r << " edges removed.\n" << lP.size_of_vertices() << " vertices.\n" << (lP.size_of_halfedges()/2) << " edges.\n" << lP.size_of_facets() << " triangles.\n" - << ( lP.is_valid() ? " valid" : " INVALID!!" ) - << endl ; + << ( lP.is_valid() ? " valid\n" : " INVALID!!\n" ) ; + + unsigned lMatches = 0 ; + + cout << "Audit report:\n" ; + for ( Audit_report_map::const_iterator ri = sAuditReport.begin() ; ri != sAuditReport.end() ; ++ ri ) + { + Audit_report_ptr lReport = ri->second ; + + if ( lReport->AuditData ) + { + if ( lReport->NewVertexMatched ) + ++ lMatches ; + + cout << "Collapsed Halfedge " << lReport->HalfedgeID << endl + << " Cost: Actual=" << to_string(lReport->Cost) << ", Expected=" << to_string(lReport->AuditData->Cost) + << ". " << matched_alpha(lReport->CostMatched) << endl + << " New vertex point: Actual=" << to_string(lReport->NewVertexPoint) << ", Expected=" + << to_string(lReport->AuditData->NewVertexPoint) + << ". " << matched_alpha(lReport->NewVertexMatched) + << endl ; + } + else + { + cout << "No audit data for Halfedge " << lReport->HalfedgeID << endl ; + ++ lMatches ; + } + } + + rSucceeded = ( lMatches == sAuditReport.size() ) ; } else { - cerr << "Unable to open test file " << testcase << endl ; - exit_code = 1 ; + cerr << "Unable to open test file " << name << endl ; } -} - -void CreateTestCase() -{ - Polyhedron lP; - - Point p( 0 , 0 , 0); - Point q( 0 ,100, 0); - Point r( 100, 0 , 0); - Point s( 0 , 0 , 100); - Halfedge_handle h = lP.make_tetrahedron( p, q, r, s); - - Halfedge_handle g = lP.create_center_vertex(h); - - g->vertex()->point() = Point(25,25,0); - - ofstream out("data/sample0.off"); - if ( out ) - out << lP ; + return rSucceeded ; } int main( int argc, char** argv ) { - CGAL::set_error_handler (error_handler); - CGAL::set_warning_handler(error_handler); + set_error_handler (error_handler); + set_warning_handler(error_handler); -#ifdef CREATE_TESTCASE - CreateTestCase(); -#else + vector cases ; + for ( int i = 1 ; i < argc ; ++i ) - Test(argv[i]); -#endif - - return exit_code; + cases.push_back( string(argv[i]) ) ; + + if ( cases.size() == 0 ) + cases.push_back( string("data/sample5") ) ; + + unsigned lOK = 0 ; + for ( vector::const_iterator it = cases.begin(); it != cases.end() ; ++ it ) + { + if ( Test(*it) ) + ++ lOK ; + } + + cout << endl + << lOK << " cases succedded." << endl + << (cases.size() - lOK ) << " cases failed." << endl ; + + return lOK == cases.size() ? 0 : 1 ; } // EOF // 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 ece740db3cf..14398b0e8c8 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 @@ -9,14 +9,14 @@ . false - + LT_edge_collapse_test executable / - data/sample0.off + data/sample5 false true @@ -26,8 +26,8 @@ 1 0 false - - + + CGAL_MAKEFILE=/home/fcacciola/Programming/CGAL/make/makefile_i686_Linux-2.6_g++-4.0.2 DEBUGGING=yes default @@ -36,17 +36,17 @@ make - + - - - - - - + + + + + + true false false @@ -126,7 +126,7 @@ 250 - + set m_,_ theValue @@ -152,8 +152,8 @@ VisualBoyAdvance - - + + false false -f0