From e6647d375161c5348f54034e18a0d95602ab811a Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Wed, 13 Nov 2013 13:50:35 +0100 Subject: [PATCH] Add benchmarks for lcc. --- .../Linear_cell_complex_2/CMakeLists.txt | 73 + .../Linear_cell_complex_2/Stop_watch.h | 113 ++ .../benchmark/Linear_cell_complex_2/cgogn | 1 + .../cgogn_performance_2.cpp | 19 + .../cgogn_performance_2.h | 290 +++ .../cmake/FindCGAL.cmake | 95 + .../cmake/FindMesquite.cmake | 32 + .../cmake/FindOpenMesh.cmake | 40 + .../lcc_performance_2.cpp | 20 + .../Linear_cell_complex_2/lcc_performance_2.h | 382 ++++ .../benchmark/Linear_cell_complex_2/openmesh | 1 + .../openmesh_performance.cpp | 20 + .../openmesh_performance.h | 230 +++ .../Linear_cell_complex_2/performance_2.cpp | 47 + .../Linear_cell_complex_2/performance_2.h | 99 + .../polyhedron_performance.cpp | 20 + .../polyhedron_performance.h | 430 +++++ .../surface_mesh/CMakeLists.txt | 10 + .../Linear_cell_complex_2/surface_mesh/IO.cpp | 74 + .../Linear_cell_complex_2/surface_mesh/IO.h | 41 + .../surface_mesh/IO_off.cpp | 325 ++++ .../surface_mesh/Surface_mesh.cpp | 1461 +++++++++++++++ .../surface_mesh/Surface_mesh.h | 1605 +++++++++++++++++ .../surface_mesh/Vector.h | 692 +++++++ .../surface_mesh/properties.h | 413 +++++ .../surface_mesh/types.h | 33 + .../surface_mesh_performance.cpp | 20 + .../surface_mesh_performance.h | 259 +++ .../Linear_cell_complex_3/CMakeLists.txt | 48 + .../Linear_cell_complex_3/Stop_watch.h | 113 ++ .../benchmark/Linear_cell_complex_3/cgogn | 1 + .../cgogn_performance_3.cpp | 20 + .../cgogn_performance_3.h | 286 +++ .../cmake/ACGCommon.cmake | 578 ++++++ .../cmake/ACGCompiler.cmake | 151 ++ .../cmake/ACGDoxygen.cmake | 122 ++ .../cmake/ACGOutput.cmake | 38 + .../cmake/FindGoogleTest.cmake | 95 + .../cmake/fixbundle.cmake.in | 57 + .../cmake/fixbundle.cmake.win.in | 24 + .../lcc_performance_3.cpp | 20 + .../Linear_cell_complex_3/lcc_performance_3.h | 697 +++++++ .../Linear_cell_complex_3/openvolumemesh | 1 + .../openvolumemesh_performance.cpp | 20 + .../openvolumemesh_performance.h | 662 +++++++ .../Linear_cell_complex_3/performance_3.cpp | 38 + .../Linear_cell_complex_3/performance_3.h | 94 + Linear_cell_complex/benchmark/README.TXT | 57 + 48 files changed, 9967 insertions(+) create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/CMakeLists.txt create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/Stop_watch.h create mode 120000 Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn_performance_2.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn_performance_2.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindCGAL.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindMesquite.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindOpenMesh.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/lcc_performance_2.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/lcc_performance_2.h create mode 120000 Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh_performance.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh_performance.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/performance_2.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/performance_2.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/polyhedron_performance.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/polyhedron_performance.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/CMakeLists.txt create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO_off.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Surface_mesh.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Surface_mesh.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Vector.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/properties.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/types.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh_performance.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh_performance.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/CMakeLists.txt create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/Stop_watch.h create mode 120000 Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn_performance_3.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn_performance_3.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGCommon.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGCompiler.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGDoxygen.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGOutput.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/FindGoogleTest.cmake create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.in create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.win.in create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/lcc_performance_3.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/lcc_performance_3.h create mode 120000 Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh_performance.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh_performance.h create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/performance_3.cpp create mode 100644 Linear_cell_complex/benchmark/Linear_cell_complex_3/performance_3.h create mode 100644 Linear_cell_complex/benchmark/README.TXT diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/CMakeLists.txt b/Linear_cell_complex/benchmark/Linear_cell_complex_2/CMakeLists.txt new file mode 100644 index 00000000000..2d0b326423d --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/CMakeLists.txt @@ -0,0 +1,73 @@ +project(LCC_performance_2) + +cmake_minimum_required(VERSION 2.6.2) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/) + +add_subdirectory(surface_mesh) + +find_package(CGAL REQUIRED) +include(${CGAL_USE_FILE}) + +include_directories(BEFORE "../../include") +include_directories(BEFORE "./surface_mesh") +include_directories(BEFORE "./cgogn" "./cgogn/include") +LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/cgogn/lib/Release) +include_directories(BEFORE "/usr/include/libxml2/") + +# For profilling with gprof +#add_definitions("-pg") +#SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") +# add_definitions("-g") + +# OpenMesh +set(OPENMESH_DIR "${CMAKE_CURRENT_SOURCE_DIR}/openmesh") +find_package(OpenMesh REQUIRED) +include_directories(${OPENMESH_INCLUDE_DIR}) +link_directories(${OPENMESH_LIBRARY_DIR}) + +# Polyhedron +add_executable(polyhedron_performance performance_2.h polyhedron_performance.h polyhedron_performance.cpp) +target_link_libraries(polyhedron_performance ${CGAL_LIBRARIES}) + +# LCC_2 +add_executable(lcc_performance_2 performance_2.h lcc_performance_2.h lcc_performance_2.cpp) +target_link_libraries(lcc_performance_2 ${CGAL_LIBRARIES}) + +# Surface_mesh +add_executable(surface_mesh_performance performance_2.h surface_mesh_performance.h surface_mesh_performance.cpp) +target_link_libraries(surface_mesh_performance surface_mesh) + +# Open_mesh +add_executable(openmesh_performance performance_2.h openmesh_performance.h openmesh_performance.cpp) +target_link_libraries(openmesh_performance ${OPENMESH_LIBRARIES}) + +# CGoGN +find_package(Qt REQUIRED) +SET(QT_USE_QTSVG TRUE) +SET(QT_USE_QTXML TRUE ) +INCLUDE(${QT_USE_FILE}) +ADD_DEFINITIONS(${QT_DEFINITIONS}) +SET (CGoGN_EXT_INCLUDES ${CGoGN_EXT_INCLUDES} ${QT_INCLUDE_DIR} ${QGLVIEWER_INCLUDE_DIR} ) +SET (CGoGN_EXT_LIBS ${CGoGN_EXT_LIBS} ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + +add_executable(cgogn_performance_2 performance_2.h cgogn_performance_2.h cgogn_performance_2.cpp) +target_link_libraries(cgogn_performance_2 algo assimp container nl topology utils Zinri z ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + +# Performance_2 +add_executable(performance_2 + performance_2.cpp + performance_2.h + polyhedron_performance.h + openmesh_performance.h + surface_mesh_performance.h + cgogn_performance_2.h + lcc_performance_2.h +) + +target_link_libraries(performance_2 + ${CGAL_LIBRARIES} + surface_mesh + algo assimp container nl topology utils Zinri z ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} + ${OPENMESH_LIBRARIES} +) diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/Stop_watch.h b/Linear_cell_complex/benchmark/Linear_cell_complex_2/Stop_watch.h new file mode 100644 index 00000000000..b19e57773c6 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/Stop_watch.h @@ -0,0 +1,113 @@ +//============================================================================= + +#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_2/cgogn b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn new file mode 120000 index 00000000000..e1dd39d4a84 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn @@ -0,0 +1 @@ +/home/gdamiand/sources/codes-autres/CGoGN/install \ No newline at end of file diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn_performance_2.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn_performance_2.cpp new file mode 100644 index 00000000000..f4e1b9d9ab3 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cgogn_performance_2.cpp @@ -0,0 +1,19 @@ +//== INCLUDES ================================================================= +#include "cgogn_performance_2.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i + +#include "Topology/generic/genericmap.h" +#include "Topology/generic/parameters.h" +#include "Topology/map/embeddedMap2.h" +#include "Topology/generic/traversor2.h" +#include "Topology/generic/traversorCell.h" +#include "Topology/generic/cellmarker.h" + +#include "Geometry/vector_gen.h" + +#include "Algo/Import/import.h" +#include "Algo/Export/export.h" + +#include "Algo/Modelisation/subdivision.h" + + +//== CLASS DEFINITION ========================================================= + +using namespace CGoGN ; + +struct PFP: public PFP_STANDARD +{ + // definition of the map + typedef EmbeddedMap2 MAP; +}; + + +class CGoGN_performance_2 : public Performance_test_2 +{ + +private: + PFP::MAP myMap; + VertexAttribute position; + VertexAttribute normalF; + VertexAttribute normalV; + + unsigned int nbv; + + void display_info() + { + std::cout << "#Darts=" << myMap.getNbDarts(); + std::cout << ", #0-cells=" << myMap.getNbOrbits(); + std::cout << ", #1-cells=" << myMap.getNbOrbits(); + std::cout << ", #2-cells=" << myMap.getNbOrbits(); + std::cout << "\t" << std::endl; + } + +public: + + CGoGN_performance_2() : Performance_test_2() + { + normalF = myMap.addAttribute("normalsF"); + normalV = myMap.addAttribute("normalsV"); + } + +private: + virtual bool read_mesh(const char* _filename) + { + std::vector attrNames ; + if(!Algo::Surface::Import::importMesh(myMap, _filename, attrNames)) + return false; + + position = myMap.getAttribute(attrNames[0]); + + myMap.enableQuickTraversal(); + myMap.enableQuickTraversal(); + + /*myMap.enableQuickLocalIncidentTraversal(myMap); + myMap.enableQuickLocalIncidentTraversal(myMap); + myMap.enableQuickLocalAdjacentTraversal(myMap); + */ + nbv = position.nbElements(); + + return true; + } + + virtual bool write_mesh(const char* _filename) + { + return Algo::Surface::Export::exportOFF(myMap, position, _filename); + } + + virtual int circulator_test() + { + int counter = 0; + + TraversorV tv(myMap); + for(Dart dit = tv.begin(); dit != tv.end(); dit = tv.next()) + { + Traversor2VF trav(myMap, dit); + for(Dart ditF = trav.begin(); ditF != trav.end(); ditF = trav.next()) + ++counter; + } + + TraversorF tf(myMap); + for(Dart dit = tf.begin(); dit != tf.end(); dit = tf.next()) + { + Traversor2FV trav(myMap, dit); + for(Dart ditV = trav.begin(); ditV != trav.end(); ditV = trav.next()) + --counter; + } + + return counter; + } + + virtual void barycenter_test(bool draw) + { + PFP::VEC3 p(0.0,0.0,0.0); + + unsigned int size = position.end(); + unsigned int count = 0; + for(unsigned int i = position.begin(); i != size; position.next(i)) + { + p += position[i]; + ++count; + } + p /= PFP::REAL(count); + + for(unsigned int i = position.begin(); i != size; position.next(i)) + position[i] -= p; + + if ( draw ) std::cout<<"Barycenter: "< tf(myMap); + for(Dart dit = tf.begin(); dit != tf.end(); dit = tf.next()) + { + const typename PFP::VEC3& p1 = position[dit]; + const typename PFP::VEC3& p2 = position[myMap.phi1(dit)]; + const typename PFP::VEC3& p3 = position[myMap.phi_1(dit)]; + normalF[dit] = ((p2 - p1) ^ (p3 - p1)).normalize(); + } + + TraversorV tv(myMap); + for(Dart dit = tv.begin(); dit != tv.end(); dit = tv.next()) + { + typename PFP::VEC3 n(0.0); + + Traversor2VF trav(myMap, dit); + for(Dart ditF = trav.begin(); ditF != trav.end(); ditF = trav.next()) + n += normalF[ditF]; + + normalV[dit] = n.normalize(); + } + } + + virtual void smoothing_test() + { + TraversorV tv(myMap); + for(Dart dit = tv.begin(); dit != tv.end(); dit = tv.next()) + { + typename PFP::VEC3 p(0.0,0.0,0.0); + unsigned int c = 0; + + Traversor2VVaE trav2VVaE(myMap, dit); + for(Dart ditVV = trav2VVaE.begin() ; ditVV != trav2VVaE.end() ; ditVV = trav2VVaE.next()) + { + p += position[ditVV]; + ++c; + } + p /= PFP::REAL(c); + position[dit] = p; + } + } + + virtual void subdivision_test() + { + VertexAutoAttribute new_position(myMap); + + //compute new positions of old vertices + TraversorV tv(myMap); + for(Dart d = tv.begin(); d != tv.end(); d = tv.next()) + { + unsigned int n = 0; + typename PFP::VEC3 p(0.0,0.0,0.0); + Traversor2VVaE trav2VVaE(myMap, d); + for(Dart ditVV = trav2VVaE.begin() ; ditVV != trav2VVaE.end() ; ditVV = trav2VVaE.next()) + { + p += position[ditVV]; + ++n; + } + typename PFP::REAL alpha = (4.0 - 2.0*cos(2.0*M_PI/PFP::REAL(n))) / 9.0; + + new_position[d] = (1.0f-alpha)*position[d] + alpha/PFP::REAL(n)*p; + } + + Dart last = myMap.end(); + + //split faces + + AttributeHandler qtF(&myMap, myMap.getQuickTraversal()); + unsigned int nbf = qtF.nbElements(); + + for(unsigned int i = qtF.begin(); i != nbf; ++i) + { + Dart d = qtF[i]; + + unsigned int c = 0; + typename PFP::VEC3 p(0.0,0.0,0.0); + + //triangule face + Traversor2FV trav(myMap, d); + for(Dart ditV = trav.begin(); ditV != trav.end(); ditV = trav.next()) + { + p += position[ditV]; + ++c; + } + + p /= PFP::REAL(c); + Dart cd = Algo::Surface::Modelisation::trianguleFace(myMap, d); + + new_position[cd] = p; + } + + myMap.swapAttributes(position, new_position); + + // flip old edges + for(Dart d = myMap.begin(); d != last; myMap.next(d)) + { + if(d < myMap.phi2(d)) + myMap.flipEdge(d); + } + } + + virtual void collapse_test() + { + myMap.updateQuickTraversal(); + + //split faces + DartMarkerNoUnmark me(myMap); + + typename PFP::VEC3 p(0,0,0); + + AttributeHandler qtF(&myMap, myMap.getQuickTraversal()); + unsigned int nbf = qtF.end(); + + for(unsigned int i = qtF.begin(); i != nbf; ++i) + { + Dart d = qtF[i]; + Dart cd = Algo::Surface::Modelisation::trianguleFace(myMap, d); + position[cd] = p; + me.markOrbit(cd); + } + + myMap.disableQuickTraversal(); + + TraversorV travV(myMap); + for(Dart d = travV.begin() ; d != travV.end() ; d = travV.next()) + { + if(me.isMarked(d)) + myMap.deleteVertex(d); + } + } + + virtual void remesh_test() + { + unsigned int nbOps = 1000; + + TraversorF travF(myMap); + for(Dart d = travF.begin(); d != travF.end(); d = travF.next()) + { + Dart cd = Algo::Surface::Modelisation::trianguleFace(myMap, d); + --nbOps; + if(nbOps == 0) + break; + } + + nbOps = 1000; + + TraversorE travE(myMap); + for(Dart d = travE.begin(); d != travE.end(); d = travE.next()) + { + if(myMap.edgeCanCollapse(d)) + { + myMap.collapseEdge(d); + --nbOps; + } + if(nbOps == 0) + break; + } + } + +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindCGAL.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindCGAL.cmake new file mode 100644 index 00000000000..76c6272cabe --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindCGAL.cmake @@ -0,0 +1,95 @@ +# +# The following module is based on FindVTK.cmake +# + +# - Find a CGAL installation or binary tree. +# The following variables are set if CGAL is found. If CGAL is not +# found, CGAL_FOUND is set to false. +# +# CGAL_FOUND - Set to true when CGAL is found. +# CGAL_USE_FILE - CMake file to use CGAL. +# + +# Construct consitent error messages for use below. +set(CGAL_DIR_DESCRIPTION "directory containing CGALConfig.cmake. This is either the binary directory where CGAL was configured or PREFIX/lib/CGAL for an installation.") +set(CGAL_DIR_MESSAGE "CGAL not found. Set the CGAL_DIR cmake variable or environment variable to the ${CGAL_DIR_DESCRIPTION}") + +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) + +if ( NOT CGAL_DIR ) + + # Get the system search path as a list. + if(UNIX) + string(REGEX MATCHALL "[^:]+" CGAL_DIR_SEARCH1 "$ENV{PATH}") + else() + string(REGEX REPLACE "\\\\" "/" CGAL_DIR_SEARCH1 "$ENV{PATH}") + endif() + + string(REGEX REPLACE "/;" ";" CGAL_DIR_SEARCH2 "${CGAL_DIR_SEARCH1}") + + # Construct a set of paths relative to the system search path. + set(CGAL_DIR_SEARCH "") + + foreach(dir ${CGAL_DIR_SEARCH2}) + + set(CGAL_DIR_SEARCH ${CGAL_DIR_SEARCH} ${dir}/../lib/CGAL ) + + endforeach() + + + # + # Look for an installation or build tree. + # + find_path(CGAL_DIR CGALConfig.cmake + + # Look for an environment variable CGAL_DIR. + $ENV{CGAL_DIR} + + # Look in places relative to the system executable search path. + ${CGAL_DIR_SEARCH} + + # Look in standard UNIX install locations. + /usr/local/lib/CGAL + /usr/lib/CGAL + + # Read from the CMakeSetup registry entries. It is likely that + # CGAL will have been recently built. + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild1] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild2] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild3] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild4] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild5] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild6] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild7] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild8] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild9] + [HKEY_CURRENT_USER\\Software\\Kitware\\CMakeSetup\\Settings\\StartPath;WhereBuild10] + + # Help the user find it if we cannot. + DOC "The ${CGAL_DIR_DESCRIPTION}" + ) + +endif() + +if ( CGAL_DIR ) + + if ( EXISTS "${CGAL_DIR}/CGALConfig.cmake" ) + include( "${CGAL_DIR}/CGALConfig.cmake" ) + set( CGAL_FOUND TRUE ) + endif() + +endif() + +if( NOT CGAL_FOUND) + if(CGAL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR ${CGAL_DIR_MESSAGE}) + else() + if(NOT CGAL_FIND_QUIETLY) + MESSAGE(STATUS ${CGAL_DIR_MESSAGE}) + endif() + endif() +endif() + +if(CGAL_FOUND) + message(STATUS "Found CGAL.") +endif() diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindMesquite.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindMesquite.cmake new file mode 100644 index 00000000000..fde7245f7cd --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindMesquite.cmake @@ -0,0 +1,32 @@ +# Find Mesquite. If found, this will define +# +# MESQUITE_FOUND - Successfully found Mesquite +# MESQUITE_INCLUDE_DIR - Mesquite include directory +# MESQUITE_LIBRARY_DIR - Mesquite library directory +# MESQUITE_LIBRARIES - Mesquite libraries +# + +if(DEFINED MESQUITE_INCLUDE_DIR) + set(MESQUITE_FIND_QUIETLY TRUE) +else() + + find_path(MESQUITE_INCLUDE_DIR Mesquite_all_headers.hpp + PATHS + /usr/local/include + /usr/include + $ENV{MESQUITE_DIR}/include + ${MESQUITE_DIR}/include + ) + + if(NOT ${MESQUITE_INCLUDE_DIR} STREQUAL "MESQUITE_INCLUDE_DIR-NOTFOUND") + + message(STATUS "Found Mesquite: " ${MESQUITE_INCLUDE_DIR}) + set(MESQUITE_FOUND true) + + set(MESQUITE_LIBRARY_DIR "${MESQUITE_INCLUDE_DIR}/../lib/" CACHE PATH "Mesquite library directory") + set(MESQUITE_LIBRARIES "mesquite" CACHE STRING "Mesquite libraries") + + else() + set(MESQUITE_FOUND FALSE) + endif() +endif() diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindOpenMesh.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindOpenMesh.cmake new file mode 100644 index 00000000000..98aefc13d23 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/cmake/FindOpenMesh.cmake @@ -0,0 +1,40 @@ +# Find OpenMesh. If found, this will define +# +# OPENMESH_FOUND - Successfully found OpenMesh +# OPENMESH_INCLUDE_DIR - OpenMesh include directory +# OPENMESH_LIBRARIES - OpenMesh libraries +# OPENMESH_LIBRARY_DIR - OpenMesh library directory +# + +if(DEFINED OPENMESH_INCLUDE_DIR) + set(OPENMESH_FIND_QUIETLY TRUE) +else() + + find_path(OPENMESH_INCLUDE_DIR OpenMesh/Core/Mesh/PolyMeshT.hh + PATHS + /usr/local/include + /usr/include + $ENV{OPENMESH_DIR}/include + ${OPENMESH_DIR}/include + ) + + if(DEFINED OPENMESH_INCLUDE_DIR) + + message(STATUS "Found OpenMesh: " ${OPENMESH_INCLUDE_DIR}) + set(OPENMESH_FOUND true) + + if(WIN32) + set(OPENMESH_LIBRARY_DIR "${OPENMESH_INCLUDE_DIR}/../lib" + CACHE PATH "OpenMesh library directory") + else() + set(OPENMESH_LIBRARY_DIR "${OPENMESH_INCLUDE_DIR}/../lib/OpenMesh" + CACHE PATH "OpenMesh library directory") + endif() + + set(OPENMESH_LIBRARIES "OpenMeshCore;OpenMeshTools" + CACHE STRING "OpenMesh libraries") + + else() + set(OPENMESH_FOUND FALSE) + endif() +endif() diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/lcc_performance_2.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/lcc_performance_2.cpp new file mode 100644 index 00000000000..8fe9352ef27 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/lcc_performance_2.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "lcc_performance_2.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i +#include +#include +#include +#include +#include "performance_2.h" + +// Comment to use cmap with handle +#define CMAP_WITH_INDEX 1 + +//== CLASS DEFINITION ========================================================= + +typedef CGAL::Simple_cartesian MyKernelLCC; +typedef MyKernelLCC::Point_3 LCCPoint_3; +typedef MyKernelLCC::Vector_3 LCCVector_3; + +typedef CGAL::Linear_cell_complex_traits<3, MyKernelLCC> MyTraitsLCC; + +#ifndef CMAP_WITH_INDEX + +class MyItemsLCC +{ +public: + + template + struct Dart_wrapper + { + typedef CGAL::Dart<2, LCC> Dart; // Dim 2 == Polyhedron + + typedef CGAL::Cell_attribute_with_point Vertex; + typedef CGAL::Cell_attribute Face; + typedef CGAL::cpp0x::tuple Attributes; + }; +}; + +typedef CGAL::Linear_cell_complex<2, 3, MyTraitsLCC, MyItemsLCC> LCC; + +#else + +class MyItemsLCCWithIndex +{ +public: + + template + struct Dart_wrapper + { + typedef CGAL::Dart_for_index<2, LCC> Dart; // Dim 2 == Polyhedron + + typedef CGAL::Cell_attribute_for_index_with_point Vertex; + typedef CGAL::Cell_attribute_for_index Face; + typedef CGAL::cpp0x::tuple Attributes; + }; +}; +typedef CGAL::Linear_cell_complex_for_index<2, 3, MyTraitsLCC, MyItemsLCCWithIndex> LCC; + +#endif + +//== CLASS DEFINITION ========================================================= + +class LCC_performance_2 : public Performance_test_2 +{ + +private: + + LCC lcc; + +private: + void display_info() + { + lcc.display_characteristics(std::cout); + std::cout << "\t" << std::endl; + } + + virtual bool read_mesh(const char* _filename) + { + std::ifstream ifs(_filename); + CGAL::load_off(lcc, ifs); + + for ( LCC::Dart_range::iterator dit=lcc.darts().begin(), + dend=lcc.darts().end(); dit!=dend; ++dit ) + { + if ( lcc.attribute<2>(dit)==NULL ) + lcc.set_attribute<2>(dit, lcc.create_attribute<2>()); + } + assert( lcc.is_valid()); + 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(bool draw) + { + LCC::Vertex_attribute_range::iterator vit, vend = lcc.vertex_attributes().end(); + LCCVector_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; + } + + if ( draw ) std::cout<<"Barycenter: "<::type::iterator fit, fend = lcc.attributes<2>().end(); + + for (fit = lcc.attributes<2>().begin(); fit != fend; ++fit) + { + LCC::Dart_handle dh = fit->dart(); + LCCPoint_3& p0 = lcc.point(dh); + dh = lcc.beta<1>(dh); + LCCPoint_3& p1 = lcc.point(dh); + dh = lcc.beta<1>(dh); + LCCPoint_3& p2 = lcc.point(dh); + LCCVector_3 n = cross_product(p0-p1, p2-p1); + n = n / sqrt(n.squared_length()); + fit->info() = n; + } + + for (vit = lcc.vertex_attributes().begin(); vit != vend; ++vit) + { + LCCVector_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 + lcc.info<2>(vhit); + } + n = n / sqrt(n.squared_length()); + vit->info() = n; + } + } + + 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; + LCCVector_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 (lcc.is_free<2>(vhit)) + { + vertex_is_border = true; + break; + } + + v = v + (lcc.point(lcc.other_extremity(vhit)) - CGAL::ORIGIN); + ++c; + } + if (!vertex_is_border) + vit->point() = CGAL::ORIGIN + (v / c); + } + assert( lcc.is_valid()); + } + + void flip_edge(LCC::Dart_handle d) + { + LCC::Dart_handle d1 = lcc.beta<1>(d); + LCC::Dart_handle d2 = lcc.beta<2, 1>(d); + + CGAL_assertion ( !lcc.is_free<1>(d1) && !lcc.is_free<1>(d2) ); + + LCC::Dart_handle d3 = lcc.beta<1>(d1); + LCC::Dart_handle d4 = lcc.beta<1>(d2); + + // We isolated the edge + lcc.link_beta_1(lcc.beta<0>(d), d2); + lcc.link_beta_1(lcc.beta<2,0>(d), d1); + + // Then we push the two extremities. + lcc.basic_link_beta_0(d3, d); + lcc.basic_link_beta_1(d1, lcc.beta<2>(d)); + lcc.basic_link_beta_1(d2, d); + lcc.basic_link_beta_0(d4, lcc.beta<2>(d)); + + // And we update the vertex attribute + lcc.set_vertex_attribute_of_dart(d, lcc.vertex_attribute(d4)); + lcc.set_vertex_attribute_of_dart(lcc.beta<2>(d), lcc.vertex_attribute(d3)); + } + + virtual void subdivision_test() + { + int nv = lcc.number_of_vertex_attributes(); + + // 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 vertex_is_border = false; + LCCVector_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 (lcc.is_free<2>(vhit)) + { + vertex_is_border = true; + break; + } + + v = v + (lcc.point(lcc.other_extremity(vhit)) - CGAL::ORIGIN); + ++n; + } + if (!vertex_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 + { + lcc.insert_barycenter_in_cell<2>(fit->dart()); + } + 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 (!lcc.is_free<2>(dit) && dit(dit) ) + flip_edge(dit); + } + + assert( lcc.is_valid()); + } + + virtual void collapse_test() + { + LCC::Attribute_range<0>::type::iterator vit, vend = lcc.attributes<0>().end(); + LCC::Attribute_range<2>::type::iterator fit, fend = lcc.attributes<2>().end(); + + // adjust end iterators + --vend; --fend; + + fit = lcc.attributes<2>().begin(); + do + { + lcc.insert_point_in_cell<2>(fit->dart(), CGAL::ORIGIN); + } + while (fit++ != fend); + + // adjust end iterators + ++vend; + + // collapse new vertices + vit=vend; vend=lcc.attributes<0>().end(); + for (; vit!=vend; ) + { + LCC::Dart_handle cur = vit->dart(); + ++vit; + collapse_edge(cur); + } + assert( lcc.is_valid()); + } + + void contract_face(LCC::Dart_handle dh) + { + CGAL_assertion( dh!=lcc.null_dart_handle ); + LCC::Dart_handle d1=lcc.beta<2>(dh); + LCC::Dart_handle d2=lcc.beta<1,2>(dh); + CGAL_assertion(d1!=lcc.null_dart_handle && + d2!=lcc.null_dart_handle); + + lcc.basic_link_beta<2>(d1, d2); + lcc.set_dart_of_attribute<0>(lcc.vertex_attribute(d1), d1); + lcc.set_dart_of_attribute<0>(lcc.vertex_attribute(d2), d2); + + lcc.erase_dart(lcc.beta<1>(dh)); + lcc.erase_dart(dh); + } + + void collapse_edge(LCC::Dart_handle dh) + { + CGAL_assertion( dh!=lcc.null_dart_handle ); + CGAL_assertion(!lcc.is_free<2>(dh)); + + LCC::Dart_handle h1=lcc.beta<0>(dh); + LCC::Dart_handle o1=lcc.beta<2,1>(dh); + + lcc.set_attribute<0>(dh, lcc.attribute<0>(lcc.beta<2>(dh))); + + lcc.basic_link_beta_1(lcc.beta<2,0>(dh),lcc.beta<2,1>(dh)); + lcc.basic_link_beta_1(lcc.beta<0>(dh),lcc.beta<1>(dh)); + + lcc.erase_dart(lcc.beta<2>(dh)); + lcc.erase_dart(dh); + + if (lcc.beta<1,1>(h1)==h1) + { + contract_face(h1); + } + + if (lcc.beta<1,1>(o1)==o1) + { + contract_face(o1); + } + } +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh b/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh new file mode 120000 index 00000000000..d05a341324b --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh @@ -0,0 +1 @@ +/home/gdamiand/sources/codes-autres/OpenMesh/builds/install/ \ No newline at end of file diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh_performance.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh_performance.cpp new file mode 100644 index 00000000000..afbec7a5f0b --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/openmesh_performance.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "openmesh_performance.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i Mesh; + Mesh mesh; + + +private: + void display_info() + { + std::cout << "#Darts=" << mesh.n_halfedges(); + std::cout << ", #0-cells=" << mesh.n_vertices(); + std::cout << ", #1-cells=" << mesh.n_edges(); + std::cout << ", #2-cells=" << mesh.n_faces(); + std::cout << "\t" << std::endl; + + } + + + virtual bool read_mesh(const char* _filename) + { + return OpenMesh::IO::read_mesh(mesh, _filename); + } + + + virtual bool write_mesh(const char* _filename) + { + return OpenMesh::IO::write_mesh(mesh, _filename); + } + + virtual int circulator_test() + { + Mesh::VIter vit, vend=mesh.vertices_end(); + Mesh::FIter fit, fend=mesh.faces_end(); + int counter = 0; + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + for (Mesh::VFIter vfit=mesh.vf_iter(vit); vfit; ++vfit) + ++counter; + + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + for (Mesh::FVIter fvit=mesh.fv_iter(fit); fvit; ++fvit) + --counter; + + return counter; + } + + virtual void barycenter_test(bool draw) + { + Mesh::VIter vit, vend=mesh.vertices_end(); + Mesh::Point p(0,0,0); + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + p += mesh.point(vit); + + p /= mesh.n_vertices(); + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + mesh.point(vit) -= p; + + if ( draw ) std::cout<<"Barycenter: "< new_pos; + mesh.add_property(new_pos); + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + { + if (!mesh.is_boundary(vit)) + { + Mesh::Scalar n = mesh.valence(vit); + Mesh::Scalar alpha = (4.0 - 2.0*cos(2.0*M_PI/n)) / 9.0; + Mesh::Point p(0,0,0); + for (Mesh::VVIter vvit = mesh.vv_iter(vit); vvit; ++vvit) + p += mesh.point(vvit); + p = (1.0f-alpha)*mesh.point(vit) + alpha/n*p; + mesh.property(new_pos, vit) = p; + } + } + + // split faces + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + { + Mesh::Point p(0,0,0); + Mesh::Scalar c(0); + for (Mesh::FVIter fvit=mesh.fv_iter(fit); fvit; ++fvit) + { + p += mesh.point(fvit); + ++c; + } + p /= c; + + mesh.split(fit, p); + } + + // set new positions of old vertices + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + if (!mesh.is_boundary(vit)) + mesh.point(vit) = mesh.property(new_pos, vit); + mesh.remove_property(new_pos); + + + // flip old edges + for (eit=mesh.edges_begin(); eit!=eend; ++eit) + if (mesh.is_flip_ok(eit)) + mesh.flip(eit); + } + + virtual void collapse_test() + { + // reserve memory + int nv = mesh.n_vertices(); + int ne = mesh.n_edges(); + int nf = mesh.n_faces(); + mesh.reserve(nv+nf, ne+3*nf, 3*nf); + + // iterators + Mesh::VIter vit, vend=mesh.vertices_end(); + Mesh::FIter fit, fend=mesh.faces_end(); + + // split faces + Mesh::Point p(0,0,0); + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + mesh.split(fit, p); + + // collapse new edges + vit = vend; vend=mesh.vertices_end(); + for (; vit!=vend; ++vit) + mesh.collapse(mesh.halfedge_handle(vit)); + + // remove deleted items + mesh.garbage_collection(); + } + + virtual void remesh_test() + { + + } +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/performance_2.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/performance_2.cpp new file mode 100644 index 00000000000..a6598ab922d --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/performance_2.cpp @@ -0,0 +1,47 @@ +//== INCLUDES ================================================================= +#include "polyhedron_performance.h" +#include "lcc_performance_2.h" +#include "openmesh_performance.h" +#include "surface_mesh_performance.h" +#include "cgogn_performance_2.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\nperformance \n"; + exit(1); + } + + for (int i=1; i +#include +#include +#include + +#include "Stop_watch.h" + + +//== CLASS DEFINITION ========================================================= + + +class Performance_test_2 +{ +public: + + Performance_test_2() {} + + 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; + display_info(); + + timer.start(); + int c; + for (int i=0; i<100; ++i) + c = circulator_test(); + timer.stop(); + CGAL_assertion(c==0); + std::cout << "Circulator: "<\n"; + exit(1); + } + + for (int i=1; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "performance_2.h" + + +//== CLASS DEFINITION ========================================================= + + +//***************************************************************************** +// control whether Polyhedron stores vertex and face normals +#define HAS_NORMALS 1 +//***************************************************************************** + + +typedef CGAL::Simple_cartesian CGALKernel; +typedef CGALKernel::Point_3 Point_3; +typedef CGAL::Vector_3 Vector_3; + + +template +struct MyVertex : public CGAL::HalfedgeDS_vertex_base +{ + typedef CGAL::HalfedgeDS_vertex_base Base; + MyVertex() : Base() {} + MyVertex(const Point_3& p) : Base(p) {} + Vector_3 normal; +}; + + +template +struct MyFace : public CGAL::HalfedgeDS_face_base +{ + Vector_3 normal; +}; + + +class MyItems +{ +public: + + template + struct Vertex_wrapper + { + typedef typename Traits::Point_3 Point; +#if HAS_NORMALS + typedef MyVertex Vertex; +#else + typedef CGAL::HalfedgeDS_vertex_base Vertex; +#endif + }; + + template + struct Halfedge_wrapper + { + typedef CGAL::HalfedgeDS_halfedge_base Halfedge; + }; + + template + struct Face_wrapper + { +#if HAS_NORMALS + typedef MyFace Face; +#else + typedef CGAL::HalfedgeDS_face_base Face; +#endif + }; +}; + +typedef CGAL::Polyhedron_3 Polyhedron; + + + + +//== CLASS DEFINITION ========================================================= + + +class Polyhedron_performance : public Performance_test_2 +{ + +private: + + Polyhedron P; + +private: + virtual void display_info() + { + std::cout<<"#darts: "<> P; + return true; + } + + + virtual bool write_mesh(const char* _filename) + { + std::ofstream ofs(_filename); + ofs << P; + return true; + } + + + virtual int circulator_test() + { + Polyhedron::Vertex_iterator vit, vend=P.vertices_end(); + Polyhedron::Face_iterator fit, fend=P.facets_end(); + + Polyhedron::Halfedge_around_vertex_circulator vhit, vhend; + Polyhedron::Halfedge_around_facet_circulator fhit, fhend; + + int counter = 0; + + for (vit = P.vertices_begin(); vit != vend; ++vit) + { + vhit = vhend = vit->vertex_begin(); + do + { + if (!vhit->is_border()) + ++counter; + } + while (++vhit != vhend); + } + + for (fit = P.facets_begin(); fit != fend; ++fit) + { + fhit = fhend = fit->facet_begin(); + do + { + --counter; + } + while (++fhit != fhend); + } + + return counter; + } + + + virtual void barycenter_test(bool draw) + { + Polyhedron::Vertex_iterator vit, vend=P.vertices_end(); + Vector_3 v(CGAL::NULL_VECTOR); + for (vit = P.vertices_begin(); vit != vend; ++vit) + { + v = v + (vit->point() - CGAL::ORIGIN); + } + v = v / P.size_of_vertices(); + for (vit = P.vertices_begin(); vit != vend; ++vit) + { + vit->point() = vit->point() - v; + } + if (draw) std::cout<<"Barycenter="<halfedge(); + Point_3& p0 = h->vertex()->point(); + h = h->next(); + Point_3& p1 = h->vertex()->point(); + h = h->next(); + Point_3& p2 = h->vertex()->point(); + Vector_3 n = cross_product(p0-p1, p2-p1); + n = n / sqrt(n.squared_length()); + fit->normal = n; + } + + for (vit=P.vertices_begin(); vit!=vend; ++vit) + { + Vector_3 n(0,0,0); + vhit = vhend = vit->vertex_begin(); + do + { + if (!vhit->is_border()) + n = n + vhit->face()->normal; + } + while (++vhit != vhend); + n = n / sqrt(n.squared_length()); + vit->normal = n; + } +#endif + } + + + virtual void smoothing_test() + { + Polyhedron::Vertex_iterator vit, vend=P.vertices_end(); + + for (vit = P.vertices_begin(); vit != vend; ++vit) + { + bool vertex_is_border = false; + Vector_3 v(0,0,0); + float c(0); + + Polyhedron::Halfedge_around_vertex_circulator hc = vit->vertex_begin(); + do + { + if (hc->is_border() || hc->opposite()->is_border()) + { + vertex_is_border = true; + break; + } + + v = v + (hc->opposite()->vertex()->point() - CGAL::ORIGIN); + ++c; + } + while (++hc != vit->vertex_begin()); + + if (!vertex_is_border) + vit->point() = CGAL::ORIGIN + (v / c); + } + } + + + virtual void subdivision_test() + { + 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(); + Polyhedron::Edge_iterator eit, eend = P.edges_end(); + + + // compute new positions of old vertices + int i; + std::vector new_pos(nv); + for (vit=P.vertices_begin(), i=0; vit!=vend; ++vit, ++i) + { + bool is_border = false; + Vector_3 v(0,0,0); + float n = CGAL::circulator_size(vit->vertex_begin()); + float alpha = (4.0 - 2.0*cos(2.0*M_PI/n)) / 9.0; + + Polyhedron::Halfedge_around_vertex_circulator hc = vit->vertex_begin(); + do + { + if (hc->is_border() || hc->opposite()->is_border()) + { + is_border = true; + break; + } + + v = v + (hc->opposite()->vertex()->point() - CGAL::ORIGIN); + } + while (++hc != vit->vertex_begin()); + + v = (1.0f-alpha)*(vit->point() - CGAL::ORIGIN) + alpha/n*v; + + new_pos[i] = (is_border ? vit->point() : CGAL::ORIGIN + v); + } + + + // adjust end iterators + --vend; --eend; --fend; + + + // split faces (a for loop does not work for list-kernel!) + fit = P.facets_begin(); + do + { + Vector_3 v(CGAL::NULL_VECTOR); + float c(0); + + Polyhedron::Halfedge_around_facet_circulator hc = fit->facet_begin(); + Polyhedron::Halfedge_around_facet_circulator hc_end(hc); + do + { + v = v + (hc->vertex()->point() - CGAL::ORIGIN); + ++c; + } + while (++hc != hc_end); + v = v / c; + + Polyhedron::Halfedge_handle h = P.create_center_vertex(fit->halfedge()); + h->vertex()->point() = CGAL::ORIGIN + v; + } + while (fit++ != fend); + + + // adjust end iterators + ++vend; ++eend; ++fend; + + + // set new positions of old vertices + for (vit=P.vertices_begin(), i=0; vit!=vend; ++vit, ++i) + vit->point() = new_pos[i]; + + + // flip old edges + for (eit = P.edges_begin(); eit!=eend; ++eit) + { + // careful: eit->is_border() does not work + Polyhedron::Halfedge_handle h = eit; + if (!(h->is_border() || h->opposite()->is_border())) + P.flip_edge(h); + } + } + + + + 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(Polyhedron::Halfedge_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_2/surface_mesh/CMakeLists.txt b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/CMakeLists.txt new file mode 100644 index 00000000000..9c7a8ad46a4 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(${CMAKE_SOURCE_DIR}/src/) + +file(GLOB_RECURSE SRCS ./*.cpp) +file(GLOB_RECURSE HDRS ./*.h) + +if(UNIX) + add_library(surface_mesh SHARED ${SRCS} ${HDRS}) +elseif(WIN32) + add_library(surface_mesh STATIC ${SRCS} ${HDRS}) +endif() diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.cpp new file mode 100644 index 00000000000..d0ca351a1e0 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.cpp @@ -0,0 +1,74 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +//== INCLUDES ================================================================= + +#include "IO.h" + + +//== IMPLEMENTATION =========================================================== + + +bool read_mesh(Surface_mesh& mesh, const std::string& filename) +{ + // clear mesh before reading from file + mesh.clear(); + + // extract file extension + std::string::size_type dot(filename.rfind(".")); + if (dot == std::string::npos) return false; + std::string ext = filename.substr(dot+1, filename.length()-dot-1); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + + // extension determines reader + if (ext == "off") + { + return read_off(mesh, filename); + } + + // we didn't find a reader module + return false; +} + + +//----------------------------------------------------------------------------- + + +bool write_mesh(const Surface_mesh& mesh, const std::string& filename) +{ + // extract file extension + std::string::size_type dot(filename.rfind(".")); + if (dot == std::string::npos) return false; + std::string ext = filename.substr(dot+1, filename.length()-dot-1); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + + + // extension determines reader + if (ext == "off") + { + return write_off(mesh, filename); + } + + + // we didn't find a writer module + return false; +} + + +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.h b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.h new file mode 100644 index 00000000000..cf71ba2a6c5 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO.h @@ -0,0 +1,41 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +#ifndef SURFACE_MESH_IO_H +#define SURFACE_MESH_IO_H + + +//== INCLUDES ================================================================= + +#include +#include "Surface_mesh.h" + +//============================================================================= + + +bool read_mesh(Surface_mesh& mesh, const std::string& filename); +bool read_off(Surface_mesh& mesh, const std::string& filename); + +bool write_mesh(const Surface_mesh& mesh, const std::string& filename); +bool write_off(const Surface_mesh& mesh, const std::string& filename); + + +//============================================================================= +#endif // SURFACE_MESH_IO_H +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO_off.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO_off.cpp new file mode 100644 index 00000000000..70a1825833d --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/IO_off.cpp @@ -0,0 +1,325 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +//== INCLUDES ================================================================= + +#include "IO.h" +#include + + +//== IMPLEMENTATION =========================================================== + + +// helper function +template void read(FILE* in, T& t) +{ + int err = 0; + err = fread(&t, 1, sizeof(t), in); +} + + +//----------------------------------------------------------------------------- + + +bool read_off_ascii(Surface_mesh& mesh, + FILE* in, + const bool has_normals, + const bool has_texcoords, + const bool has_colors) +{ + char line[100], *lp; + unsigned int i, j, items, idx, nc; + unsigned int nV, nF, nE; + Vec3f p, n, c; + Vec2f t; + Surface_mesh::Vertex v; + + + // properties + Surface_mesh::Vertex_property normals; + Surface_mesh::Vertex_property texcoords; + Surface_mesh::Vertex_property colors; + if (has_normals) normals = mesh.vertex_property("v:normal"); + if (has_texcoords) texcoords = mesh.vertex_property("v:texcoord"); + if (has_colors) colors = mesh.vertex_property("v:color"); + + + // #Vertice, #Faces, #Edges + items = fscanf(in, "%d %d %d\n", (int*)&nV, (int*)&nF, (int*)&nE); + mesh.clear(); + mesh.reserve(nV, std::max(3*nV, nE), nF); + + + // read vertices: pos [normal] [color] [texcoord] + for (i=0; i1.0f || c[1]>1.0f || c[2]>1.0f) c *= (1.0/255.0); + colors[v] = c; + } + lp += nc; + } + + // tex coord + if (has_texcoords) + { + items = sscanf(lp, "%f %f%n", &t[0], &t[1], &nc); + assert(items == 2); + texcoords[v][0] = t[0]; + texcoords[v][1] = t[1]; + lp += nc; + } + } + + + + // read faces: #N v[1] v[2] ... v[n-1] + std::vector vertices; + for (i=0; i normals; + Surface_mesh::Vertex_property texcoords; + if (has_normals) normals = mesh.vertex_property("v:normal"); + if (has_texcoords) texcoords = mesh.vertex_property("v:texcoord"); + + + // #Vertice, #Faces, #Edges + read(in, nV); + read(in, nF); + read(in, nE); + mesh.clear(); + mesh.reserve(nV, std::max(3*nV, nE), nF); + + + // read vertices: pos [normal] [color] [texcoord] + for (i=0; i vertices; + for (i=0; i points = mesh.get_vertex_property("v:point"); + for (Surface_mesh::Vertex_iterator vit=mesh.vertices_begin(); vit!=mesh.vertices_end(); ++vit) + { + const Point& p = points[*vit]; + fprintf(out, "%.10f %.10f %.10f\n", p[0], p[1], p[2]); + } + + + // faces + for (Surface_mesh::Face_iterator fit=mesh.faces_begin(); fit!=mesh.faces_end(); ++fit) + { + int nV = mesh.valence(*fit); + fprintf(out, "%d", nV); + Surface_mesh::Vertex_around_face_circulator fvit=mesh.vertices(*fit), fvend=fvit; + do + { + fprintf(out, " %d", (*fvit).idx()); + } + while (++fvit != fvend); + fprintf(out, "\n"); + } + + fclose(out); + return true; +} + + +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Surface_mesh.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Surface_mesh.cpp new file mode 100644 index 00000000000..a32367feae1 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Surface_mesh.cpp @@ -0,0 +1,1461 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +//== INCLUDES ================================================================= + + +#include "Surface_mesh.h" +#include "IO.h" + + +//== IMPLEMENTATION =========================================================== + + +Surface_mesh:: +Surface_mesh() +{ + // allocate standard properties + // same list is used in operator=() and assign() + vconn_ = add_vertex_property("v:connectivity"); + hconn_ = add_halfedge_property("h:connectivity"); + fconn_ = add_face_property("f:connectivity"); + vpoint_ = add_vertex_property("v:point"); + vdeleted_ = add_vertex_property("v:deleted", false); + edeleted_ = add_edge_property("e:deleted", false); + fdeleted_ = add_face_property("f:deleted", false); + + deleted_vertices_ = deleted_edges_ = deleted_faces_ = 0; + garbage_ = false; +} + + +//----------------------------------------------------------------------------- + + +Surface_mesh:: +~Surface_mesh() +{ +} + + +//----------------------------------------------------------------------------- + + +Surface_mesh& +Surface_mesh:: +operator=(const Surface_mesh& rhs) +{ + if (this != &rhs) + { + // deep copy of property containers + vprops_ = rhs.vprops_; + hprops_ = rhs.hprops_; + eprops_ = rhs.eprops_; + fprops_ = rhs.fprops_; + + // property handles contain pointers, have to be reassigned + vconn_ = vertex_property("v:connectivity"); + hconn_ = halfedge_property("h:connectivity"); + fconn_ = face_property("f:connectivity"); + vdeleted_ = vertex_property("v:deleted"); + edeleted_ = edge_property("e:deleted"); + fdeleted_ = face_property("f:deleted"); + vpoint_ = vertex_property("v:point"); + + // how many elements are deleted? + deleted_vertices_ = rhs.deleted_vertices_; + deleted_edges_ = rhs.deleted_edges_; + deleted_faces_ = rhs.deleted_faces_; + garbage_ = rhs.garbage_; + } + + return *this; +} + + +//----------------------------------------------------------------------------- + + +Surface_mesh& +Surface_mesh:: +assign(const Surface_mesh& rhs) +{ + if (this != &rhs) + { + // clear properties + vprops_.clear(); + hprops_.clear(); + eprops_.clear(); + fprops_.clear(); + + // allocate standard properties + vconn_ = add_vertex_property("v:connectivity"); + hconn_ = add_halfedge_property("h:connectivity"); + fconn_ = add_face_property("f:connectivity"); + vpoint_ = add_vertex_property("v:point"); + vdeleted_ = add_vertex_property("v:deleted", false); + edeleted_ = add_edge_property("e:deleted", false); + fdeleted_ = add_face_property("f:deleted", false); + + // copy properties from other mesh + vconn_.array() = rhs.vconn_.array(); + hconn_.array() = rhs.hconn_.array(); + fconn_.array() = rhs.fconn_.array(); + vpoint_.array() = rhs.vpoint_.array(); + vdeleted_.array() = rhs.vdeleted_.array(); + edeleted_.array() = rhs.edeleted_.array(); + fdeleted_.array() = rhs.fdeleted_.array(); + + // resize (needed by property containers) + vprops_.resize(rhs.vertices_size()); + hprops_.resize(rhs.halfedges_size()); + eprops_.resize(rhs.edges_size()); + fprops_.resize(rhs.faces_size()); + + // how many elements are deleted? + deleted_vertices_ = rhs.deleted_vertices_; + deleted_edges_ = rhs.deleted_edges_; + deleted_faces_ = rhs.deleted_faces_; + garbage_ = rhs.garbage_; + } + + return *this; +} + + +//----------------------------------------------------------------------------- + + +bool +Surface_mesh:: +read(const std::string& filename) +{ + return read_mesh(*this, filename); +} + + +//----------------------------------------------------------------------------- + + +bool +Surface_mesh:: +write(const std::string& filename) const +{ + return write_mesh(*this, filename); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +clear() +{ + vprops_.resize(0); + hprops_.resize(0); + eprops_.resize(0); + fprops_.resize(0); + + vprops_.free_memory(); + hprops_.free_memory(); + eprops_.free_memory(); + fprops_.free_memory(); + + deleted_vertices_ = deleted_edges_ = deleted_faces_ = 0; + garbage_ = false; +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +free_memory() +{ + vprops_.free_memory(); + hprops_.free_memory(); + eprops_.free_memory(); + fprops_.free_memory(); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +reserve(unsigned int nvertices, + unsigned int nedges, + unsigned int nfaces ) +{ + vprops_.reserve(nvertices); + hprops_.reserve(2*nedges); + eprops_.reserve(nedges); + fprops_.reserve(nfaces); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +property_stats() const +{ + std::vector props; + + std::cout << "vertex properties:\n"; + props = vertex_properties(); + for (unsigned int i=0; i v(3); + v[0] = v0; + v[1] = v1; + v[2] = v2; + return add_face(v); +} + + +//----------------------------------------------------------------------------- + + +Surface_mesh::Face +Surface_mesh:: +add_quad(Vertex v0, Vertex v1, Vertex v2, Vertex v3) +{ + std::vector v(4); + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + return add_face(v); +} + + +//----------------------------------------------------------------------------- + + +Surface_mesh::Face +Surface_mesh:: +add_face(const std::vector& vertices) +{ + Vertex v; + unsigned int i, ii, n((int)vertices.size()), id; + std::vector halfedges(n); + std::vector is_new(n), needs_adjust(n, false); + Halfedge inner_next, inner_prev, + outer_next, outer_prev, + boundary_next, boundary_prev, + patch_start, patch_end; + + // cache for set_next_halfedge and vertex' set_halfedge + typedef std::pair NextCacheEntry; + typedef std::vector NextCache; + + NextCache next_cache; + next_cache.reserve(3*n); + + + // don't allow degenerated faces + assert (n > 2); + + + // test for topological errors + for (i=0, ii=1; ifirst, ncIt->second); + + + + // adjust vertices' halfedge handle + for (i=0; i("f:normal"); + + Face_iterator fit, fend=faces_end(); + + for (fit=faces_begin(); fit!=fend; ++fit) + fnormal_[*fit] = compute_face_normal(*fit); +} + + +//----------------------------------------------------------------------------- + + +Normal +Surface_mesh:: +compute_face_normal(Face f) const +{ + Halfedge h = halfedge(f); + Halfedge hend = h; + + Point p0 = vpoint_[to_vertex(h)]; + h = next_halfedge(h); + Point p1 = vpoint_[to_vertex(h)]; + h = next_halfedge(h); + Point p2 = vpoint_[to_vertex(h)]; + + if (next_halfedge(h) == hend) // face is a triangle + { + return cross(p2-=p1, p0-=p1).normalize(); + } + + else // face is a general polygon + { + Normal n(0,0,0); + + hend = h; + do + { + n += cross(p2-p1, p0-p1); + h = next_halfedge(h); + p0 = p1; + p1 = p2; + p2 = vpoint_[to_vertex(h)]; + } + while (h != hend); + + return n.normalize(); + } +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +update_vertex_normals() +{ + if (!vnormal_) + vnormal_ = vertex_property("v:normal"); + + Vertex_iterator vit, vend=vertices_end(); + + for (vit=vertices_begin(); vit!=vend; ++vit) + vnormal_[*vit] = compute_vertex_normal(*vit); +} + + +//----------------------------------------------------------------------------- + + +Normal +Surface_mesh:: +compute_vertex_normal(Vertex v) const +{ + Point nn(0,0,0); + Halfedge h = halfedge(v); + + if (h.is_valid()) + { + const Halfedge hend = h; + const Point p0 = vpoint_[v]; + + Point n, p1, p2; + Scalar cosine, angle; + + do + { + if (!is_boundary(h)) + { + p1 = vpoint_[to_vertex(h)]; + p1 -= p0; + p1.normalize(); + + p2 = vpoint_[from_vertex(prev_halfedge(h))]; + p2 -= p0; + p2.normalize(); + + cosine = dot(p1,p2) / sqrt(dot(p1,p1)*dot(p2,p2)); + if (cosine < -1.0) cosine = -1.0; + else if (cosine > 1.0) cosine = 1.0; + angle = acos(cosine); + + n = cross(p1,p2).normalize(); + n *= angle; + nn += n; + } + + h = cw_rotated_halfedge(h); + } + while (h != hend); + + nn.normalize(); + } + + return nn; +} + + +//----------------------------------------------------------------------------- + + +Scalar +Surface_mesh:: +edge_length(Edge e) const +{ + return norm(vpoint_[vertex(e,0)] - vpoint_[vertex(e,1)]); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +split(Face f, Vertex v) +{ + /* + Split an arbitrary face into triangles by connecting each vertex of fh to vh. + - fh will remain valid (it will become one of the triangles) + - the halfedge handles of the new triangles will point to the old halfeges + */ + + Halfedge hend = halfedge(f); + Halfedge h = next_halfedge(hend); + + Halfedge hold = new_edge(to_vertex(hend), v); + + set_next_halfedge(hend, hold); + set_face(hold, f); + + hold = opposite_halfedge(hold); + + while (h != hend) + { + Halfedge hnext = next_halfedge(h); + + Face fnew = new_face(); + set_halfedge(fnew, h); + + Halfedge hnew = new_edge(to_vertex(h), v); + + set_next_halfedge(hnew, hold); + set_next_halfedge(hold, h); + set_next_halfedge(h, hnew); + + set_face(hnew, fnew); + set_face(hold, fnew); + set_face(h, fnew); + + hold = opposite_halfedge(hnew); + + h = hnext; + } + + set_next_halfedge(hold, hend); + set_next_halfedge(next_halfedge(hend), hold); + + set_face(hold, f); + + set_halfedge(v, hold); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +split(Edge e, Vertex v) +{ + Halfedge h0 = halfedge(e, 0); + Halfedge o0 = halfedge(e, 1); + + Vertex v2 = to_vertex(o0); + + Halfedge e1 = new_edge(v, v2); + Halfedge t1 = opposite_halfedge(e1); + + Face f0 = face(h0); + Face f3 = face(o0); + + set_halfedge(v, h0); + set_vertex(o0, v); + + if (!is_boundary(h0)) + { + Halfedge h1 = next_halfedge(h0); + Halfedge h2 = next_halfedge(h1); + + Vertex v1 = to_vertex(h1); + + Halfedge e0 = new_edge(v, v1); + Halfedge t0 = opposite_halfedge(e0); + + Face f1 = new_face(); + set_halfedge(f0, h0); + set_halfedge(f1, h2); + + set_face(h1, f0); + set_face(t0, f0); + set_face(h0, f0); + + set_face(h2, f1); + set_face(t1, f1); + set_face(e0, f1); + + set_next_halfedge(h0, h1); + set_next_halfedge(h1, t0); + set_next_halfedge(t0, h0); + + set_next_halfedge(e0, h2); + set_next_halfedge(h2, t1); + set_next_halfedge(t1, e0); + } + else + { + set_next_halfedge(prev_halfedge(h0), t1); + set_next_halfedge(t1, h0); + // halfedge handle of _vh already is h0 + } + + + if (!is_boundary(o0)) + { + Halfedge o1 = next_halfedge(o0); + Halfedge o2 = next_halfedge(o1); + + Vertex v3 = to_vertex(o1); + + Halfedge e2 = new_edge(v, v3); + Halfedge t2 = opposite_halfedge(e2); + + Face f2 = new_face(); + set_halfedge(f2, o1); + set_halfedge(f3, o0); + + set_face(o1, f2); + set_face(t2, f2); + set_face(e1, f2); + + set_face(o2, f3); + set_face(o0, f3); + set_face(e2, f3); + + set_next_halfedge(e1, o1); + set_next_halfedge(o1, t2); + set_next_halfedge(t2, e1); + + set_next_halfedge(o0, e2); + set_next_halfedge(e2, o2); + set_next_halfedge(o2, o0); + } + else + { + set_next_halfedge(e1, next_halfedge(o0)); + set_next_halfedge(o0, e1); + set_halfedge(v, e1); + } + + if (halfedge(v2) == h0) + set_halfedge(v2, t1); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +insert_vertex(Edge e, Vertex v) +{ + // before: + // + // v0 h0 v2 + // o--------------->o + // <--------------- + // o0 + // + // after: + // + // v0 h0 v h1 v2 + // o------>o------->o + // <------ <------- + // o0 o1 + + Halfedge h0 = halfedge(e, 0); + Halfedge h2 = next_halfedge(h0); + Halfedge o0 = opposite_halfedge(h0); + Halfedge o2 = prev_halfedge(o0); + Vertex v0 = to_vertex(o0); + Vertex v2 = to_vertex(h0); + Face fh = face(h0); + Face fo = face(o0); + + Halfedge h1 = new_edge(v, v2); + Halfedge o1 = opposite_halfedge(h1); + + // adjust halfedge connectivity + set_next_halfedge(h1, h2); + set_next_halfedge(h0, h1); + set_vertex(h0, v); + set_vertex(h1, v2); + set_face(h1, fh); + + set_next_halfedge(o1, o0); + set_next_halfedge(o2, o1); + set_vertex(o1, v); + set_face(o1, fo); + + // adjust vertex connectivity + set_halfedge(v2, o1); + adjust_outgoing_halfedge(v2); + set_halfedge(v, h1); + adjust_outgoing_halfedge(v); + + // adjust face connectivity + if (fh.is_valid()) set_halfedge(fh, h0); + if (fo.is_valid()) set_halfedge(fo, o1); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +insert_edge(Halfedge h0, Halfedge h1) +{ + assert(face(h0) == face(h1)); + assert(face(h0).is_valid()); + + Vertex v0 = to_vertex(h0); + Vertex v1 = to_vertex(h1); + + Halfedge h2 = next_halfedge(h0); + Halfedge h3 = next_halfedge(h1); + + Halfedge h4 = new_edge(v0, v1); + Halfedge h5 = opposite_halfedge(h4); + + Face f0 = face(h0); + Face f1 = new_face(); + + set_halfedge(f0, h0); + set_halfedge(f1, h1); + + set_next_halfedge(h0, h4); + set_next_halfedge(h4, h3); + set_face(h4, f0); + + set_next_halfedge(h1, h5); + set_next_halfedge(h5, h2); + Halfedge h = h2; + do + { + set_face(h, f1); + h = next_halfedge(h); + } + while (h != h2); +} + + +//----------------------------------------------------------------------------- + + +bool +Surface_mesh:: +is_flip_ok(Edge e) const +{ + // boundary edges cannot be flipped + if (is_boundary(e)) return false; + + // check if the flipped edge is already present in the mesh + + Halfedge h0 = halfedge(e, 0); + Halfedge h1 = halfedge(e, 1); + + Vertex v0 = to_vertex(next_halfedge(h0)); + Vertex v1 = to_vertex(next_halfedge(h1)); + + if (v0 == v1) // this is generally a bad sign !!! + return false; + + if (find_halfedge(v0, v1).is_valid()) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +flip(Edge e) +{ + // CAUTION : Flipping a halfedge may result in + // a non-manifold mesh, hence check for yourself + // whether this operation is allowed or not! + + //let's make it sure it is actually checked + assert(is_flip_ok(e)); + + Halfedge a0 = halfedge(e, 0); + Halfedge b0 = halfedge(e, 1); + + Halfedge a1 = next_halfedge(a0); + Halfedge a2 = next_halfedge(a1); + + Halfedge b1 = next_halfedge(b0); + Halfedge b2 = next_halfedge(b1); + + Vertex va0 = to_vertex(a0); + Vertex va1 = to_vertex(a1); + + Vertex vb0 = to_vertex(b0); + Vertex vb1 = to_vertex(b1); + + Face fa = face(a0); + Face fb = face(b0); + + set_vertex(a0, va1); + set_vertex(b0, vb1); + + set_next_halfedge(a0, a2); + set_next_halfedge(a2, b1); + set_next_halfedge(b1, a0); + + set_next_halfedge(b0, b2); + set_next_halfedge(b2, a1); + set_next_halfedge(a1, b0); + + set_face(a1, fb); + set_face(b1, fa); + + set_halfedge(fa, a0); + set_halfedge(fb, b0); + + if (halfedge(va0) == b0) + set_halfedge(va0, a1); + if (halfedge(vb0) == a0) + set_halfedge(vb0, b1); +} + + +//----------------------------------------------------------------------------- + + +bool +Surface_mesh:: +is_collapse_ok(Halfedge v0v1) +{ + Halfedge v1v0(opposite_halfedge(v0v1)); + Vertex v0(to_vertex(v1v0)); + Vertex v1(to_vertex(v0v1)); + Vertex vv, vl, vr; + Halfedge h1, h2; + + + // the edges v1-vl and vl-v0 must not be both boundary edges + if (!is_boundary(v0v1)) + { + vl = to_vertex(next_halfedge(v0v1)); + h1 = next_halfedge(v0v1); + h2 = next_halfedge(h1); + if (is_boundary(opposite_halfedge(h1)) && is_boundary(opposite_halfedge(h2))) + return false; + } + + + // the edges v0-vr and vr-v1 must not be both boundary edges + if (!is_boundary(v1v0)) + { + vr = to_vertex(next_halfedge(v1v0)); + h1 = next_halfedge(v1v0); + h2 = next_halfedge(h1); + if (is_boundary(opposite_halfedge(h1)) && is_boundary(opposite_halfedge(h2))) + return false; + } + + + // if vl and vr are equal or both invalid -> fail + if (vl == vr) return false; + + + // edge between two boundary vertices should be a boundary edge + if ( is_boundary(v0) && is_boundary(v1) && + !is_boundary(v0v1) && !is_boundary(v1v0)) + return false; + + + // test intersection of the one-rings of v0 and v1 + Vertex_around_vertex_circulator vv_it, vv_end; + vv_it = vv_end = vertices(v0); + do + { + vv = *vv_it; + if (vv != v1 && vv != vl && vv != vr) + if (find_halfedge(vv, v1).is_valid()) + return false; + } + while (++vv_it != vv_end); + + + // passed all tests + return true; +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +collapse(Halfedge h) +{ + Halfedge h0 = h; + Halfedge h1 = prev_halfedge(h0); + Halfedge o0 = opposite_halfedge(h0); + Halfedge o1 = next_halfedge(o0); + + // remove edge + remove_edge(h0); + + // remove loops + if (next_halfedge(next_halfedge(h1)) == h1) + remove_loop(h1); + if (next_halfedge(next_halfedge(o1)) == o1) + remove_loop(o1); +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +remove_edge(Halfedge h) +{ + Halfedge hn = next_halfedge(h); + Halfedge hp = prev_halfedge(h); + + Halfedge o = opposite_halfedge(h); + Halfedge on = next_halfedge(o); + Halfedge op = prev_halfedge(o); + + Face fh = face(h); + Face fo = face(o); + + Vertex vh = to_vertex(h); + Vertex vo = to_vertex(o); + + + + // halfedge -> vertex + Halfedge_around_vertex_circulator vh_it, vh_end; + vh_it = vh_end = halfedges(vo); + do + { + set_vertex(opposite_halfedge(*vh_it), vh); + } + while (++vh_it != vh_end); + + + // halfedge -> halfedge + set_next_halfedge(hp, hn); + set_next_halfedge(op, on); + + + // face -> halfedge + if (fh.is_valid()) set_halfedge(fh, hn); + if (fo.is_valid()) set_halfedge(fo, on); + + + // vertex -> halfedge + if (halfedge(vh) == o) set_halfedge(vh, hn); + adjust_outgoing_halfedge(vh); + set_halfedge(vo, Halfedge()); + + + // delete stuff + if (!vdeleted_) vdeleted_ = vertex_property("v:deleted", false); + if (!edeleted_) edeleted_ = edge_property("e:deleted", false); + vdeleted_[vo] = true; ++deleted_vertices_; + edeleted_[edge(h)] = true; ++deleted_edges_; + garbage_ = true; +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +remove_loop(Halfedge h) +{ + Halfedge h0 = h; + Halfedge h1 = next_halfedge(h0); + + Halfedge o0 = opposite_halfedge(h0); + Halfedge o1 = opposite_halfedge(h1); + + Vertex v0 = to_vertex(h0); + Vertex v1 = to_vertex(h1); + + Face fh = face(h0); + Face fo = face(o0); + + + + // is it a loop ? + assert ((next_halfedge(h1) == h0) && (h1 != o0)); + + + // halfedge -> halfedge + set_next_halfedge(h1, next_halfedge(o0)); + set_next_halfedge(prev_halfedge(o0), h1); + + + // halfedge -> face + set_face(h1, fo); + + + // vertex -> halfedge + set_halfedge(v0, h1); adjust_outgoing_halfedge(v0); + set_halfedge(v1, o1); adjust_outgoing_halfedge(v1); + + + // face -> halfedge + if (fo.is_valid() && halfedge(fo) == o0) + set_halfedge(fo, h1); + + + // delete stuff + if (!edeleted_) edeleted_ = edge_property("e:deleted", false); + if (!fdeleted_) fdeleted_ = face_property("f:deleted", false); + if (fh.is_valid()) { fdeleted_[fh] = true; ++deleted_faces_; } + edeleted_[edge(h0)] = true; ++deleted_edges_; + garbage_ = true; +} + + +//----------------------------------------------------------------------------- + + +void +Surface_mesh:: +garbage_collection() +{ + int i, i0, i1, + nV(vertices_size()), + nE(edges_size()), + nH(halfedges_size()), + nF(faces_size()); + + Vertex v; + Halfedge h; + Face f; + + + // setup handle mapping + Vertex_property vmap = add_vertex_property("v:garbage-collection"); + Halfedge_property hmap = add_halfedge_property("h:garbage-collection"); + Face_property fmap = add_face_property("f:garbage-collection"); + for (i=0; i 0) + { + i0=0; i1=nV-1; + + while (1) + { + // find first deleted and last un-deleted + while (!vdeleted_[Vertex(i0)] && i0 < i1) ++i0; + while ( vdeleted_[Vertex(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + vprops_.swap(i0, i1); + }; + + // remember new size + nV = vdeleted_[Vertex(i0)] ? i0 : i0+1; + } + + + // remove deleted edges + if (nE > 0) + { + i0=0; i1=nE-1; + + while (1) + { + // find first deleted and last un-deleted + while (!edeleted_[Edge(i0)] && i0 < i1) ++i0; + while ( edeleted_[Edge(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + eprops_.swap(i0, i1); + hprops_.swap(2*i0, 2*i1); + hprops_.swap(2*i0+1, 2*i1+1); + }; + + // remember new size + nE = edeleted_[Edge(i0)] ? i0 : i0+1; + nH = 2*nE; + } + + + // remove deleted faces + if (nF > 0) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st deleted and last un-deleted + while (!fdeleted_[Face(i0)] && i0 < i1) ++i0; + while ( fdeleted_[Face(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + fprops_.swap(i0, i1); + }; + + // remember new size + nF = fdeleted_[Face(i0)] ? i0 : i0+1; + } + + + // update vertex connectivity + for (i=0; i class Vertex_property : public Property + { + public: + + /// default constructor + explicit Vertex_property() {} + explicit Vertex_property(Property p) : Property(p) {} + + /// access the data stored for vertex \c v + typename Property::reference operator[](Vertex v) + { + return Property::operator[](v.idx()); + } + + /// access the data stored for vertex \c v + typename Property::const_reference operator[](Vertex v) const + { + return Property::operator[](v.idx()); + } + }; + + + /// Halfedge property of type T + /// \sa Vertex_property, Edge_property, Face_property + template class Halfedge_property : public Property + { + public: + + /// default constructor + explicit Halfedge_property() {} + explicit Halfedge_property(Property p) : Property(p) {} + + /// access the data stored for halfedge \c h + typename Property::reference operator[](Halfedge h) + { + return Property::operator[](h.idx()); + } + + /// access the data stored for halfedge \c h + typename Property::const_reference operator[](Halfedge h) const + { + return Property::operator[](h.idx()); + } + }; + + + /// Edge property of type T + /// \sa Vertex_property, Halfedge_property, Face_property + template class Edge_property : public Property + { + public: + + /// default constructor + explicit Edge_property() {} + explicit Edge_property(Property p) : Property(p) {} + + /// access the data stored for edge \c e + typename Property::reference operator[](Edge e) + { + return Property::operator[](e.idx()); + } + + /// access the data stored for edge \c e + typename Property::const_reference operator[](Edge e) const + { + return Property::operator[](e.idx()); + } + }; + + + /// Face property of type T + /// \sa Vertex_property, Halfedge_property, Edge_property + template class Face_property : public Property + { + public: + + /// default constructor + explicit Face_property() {} + explicit Face_property(Property p) : Property(p) {} + + /// access the data stored for face \c f + typename Property::reference operator[](Face f) + { + return Property::operator[](f.idx()); + } + + /// access the data stored for face \c f + typename Property::const_reference operator[](Face f) const + { + return Property::operator[](f.idx()); + } + }; + + + + +public: //------------------------------------------------------ iterator types + + /// this class iterates linearly over all vertices + /// \sa vertices_begin(), vertices_end() + /// \sa Halfedge_iterator, Edge_iterator, Face_iterator + class Vertex_iterator + { + public: + + /// Default constructor + Vertex_iterator(Vertex v=Vertex(), const Surface_mesh* m=NULL) : hnd_(v), mesh_(m) + { + if (mesh_ && mesh_->garbage()) while (mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + } + + /// get the vertex the iterator refers to + Vertex operator*() const { return hnd_; } + + /// are two iterators equal? + bool operator==(const Vertex_iterator& rhs) const + { + return (hnd_==rhs.hnd_); + } + + /// are two iterators different? + bool operator!=(const Vertex_iterator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment iterator + Vertex_iterator& operator++() + { + ++hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + return *this; + } + + /// pre-decrement iterator + Vertex_iterator& operator--() + { + --hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) --hnd_.idx_; + return *this; + } + + private: + Vertex hnd_; + const Surface_mesh* mesh_; + }; + + + /// this class iterates linearly over all halfedges + /// \sa halfedges_begin(), halfedges_end() + /// \sa Vertex_iterator, Edge_iterator, Face_iterator + class Halfedge_iterator + { + public: + + /// Default constructor + Halfedge_iterator(Halfedge h=Halfedge(), const Surface_mesh* m=NULL) : hnd_(h), mesh_(m) + { + if (mesh_ && mesh_->garbage()) while (mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + } + + /// get the halfedge the iterator refers to + Halfedge operator*() const { return hnd_; } + + /// are two iterators equal? + bool operator==(const Halfedge_iterator& rhs) const + { + return (hnd_==rhs.hnd_); + } + + /// are two iterators different? + bool operator!=(const Halfedge_iterator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment iterator + Halfedge_iterator& operator++() + { + ++hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + return *this; + } + + /// pre-decrement iterator + Halfedge_iterator& operator--() + { + --hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) --hnd_.idx_; + return *this; + } + + private: + Halfedge hnd_; + const Surface_mesh* mesh_; + }; + + + /// this class iterates linearly over all edges + /// \sa edges_begin(), edges_end() + /// \sa Vertex_iterator, Halfedge_iterator, Face_iterator + class Edge_iterator + { + public: + + /// Default constructor + Edge_iterator(Edge e=Edge(), const Surface_mesh* m=NULL) : hnd_(e), mesh_(m) + { + if (mesh_ && mesh_->garbage()) while (mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + } + + /// get the edge the iterator refers to + Edge operator*() const { return hnd_; } + + /// are two iterators equal? + bool operator==(const Edge_iterator& rhs) const + { + return (hnd_==rhs.hnd_); + } + + /// are two iterators different? + bool operator!=(const Edge_iterator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment iterator + Edge_iterator& operator++() + { + ++hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + return *this; + } + + /// pre-decrement iterator + Edge_iterator& operator--() + { + --hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) --hnd_.idx_; + return *this; + } + + private: + Edge hnd_; + const Surface_mesh* mesh_; + }; + + + /// this class iterates linearly over all faces + /// \sa faces_begin(), faces_end() + /// \sa Vertex_iterator, Halfedge_iterator, Edge_iterator + class Face_iterator + { + public: + + /// Default constructor + Face_iterator(Face f=Face(), const Surface_mesh* m=NULL) : hnd_(f), mesh_(m) + { + if (mesh_ && mesh_->garbage()) while (mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + } + + /// get the face the iterator refers to + Face operator*() const { return hnd_; } + + /// are two iterators equal? + bool operator==(const Face_iterator& rhs) const + { + return (hnd_==rhs.hnd_); + } + + /// are two iterators different? + bool operator!=(const Face_iterator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment iterator + Face_iterator& operator++() + { + ++hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) ++hnd_.idx_; + return *this; + } + + /// pre-decrement iterator + Face_iterator& operator--() + { + --hnd_.idx_; + assert(mesh_); + while (mesh_->garbage() && mesh_->is_valid(hnd_) && mesh_->is_deleted(hnd_)) --hnd_.idx_; + return *this; + } + + private: + Face hnd_; + const Surface_mesh* mesh_; + }; + + + + +public: //---------------------------------------------------- circulator types + + /// this class circulates through all one-ring neighbors of a vertex + /// \sa Halfedge_around_vertex_circulator, Face_around_vertex_circulator + class Vertex_around_vertex_circulator + { + public: + + /// default constructor + Vertex_around_vertex_circulator(const Surface_mesh* m=NULL, Vertex v=Vertex()) + : mesh_(m) + { + if (mesh_) halfedge_ = mesh_->halfedge(v); + } + + /// are two circulators equal? + bool operator==(const Vertex_around_vertex_circulator& rhs) const + { + assert(mesh_); + return ((mesh_==rhs.mesh_) && (halfedge_==rhs.halfedge_)); + } + + /// are two circulators different? + bool operator!=(const Vertex_around_vertex_circulator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment (rotate couter-clockwise) + Vertex_around_vertex_circulator& operator++() + { + assert(mesh_); + halfedge_ = mesh_->ccw_rotated_halfedge(halfedge_); + return *this; + } + + /// pre-decrement (rotate clockwise) + Vertex_around_vertex_circulator& operator--() + { + assert(mesh_); + halfedge_ = mesh_->cw_rotated_halfedge(halfedge_); + return *this; + } + + /// get the vertex the circulator refers to + Vertex operator*() const + { + assert(mesh_); + return mesh_->to_vertex(halfedge_); + } + + /// cast to bool: true if vertex is not isolated + operator bool() const { return halfedge_.is_valid(); } + + private: + const Surface_mesh* mesh_; + Halfedge halfedge_; + }; + + + /// this class circulates through all outgoing halfedges of a vertex + /// \sa Vertex_around_vertex_circulator, Face_around_vertex_circulator + class Halfedge_around_vertex_circulator + { + public: + + /// default constructor + Halfedge_around_vertex_circulator(const Surface_mesh* m=NULL, Vertex v=Vertex()) + : mesh_(m) + { + if (mesh_) halfedge_ = mesh_->halfedge(v); + } + + /// are two circulators equal? + bool operator==(const Halfedge_around_vertex_circulator& rhs) const + { + assert(mesh_); + return ((mesh_==rhs.mesh_) && (halfedge_==rhs.halfedge_)); + } + + /// are two circulators different? + bool operator!=(const Halfedge_around_vertex_circulator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment (rotate couter-clockwise) + Halfedge_around_vertex_circulator& operator++() + { + assert(mesh_); + halfedge_ = mesh_->ccw_rotated_halfedge(halfedge_); + return *this; + } + + /// pre-decrement (rotate clockwise) + Halfedge_around_vertex_circulator& operator--() + { + assert(mesh_); + halfedge_ = mesh_->cw_rotated_halfedge(halfedge_); + return *this; + } + + /// get the halfedge the circulator refers to + Halfedge operator*() const { return halfedge_; } + + /// cast to bool: true if vertex is not isolated + operator bool() const { return halfedge_.is_valid(); } + + private: + const Surface_mesh* mesh_; + Halfedge halfedge_; + }; + + + /// this class circulates through all incident faces of a vertex + /// \sa Vertex_around_vertex_circulator, Halfedge_around_vertex_circulator + class Face_around_vertex_circulator + { + public: + + /// construct with mesh and vertex (vertex should not be isolated!) + Face_around_vertex_circulator(const Surface_mesh* m=NULL, Vertex v=Vertex()) + : mesh_(m) + { + if (mesh_) + { + halfedge_ = mesh_->halfedge(v); + if (halfedge_.is_valid() && mesh_->is_boundary(halfedge_)) + operator++(); + } + } + + /// are two circulators equal? + bool operator==(const Face_around_vertex_circulator& rhs) const + { + assert(mesh_); + return ((mesh_==rhs.mesh_) && (halfedge_==rhs.halfedge_)); + } + + /// are two circulators different? + bool operator!=(const Face_around_vertex_circulator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment (rotates counter-clockwise) + Face_around_vertex_circulator& operator++() + { + assert(mesh_ && halfedge_.is_valid()); + do { + halfedge_ = mesh_->ccw_rotated_halfedge(halfedge_); + } while (mesh_->is_boundary(halfedge_)); + return *this; + } + + /// pre-decrement (rotate clockwise) + Face_around_vertex_circulator& operator--() + { + assert(mesh_ && halfedge_.is_valid()); + do + halfedge_ = mesh_->cw_rotated_halfedge(halfedge_); + while (mesh_->is_boundary(halfedge_)); + return *this; + } + + /// get the face the circulator refers to + Face operator*() const + { + assert(mesh_ && halfedge_.is_valid()); + return mesh_->face(halfedge_); + } + + /// cast to bool: true if vertex is not isolated + operator bool() const { return halfedge_.is_valid(); } + + private: + const Surface_mesh* mesh_; + Halfedge halfedge_; + }; + + + /// this class circulates through the vertices of a face + /// \sa Halfedge_around_face_circulator + class Vertex_around_face_circulator + { + public: + + /// default constructor + Vertex_around_face_circulator(const Surface_mesh* m=NULL, Face f=Face()) + : mesh_(m) + { + if (mesh_) halfedge_ = mesh_->halfedge(f); + } + + /// are two circulators equal? + bool operator==(const Vertex_around_face_circulator& rhs) const + { + assert(mesh_); + return ((mesh_==rhs.mesh_) && (halfedge_==rhs.halfedge_)); + } + + /// are two circulators different? + bool operator!=(const Vertex_around_face_circulator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment (rotates counter-clockwise) + Vertex_around_face_circulator& operator++() + { + assert(mesh_ && halfedge_.is_valid()); + halfedge_ = mesh_->next_halfedge(halfedge_); + return *this; + } + + /// pre-decrement (rotates clockwise) + Vertex_around_face_circulator& operator--() + { + assert(mesh_ && halfedge_.is_valid()); + halfedge_ = mesh_->prev_halfedge(halfedge_); + return *this; + } + + /// get the vertex the circulator refers to + Vertex operator*() const + { + assert(mesh_ && halfedge_.is_valid()); + return mesh_->to_vertex(halfedge_); + } + + private: + const Surface_mesh* mesh_; + Halfedge halfedge_; + }; + + + /// this class circulates through all halfedges of a face + /// \sa Vertex_around_face_circulator + class Halfedge_around_face_circulator + { + public: + + /// default constructur + Halfedge_around_face_circulator(const Surface_mesh* m=NULL, Face f=Face()) + : mesh_(m) + { + if (mesh_) halfedge_ = mesh_->halfedge(f); + } + + /// are two circulators equal? + bool operator==(const Halfedge_around_face_circulator& rhs) const + { + assert(mesh_); + return ((mesh_==rhs.mesh_) && (halfedge_==rhs.halfedge_)); + } + + /// are two circulators different? + bool operator!=(const Halfedge_around_face_circulator& rhs) const + { + return !operator==(rhs); + } + + /// pre-increment (rotates counter-clockwise) + Halfedge_around_face_circulator& operator++() + { + assert(mesh_ && halfedge_.is_valid()); + halfedge_ = mesh_->next_halfedge(halfedge_); + return *this; + } + + /// pre-decrement (rotates clockwise) + Halfedge_around_face_circulator& operator--() + { + assert(mesh_ && halfedge_.is_valid()); + halfedge_ = mesh_->prev_halfedge(halfedge_); + return *this; + } + + /// get the halfedge the circulator refers to + Halfedge operator*() const { return halfedge_; } + + private: + const Surface_mesh* mesh_; + Halfedge halfedge_; + }; + + + + +public: //-------------------------------------------- constructor / destructor + + /// \name Construct, destruct, assignment + //@{ + + /// default constructor + Surface_mesh(); + + // destructor + ~Surface_mesh(); + + /// copy constructor: copies \c rhs to \c *this. performs a deep copy of all properties. + Surface_mesh(const Surface_mesh& rhs) { operator=(rhs); } + + /// assign \c rhs to \c *this. performs a deep copy of all properties. + Surface_mesh& operator=(const Surface_mesh& rhs); + + /// assign \c rhs to \c *this. does not copy custom properties. + Surface_mesh& assign(const Surface_mesh& rhs); + + //@} + + + + +public: //------------------------------------------------------------- file IO + + /// \name File IO + //@{ + + /// read mesh from file \c filename. file extension determines file type. + /// \sa write(const std::string& filename) + bool read(const std::string& filename); + + /// write mesh to file \c filename. file extensions determines file type. + /// \sa read(const std::string& filename) + bool write(const std::string& filename) const; + + //@} + + + + +public: //----------------------------------------------- add new vertex / face + + /// \name Add new elements by hand + //@{ + + /// add a new vertex with position \c p + Vertex add_vertex(const Point& p); + + /// add a new face with vertex list \c vertices + /// \sa add_triangle, add_quad + Face add_face(const std::vector& vertices); + + /// add a new triangle connecting vertices \c v1, \c v2, \c v3 + /// \sa add_face, add_quad + Face add_triangle(Vertex v1, Vertex v2, Vertex v3); + + /// add a new quad connecting vertices \c v1, \c v2, \c v3, \c v4 + /// \sa add_triangle, add_face + Face add_quad(Vertex v1, Vertex v2, Vertex v3, Vertex v4); + + //@} + + + + +public: //--------------------------------------------------- memory management + + /// \name Memory Management + //@{ + + /// returns number of (deleted and valid) vertices in the mesh + unsigned int vertices_size() const { return (unsigned int) vprops_.size(); } + /// returns number of (deleted and valid)halfedge in the mesh + unsigned int halfedges_size() const { return (unsigned int) hprops_.size(); } + /// returns number of (deleted and valid)edges in the mesh + unsigned int edges_size() const { return (unsigned int) eprops_.size(); } + /// returns number of (deleted and valid)faces in the mesh + unsigned int faces_size() const { return (unsigned int) fprops_.size(); } + + + /// returns number of vertices in the mesh + unsigned int n_vertices() const { return vertices_size() - deleted_vertices_; } + /// returns number of halfedge in the mesh + unsigned int n_halfedges() const { return halfedges_size() - 2*deleted_edges_; } + /// returns number of edges in the mesh + unsigned int n_edges() const { return edges_size() - deleted_edges_; } + /// returns number of faces in the mesh + unsigned int n_faces() const { return faces_size() - deleted_faces_; } + + + /// returns true iff the mesh is empty, i.e., has no vertices + unsigned int empty() const { return n_vertices() == 0; } + + + /// clear mesh: remove all vertices, edges, faces + void clear(); + + /// remove unused memory from vectors + void free_memory(); + + /// reserve memory (mainly used in file readers) + void reserve(unsigned int nvertices, + unsigned int nedges, + unsigned int nfaces ); + + + /// remove deleted vertices/edges/faces + void garbage_collection(); + + + /// returns whether vertex \c v is deleted + /// \sa garbage_collection() + bool is_deleted(Vertex v) const + { + return vdeleted_[v]; + } + /// returns whether halfedge \c h is deleted + /// \sa garbage_collection() + bool is_deleted(Halfedge h) const + { + return edeleted_[edge(h)]; + } + /// returns whether edge \c e is deleted + /// \sa garbage_collection() + bool is_deleted(Edge e) const + { + return edeleted_[e]; + } + /// returns whether face \c f is deleted + /// \sa garbage_collection() + bool is_deleted(Face f) const + { + return fdeleted_[f]; + } + + + /// return whether vertex \c v is valid, i.e. the index is stores it within the array bounds. + bool is_valid(Vertex v) const + { + return (0 <= v.idx()) && (v.idx() < (int)vertices_size()); + } + /// return whether halfedge \c h is valid, i.e. the index is stores it within the array bounds. + bool is_valid(Halfedge h) const + { + return (0 <= h.idx()) && (h.idx() < (int)halfedges_size()); + } + /// return whether edge \c e is valid, i.e. the index is stores it within the array bounds. + bool is_valid(Edge e) const + { + return (0 <= e.idx()) && (e.idx() < (int)edges_size()); + } + /// return whether face \c f is valid, i.e. the index is stores it within the array bounds. + bool is_valid(Face f) const + { + return (0 <= f.idx()) && (f.idx() < (int)faces_size()); + } + + //@} + + + + +public: //---------------------------------------------- low-level connectivity + + /// \name Low-level connectivity + //@{ + + /// returns an outgoing halfedge of vertex \c v. + /// if \c v is a boundary vertex this will be a boundary halfedge. + Halfedge halfedge(Vertex v) const + { + return vconn_[v].halfedge_; + } + + /// set the outgoing halfedge of vertex \c v to \c h + void set_halfedge(Vertex v, Halfedge h) + { + vconn_[v].halfedge_ = h; + } + + /// returns whether \c v is a boundary vertex + bool is_boundary(Vertex v) const + { + Halfedge h(halfedge(v)); + return (!(h.is_valid() && face(h).is_valid())); + } + + /// returns whether \c v is isolated, i.e., not incident to any face + bool is_isolated(Vertex v) const + { + return !halfedge(v).is_valid(); + } + + + /// returns the vertex the halfedge \c h points to + Vertex to_vertex(Halfedge h) const + { + return hconn_[h].vertex_; + } + + /// returns the vertex the halfedge \c h emanates from + Vertex from_vertex(Halfedge h) const + { + return to_vertex(opposite_halfedge(h)); + } + + /// sets the vertex the halfedge \c h points to to \c v + void set_vertex(Halfedge h, Vertex v) + { + hconn_[h].vertex_ = v; + } + + /// returns the face incident to halfedge \c h + Face face(Halfedge h) const + { + return hconn_[h].face_; + } + + /// sets the incident face to halfedge \c h to \c f + void set_face(Halfedge h, Face f) + { + hconn_[h].face_ = f; + } + + /// returns the next halfedge within the incident face + Halfedge next_halfedge(Halfedge h) const + { + return hconn_[h].next_halfedge_; + } + + /// sets the next halfedge of \c h within the face to \c nh + void set_next_halfedge(Halfedge h, Halfedge nh) + { + hconn_[h].next_halfedge_ = nh; + hconn_[nh].prev_halfedge_ = h; + } + + /// returns the previous halfedge within the incident face + Halfedge prev_halfedge(Halfedge h) const + { + return hconn_[h].prev_halfedge_; + } + + /// returns the opposite halfedge of \c h + Halfedge opposite_halfedge(Halfedge h) const + { + return Halfedge((h.idx() & 1) ? h.idx()-1 : h.idx()+1); + } + + /// returns the halfedge that is rotated counter-clockwise around the + /// start vertex of \c h. it is the opposite halfedge of the previous halfedge of \c h. + Halfedge ccw_rotated_halfedge(Halfedge h) const + { + return opposite_halfedge(prev_halfedge(h)); + } + + /// returns the halfedge that is rotated clockwise around the + /// start vertex of \c h. it is the next halfedge of the opposite halfedge of \c h. + Halfedge cw_rotated_halfedge(Halfedge h) const + { + return next_halfedge(opposite_halfedge(h)); + } + + /// return the edge that contains halfedge \c h as one of its two halfedges. + Edge edge(Halfedge h) const + { + return Edge(h.idx() >> 1); + } + + /// returns whether h is a boundary halfege, i.e., if its face does not exist. + bool is_boundary(Halfedge h) const + { + return !face(h).is_valid(); + } + + + /// returns the \c i'th halfedge of edge \c e. \c i has to be 0 or 1. + Halfedge halfedge(Edge e, unsigned int i) const + { + assert(i<=1); + return Halfedge((e.idx() << 1) + i); + } + + /// returns the \c i'th vertex of edge \c e. \c i has to be 0 or 1. + Vertex vertex(Edge e, unsigned int i) const + { + assert(i<=1); + return to_vertex(halfedge(e, i)); + } + + /// returns whether \c e is a boundary edge, i.e., if one of its + /// halfedges is a boundary halfedge. + bool is_boundary(Edge e) const + { + return (is_boundary(halfedge(e, 0)) || is_boundary(halfedge(e, 1))); + } + + /// returns a halfedge of face \c f + Halfedge halfedge(Face f) const + { + return fconn_[f].halfedge_; + } + + /// sets the halfedge of face \c f to \c h + void set_halfedge(Face f, Halfedge h) + { + fconn_[f].halfedge_ = h; + } + + /// returns whether \c f is a boundary face, i.e., it one of its edges is a boundary edge. + bool is_boundary(Face f) const + { + Halfedge h = halfedge(f); + Halfedge hh = h; + do + { + if (is_boundary(opposite_halfedge(h))) + return true; + h = next_halfedge(h); + } + while (h != hh); + return false; + } + + //@} + + + + +public: //--------------------------------------------------- property handling + + /// \name Property handling + //@{ + + /** add a vertex property of type \c T with name \c name and default value \c t. + fails if a property named \c name exists already, since the name has to be unique. + in this case it returns an invalid property */ + template Vertex_property add_vertex_property(const std::string& name, const T t=T()) + { + return Vertex_property(vprops_.add(name, t)); + } + /** add a halfedge property of type \c T with name \c name and default value \c t. + fails if a property named \c name exists already, since the name has to be unique. + in this case it returns an invalid property */ + template Halfedge_property add_halfedge_property(const std::string& name, const T t=T()) + { + return Halfedge_property(hprops_.add(name, t)); + } + /** add a edge property of type \c T with name \c name and default value \c t. + fails if a property named \c name exists already, since the name has to be unique. + in this case it returns an invalid property */ + template Edge_property add_edge_property(const std::string& name, const T t=T()) + { + return Edge_property(eprops_.add(name, t)); + } + /** add a face property of type \c T with name \c name and default value \c t. + fails if a property named \c name exists already, since the name has to be unique. + in this case it returns an invalid property */ + template Face_property add_face_property(const std::string& name, const T t=T()) + { + return Face_property(fprops_.add(name, t)); + } + + + /** get the vertex property named \c name of type \c T. returns an invalid + Vertex_property if the property does not exist or if the type does not match. */ + template Vertex_property get_vertex_property(const std::string& name) const + { + return Vertex_property(vprops_.get(name)); + } + /** get the halfedge property named \c name of type \c T. returns an invalid + Vertex_property if the property does not exist or if the type does not match. */ + template Halfedge_property get_halfedge_property(const std::string& name) const + { + return Halfedge_property(hprops_.get(name)); + } + /** get the edge property named \c name of type \c T. returns an invalid + Vertex_property if the property does not exist or if the type does not match. */ + template Edge_property get_edge_property(const std::string& name) const + { + return Edge_property(eprops_.get(name)); + } + /** get the face property named \c name of type \c T. returns an invalid + Vertex_property if the property does not exist or if the type does not match. */ + template Face_property get_face_property(const std::string& name) const + { + return Face_property(fprops_.get(name)); + } + + + /** if a vertex property of type \c T with name \c name exists, it is returned. + otherwise this property is added (with default value \c t) */ + template Vertex_property vertex_property(const std::string& name, const T t=T()) + { + return Vertex_property(vprops_.get_or_add(name, t)); + } + /** if a halfedge property of type \c T with name \c name exists, it is returned. + otherwise this property is added (with default value \c t) */ + template Halfedge_property halfedge_property(const std::string& name, const T t=T()) + { + return Halfedge_property(hprops_.get_or_add(name, t)); + } + /** if an edge property of type \c T with name \c name exists, it is returned. + otherwise this property is added (with default value \c t) */ + template Edge_property edge_property(const std::string& name, const T t=T()) + { + return Edge_property(eprops_.get_or_add(name, t)); + } + /** if a face property of type \c T with name \c name exists, it is returned. + otherwise this property is added (with default value \c t) */ + template Face_property face_property(const std::string& name, const T t=T()) + { + return Face_property(fprops_.get_or_add(name, t)); + } + + + /// remove the vertex property \c p + template void remove_vertex_property(Vertex_property& p) + { + vprops_.remove(p); + } + /// remove the halfedge property \c p + template void remove_halfedge_property(Halfedge_property& p) + { + hprops_.remove(p); + } + /// remove the edge property \c p + template void remove_edge_property(Edge_property& p) + { + eprops_.remove(p); + } + /// remove the face property \c p + template void remove_face_property(Face_property& p) + { + fprops_.remove(p); + } + + + /** get the type_info \c T of vertex property named \c name. returns an typeid(void) + if the property does not exist or if the type does not match. */ + const std::type_info& get_vertex_property_type(const std::string& name) + { + return vprops_.get_type(name); + } + /** get the type_info \c T of halfedge property named \c name. returns an typeid(void) + if the property does not exist or if the type does not match. */ + const std::type_info& get_halfedge_property_type(const std::string& name) + { + return hprops_.get_type(name); + } + /** get the type_info \c T of edge property named \c name. returns an typeid(void) + if the property does not exist or if the type does not match. */ + const std::type_info& get_edge_property_type(const std::string& name) + { + return eprops_.get_type(name); + } + /** get the type_info \c T of face property named \c name. returns an typeid(void) + if the property does not exist or if the type does not match. */ + const std::type_info& get_face_property_type(const std::string& name) + { + return fprops_.get_type(name); + } + + + /// returns the names of all vertex properties + std::vector vertex_properties() const + { + return vprops_.properties(); + } + /// returns the names of all halfedge properties + std::vector halfedge_properties() const + { + return hprops_.properties(); + } + /// returns the names of all edge properties + std::vector edge_properties() const + { + return eprops_.properties(); + } + /// returns the names of all face properties + std::vector face_properties() const + { + return fprops_.properties(); + } + /// prints the names of all properties + void property_stats() const; + + //@} + + + + +public: //--------------------------------------------- iterators & circulators + + /// \name Iterators & Circulators + //@{ + + /// returns start iterator for vertices + Vertex_iterator vertices_begin() const + { + return Vertex_iterator(Vertex(0), this); + } + + /// returns end iterator for vertices + Vertex_iterator vertices_end() const + { + return Vertex_iterator(Vertex(vertices_size()), this); + } + + /// returns start iterator for halfedges + Halfedge_iterator halfedges_begin() const + { + return Halfedge_iterator(Halfedge(0), this); + } + + /// returns end iterator for halfedges + Halfedge_iterator halfedges_end() const + { + return Halfedge_iterator(Halfedge(halfedges_size()), this); + } + + /// returns start iterator for edges + Edge_iterator edges_begin() const + { + return Edge_iterator(Edge(0), this); + } + + /// returns end iterator for edges + Edge_iterator edges_end() const + { + return Edge_iterator(Edge(edges_size()), this); + } + + /// returns start iterator for faces + Face_iterator faces_begin() const + { + return Face_iterator(Face(0), this); + } + + /// returns end iterator for faces + Face_iterator faces_end() const + { + return Face_iterator(Face(faces_size()), this); + } + + /// returns circulator for vertices around vertex \c v + Vertex_around_vertex_circulator vertices(Vertex v) const + { + return Vertex_around_vertex_circulator(this, v); + } + + /// returns circulator for outgoing halfedges around vertex \c v + Halfedge_around_vertex_circulator halfedges(Vertex v) const + { + return Halfedge_around_vertex_circulator(this, v); + } + + /// returns circulator for faces around vertex \c v + Face_around_vertex_circulator faces(Vertex v) const + { + return Face_around_vertex_circulator(this, v); + } + + /// returns circulator for vertices of face \c f + Vertex_around_face_circulator vertices(Face f) const + { + return Vertex_around_face_circulator(this, f); + } + + /// returns circulator for halfedges of face \c f + Halfedge_around_face_circulator halfedges(Face f) const + { + return Halfedge_around_face_circulator(this, f); + } + + //@} + + + + + +public: //--------------------------------------------- higher-level operations + + /// \name Higher-level Topological Operations + //@{ + + /// returns whether the mesh a triangle mesh. this function simply tests + /// each face, and therefore is not very efficient. + /// \sa trianglate(), triangulate(Face) + bool is_triangle_mesh() const; + + /// triangulate the entire mesh, by calling triangulate(Face) for each face. + /// \sa trianglate(Face) + void triangulate(); + + /// triangulate the face \c f + /// \sa trianglate() + void triangulate(Face f); + + + /// returns whether collapsing the halfedge \c h is topologically legal. + /// \attention This function is only valid for triangle meshes. + bool is_collapse_ok(Halfedge h); + + /** Collapse the halfedge \c h by moving its start vertex into its target + vertex. For non-boundary halfedges this function removes one vertex, three + edges, and two faces. For boundary halfedges it removes one vertex, two + edges and one face. + \attention This function is only valid for triangle meshes. + \attention Halfedge collapses might lead to invalid faces. Call + is_collapse_ok(Halfedge) to be sure the collapse is legal. + \attention The removed items are only marked as deleted. You have + to call garbage_collection() to finally remove them. + */ + void collapse(Halfedge h); + + + /** Split the face \c f by first adding point \c p to the mesh and then + inserting edges between \c p and the vertices of \c f. For a triangle + this is a standard one-to-three split. + \sa split(Face, Vertex) + */ + Vertex split(Face f, const Point& p) { Vertex v=add_vertex(p); split(f,v); return v; } + + /** Split the face \c f by inserting edges between \c p and the vertices + of \c f. For a triangle this is a standard one-to-three split. + \sa split(Face, const Point&) + */ + void split(Face f, Vertex v); + + + /** Split the edge \c e by first adding point \c p to the mesh and then + connecting it to the two vertices of the adjacent triangles that are + opposite to edge \c e. + \attention This function is only valid for triangle meshes. + \sa split(Edge, Vertex) + */ + Vertex split(Edge e, const Point& p) { Vertex v=add_vertex(p); split(e,v); return v; } + + /** Split the edge \c e by connecting vertex \c v it to the two vertices + of the adjacent triangles that are opposite to edge \c e. + \attention This function is only valid for triangle meshes. + \sa split(Edge, Point) + */ + void split(Edge e, Vertex v); + + + /** Subdivide the edge \c e = (v0,v1) by splitting it into the two edge + (v0,p) and (p,v1). Note that this function does not introduce any other + edge or faces. It simply splits the edge. + \sa insert_vertex(Edge, Vertex) + */ + Vertex insert_vertex(Edge e, const Point& p) { Vertex v=add_vertex(p); insert_vertex(e,v); return v; } + + /** Subdivide the edge \c e = (v0,v1) by splitting it into the two edge + (v0,v) and (v,v1). Note that this function does not introduce any other + edge or faces. It simply splits the edge. + \sa insert_vertex(Edge, Point) + */ + void insert_vertex(Edge e, Vertex v); + + + /// insert edge between the to-vertices of h0 and h1. + /// \attention h0 and h1 have to belong to the same face + void insert_edge(Halfedge h0, Halfedge h1); + + + /** Check whether flipping edge \c e is topologically + \attention This function is only valid for triangle meshes. + \sa flip(Edge) + */ + bool is_flip_ok(Edge e) const; + + /** Flip edge \c e: Remove edge \c e and add an edge between the two vertices + opposite to edge \c e of the two incident triangles. + \attention This function is only valid for triangle meshes. + \sa is_flip_ok(Edge) + */ + void flip(Edge e); + + + /** returns the valence (number of incident edges or neighboring vertices) + of vertex \c v. */ + unsigned int valence(Vertex v) const; + + /// returns the valence of face \c f (its number of vertices) + unsigned int valence(Face f) const; + + //@} + + + + +public: //------------------------------------------ geometry-related functions + + /// \name Geometry-related Functions + //@{ + + /// position of a vertex (read only) + const Point& position(Vertex v) const { return vpoint_[v]; } + + /// position of a vertex + Point& position(Vertex v) { return vpoint_[v]; } + + /// compute face normals by calling compute_face_normal(Face) for each face. + void update_face_normals(); + + /// compute normal vector of face \c f. + Normal compute_face_normal(Face f) const; + + /// compute vertex normals by calling compute_vertex_normal(Vertex) for each vertex. + void update_vertex_normals(); + + /// compute normal vector of vertex \c v. + Normal compute_vertex_normal(Vertex v) const; + + /// compute the length of edge \c e. + Scalar edge_length(Edge e) const; + + //@} + + + + +private: //---------------------------------------------- allocate new elements + + /// allocate a new vertex, resize vertex properties accordingly. + Vertex new_vertex() + { + vprops_.push_back(); + return Vertex(vertices_size()-1); + } + + /// allocate a new edge, resize edge and halfedge properties accordingly. + Halfedge new_edge(Vertex start, Vertex end) + { + assert(start != end); + + eprops_.push_back(); + hprops_.push_back(); + hprops_.push_back(); + + Halfedge h0(halfedges_size()-2); + Halfedge h1(halfedges_size()-1); + + set_vertex(h0, end); + set_vertex(h1, start); + + return h0; + } + + /// allocate a new face, resize face properties accordingly. + Face new_face() + { + fprops_.push_back(); + return Face(faces_size()-1); + } + + + + +private: //--------------------------------------------------- helper functions + + /// find the halfedge from start to end + Halfedge find_halfedge(Vertex start, Vertex end) const; + + /** make sure that the outgoing halfedge of vertex v is a boundary halfedge + if v is a boundary vertex. */ + void adjust_outgoing_halfedge(Vertex v); + + /// Helper for halfedge collapse + void remove_edge(Halfedge h); + + /// Helper for halfedge collapse + void remove_loop(Halfedge h); + + /// are there deleted vertices, edges or faces? + bool garbage() const { return garbage_; } + + + +private: //------------------------------------------------------- private data + + friend bool read_poly(Surface_mesh& mesh, const std::string& filename); + + Property_container vprops_; + Property_container hprops_; + Property_container eprops_; + Property_container fprops_; + + Vertex_property vconn_; + Halfedge_property hconn_; + Face_property fconn_; + + Vertex_property vdeleted_; + Edge_property edeleted_; + Face_property fdeleted_; + + Vertex_property vpoint_; + Vertex_property vnormal_; + Face_property fnormal_; + + unsigned int deleted_vertices_; + unsigned int deleted_edges_; + unsigned int deleted_faces_; + bool garbage_; +}; + + +//------------------------------------------------------------ output operators + + +inline std::ostream& operator<<(std::ostream& os, Surface_mesh::Vertex v) +{ + return (os << 'v' << v.idx()); +} + +inline std::ostream& operator<<(std::ostream& os, Surface_mesh::Halfedge h) +{ + return (os << 'h' << h.idx()); +} + +inline std::ostream& operator<<(std::ostream& os, Surface_mesh::Edge e) +{ + return (os << 'e' << e.idx()); +} + +inline std::ostream& operator<<(std::ostream& os, Surface_mesh::Face f) +{ + return (os << 'f' << f.idx()); +} + + +//============================================================================= +/// @} +//============================================================================= +#endif // SURFACE_MESH_H +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Vector.h b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Vector.h new file mode 100644 index 00000000000..977eb9f1877 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/Vector.h @@ -0,0 +1,692 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +#ifndef SURFACE_MESH_VECTOR_H +#define SURFACE_MESH_VECTOR_H + + +//== INCLUDES ================================================================= + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#undef min +#undef max +#endif + + +/// \addtogroup geometry geometry +/// @{ + + + +//== CLASS DEFINITION ========================================================= + + +/** A vector class for an N-dimensional vector of scalar type T. + Elements of a vector v can be accessed by v[0], v[1], ... + For 3D vectors one can also use v.x, v.y and v.z. + */ +template +class Vector +{ +public: + + /// the scalar type of the vector + typedef Scalar value_type; + + /// returns the dimension of the vector + static int size() { return N; } + + + /// default constructor, creates uninitialized values. + Vector() {} + + /// construct from scalar s (fills all components with s) + explicit Vector(const Scalar s) + { + for (int i=0; i + explicit Vector(const Vector& o) + { + for (int i=0; i + operator Vector() + { + Vector v; + for (int i=0; i& operator=(const Scalar s) + { + for (int i=0; i + Vector& operator=(const Vector& o) + { + for (int i=0; i& other) const + { + for (int i=0; i& other) const + { + for (int i=0; i& operator*=(const Scalar s) + { + for (int i=0; i& operator/=(const Scalar s) + { + for (int i=0; i& operator-=(const Vector& v) + { + for (int i=0; i& operator+=(const Vector& v) + { + for (int i=0; i& normalize() + { + Scalar n = norm(*this); + if (n > std::numeric_limits::min()) + *this *= 1.0/n; + return *this; + } + + + /// return vector with minimum of this and other in each component + Vector minimize(const Vector& other) + { + for (int i = 0; i < N; ++i) + if (other[i] < data_[i]) + data_[i] = other[i]; + return *this; + } + + + /// return vector with maximum of this and other in each component + Vector maximize(const Vector& other) + { + for (int i = 0; i < N; ++i) + if (other[i] > data_[i]) + data_[i] = other[i]; + return *this; + } + + +public: + /** The N values of type Scalar are the only data members + of this class. This guarantees 100% compatibility with arrays of type + Scalar and size N, allowing us to define the cast operators to and from + arrays and array pointers */ + Scalar data_[N]; +}; + + + +//== FUNCTIONS ================================================================ + + +/// read the space-separated components of a vector from a stream +template +inline std::istream& operator>>(std::istream& is, Vector& vec) +{ + for (int i=0; i> vec[i]; + return is; +} + + +/// output a vector by printing its space-separated compontens +template +inline std::ostream& operator<<(std::ostream& os, const Vector& vec) +{ + for (int i=0; i +inline Vector operator-(const Vector& v) +{ + Vector vv; + for (int i=0; i +inline Vector operator*(const Scalar2 s, const Vector& v ) +{ + return Vector(v) *= (Scalar)s; +} + + +/// vector * scalar +template +inline Vector operator*(const Vector& v, const Scalar2 s) +{ + return Vector(v) *= (Scalar)s; +} + + +/// vector / scalar +template +inline Vector operator/(const Vector& v, const Scalar2 s) +{ + return Vector(v) /= Scalar(s); +} + + +/// vector + vector +template +inline Vector operator+(const Vector& v0, const Vector& v1) +{ + return Vector(v0) += v1; +} + + +/// vector - vector +template +inline Vector operator-(const Vector& v0, const Vector& v1) +{ + return Vector(v0) -= v1; +} + + +/// compute the Euclidean norm of a vector +template +inline Scalar norm(const Vector& v) +{ + Scalar s = v[0]*v[0]; + for (int i=1; i +inline Vector normalize(const Vector& v) +{ + return v/norm(v); +} + + +/// compute the squared Euclidean norm of a vector +template +inline Scalar sqrnorm(const Vector& v) +{ + Scalar s = v[0]*v[0]; + for (int i=1; i +inline Scalar dot(const Vector& v0, const Vector& v1) +{ + Scalar p = v0[0]*v1[0]; + for (int i=1; i +inline Scalar distance(const Vector& v0, const Vector& v1) +{ + Scalar dist(0), d; + for (int i=0; i +inline Vector cross(const Vector& v0, const Vector& v1) +{ + return Vector(v0[1]*v1[2] - v0[2]*v1[1], + v0[2]*v1[0] - v0[0]*v1[2], + v0[0]*v1[1] - v0[1]*v1[0]); +} + + +//== TEMPLATE SPECIALIZATIONS FOR 3D ========================================== + + +#if 1 + +template +class Vector +{ +public: + + typedef Scalar value_type; + static int size() { return 3; } + + + Vector() {} + + explicit Vector(const Scalar s) : x(s), y(s), z(s) {} + + Vector(const Scalar xx, const Scalar yy, const Scalar zz) + : x(xx), y(yy), z(zz) {} + + template + explicit Vector(const Vector& o) + : x((Scalar)o.x), y((Scalar)o.y), z((Scalar)o.z) {} + + template + operator Vector() + { + return Vector(x,y,z); + } + + operator Scalar*() { return &x;} + operator const Scalar*() const { return &x; } + const Scalar* data() const { return &x; } + + Scalar& operator[](unsigned int i) + { + assert(i<3); + return (&x)[i]; + } + + const Scalar operator[](unsigned int i) const + { + assert(i<3); + return (&x)[i]; + } + + Vector& operator=(const Scalar s) + { + x=y=z=s; + return *this; + } + + template + Vector& operator=(const Vector& o) + { + x = (Scalar)o.x; + y = (Scalar)o.y; + z = (Scalar)o.z; + return *this; + } + + bool operator==(const Vector& o) const + { + if (x != o.x) return false; + if (y != o.y) return false; + if (z != o.z) return false; + return true; + } + + bool operator!=(const Vector& o) const + { + if (x != o.x) return true; + if (y != o.y) return true; + if (z != o.z) return true; + return false; + } + + Vector& operator*=(const Scalar s) + { + x *= s; + y *= s; + z *= s; + return *this; + } + + Vector& operator/=(const Scalar s) + { + x /= s; + y /= s; + z /= s; + return *this; + } + + Vector& operator-=(const Vector& v) + { + x -= v.x; + y -= v.y; + z -= v.z; + return *this; + } + + Vector& operator+=(const Vector& v) + { + x += v.x; + y += v.y; + z += v.z; + return *this; + } + + Vector& normalize() + { + Scalar n = norm(*this); + n = (n > std::numeric_limits::min()) ? 1.0/n : 0.0; + x *= n; + y *= n; + z *= n; + return *this; + } + + Vector minimize(const Vector& o) + { + if (o.x < x) x = o.x; + if (o.y < y) y = o.y; + if (o.z < z) z = o.z; + return *this; + } + + Vector maximize(const Vector& o) + { + if (o.x > x) x = o.x; + if (o.y > y) y = o.y; + if (o.z > z) z = o.z; + return *this; + } + + +public: + + Scalar x,y,z; +}; + + +template +inline Vector operator-(const Vector& v) +{ + return Vector(-v.x, -v.y, -v.z); +} + +template +inline Vector operator*(const Scalar2 s, const Vector& v ) +{ + return Vector(v.x*Scalar(s), v.y*Scalar(s), v.z*Scalar(s)); +} + +template +inline Vector operator*(const Vector& v, const Scalar2 s) +{ + return Vector(v.x*Scalar(s), v.y*Scalar(s), v.z*Scalar(s)); +} + +template +inline Vector operator/(const Vector& v, const Scalar2 s) +{ + return Vector(v.x/s, v.y/s, v.z/s); +} + +template +inline Vector operator+(const Vector& v0, const Vector& v1) +{ + return Vector(v0.x+v1.x, v0.y+v1.y, v0.z+v1.z); +} + +template +inline Vector operator-(const Vector& v0, const Vector& v1) +{ + return Vector(v0.x-v1.x, v0.y-v1.y, v0.z-v1.z); +} + +template +inline Scalar norm(const Vector& v) +{ + Scalar s = v.x*v.x; + s += v.y*v.y; + s += v.z*v.z; + return (Scalar)sqrt(s); +} + +template +inline Scalar sqrnorm(const Vector& v) +{ + Scalar s = v.x*v.x; + s += v.y*v.y; + s += v.z*v.z; + return s; +} + +template +inline Vector normalize(const Vector& v) +{ + Scalar n = v.x*v.x; + n += v.y*v.y; + n += v.z*v.z; + n = (Scalar)sqrt(n); + return Vector(v.x/n, v.y/n, v.z/n); +} + +template +inline Scalar dot(const Vector& v0, const Vector& v1) +{ + Scalar s = v0.x*v1.x; + s += v0.y*v1.y; + s += v0.z*v1.z; + return s; +} + +template +inline Scalar distance(const Vector& v0, const Vector& v1) +{ + Scalar dist(0), d; + for (int i=0; i<3; ++i) + { + d = v0[i] - v1[i]; + d *= d; + dist += d; + } + return (Scalar)sqrt(dist); +} + +#endif + + + +//== TYPEDEFS ================================================================= + + +/** 2-byte signed vector */ +typedef Vector Vec2c; +/** 2-byte unsigned vector */ +typedef Vector Vec2uc; +/** 2-short signed vector */ +typedef Vector Vec2s; +/** 2-short unsigned vector */ +typedef Vector Vec2us; +/** 2-int signed vector */ +typedef Vector Vec2i; +/** 2-int unsigned vector */ +typedef Vector Vec2ui; +/** 2-float vector */ +typedef Vector Vec2f; +/** 2-double vector */ +typedef Vector Vec2d; + +/** 3-byte signed vector */ +typedef Vector Vec3c; +/** 3-byte unsigned vector */ +typedef Vector Vec3uc; +/** 3-short signed vector */ +typedef Vector Vec3s; +/** 3-short unsigned vector */ +typedef Vector Vec3us; +/** 3-int signed vector */ +typedef Vector Vec3i; +/** 3-int unsigned vector */ +typedef Vector Vec3ui; +/** 3-float vector */ +typedef Vector Vec3f; +/** 3-double vector */ +typedef Vector Vec3d; + +/** 4-byte signed vector */ +typedef Vector Vec4c; +/** 4-byte unsigned vector */ +typedef Vector Vec4uc; +/** 4-short signed vector */ +typedef Vector Vec4s; +/** 4-short unsigned vector */ +typedef Vector Vec4us; +/** 4-int signed vector */ +typedef Vector Vec4i; +/** 4-int unsigned vector */ +typedef Vector Vec4ui; +/** 4-float vector */ +typedef Vector Vec4f; +/** 4-double vector */ +typedef Vector Vec4d; + + +//============================================================================= +/// @} +//============================================================================= +#endif // VECTOR_H +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/properties.h b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/properties.h new file mode 100644 index 00000000000..2b36e4e761e --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/properties.h @@ -0,0 +1,413 @@ +//============================================================================= +// Copyright (C) 2001-2005 by Computer Graphics Group, RWTH Aachen +// Copyright (C) 2011 by Graphics & Geometry Group, Bielefeld University +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public License +// as published by the Free Software Foundation, version 2. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + + +#ifndef SURFACE_MESH_PROPERTY_H +#define SURFACE_MESH_PROPERTY_H + + +//== INCLUDES ================================================================= + + +#include +#include +#include +#include + + +//== CLASS DEFINITION ========================================================= + + +class Base_property_array +{ +public: + + /// Default constructor + Base_property_array(const std::string& name) : name_(name) {} + + /// Destructor. + virtual ~Base_property_array() {} + + /// Reserve memory for n elements. + virtual void reserve(size_t n) = 0; + + /// Resize storage to hold n elements. + virtual void resize(size_t n) = 0; + + /// Free unused memory. + virtual void free_memory() = 0; + + /// Extend the number of elements by one. + virtual void push_back() = 0; + + /// Let two elements swap their storage place. + virtual void swap(size_t i0, size_t i1) = 0; + + /// Return a deep copy of self. + virtual Base_property_array* clone () const = 0; + + /// Return the type_info of the property + virtual const std::type_info& type() = 0; + + /// Return the name of the property + const std::string& name() const { return name_; } + + +protected: + + std::string name_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +template +class Property_array : public Base_property_array +{ +public: + + typedef T value_type; + typedef std::vector vector_type; + typedef typename vector_type::reference reference; + typedef typename vector_type::const_reference const_reference; + + Property_array(const std::string& name, T t=T()) : Base_property_array(name), value_(t) {} + + +public: // virtual interface of Base_property_array + + virtual void reserve(size_t n) + { + data_.reserve(n); + } + + virtual void resize(size_t n) + { + data_.resize(n, value_); + } + + virtual void push_back() + { + data_.push_back(value_); + } + + virtual void free_memory() + { + vector_type(data_).swap(data_); + } + + virtual void swap(size_t i0, size_t i1) + { + T d(data_[i0]); + data_[i0]=data_[i1]; + data_[i1]=d; + } + + virtual Base_property_array* clone() const + { + Property_array* p = new Property_array(name_, value_); + p->data_ = data_; + return p; + } + + virtual const std::type_info& type() { return typeid(T); } + + +public: + + /// Get pointer to array (does not work for T==bool) + const T* data() const + { + return &data_[0]; + } + + /// Access the i'th element. No range check is performed! + reference operator[](int _idx) + { + assert( size_t(_idx) < data_.size() ); + return data_[_idx]; + } + + /// Const access to the i'th element. No range check is performed! + const_reference operator[](int _idx) const + { + assert( size_t(_idx) < data_.size()); + return data_[_idx]; + } + + + +private: + vector_type data_; + value_type value_; +}; + + +// specialization for bool properties +template <> +inline const bool* +Property_array::data() const +{ + assert(false); + return NULL; +} + + + +//== CLASS DEFINITION ========================================================= + + +template +class Property +{ +public: + + typedef typename Property_array::reference reference; + typedef typename Property_array::const_reference const_reference; + + friend class Property_container; + friend class Surface_mesh; + + +public: + + Property(Property_array* p=NULL) : parray_(p) {} + + void reset() + { + parray_ = NULL; + } + + operator bool() const + { + return parray_ != NULL; + } + + reference operator[](int i) + { + assert(parray_ != NULL); + return (*parray_)[i]; + } + + const_reference operator[](int i) const + { + assert(parray_ != NULL); + return (*parray_)[i]; + } + + const T* data() const + { + assert(parray_ != NULL); + return parray_->data(); + } + + +private: + + Property_array& array() + { + assert(parray_ != NULL); + return *parray_; + } + + const Property_array& array() const + { + assert(parray_ != NULL); + return *parray_; + } + + +private: + Property_array* parray_; +}; + + + +//== CLASS DEFINITION ========================================================= + + +class Property_container +{ +public: + + // default constructor + Property_container() : size_(0) {} + + // destructor (deletes all property arrays) + virtual ~Property_container() { clear(); } + + // copy constructor: performs deep copy of property arrays + Property_container(const Property_container& _rhs) { operator=(_rhs); } + + // assignment: performs deep copy of property arrays + Property_container& operator=(const Property_container& _rhs) + { + if (this != &_rhs) + { + clear(); + parrays_.resize(_rhs.n_properties()); + size_ = _rhs.size(); + for (unsigned int i=0; iclone(); + } + return *this; + } + + // returns the current size of the property arrays + size_t size() const { return size_; } + + // returns the number of property arrays + size_t n_properties() const { return parrays_.size(); } + + // returns a vector of all property names + std::vector properties() const + { + std::vector names; + for (unsigned int i=0; iname()); + return names; + } + + + // add a property with name \c name and default value \c t + template Property add(const std::string& name, const T t=T()) + { + // if a property with this name already exists, return an invalid property + for (unsigned int i=0; iname() == name) + { + std::cerr << "[Property_container] A property with name \"" + << name << "\" already exists. Returning invalid property.\n"; + return Property(); + } + } + + // otherwise add the property + Property_array* p = new Property_array(name, t); + p->resize(size_); + parrays_.push_back(p); + return Property(p); + } + + + // get a property by its name. returns invalid property if it does not exist. + template Property get(const std::string& name) const + { + for (unsigned int i=0; iname() == name) + return Property(dynamic_cast*>(parrays_[i])); + return Property(); + } + + + // returns a property if it exists, otherwise it creates it first. + template Property get_or_add(const std::string& name, const T t=T()) + { + Property p = get(name); + if (!p) p = add(name, t); + return p; + } + + + // get the type of property by its name. returns typeid(void) if it does not exist. + const std::type_info& get_type(const std::string& name) + { + for (unsigned int i=0; iname() == name) + return parrays_[i]->type(); + return typeid(void); + } + + + // delete a property + template void remove(Property& h) + { + std::vector::iterator it=parrays_.begin(), end=parrays_.end(); + for (; it!=end; ++it) + { + if (*it == h.parray_) + { + delete *it; + parrays_.erase(it); + h.reset(); + break; + } + } + } + + + // delete all properties + void clear() + { + for (unsigned int i=0; ireserve(n); + } + + // resize all arrays to size n + void resize(size_t n) + { + for (unsigned int i=0; iresize(n); + size_ = n; + } + + // free unused space in all arrays + void free_memory() const + { + for (unsigned int i=0; ifree_memory(); + } + + // add a new element to each vector + void push_back() + { + for (unsigned int i=0; ipush_back(); + ++size_; + } + + // swap elements i0 and i1 in all arrays + void swap(size_t i0, size_t i1) const + { + for (unsigned int i=0; iswap(i0, i1); + } + + +private: + std::vector parrays_; + size_t size_; +}; + + +//============================================================================= +#endif // SURFACE_MESH_PROPERTY_H +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/types.h b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/types.h new file mode 100644 index 00000000000..03b631b9830 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh/types.h @@ -0,0 +1,33 @@ +//============================================================================= + +#ifndef SURFACE_MESH_TYPES_H +#define SURFACE_MESH_TYPES_H + + +//== INCLUDES ================================================================= + +#include "Vector.h" + + +//== CLASS DEFINITION ========================================================= + + +/// Scalar type +typedef double Scalar; + +/// Point type +typedef Vector Point; + +/// Normal type +typedef Vector Normal; + +/// Color type +typedef Vector Color; + +/// Texture coordinate type +typedef Vector Texture_coordinate; + + +//============================================================================ +#endif +//============================================================================ diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh_performance.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh_performance.cpp new file mode 100644 index 00000000000..44860fdb457 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_2/surface_mesh_performance.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "surface_mesh_performance.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i("v:point"); + vnormals = mesh.vertex_property("v:normal"); + fnormals = mesh.face_property("f:normal"); + } + + +private: + + Surface_mesh mesh; + Surface_mesh::Vertex_property points; + Surface_mesh::Vertex_property vnormals; + Surface_mesh::Face_property fnormals; + + +private: + + void display_info() + { + std::cout << "#Darts=" << mesh.n_halfedges(); + std::cout << ", #0-cells=" << mesh.n_vertices(); + std::cout << ", #1-cells=" << mesh.n_edges(); + std::cout << ", #2-cells=" << mesh.n_faces(); + std::cout << "\t" << std::endl; + } + + virtual bool read_mesh(const char* _filename) + { + return mesh.read(_filename); + } + + + virtual bool write_mesh(const char* _filename) + { + return mesh.write(_filename); + } + + + virtual int circulator_test() + { + Surface_mesh::Vertex_iterator vit, vend=mesh.vertices_end(); + Surface_mesh::Face_iterator fit, fend=mesh.faces_end(); + + Surface_mesh::Face_around_vertex_circulator vfit, vfend; + Surface_mesh::Vertex_around_face_circulator fvit, fvend; + + int counter = 0; + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + { + vfit = vfend = mesh.faces(*vit); + if (vfit) do + { + ++counter; + } + while (++vfit != vfend); + } + + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + { + fvit = fvend = mesh.vertices(*fit); + do + { + --counter; + } + while (++fvit != fvend); + } + + return counter; + } + + + virtual void barycenter_test(bool draw) + { + Point p(0,0,0); + Surface_mesh::Vertex_iterator vit, vend=mesh.vertices_end(); + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + p += points[*vit]; + + p /= mesh.n_vertices(); + + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + points[*vit] -= p; + + if ( draw ) std::cout<<"Barycenter: "< new_pos = mesh.add_vertex_property("v:np"); + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + { + if (!mesh.is_boundary(*vit)) + { + Scalar n = mesh.valence(*vit); + Scalar alpha = (4.0 - 2.0*cos(2.0*M_PI/n)) / 9.0; + Point p(0,0,0); + Surface_mesh::Vertex_around_vertex_circulator vvit=mesh.vertices(*vit), vvend=vvit; + do + { + p += points[*vvit]; + } + while (++vvit != vvend); + p = (1.0f-alpha)*points[*vit] + alpha/n*p; + new_pos[*vit] = p; + } + } + + + // split faces + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + { + Point p(0,0,0); + Scalar c(0); + Surface_mesh::Vertex_around_face_circulator fvit = mesh.vertices(*fit), fvend=fvit; + do + { + p += points[*fvit]; + ++c; + } + while (++fvit!=fvend); + p /= c; + + mesh.split(*fit, p); + } + + + // set new positions of old vertices + for (vit=mesh.vertices_begin(); vit!=vend; ++vit) + if (!mesh.is_boundary(*vit)) + points[*vit] = new_pos[*vit]; + mesh.remove_vertex_property(new_pos); + + + // flip old edges + for (eit=mesh.edges_begin(); eit!=eend; ++eit) + if (mesh.is_flip_ok(*eit)) + mesh.flip(*eit); + } + + + virtual void collapse_test() + { + // reserve memory + int nv = mesh.n_vertices(); + int ne = mesh.n_edges(); + int nf = mesh.n_faces(); + mesh.reserve(nv+nf, ne+3*nf, 3*nf); + + + // iterators + Surface_mesh::Vertex_iterator vit, vend=mesh.vertices_end(); + Surface_mesh::Face_iterator fit, fend=mesh.faces_end(); + + // split faces + Point p(0,0,0); + for (fit=mesh.faces_begin(); fit!=fend; ++fit) + mesh.split(*fit, p); + + // collapse new edges + vit = vend; vend=mesh.vertices_end(); + for (; vit!=vend; ++vit) + mesh.collapse(mesh.halfedge(*vit)); + + // remove deleted items + mesh.garbage_collection(); + } + +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/CMakeLists.txt b/Linear_cell_complex/benchmark/Linear_cell_complex_3/CMakeLists.txt new file mode 100644 index 00000000000..82698c9694e --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/CMakeLists.txt @@ -0,0 +1,48 @@ +project(LCC_performance_3) + +cmake_minimum_required(VERSION 2.8) + +find_package(CGAL REQUIRED) +include(${CGAL_USE_FILE}) + +find_package(Boost 1.43.0) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) +else() + set (USE_IN_SOURCE_TREE_BOOST true) +endif() + +add_subdirectory(openvolumemesh) + +include_directories(BEFORE openvolumemesh/src) +include_directories(BEFORE "../../include") +include_directories(BEFORE "./cgogn" "./cgogn/include") +include_directories(BEFORE "/usr/include/libxml2/") +include_directories(BEFORE "/usr/include/eigen3/") + +LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/cgogn/lib/Release) + +find_package(Qt REQUIRED) +SET(QT_USE_QTSVG TRUE) +SET(QT_USE_QTXML TRUE ) +INCLUDE(${QT_USE_FILE}) +ADD_DEFINITIONS(${QT_DEFINITIONS}) + +add_definitions(-DINCLUDE_TEMPLATES) + +# Performance_3 +add_executable(performance_3 performance_3.cpp) +add_dependencies(performance_3 OpenVolumeMesh) +target_link_libraries(performance_3 OpenVolumeMesh boost_timer boost_system ${CGAL_LIBRARIES} algo assimp container nl topology utils Zinri z xml2 ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ${MAP_VIEWER_LIBRARIES}) + +# CGoGN +add_executable(cgogn_performance_3 performance_3.h cgogn_performance_3.h cgogn_performance_3.cpp) +target_link_libraries(cgogn_performance_3 algo assimp container nl topology utils Zinri z xml2 ${QT_LIBRARIES} ${QGLVIEWER_LIBRARIES} ) + +# LCC_3 +add_executable(lcc_performance_3 performance_3.h lcc_performance_3.h lcc_performance_3.cpp) +target_link_libraries(lcc_performance_3 ${CGAL_LIBRARIES} ${MAP_VIEWER_LIBRARIES}) + +# OpenVolumeMesh +add_executable(openvolumemesh_performance performance_3.h openvolumemesh_performance.h openvolumemesh_performance.cpp) +target_link_libraries(openvolumemesh_performance OpenVolumeMesh boost_timer boost_system) diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/Stop_watch.h b/Linear_cell_complex/benchmark/Linear_cell_complex_3/Stop_watch.h new file mode 100644 index 00000000000..b19e57773c6 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/Stop_watch.h @@ -0,0 +1,113 @@ +//============================================================================= + +#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_3/cgogn b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn new file mode 120000 index 00000000000..e1dd39d4a84 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn @@ -0,0 +1 @@ +/home/gdamiand/sources/codes-autres/CGoGN/install \ No newline at end of file diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn_performance_3.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn_performance_3.cpp new file mode 100644 index 00000000000..b9bb4d3bc76 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cgogn_performance_3.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "cgogn_performance_3.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i + +#include "Topology/generic/parameters.h" +#include "Topology/map/embeddedMap3.h" +#include "Topology/generic/traversor3.h" +#include "Topology/generic/traversorCell.h" +#include "Topology/generic/cellmarker.h" + +#include "Geometry/vector_gen.h" + +#include "Algo/Modelisation/tetrahedralization.h" + +#include "Algo/Import/import.h" +#include "Algo/Export/exportVol.h" + +#include "Container/fakeAttribute.h" + + +//== CLASS DEFINITION ========================================================= + +using namespace CGoGN ; + +#define TEST_QUICK 0 + +#define TEST_MR 1 + +struct PFP: public PFP_STANDARD +{ + // definition of the myMap + typedef EmbeddedMap3 MAP; +}; + + +class CGoGN_performance_3 : public Performance_test_3 +{ + +private: + PFP::MAP myMap; + VertexAttribute position; + VertexAttribute position_smooting; + VertexAttribute boundary_vertex; + +public: + + CGoGN_performance_3() : Performance_test_3() + { + position_smooting = myMap.addAttribute("positionSmoothing"); + } + + +private: + void display_info() + { + std::cout << "#Darts=" << myMap.getNbDarts(); + std::cout << ", #0-cells=" << myMap.getNbOrbits(); + std::cout << ", #1-cells=" << myMap.getNbOrbits(); + std::cout << ", #2-cells=" << myMap.getNbOrbits(); + std::cout << ", #3-cells=" << myMap.getNbOrbits(); + std::cout << "\t" << std::endl; + } + + Dart getShortestEdge() + { + double weight = std::numeric_limits::max(); + Dart dart = NIL; + bool boundary=false; + + TraversorE te(myMap); + for(Dart dit = te.begin() ; dit != te.end() ; dit = te.next()) + { + Dart dit1 = myMap.phi1(dit); + + boundary=false; + if (boundary_vertex[dit]==0) + { + if (myMap.isBoundaryVertex(dit)) + { + boundary=true; + boundary_vertex[dit]=1; + } + else + { + boundary_vertex[dit]=2; + } + } + else + { + boundary = (boundary_vertex[dit]==1); + } + if (boundary_vertex[dit1]==0) + { + if (myMap.isBoundaryVertex(dit1)) + { + boundary=true; + boundary_vertex[dit1]=1; + } + else + { + boundary_vertex[dit1]=2; + } + } + else + { + boundary = (boundary_vertex[dit1]==1); + } + + if (boundary) continue; + + PFP::VEC3 p1 = position[dit]; + PFP::VEC3 p0 = position[dit1]; + PFP::VEC3 v = (p1 - p0); + + double w = sqrt(v.norm2()); + if(w < weight) + { + weight = w; + dart = dit; + } + } + + return dart; + } + +private: + virtual bool read_mesh(const char* _filename) + { + std::vector attrNames ; + Algo::Volume::Import::importMesh(myMap, _filename, attrNames); + position = myMap.getAttribute(attrNames[0]); + + myMap.enableQuickTraversal(); + myMap.enableQuickTraversal(); + + // if enabled, don't forget activate disable functions in split_tet + myMap.enableQuickIncidentTraversal(); + myMap.enableQuickIncidentTraversal(); + + myMap.enableQuickAdjacentTraversal(); + myMap.enableQuickAdjacentTraversal(); + + return true; + } + + virtual bool write_mesh(const char* _filename) + { + // Algo::Volume::Export::exportTetmesh(myMap, position, _filename); + return true; + } + + virtual int circulator_test() + { + int counter = 0; + + + //for each vertex enumerate its incident volumes + TraversorV tv(myMap); + for(Dart dit = tv.begin() ; dit != tv.end() ; dit = tv.next()) + { + Traversor3VW tvw(myMap,dit); + for(Dart ditvw = tvw.begin() ; ditvw != tvw.end() ; ditvw = tvw.next()) + { + ++counter; + } + } + + //for each volumes enumerate its vertices + TraversorW tw(myMap); + for(Dart dit = tw.begin() ; dit != tw.end() ; dit = tw.next()) + { + Traversor3WV twv(myMap,dit); + for(Dart ditwv = twv.begin() ; ditwv != twv.end() ; ditwv = twv.next()) + { + --counter; + } + } + return counter; + } + + + virtual int circulator2_test() + { + int counter = 0; + //for each vertex enumerate its incident volumes + TraversorV tv(myMap); + for(Dart dit = tv.begin() ; dit != tv.end() ; dit = tv.next()) + { + Traversor3VVaW twv(myMap,dit); + for(Dart ditwv = twv.begin() ; ditwv != twv.end() ; ditwv = twv.next()) + { + ++counter; + } + } + return counter; + } + + virtual void barycenter_test(bool draw) + { + PFP::VEC3 sum(0.0, 0.0, 0.0); + + TraversorW tw(myMap); + for(Dart dit = tw.begin() ; dit != tw.end() ; dit = tw.next()) + { + PFP::VEC3 p = Algo::Surface::Geometry::volumeCentroid(myMap,dit,position); + sum += p; + } + + if ( draw ) std::cout<<"CGoGn::barycenter: "< tv(myMap); + for(Dart dit = tv.begin() ; dit != tv.end() ; dit = tv.next()) + { + PFP::VEC3 p(0.0); + unsigned int c = 0; + + Traversor3VVaE trav3VVaE(myMap, dit); + for(Dart dit3VVaF = trav3VVaE.begin() ; dit3VVaF != trav3VVaE.end() ; dit3VVaF = trav3VVaE.next()) + { + p += position[dit3VVaF]; + ++c; + } + p /= double(c); + + position_smooting[dit] = p; + } + + myMap.swapAttributes(position, position_smooting); + } + + virtual void split_tet_test() + { + myMap.disableQuickTraversal(); + myMap.disableQuickTraversal(); + + myMap.disableQuickIncidentTraversal(); + myMap.disableQuickIncidentTraversal(); + + myMap.disableQuickAdjacentTraversal(); + myMap.disableQuickAdjacentTraversal(); + + TraversorW tW(myMap); + for(Dart dit = tW.begin() ; dit != tW.end() ; dit = tW.next()) + { + typename PFP::VEC3 volCenter(0.0); + volCenter += position[dit]; + volCenter += position[myMap.phi1(dit)]; + volCenter += position[myMap.phi_1(dit)]; + volCenter += position[myMap.phi_1(myMap.phi2(dit))]; + volCenter /= 4; + + Dart dres = Algo::Volume::Modelisation::Tetrahedralization::flip1To4(myMap, dit); + position[dres] = volCenter; + } + } + + virtual void collapse_test(unsigned int n) + { + boundary_vertex = myMap.addAttribute("boundaryVertex"); + TraversorE te(myMap); + for(Dart dit = te.begin() ; dit != te.end() ; dit = te.next()) + boundary_vertex[dit]=0; + + for(unsigned int i = 0; i < n; ++i) + { + Dart dit = getShortestEdge(); + + if(dit == NIL) + { + std::cerr << "No valid edge anymore, aborting at step "<\".") +endif ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + +# allow only Debug and Release builds +set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) +mark_as_advanced (CMAKE_CONFIGURATION_TYPES) + +# set Debus as default build target +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Debug CACHE STRING + "Choose the type of build, options are: Debug, Release." + FORCE) +endif () + +# create our output directroy +if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build) + file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build) +endif () + +# read version from file +macro (acg_get_version) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${ARGN}/VERSION") + file (READ "${CMAKE_CURRENT_SOURCE_DIR}/${ARGN}/VERSION" _file) + else () + file (READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" _file) + endif () + + string ( + REGEX REPLACE + "^.*ID=([^\n]*).*$" "\\1" + _id ${_file} + ) + string ( + REGEX REPLACE + "^.*VERSION=([^\n]*).*$" "\\1" + _version ${_file} + ) + string ( + REGEX REPLACE + "^.*MAJOR=([^\n]*).*$" "\\1" + _major ${_file} + ) + string ( + REGEX REPLACE + "^.*MINOR=([^\n]*).*$" "\\1" + _minor ${_file} + ) + string ( + REGEX REPLACE + "^.*PATCH=([^\n]*).*$" "\\1" + _patch ${_file} + ) + + set (${_id}_VERSION ${_version}) + set (${_id}_VERSION_MAJOR ${_major}) + set (${_id}_VERSION_MINOR ${_minor}) + set (${_id}_VERSION_PATCH ${_patch}) +endmacro () + + +# set directory structures for the different platforms +if (WIN32) + set (ACG_PROJECT_DATADIR ".") + set (ACG_PROJECT_LIBDIR "lib") + set (ACG_PROJECT_BINDIR ".") + set (ACG_PROJECT_PLUGINDIR "Plugins") + if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}) + file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}) + endif () +else () + set (ACG_PROJECT_DATADIR "share/${CMAKE_PROJECT_NAME}") + set (ACG_PROJECT_LIBDIR "lib/${CMAKE_PROJECT_NAME}") + set (ACG_PROJECT_PLUGINDIR "lib/${CMAKE_PROJECT_NAME}/plugins") + set (ACG_PROJECT_BINDIR "bin") +endif () + +if( NOT APPLE ) + # check 64 bit + if( CMAKE_SIZEOF_VOID_P MATCHES 4 ) + set( HAVE_64_BIT 0 ) + else( CMAKE_SIZEOF_VOID_P MATCHES 4 ) + set( HAVE_64_BIT 1 ) + endif( CMAKE_SIZEOF_VOID_P MATCHES 4 ) +endif ( NOT APPLE ) + +# allow a project to modify the directories +if (COMMAND acg_modify_project_dirs) + acg_modify_project_dirs () +endif () + +if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_DATADIR}) + file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_DATADIR}) +endif () + + +# sets default build properties +macro (acg_set_target_props target) + if (WIN32) + set_target_properties ( + ${target} PROPERTIES + BUILD_WITH_INSTALL_RPATH 1 + SKIP_BUILD_RPATH 0 + ) + elseif (APPLE AND NOT ACG_PROJECT_MACOS_BUNDLE) + set_target_properties ( + ${target} PROPERTIES + #INSTALL_NAME_DIR "@executable_path/../lib/${CMAKE_PROJECT_NAME}" + INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_PROJECT_NAME}" +# BUILD_WITH_INSTALL_RPATH 1 + SKIP_BUILD_RPATH 0 + ) + elseif (NOT APPLE) + + set_target_properties ( + ${target} PROPERTIES + INSTALL_RPATH "$ORIGIN/../lib/${CMAKE_PROJECT_NAME}" + BUILD_WITH_INSTALL_RPATH 1 + SKIP_BUILD_RPATH 0 + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_BINDIR}" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}" + ) + endif () +endmacro () + +include (AddFileDependencies) +include (ACGCompiler) + +# define INCLUDE_TEMPLATES for everything we build +add_definitions (-DINCLUDE_TEMPLATES) + +# look for selected qt dependencies +macro (acg_qt4) + if (NOT QT4_FOUND) + find_package (Qt4 COMPONENTS QtCore QtGui ${ARGN}) + + set (QT_USE_QTOPENGL 1) + set (QT_USE_QTNETWORK 1) + set (QT_USE_QTSCRIPT 1) + set (QT_USE_QTSQL 1) + set (QT_USE_QTXML 1) + set (QT_USE_QTXMLPATTERNS 1) + set (QT_USE_QTHELP 1) + set (QT_USE_QTWEBKIT 1) + set (QT_USE_QTUITOOLS 1) + + include (${QT_USE_FILE}) + endif () +endmacro () + +# unsets the given variable +macro (acg_unset var) + set (${var} "" CACHE INTERNAL "") +endmacro () + +# sets the given variable +macro (acg_set var value) + set (${var} ${value} CACHE INTERNAL "") +endmacro () + +# test for OpenMP +macro (acg_openmp) + if (NOT OPENMP_NOTFOUND) + find_package(OpenMP) + if (OPENMP_FOUND) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + add_definitions(-DUSE_OPENMP) + else () + set (OPENMP_NOTFOUND 1) + endif () + endif () +endmacro () + +# test for FTGL +macro (acg_ftgl) + find_package (Freetype) + + if (FREETYPE_FOUND) + find_package (FTGL) + + if (FTGL_FOUND) + add_definitions (-DUSE_FTGL) + include_directories (${FTGL_INCLUDE_DIR} ${FREETYPE_INCLUDE_DIR_freetype2}) + set (FTGL_LIBS ${FREETYPE_LIBRARIES} ${FTGL_LIBRARIES}) + endif () + endif () +endmacro () + +# append all files with extension "ext" in the "dirs" directories to "ret" +# excludes all files starting with a '.' (dot) +macro (acg_append_files ret ext) + foreach (_dir ${ARGN}) + file (GLOB _files "${_dir}/${ext}") + foreach (_file ${_files}) + get_filename_component (_filename ${_file} NAME) + if (_filename MATCHES "^[.]") + list (REMOVE_ITEM _files ${_file}) + endif () + endforeach () + list (APPEND ${ret} ${_files}) + endforeach () +endmacro () + +# append all files with extension "ext" in the "dirs" directories and its subdirectories to "ret" +# excludes all files starting with a '.' (dot) +macro (acg_append_files_recursive ret ext) + foreach (_dir ${ARGN}) + file (GLOB_RECURSE _files "${_dir}/${ext}") + foreach (_file ${_files}) + get_filename_component (_filename ${_file} NAME) + if (_filename MATCHES "^[.]") + list (REMOVE_ITEM _files ${_file}) + endif () + endforeach () + list (APPEND ${ret} ${_files}) + endforeach () +endmacro () + + +# drop all "*T.cc" files from list +macro (acg_drop_templates list) + foreach (_file ${${list}}) + if (_file MATCHES "T.cc$") + list (REMOVE_ITEM ${list} ${_file}) + endif () + endforeach () +endmacro () + +# generate moc targets for sources in list +macro (acg_qt4_automoc moc_SRCS) + qt4_get_moc_flags (_moc_INCS) + + set (_matching_FILES ) + foreach (_current_FILE ${ARGN}) + + get_filename_component (_abs_FILE ${_current_FILE} ABSOLUTE) + # if "SKIP_AUTOMOC" is set to true, we will not handle this file here. + # here. this is required to make bouic work correctly: + # we need to add generated .cpp files to the sources (to compile them), + # but we cannot let automoc handle them, as the .cpp files don't exist yet when + # cmake is run for the very first time on them -> however the .cpp files might + # exist at a later run. at that time we need to skip them, so that we don't add two + # different rules for the same moc file + get_source_file_property (_skip ${_abs_FILE} SKIP_AUTOMOC) + + if ( NOT _skip AND EXISTS ${_abs_FILE} ) + + file (READ ${_abs_FILE} _contents) + + get_filename_component (_abs_PATH ${_abs_FILE} PATH) + + string (REGEX MATCHALL "Q_OBJECT" _match "${_contents}") + if (_match) + get_filename_component (_basename ${_current_FILE} NAME_WE) + set (_header ${_abs_FILE}) + set (_moc ${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp) + + add_custom_command (OUTPUT ${_moc} + COMMAND ${QT_MOC_EXECUTABLE} + ARGS ${_moc_INCS} ${_header} -o ${_moc} + DEPENDS ${_header} + ) + + add_file_dependencies (${_abs_FILE} ${_moc}) + set (${moc_SRCS} ${${moc_SRCS}} ${_moc}) + + endif () + endif () + endforeach () +endmacro () + +# generate uic targets for sources in list +macro (acg_qt4_autouic uic_SRCS) + + set (_matching_FILES ) + foreach (_current_FILE ${ARGN}) + + get_filename_component (_abs_FILE ${_current_FILE} ABSOLUTE) + + if ( EXISTS ${_abs_FILE} ) + + file (READ ${_abs_FILE} _contents) + + get_filename_component (_abs_PATH ${_abs_FILE} PATH) + + get_filename_component (_basename ${_current_FILE} NAME_WE) + string (REGEX REPLACE "Ui$" "" _cbasename ${_basename}) + set (_outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${_basename}.hh) + set (_header ${_basename}.hh) + set (_source ${_abs_PATH}/${_cbasename}.cc) + + add_custom_command (OUTPUT ${_outfile} + COMMAND ${QT_UIC_EXECUTABLE} + ARGS -o ${_outfile} ${_abs_FILE} + DEPENDS ${_abs_FILE}) + + add_file_dependencies (${_source} ${_outfile}) + set (${uic_SRCS} ${${uic_SRCS}} ${_outfile}) + + endif () + endforeach () +endmacro () + + +# generate qrc targets for sources in list +macro (acg_qt4_autoqrc qrc_SRCS) + + set (_matching_FILES ) + foreach (_current_FILE ${ARGN}) + + get_filename_component (_abs_FILE ${_current_FILE} ABSOLUTE) + + if ( EXISTS ${_abs_FILE} ) + + file (READ ${_abs_FILE} _contents) + + get_filename_component (_abs_PATH ${_abs_FILE} PATH) + + get_filename_component (_basename ${_current_FILE} NAME_WE) + set (_outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${_basename}.cpp) + + add_custom_command (OUTPUT ${_outfile} + COMMAND ${QT_RCC_EXECUTABLE} + ARGS -o ${_outfile} ${_abs_FILE} + DEPENDS ${_abs_FILE}) + + add_file_dependencies (${_source} ${_outfile}) + set (${qrc_SRCS} ${${qrc_SRCS}} ${_outfile}) + + endif () + endforeach () +endmacro () + +# get all files in directory, but ignore svn +macro (acg_get_files_in_dir ret dir) + file (GLOB_RECURSE __files RELATIVE "${dir}" "${dir}/*") + foreach (_file ${__files}) + if (NOT _file MATCHES ".*svn.*") + list (APPEND ${ret} "${_file}") + endif () + endforeach () +endmacro () + +# copy the whole directory without svn files +function (acg_copy_after_build target src dst) + acg_unset (_files) + acg_get_files_in_dir (_files ${src}) + foreach (_file ${_files}) + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${src}/${_file}" "${dst}/${_file}" + ) + endforeach () +endfunction () + +# install the whole directory without svn files +function (acg_install_dir src dst) + acg_unset (_files) + acg_get_files_in_dir (_files ${src}) + foreach (_file ${_files}) + get_filename_component (_file_PATH ${_file} PATH) + install(FILES "${src}/${_file}" + DESTINATION "${dst}/${_file_PATH}" + ) + endforeach () +endfunction () + +# extended version of add_executable that also copies output to out Build directory +function (acg_add_executable _target) + add_executable (${_target} ${ARGN}) + + # set common target properties defined in common.cmake + acg_set_target_props (${_target}) + + if (WIN32) + # copy exe file to "Build" directory + # Visual studio will create this file in a subdirectory so we can't use + # RUNTIME_OUTPUT_DIRECTORY directly here + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_target}.exe + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_BINDIR}/${_target}.exe) + elseif (APPLE AND NOT ACG_PROJECT_MACOS_BUNDLE) + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_target} + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_BINDIR}/${_target}) + endif () + if (NOT ACG_PROJECT_MACOS_BUNDLE OR NOT APPLE) + install (TARGETS ${_target} DESTINATION ${ACG_PROJECT_BINDIR}) + endif () +endfunction () + +# extended version of add_library that also copies output to out Build directory +function (acg_add_library _target _libtype) + + if (${_libtype} STREQUAL SHAREDANDSTATIC) + set (_type SHARED) + if (NOT WIN32) + set (_and_static 1) + else () + set (_and_static 0) + endif () + else () + set (_type ${_libtype}) + set (_and_static 0) + endif () + + add_library (${_target} ${_type} ${ARGN} ) + + # set common target properties defined in common.cmake + acg_set_target_props (${_target}) + + if (_and_static) + add_library (${_target}Static STATIC ${ARGN}) + + # set common target properties defined in common.cmake + acg_set_target_props (${_target}Static) + + if (NOT APPLE) + set_target_properties (${_target}Static PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" + ) + endif () + endif () + + if (WIN32) + # copy exe file to "Build" directory + # Visual studio will create this file in a subdirectory so we can't use + # RUNTIME_OUTPUT_DIRECTORY directly here + if (${_type} STREQUAL SHARED) + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_target}.dll + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_BINDIR}/${_target}.dll) + elseif (${_type} STREQUAL MODULE) + if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}) + file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}) + endif () + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_target}.dll + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}/${_target}.dll) + endif () + if (${_type} STREQUAL SHARED OR ${_type} STREQUAL STATIC) + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${_target}.lib + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}/${_target}.lib) + endif () + elseif (APPLE AND NOT ACG_PROJECT_MACOS_BUNDLE) + if (${_type} STREQUAL SHARED) + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}.dylib + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}/lib${_target}.dylib) + elseif (${_type} STREQUAL MODULE) + if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}) + file (MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}) + endif () + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}.so + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_PLUGINDIR}/lib${_target}.so) + elseif (${_type} STREQUAL STATIC) + add_custom_command (TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}.a + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}/lib${_target}.a) + endif () + if (_and_static) + add_custom_command (TARGET ${_target}Static POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}Static.a + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}/lib${_target}.a) + endif () + + elseif (NOT APPLE AND _and_static) + add_custom_command (TARGET ${_target}Static POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}Static.a + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_LIBDIR}/lib${_target}.a) + + endif () + + + # Block installation of libraries by setting ACG_NO_LIBRARY_INSTALL + if ( NOT ACG_NO_LIBRARY_INSTALL ) + if (NOT ACG_PROJECT_MACOS_BUNDLE OR NOT APPLE) + if (${_type} STREQUAL SHARED OR ${_type} STREQUAL STATIC ) + install (TARGETS ${_target} + RUNTIME DESTINATION ${ACG_PROJECT_BINDIR} + LIBRARY DESTINATION ${ACG_PROJECT_LIBDIR} + ARCHIVE DESTINATION ${ACG_PROJECT_LIBDIR}) + if (_and_static) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${_target}Static.a + DESTINATION ${ACG_PROJECT_LIBDIR} + RENAME lib${_target}.a + PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + endif () + elseif (${_type} STREQUAL MODULE) + install (TARGETS ${_target} DESTINATION ${ACG_PROJECT_PLUGINDIR}) + endif () + endif () + endif() + +endfunction () + +#generates qt translations +function (acg_add_translations _target _languages _sources) + + string (TOUPPER ${_target} _TARGET) + # generate/use translation files + # run with UPDATE_TRANSLATIONS set to on to build qm files + option (UPDATE_TRANSLATIONS_${_TARGET} "Update source translation *.ts files (WARNING: make clean will delete the source .ts files! Danger!)") + + set (_new_ts_files) + set (_ts_files) + + foreach (lang ${_languages}) + if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/translations/${_target}_${lang}.ts" OR UPDATE_TRANSLATIONS_${_TARGET}) + list (APPEND _new_ts_files "translations/${_target}_${lang}.ts") + else () + list (APPEND _ts_files "translations/${_target}_${lang}.ts") + endif () + endforeach () + + + set (_qm_files) + if ( _new_ts_files ) + qt4_create_translation(_qm_files ${_sources} ${_new_ts_files}) + endif () + + if ( _ts_files ) + qt4_add_translation(_qm_files2 ${_ts_files}) + list (APPEND _qm_files ${_qm_files2}) + endif () + + # create a target for the translation files ( and object files ) + # Use this target, to update only the translations + add_custom_target (translations_target_${_target} DEPENDS ${_qm_files}) + + # Build translations with the application + add_dependencies(${_target} translations_target_${_target} ) + + if (NOT EXISTS ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_DATADIR}/Translations) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_DATADIR}/Translations ) + endif () + + foreach (_qm ${_qm_files}) + get_filename_component (_qm_name "${_qm}" NAME) + add_custom_command (TARGET translations_target_${_target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E + copy_if_different + ${_qm} + ${CMAKE_BINARY_DIR}/Build/${ACG_PROJECT_DATADIR}/Translations/${_qm_name}) + endforeach () + + if (NOT ACG_PROJECT_MACOS_BUNDLE OR NOT APPLE) + install (FILES ${_qm_files} DESTINATION "${ACG_PROJECT_DATADIR}/Translations") + endif () +endfunction () diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGCompiler.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGCompiler.cmake new file mode 100644 index 00000000000..599f49c7d7d --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGCompiler.cmake @@ -0,0 +1,151 @@ +################################################################################ +# Custom settings for compiler flags and similar +################################################################################ + +if (UNIX) + + set ( ADDITIONAL_CXX_DEBUG_FLAGS ) + set ( ADDITIONAL_CXX_RELEASE_FLAGS ) + set ( ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS ) + + set ( ADDITIONAL_C_DEBUG_FLAGS ) + set ( ADDITIONAL_C_RELEASE_FLAGS ) + set ( ADDITIONAL_C_RELWITHDEBINFO_FLAGS ) + + ################################################################################ + # Defaults + ################################################################################ + + # add our standard flags for Template inclusion + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-DINCLUDE_TEMPLATES" ) + list(APPEND ADDITIONAL_CXX_RELEASE_FLAGS "-DINCLUDE_TEMPLATES" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-DINCLUDE_TEMPLATES" ) + + # add our standard flags for Template inclusion + list(APPEND ADDITIONAL_C_DEBUG_FLAGS "-DINCLUDE_TEMPLATES" ) + list(APPEND ADDITIONAL_C_RELEASE_FLAGS "-DINCLUDE_TEMPLATES" ) + list(APPEND ADDITIONAL_C_RELWITHDEBINFO_FLAGS "-DINCLUDE_TEMPLATES" ) + + # Increase the template depth as this might be exceeded from time to time + IF( NOT CMAKE_SYSTEM MATCHES "SunOS*") + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-ftemplate-depth-100" ) + list(APPEND ADDITIONAL_CXX_RELEASE_FLAGS "-ftemplate-depth-100" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-ftemplate-depth-100" ) + ENDIF() + + ################################################################################ + # OS Defines + ################################################################################ + + if (APPLE) + add_definitions( -DARCH_DARWIN ) + endif() + + ################################################################################ + # Build/Release Defines + ################################################################################ + IF( NOT CMAKE_SYSTEM MATCHES "SunOS*") + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-DDEBUG" ) + list(APPEND ADDITIONAL_CXX_RELEASE_FLAGS "-DNDEBUG" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-DDEBUG" ) + + list(APPEND ADDITIONAL_C_DEBUG_FLAGS "-DDEBUG" ) + list(APPEND ADDITIONAL_C_RELEASE_FLAGS "-DNDEBUG" ) + list(APPEND ADDITIONAL_C_RELWITHDEBINFO_FLAGS "-DDEBUG" ) + ENDIF() + + ################################################################################ + # Warnings + ################################################################################ + + IF( NOT CMAKE_SYSTEM MATCHES "SunOS*") + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-W" "-Wall" "-Wno-unused" ) + list(APPEND ADDITIONAL_CXX_RELEASE_FLAGS "-W" "-Wall" "-Wno-unused" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-W" "-Wall" "-Wno-unused" ) + + list(APPEND ADDITIONAL_C_DEBUG_FLAGS "-W" "-Wall" "-Wno-unused" ) + list(APPEND ADDITIONAL_C_RELEASE_FLAGS "-W" "-Wall" "-Wno-unused" ) + list(APPEND ADDITIONAL_C_RELWITHDEBINFO_FLAGS "-W" "-Wall" "-Wno-unused" ) + ENDIF() + + if (APPLE) + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-Wno-non-virtual-dtor" ) + list(APPEND ADDITIONAL_CXX_RELEASE_FLAGS "-Wno-non-virtual-dtor" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-Wno-non-virtual-dtor" ) + endif () + + ################################################################################ + # STL Vector checks + ################################################################################ + + # Pre initialize stl vector check variable + if ( NOT STL_VECTOR_CHECKS ) + set ( STL_VECTOR_CHECKS false CACHE BOOL "Include full stl vector checks in debug mode (This option is only used in debug Mode!)" ) + endif ( NOT STL_VECTOR_CHECKS ) + + # Add a flag to check stl vectors in debugging mode + if ( STL_VECTOR_CHECKS AND NOT CMAKE_SYSTEM MATCHES "SunOS*" ) + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-D_GLIBCXX_DEBUG" ) + list(APPEND ADDITIONAL_CXX_DEBUG_FLAGS "-D_GLIBCXX_DEBUG_PEDANTIC") + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-D_GLIBCXX_DEBUG" ) + list(APPEND ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS "-D_GLIBCXX_DEBUG_PEDANTIC") + + list(APPEND ADDITIONAL_C_DEBUG_FLAGS "-D_GLIBCXX_DEBUG" ) + list(APPEND ADDITIONAL_C_DEBUG_FLAGS "-D_GLIBCXX_DEBUG_PEDANTIC") + list(APPEND ADDITIONAL_C_RELWITHDEBINFO_FLAGS "-D_GLIBCXX_DEBUG" ) + list(APPEND ADDITIONAL_C_RELWITHDEBINFO_FLAGS "-D_GLIBCXX_DEBUG_PEDANTIC") + endif() + + ################################################################################ + # Process the additional flags: + ################################################################################ + + # Add the debug flags + foreach( flag ${ADDITIONAL_CXX_DEBUG_FLAGS} ) + if( NOT CMAKE_CXX_FLAGS_DEBUG MATCHES "${flag}" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${flag} ") + endif() + endforeach() + + # Add the release flags + foreach( flag ${ADDITIONAL_CXX_RELEASE_FLAGS} ) + if( NOT CMAKE_CXX_FLAGS_RELEASE MATCHES "${flag}" ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${flag} ") + endif() + endforeach() + + # Add the release with debug info flags + foreach( flag ${ADDITIONAL_CXX_RELWITHDEBINFO_FLAGS} ) + if( NOT CMAKE_CXX_FLAGS_RELWITHDEBINFO MATCHES "${flag}" ) + set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${flag} ") + endif() + endforeach() + + # Add the debug flags + foreach( flag ${ADDITIONAL_C_DEBUG_FLAGS} ) + if( NOT CMAKE_C_FLAGS_DEBUG MATCHES "${flag}" ) + set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${flag} ") + endif() + endforeach() + + # Add the release flags + foreach( flag ${ADDITIONAL_C_RELEASE_FLAGS} ) + if( NOT CMAKE_C_FLAGS_RELEASE MATCHES "${flag}" ) + set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${flag} ") + endif() + endforeach() + + # Add the release with debug info flags + foreach( flag ${ADDITIONAL_C_RELWITHDEBINFO_FLAGS} ) + if( NOT CMAKE_C_FLAGS_RELWITHDEBINFO MATCHES "${flag}" ) + set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${flag} ") + endif() + endforeach() + + #TODO : Test and remove it?! + IF( CMAKE_SYSTEM MATCHES "SunOS*") + set (CMAKE_CFLAGS_RELEASE "-xO3") + set (CMAKE_CXX_FLAGS_RELEASE "-xO3") + endif ( CMAKE_SYSTEM MATCHES "SunOS*" ) + +endif () diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGDoxygen.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGDoxygen.cmake new file mode 100644 index 00000000000..69cd6a8ce02 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGDoxygen.cmake @@ -0,0 +1,122 @@ +# -helper macro to add a "doc" target with CMake build system. +# and configure doxy.config.in to doxy.config +# +# target "doc" allows building the documentation with doxygen/dot on WIN32 and Linux +# Creates .chm windows help file if MS HTML help workshop +# (available from http://msdn.microsoft.com/workshop/author/htmlhelp) +# is installed with its DLLs in PATH. +# +# +# Please note, that the tools, e.g.: +# doxygen, dot, latex, dvips, makeindex, gswin32, etc. +# must be in path. +# +# Note about Visual Studio Projects: +# MSVS hast its own path environment which may differ from the shell. +# See "Menu Tools/Options/Projects/VC++ Directories" in VS 7.1 +# +# author Jan Woetzel 2004-2006 +# www.mip.informatik.uni-kiel.de/~jw + + +FIND_PACKAGE(Doxygen) + +IF (DOXYGEN_FOUND) + + # click+jump in Emacs and Visual Studio (for doxy.config) (jw) + IF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") + SET(DOXY_WARN_FORMAT "\"$file($line) : $text \"") + ELSE (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") + SET(DOXY_WARN_FORMAT "\"$file:$line: $text \"") + ENDIF (CMAKE_BUILD_TOOL MATCHES "(msdev|devenv)") + + # we need latex for doxygen because of the formulas + FIND_PACKAGE(LATEX) + IF (NOT LATEX_COMPILER) + MESSAGE(STATUS "latex command LATEX_COMPILER not found but usually required. You will probably get warnings and user inetraction on doxy run.") + ENDIF (NOT LATEX_COMPILER) + IF (NOT MAKEINDEX_COMPILER) + MESSAGE(STATUS "makeindex command MAKEINDEX_COMPILER not found but usually required.") + ENDIF (NOT MAKEINDEX_COMPILER) + IF (NOT DVIPS_CONVERTER) + MESSAGE(STATUS "dvips command DVIPS_CONVERTER not found but usually required.") + ENDIF (NOT DVIPS_CONVERTER) + + IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") + MESSAGE(STATUS "configured ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in --> ${CMAKE_CURRENT_BINARY_DIR}/doxy.config") + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in + ${CMAKE_CURRENT_BINARY_DIR}/doxy.config + @ONLY ) + # use (configured) doxy.config from (out of place) BUILD tree: + SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config") + ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") + # use static hand-edited doxy.config from SOURCE tree: + SET(DOXY_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") + IF (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") + MESSAGE(STATUS "WARNING: using existing ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config instead of configuring from doxy.config.in file.") + ELSE (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") + IF (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") + # using template doxy.config.in + MESSAGE(STATUS "configured ${CMAKE_CMAKE_MODULE_PATH}/doxy.config.in --> ${CMAKE_CURRENT_BINARY_DIR}/doxy.config") + CONFIGURE_FILE(${CMAKE_MODULE_PATH}/doxy.config.in + ${CMAKE_CURRENT_BINARY_DIR}/doxy.config + @ONLY ) + SET(DOXY_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/doxy.config") + ELSE (EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") + # failed completely... + MESSAGE(SEND_ERROR "Please create ${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in (or doxy.config as fallback)") + ENDIF(EXISTS "${CMAKE_MODULE_PATH}/doxy.config.in") + + ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config") + ENDIF(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/doxy.config.in") + + ADD_CUSTOM_TARGET(doc ${DOXYGEN_EXECUTABLE} ${DOXY_CONFIG}) + + # create a windows help .chm file using hhc.exe + # HTMLHelp DLL must be in path! + # fallback: use hhw.exe interactively + IF (WIN32) + FIND_PACKAGE(HTMLHelp) + IF (HTML_HELP_COMPILER) + SET (TMP "${CMAKE_CURRENT_BINARY_DIR}\\Doc\\html\\index.hhp") + STRING(REGEX REPLACE "[/]" "\\\\" HHP_FILE ${TMP} ) + # MESSAGE(SEND_ERROR "DBG HHP_FILE=${HHP_FILE}") + ADD_CUSTOM_TARGET(winhelp ${HTML_HELP_COMPILER} ${HHP_FILE}) + ADD_DEPENDENCIES (winhelp doc) + + IF (NOT TARGET_DOC_SKIP_INSTALL) + # install windows help? + # determine useful name for output file + # should be project and version unique to allow installing + # multiple projects into one global directory + IF (EXISTS "${PROJECT_BINARY_DIR}/Doc/html/index.chm") + IF (PROJECT_NAME) + SET(OUT "${PROJECT_NAME}") + ELSE (PROJECT_NAME) + SET(OUT "Documentation") # default + ENDIF(PROJECT_NAME) + IF (${PROJECT_NAME}_VERSION_MAJOR) + SET(OUT "${OUT}-${${PROJECT_NAME}_VERSION_MAJOR}") + IF (${PROJECT_NAME}_VERSION_MINOR) + SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_MINOR}") + IF (${PROJECT_NAME}_VERSION_PATCH) + SET(OUT "${OUT}.${${PROJECT_NAME}_VERSION_PATCH}") + ENDIF(${PROJECT_NAME}_VERSION_PATCH) + ENDIF(${PROJECT_NAME}_VERSION_MINOR) + ENDIF(${PROJECT_NAME}_VERSION_MAJOR) + # keep suffix + SET(OUT "${OUT}.chm") + + #MESSAGE("DBG ${PROJECT_BINARY_DIR}/Doc/html/index.chm \n${OUT}") + # create target used by install and package commands + INSTALL(FILES "${PROJECT_BINARY_DIR}/Doc/html/index.chm" + DESTINATION "doc" + RENAME "${OUT}" + ) + ENDIF(EXISTS "${PROJECT_BINARY_DIR}/Doc/html/index.chm") + ENDIF(NOT TARGET_DOC_SKIP_INSTALL) + + ENDIF(HTML_HELP_COMPILER) + # MESSAGE(SEND_ERROR "HTML_HELP_COMPILER=${HTML_HELP_COMPILER}") + ENDIF (WIN32) +ENDIF(DOXYGEN_FOUND) diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGOutput.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGOutput.cmake new file mode 100644 index 00000000000..1609c029f91 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/ACGOutput.cmake @@ -0,0 +1,38 @@ +# fill string with spaces +macro (acg_format_string str length return) + string (LENGTH "${str}" _str_len) + math (EXPR _add_chr "${length} - ${_str_len}") + set (${return} "${str}") + while (_add_chr GREATER 0) + set (${return} "${${return}} ") + math (EXPR _add_chr "${_add_chr} - 1") + endwhile () +endmacro () + +# print message with color escape sequences if CMAKE_COLOR_MAKEFILE is set +string (ASCII 27 _escape) +function (acg_color_message _str) + if (CMAKE_COLOR_MAKEFILE AND NOT WIN32) + message (${_str}) + else () + string (REGEX REPLACE "${_escape}.[0123456789;]*m" "" __str ${_str}) + message (${__str}) + endif () +endfunction () + +# info header +function (acg_print_configure_header _id _name) + acg_format_string ("${_name}" 40 _project) + acg_format_string ("${${_id}_VERSION}" 40 _version) + acg_color_message ("\n${_escape}[40;37m************************************************************${_escape}[0m") + acg_color_message ("${_escape}[40;37m* ${_escape}[1;31mACG ${_escape}[0;40;34mBuildsystem${_escape}[0m${_escape}[40;37m *${_escape}[0m") + acg_color_message ("${_escape}[40;37m* *${_escape}[0m") + acg_color_message ("${_escape}[40;37m* Package : ${_escape}[32m${_project} ${_escape}[37m *${_escape}[0m") + acg_color_message ("${_escape}[40;37m* Version : ${_escape}[32m${_version} ${_escape}[37m *${_escape}[0m") + acg_color_message ("${_escape}[40;37m************************************************************${_escape}[0m") +endfunction () + +# info line +function (acg_print_configure_footer) + acg_color_message ("${_escape}[40;37m************************************************************${_escape}[0m\n") +endfunction () diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/FindGoogleTest.cmake b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/FindGoogleTest.cmake new file mode 100644 index 00000000000..37bd9a812d6 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/FindGoogleTest.cmake @@ -0,0 +1,95 @@ +# Locate and configure the Google Test libraries. +# +# Defines the following variable: +# +# GTEST_FOUND - Found the Google Test libraries +# GTEST_INCLUDE_DIRS - The directories needed on the include paths +# GTEST_LIBRARIES - The libraries to link to test executables +# GTEST_MAIN_LIBRARIES - The libraries to link for automatic main() provision +# +# Copyright 2008 Chandler Carruth +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +if(GTEST_INCLUDE_DIRS AND GTEST_LIBRARIES AND GTEST_MAIN_LIBRARIES) + set(GTEST_FOUND true) +else(GTEST_INCLUDE_DIRS AND GTEST_LIBRARIES AND GTEST_MAIN_LIBRARIES) + set(GTEST_PREFIX "" CACHE PATH "Installation prefix for Google Test") + if(GTEST_PREFIX) + find_path(_GTEST_INCLUDE_DIR "gtest/gtest.h" + PATHS "${GTEST_PREFIX}/include" + NO_DEFAULT_PATH) + find_library(_GTEST_LIBRARY gtest + PATHS "${GTEST_PREFIX}/lib" + NO_DEFAULT_PATH) + find_library(_GTEST_MAIN_LIBRARY gtest_main + PATHS "${GTEST_PREFIX}/lib" + NO_DEFAULT_PATH) + + if ( _GTEST_LIBRARY ) + get_filename_component(_GTEST_LIBRARY_DIR ${_GTEST_LIBRARY} PATH CACHE ) + endif() + else(GTEST_PREFIX) + find_path(_GTEST_INCLUDE_DIR "gtest/gtest.h" + PATHS + ~/sw/gtest/include + /opt/local/include + /usr/local/include + "C:/libs/win32/gtest/include") + find_library(_GTEST_LIBRARY gtest + PATHS + ~/sw/gtest/lib + /opt/local/lib + /usr/local/lib + "C:/libs/win32/gtest/lib") + find_library(_GTEST_MAIN_LIBRARY gtest_main + PATHS + ~/sw/gtest/lib + /opt/local/lib + /usr/local/lib + "C:/libs/win32/gtest/lib") + + if ( _GTEST_LIBRARY ) + get_filename_component(_GTEST_LIBRARY_DIR ${_GTEST_LIBRARY} PATH CACHE ) + endif() + + endif(GTEST_PREFIX) + if(_GTEST_INCLUDE_DIR AND _GTEST_LIBRARY AND _GTEST_MAIN_LIBRARY) + set(GTEST_FOUND true) + set(GTEST_INCLUDE_DIRS ${_GTEST_INCLUDE_DIR} CACHE PATH + "Include directories for Google Test framework") + + if ( NOT WIN32 ) + set(GTEST_LIBRARIES ${_GTEST_LIBRARY} CACHE FILEPATH + "Libraries to link for Google Test framework") + set(GTEST_MAIN_LIBRARIES ${_GTEST_MAIN_LIBRARY} CACHE FILEPATH + "Libraries to link for Google Test automatic main() definition") + else() + set(GTEST_LIBRARIES "optimized;gtest;debug;gtestd" CACHE FILEPATH + "Libraries to link for Google Test framework") + set(GTEST_MAIN_LIBRARIES "optimized;gtest_main;debug;gtest_maind" CACHE FILEPATH + "Libraries to link for Google Test automatic main() definition") + endif() + + set(GTEST_LIBRARY_DIR ${_GTEST_LIBRARY_DIR} CACHE FILEPATH + "Library dir containing Google Test libraries") + mark_as_advanced(GTEST_INCLUDE_DIRS GTEST_LIBRARIES GTEST_MAIN_LIBRARIES GTEST_LIBRARY_DIR ) + if(NOT GoogleTest_FIND_QUIETLY) + message(STATUS "Found Google Test: ${GTEST_LIBRARIES}") + endif(NOT GoogleTest_FIND_QUIETLY) + else(_GTEST_INCLUDE_DIR AND _GTEST_LIBRARY AND _GTEST_MAIN_LIBRARY) + if(GoogleTest_FIND_REQUIRED) + message(FATAL_ERROR "Could not find the Google Test framework") + endif(GoogleTest_FIND_REQUIRED) + endif(_GTEST_INCLUDE_DIR AND _GTEST_LIBRARY AND _GTEST_MAIN_LIBRARY) +endif(GTEST_INCLUDE_DIRS AND GTEST_LIBRARIES AND GTEST_MAIN_LIBRARIES) diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.in b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.in new file mode 100644 index 00000000000..a655b26d9be --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.in @@ -0,0 +1,57 @@ +# gp_item_default_embedded_path_override item default_embedded_path_var +# +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# This is a project-specific override of BundleUtilities.cmake's +# gp_item_default_embedded_path +# +function(gp_item_default_embedded_path_override item default_embedded_path_var) + + # By default, embed items as set by gp_item_default_embedded_path: + # + set(path "${${default_embedded_path_var}}") + + # But for OpenFlipper... + # + # ...embed *.dylib in the Libraries folder: + # + if(item MATCHES "\\.dylib$") + set(path "@executable_path/../Libraries") + endif() + + # ...embed qt plugins in the Libraries folder: + # + if(item MATCHES "@QT_PLUGINS_DIR@" AND item MATCHES "\\.bundle") + file (RELATIVE_PATH _plugin "@QT_PLUGINS_DIR@" "${item}") + get_filename_component(_dir "${_plugin}" PATH) + set(path "@executable_path/../Resources/QtPlugins/${_dir}") + endif() + + # ...embed *.so in the Plugins folder: + # + if(item MATCHES "\\.so$") + set(path "@executable_path/../Resources/Plugins") + endif() + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction(gp_item_default_embedded_path_override) + +include (BundleUtilities) + +# copy qt plugins to bundle +file (GLOB _plugins "@CMAKE_BINARY_DIR@/Build/OpenFlipper.app/Contents/Resources/Plugins/*.so") +file (GLOB_RECURSE _qtplugins "@QT_PLUGINS_DIR@/*.bundle") +foreach (_qtp ${_qtplugins}) + get_filename_component(_dir "${_qtp}" PATH) + list(APPEND _qtdirs "${_dir}") +endforeach () + +# Get library paths +get_filename_component(_GlutDir "@GLUT_glut_LIBRARY@" PATH) + +# fix all dependencies +fixup_bundle (@CMAKE_BINARY_DIR@/Build/bin/QtViewer "${_qtplugins}" "/usr/lib;${_qtdirs};${_GlutDir}") + +# create qt plugin configuration file +# file(WRITE "@CMAKE_BINARY_DIR@/Build/OpenVolumeMesh.app/Contents/Resources/qt.conf" "[Paths]\nPlugins = Resources/QtPlugins") diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.win.in b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.win.in new file mode 100644 index 00000000000..08469532a26 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/cmake/fixbundle.cmake.win.in @@ -0,0 +1,24 @@ +# gp_item_default_embedded_path_override item default_embedded_path_var +# +# Return the path that others should refer to the item by when the item +# is embedded inside a bundle. +# +# This is a project-specific override of BundleUtilities.cmake's +# gp_item_default_embedded_path +# +function(gp_item_default_embedded_path_override item default_embedded_path_var) + + # By default, embed items as set by gp_item_default_embedded_path: + # + set(path "${${default_embedded_path_var}}") + + set(${default_embedded_path_var} "${path}" PARENT_SCOPE) +endfunction(gp_item_default_embedded_path_override) + +include (BundleUtilities) + +# Get library paths +get_filename_component(_GlutDir "@GLUT_glut_LIBRARY@" PATH) + +# fix all dependencies +fixup_bundle ("@CMAKE_BINARY_DIR@/Build/QtViewer.exe" "" "${_GlutDir};@QT_BINARY_DIR@") diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/lcc_performance_3.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_3/lcc_performance_3.cpp new file mode 100644 index 00000000000..10623280c91 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/lcc_performance_3.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "lcc_performance_3.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i +#include +#include +#include + +#include +#include +#include +#include +#include "performance_3.h" + +// Comment to use cmap with handle +#define CMAP_WITH_INDEX 1 + +//== CLASS DEFINITION ========================================================= + +typedef CGAL::Simple_cartesian Kernel; +typedef Kernel::Point_3 Point_3; +typedef CGAL::Vector_3 Vector_3; + +struct Info_for_vertex +{ + Info_for_vertex() : v(CGAL::NULL_VECTOR), m(0) + {} + + Vector_3 v; + int m; +}; + +struct Info_for_volume +{ + Info_for_volume() : m(0) + {} + + int m; +}; + +#ifndef CMAP_WITH_INDEX + +struct MyItem +{ + template + struct Dart_wrapper + { + typedef CGAL::Dart<3, Refs> Dart; + + typedef CGAL::Cell_attribute_with_point Vertex_attribute; + + typedef CGAL::Cell_attribute Vol_attribute; + + typedef CGAL::cpp0x::tuple Attributes; + }; +}; + +typedef CGAL::Linear_cell_complex<3,3,CGAL::Linear_cell_complex_traits<3,Kernel>, MyItem> LCC_3; + +#else + +struct MyItem +{ + template + struct Dart_wrapper + { + typedef CGAL::Dart_for_index<3, Refs> Dart; + + typedef CGAL::Cell_attribute_for_index_with_point Vertex_attribute; + + typedef CGAL::Cell_attribute_for_index Vol_attribute; + + typedef CGAL::cpp0x::tuple Attributes; + }; +}; + +typedef CGAL::Linear_cell_complex_for_index<3,3,CGAL::Linear_cell_complex_traits<3,Kernel>, MyItem> LCC_3; + +#endif + +typedef LCC_3::Dart_handle Dart_handle; +typedef LCC_3::Vertex_attribute_handle Vertex_handle; +typedef LCC_3::Attribute_handle<3>::type Volume_handle; +typedef LCC_3::Point Point; +typedef LCC_3::Vector Vector; +typedef LCC_3::FT FT; + + +//== CLASS DEFINITION ========================================================= + +class LCC_performance_3 : public Performance_test_3 +{ + +private: + + LCC_3 lcc; + CGAL::Unique_hash_map, + typename LCC_3::Hash_function > adjacent_vertices; + +private: + void update_accelerators() + { + // We use accelerators, similarly than in cgogn. the only difference is that in cgogn + // they are use internally (i.e inside the library) while here they are use externally + // (i.e. inside the benchmarks). + // Note that in the current bench, they use 4 accelerators: + // 1) indicent VERTEX, VOLUME; 2) incident VOLUME, VERTEX; + // 3) adjacent VERTEX, EDGE; 4) adjacent VERTEX, VOLUME + + // Here we only use adjacent VERTEX, EDGE and indicent VERTEX, VOLUME. + + // First we update all adjacent vertices + adjacent_vertices.clear(); + for (LCC_3::Vertex_attribute_range::iterator vit = lcc.vertex_attributes().begin(), + vend = lcc.vertex_attributes().end(); vit != vend; ++vit) + { + std::vector adj; + for(LCC_3::One_dart_per_incident_cell_range<1,0>::iterator + it = lcc.one_dart_per_incident_cell<1,0>(vit->dart()).begin(), + itend = lcc.one_dart_per_incident_cell<1,0>(vit->dart()).end(); + it != itend; ++it) + { + if ( lcc.vertex_attribute(it)==vit ) + { + adj.push_back(lcc.vertex_attribute(lcc.other_extremity(it))); + } + else + { + adj.push_back(lcc.vertex_attribute(it)); + } + } + + adjacent_vertices[vit]=adj; + } + } + + void display_info() + { + lcc.display_characteristics(std::cout); + std::cout << "\t" << std::endl; + } + + void collapse(Dart_handle dart) + { + std::vector tet_ring; + + // Get ring of tets + // incident to the current edge + + Dart_handle iter = dart; + do + { + tet_ring.push_back(iter); + + // Go over to adjacent tet in tet-ring + iter = lcc.beta<2,3>(iter); + } + while(iter != dart); + + // Get top vertex + Dart_handle topVertex = dart; + Dart_handle botVertex = lcc.beta<1>(dart); + + // Get barycenter of current edge + Point bc = lcc.barycenter<1>(dart); + + // Set geometry of top and bottom vertex to barycenter of former edge + lcc.point(topVertex) = bc; + lcc.point(botVertex) = bc; + + // 0=not known; 1=boundary; 2=no boundary + if ( lcc.info<0>(topVertex).m==1 ) + lcc.info<0>(botVertex).m = 1; + else if ( lcc.info<0>(topVertex).m==0 ) + lcc.info<0>(botVertex).m = 0; + + if ( lcc.info<0>(botVertex).m==1 ) + lcc.info<0>(topVertex).m = 1; + else if ( lcc.info<0>(botVertex).m==0 ) + lcc.info<0>(topVertex).m = 0; + + // Delete tets in ring + for(std::vector::const_iterator cr_it = tet_ring.begin(), + cr_end = tet_ring.end(); + cr_it != cr_end; + ++cr_it) + { + Dart_handle top = lcc.beta<1,2,3>(*cr_it); + Dart_handle bottom = lcc.beta<0,2,3>(*cr_it); + CGAL::remove_cell(lcc, *cr_it); + lcc.sew<3>(top,bottom); + } + } + + Dart_handle create_face(Dart_handle old1, + Vertex_handle v1, Vertex_handle v2, Vertex_handle v3, + Volume_handle vol) + { + Dart_handle old2 = lcc.beta<2>(old1); + + Dart_handle d1=lcc.create_dart(v1); + Dart_handle d2=lcc.create_dart(v2); + Dart_handle d3=lcc.create_dart(v3); + lcc.set_dart_attribute<3>(d1,vol); + lcc.set_dart_attribute<3>(d2,vol); + lcc.set_dart_attribute<3>(d3,vol); + + lcc.basic_link_beta_1(d1,d2); + lcc.basic_link_beta_1(d2,d3); + lcc.basic_link_beta_1(d3,d1); + + Dart_handle dd1=lcc.create_dart(v2); + Dart_handle dd2=lcc.create_dart(v1); + Dart_handle dd3=lcc.create_dart(v3); + lcc.set_dart_attribute<3>(dd1,vol); + lcc.set_dart_attribute<3>(dd2,vol); + lcc.set_dart_attribute<3>(dd3,vol); + + lcc.basic_link_beta_1(dd1,dd2); + lcc.basic_link_beta_1(dd2,dd3); + lcc.basic_link_beta_1(dd3,dd1); + + lcc.basic_link_beta_for_involution<3>(d1,dd1); + lcc.basic_link_beta_for_involution<3>(d2,dd3); + lcc.basic_link_beta_for_involution<3>(d3,dd2); + + lcc.basic_link_beta_for_involution<2>(old1,d1); + lcc.basic_link_beta_for_involution<2>(old2,dd1); + + return lcc.beta<1>(d1); + } + + Dart_handle tet_split(Dart_handle d1) + { + Point_3 c = LCC_3::Traits::Construct_translated_point() + (CGAL::ORIGIN, barycenter_3(d1)); + + Dart_handle d2=lcc.beta<1,2>(d1); + Dart_handle d3=lcc.beta<2>(d1); + Dart_handle d4=lcc.beta<1,2>(d3); + + Vertex_handle v0 = lcc.create_vertex_attribute(c); + Vertex_handle v1 = lcc.vertex_attribute(d1); + Vertex_handle v2 = lcc.vertex_attribute(d2); + Vertex_handle v3 = lcc.vertex_attribute(d3); + Vertex_handle v4 = lcc.vertex_attribute(d4); + + Dart_handle n1 = create_face(d1, v3, v1, v0, lcc.attribute<3>(d1)); + Dart_handle n2 = create_face(d2, v3, v2, v0, lcc.attribute<3>(d1)); + Dart_handle n3 = create_face(lcc.beta<0>(d1), v1, v2, v0, lcc.attribute<3>(d1)); + Dart_handle n4 = create_face(lcc.beta<0>(d2), v4, v2, v0, lcc.attribute<3>(d1)); + Dart_handle n5 = create_face(d4, v1, v4, v0, lcc.attribute<3>(d1)); + Dart_handle n6 = create_face(lcc.beta<1>(d2), v4, v3, v0, lcc.attribute<3>(d1)); + + lcc.basic_link_beta_for_involution<2>(n1, lcc.beta<1>(n3)); + lcc.basic_link_beta_for_involution<2>(lcc.beta<1>(n1),lcc.beta<1,3>(n2)); + + lcc.basic_link_beta_for_involution<2>(lcc.beta<3>(n1),lcc.beta<1,3>(n5)); + lcc.basic_link_beta_for_involution<2>(lcc.beta<1,3>(n1),lcc.beta<3>(n6)); + + lcc.basic_link_beta_for_involution<2>(n2, lcc.beta<1>(n4)); + lcc.basic_link_beta_for_involution<2>(lcc.beta<1>(n2), n6); + lcc.basic_link_beta_for_involution<2>(lcc.beta<3>(n2), n3); + + lcc.basic_link_beta_for_involution<2>(lcc.beta<3>(n3), lcc.beta<1,3>(n4)); + lcc.basic_link_beta_for_involution<2>(lcc.beta<1,3>(n3), lcc.beta<1>(n5)); + + lcc.basic_link_beta_for_involution<2>(lcc.beta<3>(n4), n5); + lcc.basic_link_beta_for_involution<2>(n4, lcc.beta<1>(n6)); + + lcc.basic_link_beta_for_involution<2>(lcc.beta<3>(n5), lcc.beta<1,3>(n6)); + + lcc.set_attribute<3>(d2, lcc.create_attribute<3>()); + lcc.set_attribute<3>(d3, lcc.create_attribute<3>()); + lcc.set_attribute<3>(d4, lcc.create_attribute<3>()); + + return d1; + } + + bool isBoundary(const Dart_handle& _dart) + { + // 0=not known; 1=boundary; 2=no boundary + if ( lcc.info<0>(_dart).m==1 || + lcc.info<0>(lcc.beta<1>(_dart)).m==1 ) return true; + + // Both endpoints have to lie in the interior of the mesh + if ( lcc.info<0>(_dart).m==0 ) + { + for(LCC_3::Dart_of_cell_range<0>::iterator + vv_it = lcc.darts_of_cell<0>(_dart).begin(), + vv_itend = lcc.darts_of_cell<0>(_dart).end(); + vv_it != vv_itend; ++vv_it) + { + if(lcc.is_free<3>(vv_it)) + { + lcc.info<0>(_dart).m = 1; + return true; + } + } + lcc.info<0>(_dart).m = 2; + } + + if ( lcc.info<0>(lcc.beta<1>(_dart)).m==0 ) + { + for(LCC_3::Dart_of_cell_range<0>::iterator + vv_it = lcc.darts_of_cell<0>(lcc.beta<1>(_dart)).begin(), + vv_itend = lcc.darts_of_cell<0>(lcc.beta<1>(_dart)).end(); + vv_it != vv_itend; ++vv_it) + { + if (lcc.is_free<3>(vv_it)) + { + lcc.info<0>(vv_it).m = 1; + return true; + } + } + lcc.info<0>(lcc.beta<1>(_dart)).m = 2; + } + + return false; + } + + Dart_handle getShortestEdge() + { + double weight = std::numeric_limits::max(); + Dart_handle dart = lcc.null_dart_handle; + + int m=lcc.get_new_mark(); + for (typename LCC_3::Dart_range::iterator e_it=lcc.darts().begin(), e_end=lcc.darts().end(); + e_it != e_end; ++e_it) + { + if ( !lcc.is_marked(e_it, m) ) + { + CGAL::mark_cell(lcc, e_it, m); + if( !isBoundary(e_it) ) + { + Point p1 = lcc.point(e_it); + Point p0 = lcc.point(lcc.other_extremity(e_it)); + Vector v = (p1 - p0); + + double w = sqrt(v.squared_length()); + if(w < weight) + { + weight = w; + dart = e_it; + } + } + } + } + lcc.free_mark(m); + return dart; + } + + +private: + + virtual bool read_mesh(const char* _filename) + { + // variables + size_t i, num_vertices, num_tetras; + std::vector points; + std::string line; + std::stringstream sStream; + + // try to open the file + std::ifstream fin(_filename); + if(!fin) + return false; + + // load number of vertices + + // skip Vertices label + std::getline(fin, line); + + std::getline(fin, line); // num_vertices x + sStream << line; + sStream >> num_vertices; + sStream.clear(); + + // reverse the order of the vertices + points.reserve(num_vertices); + + for(i = 0; i < num_vertices; ++i) + { + float x, y, z; + std::getline(fin, line); + sStream << line; + sStream >> x >> y >> z; + std::getline(sStream, line); + sStream.clear(); + + points.push_back(LCC_3::Point(x,y,z)); + } + + // skip Tetrahedra label + std::getline(fin, line); + + // read number of tetraeders + std::getline(fin, line); // num_tetras x + sStream << line; + sStream >> num_tetras; + sStream.clear(); + + + for(i = 0; i < num_tetras; ++i) + { + int v0,v1,v2,v3; + //int m; + std::getline(fin, line); + sStream << line; + sStream >> v0 >> v1 >> v2 >> v3; + std::getline(sStream, line); + sStream.clear(); + + Dart_handle dart= + lcc.make_tetrahedron(points[v0-1], points[v1-1], points[v2-1], points[v3-1]); + lcc.set_attribute<3>(dart, lcc.create_attribute<3>()); + } + + lcc.sew3_same_facets(); + + // close file + fin.close(); + // finished + + // display_lcc(lcc); + + update_accelerators(); + + return true; + } + + virtual bool write_mesh(const char *_filename) + { + return true; + } + + virtual int circulator_test() + { + int counter = 0; + + int m = lcc.get_new_mark(); + + //for each vertex enumerate its incident volumes + for (LCC_3::Vertex_attribute_range::iterator vit = lcc.vertex_attributes().begin(), + vend = lcc.vertex_attributes().end(); vit != vend; ++vit) + { + for (LCC_3::Dart_of_cell_basic_range<0>::iterator + vv_it = lcc.darts_of_cell_basic<0>(vit->dart(), m).begin(), + vv_itend = lcc.darts_of_cell_basic<0>(vit->dart(), m).end(); + vv_it != vv_itend; ++vv_it) + { + lcc.mark(vv_it, m); + if (!lcc.info<3>(vv_it).m) + { + lcc.info<3>(vv_it).m = 1; + ++counter; + } + } + lcc.negate_mark(m); + for (LCC_3::Dart_of_cell_basic_range<0>::iterator + vv_it = lcc.darts_of_cell_basic<0>(vit->dart(), m).begin(), + vv_itend = lcc.darts_of_cell_basic<0>(vit->dart(), m).end(); + vv_it != vv_itend; ++vv_it) + { + lcc.mark(vv_it, m); + if (lcc.info<3>(vv_it).m) + { + lcc.info<3>(vv_it).m = 0; + } + } + lcc.negate_mark(m); + } + + assert( lcc.is_whole_map_unmarked(m) ); + + //for each volume enumerate its incident vertices + for (LCC_3::Attribute_range<3>::type::iterator vit = lcc.attributes<3>().begin(), + vend = lcc.attributes<3>().end(); vit != vend; ++vit) + { + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(vit->dart(), m).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(vit->dart(), m).end(); + vv_it != vv_itend; ++vv_it) + { + if (!lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 1; + --counter; + } + } + lcc.negate_mark(m); + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(vit->dart(), m).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(vit->dart(), m).end(); + vv_it != vv_itend; ++vv_it) + { + if (lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 0; + } + } + lcc.negate_mark(m); + } + + assert( lcc.is_whole_map_unmarked(m) ); + lcc.free_mark(m); + + return counter; + } + + virtual int circulator2_test() + { + int counter = 0; + + //for each vertex enumerate its vertices adjacent through a common volume. + int m = lcc.get_new_mark(); + int m2 = lcc.get_new_mark(); + + for (LCC_3::Vertex_attribute_range::iterator vit = lcc.vertex_attributes().begin(), + vend = lcc.vertex_attributes().end(); vit != vend; ++vit) + { + vit->info().m = 1; + for (LCC_3::Dart_of_cell_basic_range<0>::iterator + v_it = lcc.darts_of_cell_basic<0>(vit->dart(), m).begin(), + v_itend = lcc.darts_of_cell_basic<0>(vit->dart(), m).end(); + v_it != v_itend; ++v_it) + { + if ( !lcc.is_marked(v_it, m2) ) + { + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(v_it, m2).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(v_it, m2).end(); + vv_it != vv_itend; ++vv_it) + { + lcc.mark(vv_it, m2); + + if (!lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 1; + ++counter; + } + } + } + } + + // Here we unmark things + lcc.negate_mark(m); + lcc.negate_mark(m2); + vit->info().m = 0; + for (LCC_3::Dart_of_cell_basic_range<0>::iterator + v_it = lcc.darts_of_cell_basic<0>(vit->dart(), m).begin(), + v_itend = lcc.darts_of_cell_basic<0>(vit->dart(), m).end(); + v_it != v_itend; ++v_it) + { + if ( !lcc.is_marked(v_it, m2) ) + { + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(v_it, m2).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(v_it, m2).end(); + vv_it != vv_itend; ++vv_it) + { + lcc.mark(vv_it, m2); + + if (lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 0; + } + } + } + } + lcc.negate_mark(m2); + lcc.negate_mark(m); + } + + assert( lcc.is_whole_map_unmarked(m) ); + assert( lcc.is_whole_map_unmarked(m2) ); + lcc.free_mark(m); + lcc.free_mark(m2); + + return counter; + } + + virtual void barycenter_test(bool draw) + { + Vector_3 s(CGAL::NULL_VECTOR); + + for (LCC_3::Attribute_range<3>::type::iterator vit = lcc.attributes<3>().begin(), + vend = lcc.attributes<3>().end(); vit != vend; ++vit) + { + s = s + barycenter_3(vit->dart()); + } + if (draw) std::cout<<"LCC::barycenter: "<::iterator it= adjacent_vertices[vit].begin(), + itend=adjacent_vertices[vit].end(); it!=itend; ++it ) + { + v = v + (lcc.point_of_vertex_attribute(*it) - CGAL::ORIGIN); + ++valence; + } + + v = v / double(valence); + + vit->info().v = v; + } + + // Update all vertices's positions + for (LCC_3::Vertex_attribute_range::iterator vit = lcc.vertex_attributes().begin(), + vend = lcc.vertex_attributes().end(); vit != vend; ++vit) + { + lcc.point_of_vertex_attribute(vit) = CGAL::ORIGIN + lcc.info_of_attribute<0>(vit).v; + } + } + + virtual void split_tet_test() + { + LCC_3::Attribute_range<3>::type::iterator vit = lcc.attributes<3>().begin(), + vend = lcc.attributes<3>().end(); + --vend; + while ( vit!=vend ) + { + Dart_handle d = vit->dart(); + ++vit; + tet_split(d); + } + tet_split(vend->dart()); + } + + virtual void collapse_test(unsigned int n) + { + for(unsigned int i = 0; i < n; ++i) + { + Dart_handle dart = getShortestEdge(); + + if(dart == lcc.null_dart_handle) + { + std::cerr << "No valid edge anymore, aborting at step "<(dart).m = 0; + lcc.info<0>(lcc.other_extremity(dart)).m = 0; + + CGAL::contract_cell(lcc, dart); + } + + for (LCC_3::Vertex_attribute_range::iterator vit = lcc.vertex_attributes().begin(), + vend = lcc.vertex_attributes().end(); vit != vend; ++vit) + { + vit->info().m = 0; + } + + } + + Vector_3 barycenter_3(Dart_handle d) + { + int m = lcc.get_new_mark(); + + Vector_3 v = CGAL::NULL_VECTOR; + int count=0; + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(d, m).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(d, m).end(); + vv_it != vv_itend; ++vv_it) + { + if (!lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 1; + v = v + (lcc.point(vv_it)- CGAL::ORIGIN); + ++count; + } + } + // Unmark + lcc.negate_mark(m); + for (LCC_3::Dart_of_cell_basic_range<3>::iterator + vv_it = lcc.darts_of_cell_basic<3>(d, m).begin(), + vv_itend = lcc.darts_of_cell_basic<3>(d, m).end(); + vv_it != vv_itend; ++vv_it) + { + if (lcc.info<0>(vv_it).m) + { + lcc.info<0>(vv_it).m = 0; + } + } + + lcc.free_mark(m); + return v/count; + } +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh b/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh new file mode 120000 index 00000000000..d6a38774787 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh @@ -0,0 +1 @@ +/home/gdamiand/sources/codes-autres/OpenVolumeMesh \ No newline at end of file diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh_performance.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh_performance.cpp new file mode 100644 index 00000000000..52c16c7f3d4 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/openvolumemesh_performance.cpp @@ -0,0 +1,20 @@ +//== INCLUDES ================================================================= +#include "openvolumemesh_performance.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\n" << argv[0] << " \n"; + exit(1); + } + + for (int i=1; i +#include +#include + +#include "performance_3.h" +#include +#include +#include +#include + + +//== CLASS DEFINITION ========================================================= + + +using namespace OpenVolumeMesh; + +class OpenVolumeMesh_performance : public Performance_test_3 +{ +private: + + typedef Geometry::Vec3d Vec3d; + typedef GeometryKernel Mesh; + Mesh mesh; + + OpenVolumeMesh::VertexPropertyT* boundary_vertex; + +public: + + OpenVolumeMesh_performance() : Performance_test_3() + { + + } + + +private: + + void display_info() + { + std::cout << "#0-cells=" << mesh.n_vertices(); + std::cout << ", #1-cells=" << mesh.n_edges(); + std::cout << ", #2-cells=" << mesh.n_faces(); + std::cout << ", #3-cells=" << mesh.n_cells(); + std::cout << "\t" << std::endl; + } + + void edge_collapse(const EdgeHandle& _eh) + { + Vec3d p = mesh.barycenter(_eh); + + // Get vertices incident to edge _eh + const VertexHandle cvh = mesh.edge(_eh).from_vertex(); + const VertexHandle tvh = mesh.edge(_eh).to_vertex(); + + const HalfEdgeHandle he = mesh.halfedge_handle(_eh, 0); + + std::set toBeProcessed; + + // Get all cells incident to the center vertex + for(VertexCellIter vc_it = mesh.vc_iter(cvh); vc_it.valid(); ++vc_it) + { + toBeProcessed.insert(*vc_it); + } + + // Exclude cells incident to edge _eh from this set + // These are the cells that need new geometry + for(HalfEdgeCellIter hec_it = mesh.hec_iter(he); hec_it.valid(); ++hec_it) + { + toBeProcessed.erase(*hec_it); + } + + // Create a new cell for each of the cells in toBeProcessed + // The new cells are now incident to the top vertex instead + // of the one in the center + std::vector< std::vector > newCells; + for(std::set::const_iterator c_it = toBeProcessed.begin(), c_end = toBeProcessed.end(); c_it != c_end; ++c_it) + { + + std::vector newVertices; + + const std::vector& hfs = mesh.cell(*c_it).halffaces(); + for(HalfFaceVertexIter hfv_it = mesh.hfv_iter(*hfs.begin()); hfv_it.valid(); ++hfv_it) + { + VertexHandle nvh = (*hfv_it == cvh ? tvh : *hfv_it); + nvh.idx((nvh.idx() > cvh.idx() ? nvh.idx() - 1 : nvh.idx())); + newVertices.push_back(nvh); + } + + HalfFaceHandle curHF = *hfs.begin(); + HalfEdgeHandle curHE = *mesh.halfface(curHF).halfedges().begin(); + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + curHE = mesh.opposite_halfedge_handle(curHE); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle nextVH = mesh.halfedge(curHE).to_vertex(); + + nextVH = (nextVH == cvh ? tvh : nextVH); + nextVH.idx((nextVH.idx() > cvh.idx() ? nextVH.idx() - 1 : nextVH.idx())); + + newVertices.push_back(nextVH); + + newCells.push_back(newVertices); + } + + // Set position of top vertex to be the barycenter + // of edge _eh + mesh.set_vertex(tvh, p); + + // Delete center vertex + // This deletes all incident edges, faces, and cells, too + mesh.delete_vertex(cvh); + + // Create a new tet for each of the cells in toBeProcessed + for(std::vector< std::vector >::const_iterator nc_it = newCells.begin(), + nc_end = newCells.end(); nc_it != nc_end; ++nc_it) + { + if(!createTet(*nc_it)) + { + std::cerr << "Error: Could not create tet!" << std::endl; + return; + } + } + } + + + // Find the mesh's shortest edge + EdgeHandle getShortestEdge() + { + double max_weight = std::numeric_limits::max(); + EdgeHandle eh = Mesh::InvalidEdgeHandle; + bool boundary=false; + + for(OpenVolumeMesh::EdgeIter e_it = mesh.edges_begin(), + e_end = mesh.edges_end(); e_it != e_end; ++e_it) + { + + const OpenVolumeMesh::VertexHandle& v0 = mesh.edge(*e_it).from_vertex(); + const OpenVolumeMesh::VertexHandle& v1 = mesh.edge(*e_it).to_vertex(); + + boundary=false; + if ((*boundary_vertex)[v0]==0) + { + if (mesh.is_boundary(v0)) + { + boundary=true; + (*boundary_vertex)[v0]=1; + } + else + { + (*boundary_vertex)[v0]=2; + } + } + else + { + boundary = ((*boundary_vertex)[v0]==1); + } + if ((*boundary_vertex)[v1]==0) + { + if (mesh.is_boundary(v1)) + { + boundary=true; + (*boundary_vertex)[v1]=1; + } + else + { + (*boundary_vertex)[v1]=2; + } + } + else + { + boundary = ((*boundary_vertex)[v1]==1); + } + + if (boundary) continue; + + double l = mesh.length(*e_it); + if(l < max_weight) + { + max_weight = l; + eh = *e_it; + } + } + + return eh; + } + + + /* + * Create a new tetrahedron with the specified vertices. + * + * v2 v3 + * O--O + * / \ | + * / \| + * O-----O + * v0 v1 + * + * The vertices have to be in the order depicted above. + */ + CellHandle createTet(const std::vector& _vs) + { + std::vector tvs; + tvs.resize(3); + + tvs[0] = _vs[0]; + tvs[1] = _vs[1]; + tvs[2] = _vs[2]; + + HalfFaceHandle hf0 = mesh.halfface(tvs); + + if(!hf0.is_valid()) + { + // Create face + hf0 = mesh.halfface_handle(mesh.add_face(tvs), 0); + } + + tvs[0] = _vs[0]; + tvs[1] = _vs[2]; + tvs[2] = _vs[3]; + + HalfFaceHandle hf1 = mesh.halfface(tvs); + + if(!hf1.is_valid()) + { + // Create face + hf1 = mesh.halfface_handle(mesh.add_face(tvs), 0); + } + + tvs[0] = _vs[1]; + tvs[1] = _vs[3]; + tvs[2] = _vs[2]; + + HalfFaceHandle hf2 = mesh.halfface(tvs); + + if(!hf2.is_valid()) + { + // Create face + hf2 = mesh.halfface_handle(mesh.add_face(tvs), 0); + } + + tvs[0] = _vs[0]; + tvs[1] = _vs[3]; + tvs[2] = _vs[1]; + + HalfFaceHandle hf3 = mesh.halfface(tvs); + + if(!hf3.is_valid()) + { + // Create face + hf3 = mesh.halfface_handle(mesh.add_face(tvs), 0); + } + + if(hf0.is_valid() && hf1.is_valid() && + hf2.is_valid() && hf3.is_valid()) + { + + std::vector hfs; + hfs.push_back(hf0); hfs.push_back(hf1); + hfs.push_back(hf2); hfs.push_back(hf3); + + return mesh.add_cell(hfs, true); + } + + std::cerr << "Could not create cell!" << std::endl; + return Mesh::InvalidCellHandle; + } + +private: + + virtual bool read_mesh(const char* _filename) + { + bool checkTopo = false; + bool computeBottomUpIncidences = true; // Incidence Dependent Iterators need bottom-up incidences to be computed before they can be used. + + IO::FileManager fileManager; + bool res = fileManager.readFile(_filename, mesh, checkTopo, computeBottomUpIncidences); + + return res; + } + + + virtual bool write_mesh(const char* _filename) + { + // IO::FileManager fileManager; + // return fileManager.writeFile(_filename, mesh); + return true; + } + + + virtual int circulator_test() + { + int counter = 0; + + //for each vertex enumerate its incident volumes + for(VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) + { + for(VertexCellIter vc_it = mesh.vc_iter(*v_it); vc_it.valid(); ++vc_it) + { + ++counter; + } + } + + //for each volumes enumerate its vertices + for(CellIter c_it = mesh.cells_begin(); c_it != mesh.cells_end(); ++c_it) + { + for(CellVertexIter cv_it = mesh.cv_iter(*c_it); cv_it.valid(); ++cv_it) + { + --counter; + } + } + + return counter; + } + + virtual int circulator2_test() + { + int counter = 0; + + //for each vertex enumerate its vertices adjacent through a common volume. + for(VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) + { + for(VertexCellIter vc_it = mesh.vc_iter(*v_it); vc_it.valid(); ++vc_it) + { + for(CellVertexIter cv_it = mesh.cv_iter(*vc_it); cv_it.valid(); ++cv_it) + { + ++counter; + } + } + } + + return counter; + } + + virtual void barycenter_test(bool draw) + { + Vec3d sum(0.0, 0.0, 0.0); + + //for each volumes + for(CellIter c_it = mesh.cells_begin(); c_it != mesh.cells_end(); ++c_it) + { + Vec3d p = mesh.barycenter(*c_it); + sum += p; + } + if ( draw ) std::cout<<"OVM::barycenter: "< position_smoothing = mesh.request_vertex_property("positionSmoothing"); + + for(VertexIter v_it = mesh.vertices_begin(), v_end = mesh.vertices_end() ; + v_it != v_end ; + ++v_it) + { + Vec3d p(0.0); + unsigned int c = 0; + + for(VertexOHalfEdgeIter vh_it = mesh.voh_iter(*v_it); vh_it.valid(); ++vh_it) + { + p += mesh.vertex(mesh.halfedge(*vh_it).to_vertex()); + ++c; + } + + p /= double(c); + + position_smoothing[*v_it] = p; + } + + // Update positions + for(VertexIter v_it = mesh.vertices_begin(), v_end = mesh.vertices_end(); v_it != v_end; ++v_it) + { + mesh.set_vertex(*v_it, position_smoothing[*v_it]); + } + } + + + virtual void split_tet_test() + { + mesh.enable_edge_bottom_up_incidences(false); + + unsigned int n = mesh.n_cells(); + const unsigned int n_c = n; + + for(CellIter c_it = mesh.cells_begin(); n-- > 0; ++c_it) + { + /* + * Compute geometry of inner cells and add them + * to the mesh afterwards + * + * In the end, all cells up until cell + * with index n_c will be deleted in one chunk + */ + + Vec3d c = mesh.barycenter(*c_it); + + // Center vertex + VertexHandle vhc = mesh.add_vertex(c); + + // Get first half-face + HalfFaceHandle curHF = *mesh.cell(*c_it).halffaces().begin(); + + HalfFaceHandle ohf0, ohf1, ohf2, ohf3; + ohf0 = curHF; + + // Get first half-edge + HalfEdgeHandle curHE = *mesh.halfface(curHF).halfedges().begin(); + + VertexHandle vh0 = mesh.halfedge(curHE).from_vertex(); + + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh1 = mesh.halfedge(curHE).from_vertex(); + + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh2 = mesh.halfedge(curHE).from_vertex(); + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + curHE = mesh.opposite_halfedge_handle(curHE); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh3 = mesh.halfedge(curHE).to_vertex(); + + ohf3 = curHF; + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + curHE = mesh.opposite_halfedge_handle(curHE); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + ohf1 = curHF; + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + + ohf2 = curHF; + + std::vector vs(3); + + vs[0] = vh2; vs[1] = vh1; vs[2] = vhc; + FaceHandle fh0 = mesh.add_face(vs); + + vs[0] = vh0; vs[1] = vh2; vs[2] = vhc; + FaceHandle fh1 = mesh.add_face(vs); + + vs[0] = vh1; vs[1] = vh0; vs[2] = vhc; + FaceHandle fh2 = mesh.add_face(vs); + + vs[0] = vh2; vs[1] = vh3; vs[2] = vhc; + FaceHandle fh3 = mesh.add_face(vs); + + vs[0] = vh3; vs[1] = vh1; vs[2] = vhc; + FaceHandle fh4 = mesh.add_face(vs); + + vs[0] = vh3; vs[1] = vh0; vs[2] = vhc; + FaceHandle fh5 = mesh.add_face(vs); + + std::vector hfs(4); + + hfs[0] = mesh.halfface_handle(fh0, 0); + hfs[1] = mesh.halfface_handle(fh1, 0); + hfs[2] = mesh.halfface_handle(fh2, 0); + hfs[3] = ohf0; + mesh.add_cell(hfs); + + hfs[0] = mesh.halfface_handle(fh3, 0); + hfs[1] = mesh.halfface_handle(fh4, 0); + hfs[2] = mesh.halfface_handle(fh0, 1); + hfs[3] = ohf1; + mesh.add_cell(hfs); + + hfs[0] = mesh.halfface_handle(fh2, 1); + hfs[1] = mesh.halfface_handle(fh4, 1); + hfs[2] = mesh.halfface_handle(fh5, 0); + hfs[3] = ohf2; + mesh.add_cell(hfs); + + hfs[0] = mesh.halfface_handle(fh1, 1); + hfs[1] = mesh.halfface_handle(fh3, 1); + hfs[2] = mesh.halfface_handle(fh5, 1); + hfs[3] = ohf3; + mesh.add_cell(hfs); + } + + CellIter first = mesh.cells_begin(); + CellIter last = mesh.cells_begin(); + + // Delete all former cells in one chunk + last += n_c; + mesh.delete_cell_range(first, last); + + mesh.enable_edge_bottom_up_incidences(true); + } + + virtual void collapse_test(unsigned int n) + { + OpenVolumeMesh::VertexPropertyT tmp= mesh.request_vertex_property("boundaryVertex"); + boundary_vertex = &tmp; + + for(VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) + (*boundary_vertex)[*v_it] = 0; + + mesh.enable_bottom_up_incidences(true); + + for(unsigned int i = 0; i < n; ++i) + { + EdgeHandle eh = getShortestEdge(); + + if(!eh.is_valid()) + { + std::cerr << "No valid edge anymore, aborting at step "< save; + + unsigned int n = mesh.n_cells(); + const unsigned int n_c = n; + + for(CellIter c_it = mesh.cells_begin(); n-- > 0; ++c_it) + { + // + // Compute geometry of inner cells and add them + // to the mesh afterwards + // + // In the end, all cells up until cell + // with index n_c will be deleted in one chunk + /// + + Vec3d c = mesh.barycenter(*c_it); + + // Center vertex + VertexHandle vhc = mesh.add_vertex(c); + + // Get first half-face + HalfFaceHandle curHF = *mesh.cell(*c_it).halffaces().begin(); + + HalfFaceHandle ohf0, ohf1, ohf2, ohf3; + ohf0 = curHF; + + // Get first half-edge + HalfEdgeHandle curHE = *mesh.halfface(curHF).halfedges().begin(); + + VertexHandle vh0 = mesh.halfedge(curHE).from_vertex(); + + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh1 = mesh.halfedge(curHE).from_vertex(); + + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh2 = mesh.halfedge(curHE).from_vertex(); + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + curHE = mesh.opposite_halfedge_handle(curHE); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + VertexHandle vh3 = mesh.halfedge(curHE).to_vertex(); + + ohf3 = curHF; + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + curHE = mesh.opposite_halfedge_handle(curHE); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + curHE = mesh.next_halfedge_in_halfface(curHE, curHF); + + ohf1 = curHF; + + curHF = mesh.adjacent_halfface_in_cell(curHF, curHE); + + ohf2 = curHF; + + std::vector vs(3); + + vs[0] = vh2; vs[1] = vh1; vs[2] = vhc; + FaceHandle fh0 = mesh.add_face(vs); + + vs[0] = vh0; vs[1] = vh2; vs[2] = vhc; + FaceHandle fh1 = mesh.add_face(vs); + + vs[0] = vh1; vs[1] = vh0; vs[2] = vhc; + FaceHandle fh2 = mesh.add_face(vs); + + vs[0] = vh2; vs[1] = vh3; vs[2] = vhc; + FaceHandle fh3 = mesh.add_face(vs); + + vs[0] = vh3; vs[1] = vh1; vs[2] = vhc; + FaceHandle fh4 = mesh.add_face(vs); + + vs[0] = vh3; vs[1] = vh0; vs[2] = vhc; + FaceHandle fh5 = mesh.add_face(vs); + + std::vector hfs(4); + + hfs[0] = mesh.halfface_handle(fh0, 0); + hfs[1] = mesh.halfface_handle(fh1, 0); + hfs[2] = mesh.halfface_handle(fh2, 0); + hfs[3] = ohf0; + mesh.add_cell(hfs); + + // Save center half edge handle + //HalfEdgeHandle t = *mesh.halfface(hfs[2]).halfedges().begin(); + //HalfEdgeHandle t2 = mesh.next_halfedge_in_halfface(t,hfs[2]); + HalfEdgeHandle t2 = mesh.halfedge(vhc, vh0); + save.push_back(t2); + + hfs[0] = mesh.halfface_handle(fh3, 0); + hfs[1] = mesh.halfface_handle(fh4, 0); + hfs[2] = mesh.halfface_handle(fh0, 1); + hfs[3] = ohf1; + mesh.add_cell(hfs); + + hfs[0] = mesh.halfface_handle(fh2, 1); + hfs[1] = mesh.halfface_handle(fh4, 1); + hfs[2] = mesh.halfface_handle(fh5, 0); + hfs[3] = ohf2; + mesh.add_cell(hfs); + + hfs[0] = mesh.halfface_handle(fh1, 1); + hfs[1] = mesh.halfface_handle(fh3, 1); + hfs[2] = mesh.halfface_handle(fh5, 1); + hfs[3] = ohf3; + mesh.add_cell(hfs); + } + + CellIter first = mesh.cells_begin(); + CellIter last = mesh.cells_begin(); + + // Delete all former cells in one chunk + last += n_c; + mesh.delete_cell_range(first, last); + + //std::cout << "size = " << save.size() << std::endl; + //int count = 0; + //delete edges + for(std::vector::iterator it = save.begin() ; + it != save.end(); + ++it) + { + EdgeHandle eh = mesh.edge_handle(*it); + //edge_collapse(eh); + //++count; + //std::cout << count << std::endl; + } + } + +}; +//============================================================================= diff --git a/Linear_cell_complex/benchmark/Linear_cell_complex_3/performance_3.cpp b/Linear_cell_complex/benchmark/Linear_cell_complex_3/performance_3.cpp new file mode 100644 index 00000000000..80097636939 --- /dev/null +++ b/Linear_cell_complex/benchmark/Linear_cell_complex_3/performance_3.cpp @@ -0,0 +1,38 @@ +//== INCLUDES ================================================================= +#include "cgogn_performance_3.h" +#include "lcc_performance_3.h" +#include "openvolumemesh_performance.h" +//============================================================================= +int main(int argc, char** argv) +{ + if (argc < 2) + { + std::cerr << "Usage:\nperformance \n"; + exit(1); + } + + for (int i=1; i +#include +#include +#include + +#include "Stop_watch.h" + + +//== CLASS DEFINITION ========================================================= + + +class Performance_test_3 +{ +public: + + Performance_test_3() {} + + 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; + display_info(); + + timer.start(); + int c; + for (int i=0; i<7; ++i) + c = circulator_test(); + timer.stop(); + assert(c==0); + std::cout << "Circulator: "<