From aa31f66f50eefa7a336b0508db5d04b518587abb Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Tue, 20 Nov 2012 09:15:01 +0100 Subject: [PATCH] Add benchmark code (from branch Surface_mesh-GF, thanks to Philipp). --- .../Linear_cell_complex/CMakeLists.txt | 11 + .../Linear_cell_complex/Stop_watch.h | 114 +++++ .../Linear_cell_complex/lcc_performance.cpp | 24 + .../Linear_cell_complex/lcc_performance.h | 447 ++++++++++++++++++ .../Linear_cell_complex/performance.h | 95 ++++ 5 files changed, 691 insertions(+) create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex/CMakeLists.txt create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex/Stop_watch.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex/performance.h diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/benchmark/Linear_cell_complex/CMakeLists.txt new file mode 100644 index 00000000000..0e49524efff --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex/CMakeLists.txt @@ -0,0 +1,11 @@ +project(LCC_performance) + +cmake_minimum_required(VERSION 2.6.2) + +find_package(CGAL REQUIRED) +include(${CGAL_USE_FILE}) + +include_directories(BEFORE "../../include") + +add_executable(lcc_performance performance.h lcc_performance.h lcc_performance.cpp) +target_link_libraries(lcc_performance ${CGAL_LIBRARIES}) diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex/Stop_watch.h b/Linear_cell_complex/benchmark/Linear_cell_complex/Stop_watch.h new file mode 100644 index 00000000000..7051026584b --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex/Stop_watch.h @@ -0,0 +1,114 @@ +//============================================================================= + +#ifndef STOPWATCH_HH +#define STOPWATCH_HH + + +//== INCLUDES ================================================================= + +#ifdef _WIN32 +# include +#else // Unix +# include +#endif + +#include + + +//== NAMESPACE ================================================================ + +namespace graphene { + + +//== CLASS DEFINITION ========================================================= + + +/// Simple class for a stop watch +class StopWatch +{ +public: + + /// Constructor + StopWatch() + { +#ifdef _WIN32 // Windows + QueryPerformanceFrequency(&freq_); +#endif + } + + + /// Start time measurement + void start() + { +#ifdef _WIN32 // Windows + QueryPerformanceCounter(&starttime_); +#else // Linux + starttime_ = current_time(); +#endif + } + + + /// Stop time measurement, return elapsed time in ms + double stop() + { +#ifdef _WIN32 // Windows + QueryPerformanceCounter(&endtime_); +#else // Unix + endtime_ = current_time(); +#endif + return elapsed(); + } + + /// Return elapsed time in ms (watch has to be stopped). + double elapsed() const + { +#ifdef _WIN32 // Windows + return ((double)(endtime_.QuadPart - starttime_.QuadPart) + / (double)freq_.QuadPart * 1000.0f); +#else // Unix + return ((endtime_.tv_sec - starttime_.tv_sec )*1000.0 + + (endtime_.tv_usec - starttime_.tv_usec)*0.001); +#endif + } + + +private: + +#ifdef _WIN32 // Windows + + LARGE_INTEGER starttime_, endtime_; + LARGE_INTEGER freq_; + +#else // Unix + + timeval current_time() const + { + struct timeval tv; + gettimeofday(&tv, 0); + return tv; + } + + timeval starttime_, endtime_; + +#endif +}; + + +//============================================================================= + + +/// output a timer to a stream +inline std::ostream& +operator<<(std::ostream& _os, const StopWatch& _timer) +{ + _os << _timer.elapsed() << " ms"; + return _os; +} + + +//============================================================================= +} // namespace graphene +//============================================================================= +#endif // STOPWATCH_HH defined +//============================================================================= + diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.cpp new file mode 100644 index 00000000000..a69e3d5e0bc --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.cpp @@ -0,0 +1,24 @@ +//== INCLUDES ================================================================= + + +#include "lcc_performance.h" + + +//============================================================================= + + +int main(int argc, char** argv) +{ + if (argc != 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + LCC_performance().run(argv[1], "output_cgal.off"); + + return 0; +} + + +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.h b/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.h new file mode 100644 index 00000000000..928f16a08ef --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex/lcc_performance.h @@ -0,0 +1,447 @@ +//== INCLUDES ================================================================= + + +#include +#include +#include +#include +#include +#include "performance.h" + +#define HAS_NORMALS 1 + +//== CLASS DEFINITION ========================================================= + +typedef CGAL::Simple_cartesian MyKernelLCC; +typedef MyKernelLCC::Point_3 Point_3; +typedef MyKernelLCC::Vector_3 Vector_3; + +class MyItemsLCC +{ +public: + + template + struct Dart_wrapper + { + typedef CGAL::Dart<2, LCC> Dart; // Dim 2 == Polyhedron + +#if HAS_NORMALS + typedef CGAL::Cell_attribute_with_point Vertex; + typedef CGAL::Cell_attribute Face; +#else + typedef CGAL::Cell_attribute_with_point Vertex; + typedef CGAL::Cell_attribute Face; +#endif + typedef CGAL::cpp0x::tuple Attributes; + }; +}; + +typedef CGAL::Linear_cell_complex_traits<3, MyKernelLCC> MyTraitsLCC; +typedef CGAL::Linear_cell_complex<2, 3, MyTraitsLCC, MyItemsLCC> LCC; + +//== CLASS DEFINITION ========================================================= + +class LCC_performance : public Performance_test +{ + +private: + + LCC lcc; + +private: + + virtual bool read_mesh(const char* _filename) + { + std::ifstream ifs(_filename); + CGAL::load_off(lcc, ifs); + // lcc.display_characteristics(std::cout); + + for ( LCC::Dart_range::iterator dit=lcc.darts().begin(), + dend=lcc.darts().end(); dit!=dend; ++dit ) + { + if ( dit->attribute<2>()==NULL ) + lcc.set_attribute<2>(dit, lcc.create_attribute<2>()); + } + + return true; + } + + + virtual bool write_mesh(const char* _filename) + { + std::ofstream ofs(_filename); + // CGAL::write_off(lcc, ofs); + return true; + } + + + virtual int circulator_test() + { + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + LCC::Attribute_range<2>::type::iterator fit, fend = lcc.attributes<2>().end(); + + int counter = 0; + + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + for( LCC::Dart_of_cell_range<0>::iterator + vhit = lcc.darts_of_cell<0>(vit->dart()).begin(), + vhend = lcc.darts_of_cell<0>(vit->dart()).end(); + vhit!=vhend; ++vhit ) + { + ++counter; + } + } + + for (fit = lcc.attributes<2>().begin(); fit != fend; ++fit) + { + for( LCC::Dart_of_cell_range<2>::iterator + fhit = lcc.darts_of_cell<2>(fit->dart()).begin(), + fhend = lcc.darts_of_cell<2>(fit->dart()).end(); + fhit!=fhend; ++fhit ) + { + --counter; + } + } + + return counter; + } + + + virtual void barycenter_test() + { + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + Vector_3 v(CGAL::NULL_VECTOR); + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + v = v + (vit->point() - CGAL::ORIGIN); + } + v = v / lcc.number_of_vertex_attributes(); + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + vit->point() = vit->point() - v; + } + } + + + virtual void normal_test() + { +#if HAS_NORMALS + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + LCC::Attribute_range<2>::type::iterator fit, fend = lcc.attributes<2>().end(); + + for (fit = lcc.attributes<2>().begin(); fit != fend; ++fit) + { + LCC::Dart_handle dh = fit->dart(); + Point_3 p0 = LCC::point(dh); + dh = dh->beta(1); + Point_3 p1 = LCC::point(dh); + dh = dh->beta(1); + Point_3 p2 = LCC::point(dh); + Vector_3 n = cross_product(p0-p1, p2-p1); + n = n / sqrt(n.squared_length()); + fit->info() = n; // info is here the normal + } + + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + Vector_3 n(0,0,0); + for( LCC::Dart_of_cell_range<0>::iterator + vhit = lcc.darts_of_cell<0>(vit->dart()).begin(), + vhend = lcc.darts_of_cell<0>(vit->dart()).end(); + vhit!=vhend; ++vhit ) + { + n = n + vhit->attribute<2>()->info(); + } + n = n / sqrt(n.squared_length()); + vit->info() = n; // info is here the normal + } +#endif + } + + virtual void smoothing_test() + { + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + bool vertex_is_border = false; + Vector_3 v(0,0,0); + float c(0); + for( LCC::Dart_of_cell_range<0>::iterator + vhit = lcc.darts_of_cell<0>(vit->dart()).begin(), + vhend = lcc.darts_of_cell<0>(vit->dart()).end(); + vhit!=vhend; ++vhit ) + { + if (vhit->is_free(2)) + { + vertex_is_border = true; + break; + } + v = v + (LCC::point(vhit->other_extremity()) - CGAL::ORIGIN); + ++c; + } + if (!vertex_is_border) + vit->point() = CGAL::ORIGIN + (v / c); + } + + } + + void flip_edge(LCC::Dart_handle d) + { + LCC::Dart_handle d1 = d->beta(1); + LCC::Dart_handle d2 = d->beta(2)->beta(0); + + CGAL_assertion ( !d1->is_free(1) && !d2->is_free(0) ); + + LCC::Dart_handle d3 = d1->beta(1); + LCC::Dart_handle d4 = d2->beta(0); + + // We isolated the edge + lcc.basic_link_beta_1(d->beta(0), d->beta(2)->beta(1)); + lcc.basic_link_beta_0(d->beta(1), d->beta(2)->beta(0)); + + // Then we push the two extremities. + lcc.basic_link_beta_0(d3, d); + lcc.basic_link_beta_0(d2, d->beta(2)); + lcc.link_beta_1(d4, d); + lcc.link_beta_1(d1, d->beta(2)); + } + + virtual void subdivision_test() + { + // for vector-storage we *must* reserve memory first! + int nv = lcc.number_of_vertex_attributes(); + /*int nh = lcc.number_of_darts(); + int nf = lcc.number_of_attributes<2>();*/ + // lcc.reserve(nv+nf, nh+6*nf, 3*nf); /: TODO implement in CMap ? + + // iterators + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + LCC::Attribute_range<2>::type::iterator fit, fend = lcc.attributes<2>().end(); + LCC::Dart_range::iterator dit, dend =lcc.darts().end(); + + // compute new positions of old vertices + int i; + std::vector new_pos(nv); + for (vit = lcc.vertex_attributes().begin(), i=0; vit != vend; ++vit, ++i) + { + bool is_border = false; + Vector_3 v(0,0,0); + float n = 0; + + for( LCC::Dart_of_cell_range<0>::iterator + vhit = lcc.darts_of_cell<0>(vit->dart()).begin(), + vhend = lcc.darts_of_cell<0>(vit->dart()).end(); + vhit!=vhend; ++vhit ) + { + if (vhit->is_free(2)) + { + is_border = true; + break; + } + + v = v + (LCC::point(vhit->other_extremity()) - CGAL::ORIGIN); + ++n; + } + + if ( !is_border ) + { + float alpha = (4.0 - 2.0*cos(2.0*M_PI/n)) / 9.0; + v = (1.0f-alpha)*(vit->point() - CGAL::ORIGIN) + alpha/n*v; + new_pos[i] = CGAL::ORIGIN + v; + } + else + { + new_pos[i] = vit->point(); + } + } + + // adjust end iterators + --vend; --fend; --dend; + + // split faces + fit = lcc.attributes<2>().begin(); + do + { + Vector_3 v(CGAL::NULL_VECTOR); + float c(0); + + for( LCC::Dart_of_cell_range<2>::iterator + vhit = lcc.darts_of_cell<2>(fit->dart()).begin(), + vhend = lcc.darts_of_cell<2>(fit->dart()).end(); + vhit!=vhend; ++vhit ) + { + v = v + (LCC::point(vhit) - CGAL::ORIGIN); + ++c; + } + v = v / c; + + { // Here we insert a point in cell_2: equivalent to + // lcc.insert_point_in_cell<2>(fit->dart(), CGAL::ORIGIN + v); + // but optimized, and we create faces. + typename LCC::Dart_handle firstdart = fit->dart(); + typename LCC::Dart_handle currentdart = firstdart; + typename LCC::Dart_handle nextdart = currentdart->beta(1); + + typename LCC::Attribute_handle<2>::type newf; + + typename LCC::Vertex_attribute_handle + newv = lcc.create_vertex_attribute(CGAL::ORIGIN + v); + typename LCC::Dart_handle newdart = lcc.create_dart(newv); + typename LCC::Dart_handle newdart2 = lcc.create_dart(nextdart->attribute<0>()); + + lcc.basic_link_beta(newdart2, newdart, 2); + lcc.basic_link_beta(newdart, nextdart, 1); + lcc.basic_link_beta(currentdart, newdart2, 1); + + for ( currentdart=nextdart, nextdart=nextdart->beta(1); + currentdart!=firstdart; + currentdart=nextdart, nextdart=nextdart->beta(1) ) + { + newf = lcc.create_attribute<2>(); + + newdart = lcc.create_dart(newv); + newdart2 = lcc.create_dart(nextdart->attribute<0>()); + + lcc.set_attribute_of_dart<2>(newdart2, newf); + lcc.set_attribute_of_dart<2>(currentdart, newf); + lcc.set_attribute_of_dart<2>(currentdart->beta(0), newf); + + lcc.basic_link_beta(newdart2, newdart, 2); + lcc.basic_link_beta(newdart, nextdart, 1); + lcc.basic_link_beta(currentdart, newdart2, 1); + lcc.basic_link_beta(newdart2, currentdart->beta(0), 1); + } + + lcc.basic_link_beta(firstdart->beta(1), firstdart->beta(0), 1); + lcc.set_attribute_of_dart<2>(firstdart->beta(0), + firstdart->attribute<2>()); + lcc.set_attribute_of_dart<2>(firstdart->beta(1), + firstdart->attribute<2>()); + } + + } + while (fit++ != fend); + + // adjust end iterators + ++vend; ++fend; ++dend; + + // set new positions of old vertices + for (vit = lcc.vertex_attributes().begin(), i=0; vit != vend; ++vit, ++i) + vit->point() = new_pos[i]; + + // flip old edges + for (dit = lcc.darts().begin(); dit != dend; ++dit) + { + if (!dit->is_free(2) && ditbeta(2) ) + flip_edge(dit); + } + + // write_mesh("reslcc.off"); + } + + virtual void collapse_test() + { + + // reserve memory + /* int nv = P.size_of_vertices(); + int nh = P.size_of_halfedges(); + int nf = P.size_of_facets(); + P.reserve(nv+nf, nh+6*nf, 3*nf); + + // iterators + Polyhedron::Vertex_iterator vit, vend = P.vertices_end(); + Polyhedron::Face_iterator fit, fend = P.facets_end(); + + + // adjust end iterators + --vend; --fend; + + + // split faces (a for loop does not work for list-kernel!) + Point_3 p(0,0,0); + fit = P.facets_begin(); + do + { + Polyhedron::Halfedge_handle h = P.create_center_vertex(fit->halfedge()); + h->vertex()->point() = p; + } + while (++fit != fend); + + + // adjust end iterators + ++vend; ++fend; + + + // collapse new edges + vit=vend; vend=P.vertices_end(); + for (; vit!=vend; ++vit) + halfedge_collapse(vit->halfedge()->opposite());*/ + } + + + void halfedge_collapse(LCC::Dart_handle pq) + { + // this code is copied from the CGAL surface simplification package + /* + Polyhedron::Halfedge_handle qp = pq->opposite(); + Polyhedron::Halfedge_handle pt = pq->prev()->opposite(); + Polyhedron::Halfedge_handle qb = qp->prev()->opposite(); + + bool lTopFaceExists = !pq->is_border() ; + bool lBottomFaceExists = !qp->is_border() ; + bool lTopLeftFaceExists = lTopFaceExists && !pt->is_border() ; + bool lBottomRightFaceExists = lBottomFaceExists && !qb->is_border() ; + + Polyhedron::Vertex_handle q = pq->vertex(); + Polyhedron::Vertex_handle p = pq->opposite()->vertex(); + + bool lP_Erased = false, lQ_Erased = false ; + + if ( lTopFaceExists ) + { + if ( lTopLeftFaceExists ) + { + P.join_facet (pt); + } + else + { + P.erase_facet(pt->opposite()); + + if ( !lBottomFaceExists ) + { + lP_Erased = true ; + } + } + } + + if ( lBottomFaceExists ) + { + if ( lBottomRightFaceExists ) + { + P.join_facet (qb); + } + else + { + P.erase_facet(qb->opposite()); + + if ( !lTopFaceExists ) + { + lQ_Erased = true ; + } + } + } + + if ( !lP_Erased && !lQ_Erased ) + { + P.join_vertex(pq); + lP_Erased = true ; + } + */ + } + +}; + + +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex/performance.h b/Linear_cell_complex/benchmark/Linear_cell_complex/performance.h new file mode 100644 index 00000000000..fad3ae6e7ea --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex/performance.h @@ -0,0 +1,95 @@ +//============================================================================= + +#ifndef PERFORMANCE_TEST_H +#define PERFORMANCE_TEST_H + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include + +#include "Stop_watch.h" + + +//== CLASS DEFINITION ========================================================= + + +class Performance_test +{ +public: + + Performance_test() {} + + void run(const char* input, const char* output) + { + graphene::StopWatch timer; + + timer.start(); + if (!read_mesh(input)) { std::cerr << "read error\n"; exit(1); } + timer.stop(); + std::cout << "Read mesh : " << timer << std::endl; + + timer.start(); + int c; + for (int i=0; i<100; ++i) + c = circulator_test(); + timer.stop(); + assert(c==0); + std::cout << "Circulator : " << timer << std::endl; + + timer.start(); + for (int i=0; i<1000; ++i) + barycenter_test(); + timer.stop(); + std::cout << "Barycenter : " << timer << std::endl; + + timer.start(); + for (int i=0; i<100; ++i) + normal_test(); + timer.stop(); + std::cout << "Normals : " << timer << std::endl; + + timer.start(); + for (int i=0; i<100; ++i) + smoothing_test(); + timer.stop(); + std::cout << "Smoothing : " << timer << std::endl; + + timer.start(); + subdivision_test(); + timer.stop(); + std::cout << "Subdivision : " << timer << std::endl; + + timer.start(); + collapse_test(); + timer.stop(); + std::cout << "Collapse : " << timer << std::endl; + + timer.start(); + if (!write_mesh(output)) { std::cerr << "write error\n"; exit(1); } + timer.stop(); + std::cout << "Write mesh : " << timer << std::endl; + + std::cout << std::endl; + } + + +protected: + + virtual bool read_mesh(const char* _filename) = 0; + virtual bool write_mesh(const char* _filename) = 0; + virtual int circulator_test() { return 0; } + virtual void barycenter_test() {} + virtual void normal_test() {} + virtual void smoothing_test() {} + virtual void subdivision_test() {} + virtual void collapse_test() {} +}; + + +//============================================================================= +#endif +//=============================================================================