From 2ccdfcfbacaa616c833fecbb9c41e2e328e54869 Mon Sep 17 00:00:00 2001 From: Alexander Schier Date: Tue, 19 Feb 2019 14:59:48 +0100 Subject: [PATCH] Added an OpenMesh interface Added an interface to parameterize OpenMesh triangle meshes. --- CMakeLists.txt | 30 ++++- cmake/FindOpenMesh.cmake | 59 ++++++++++ openmesh-interface/include/bffOpenMesh.hpp | 122 +++++++++++++++++++++ 3 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 cmake/FindOpenMesh.cmake create mode 100644 openmesh-interface/include/bffOpenMesh.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cc83665..023ec29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(bff) option(BUILD_CLI "Build BFF command line" ON) option(BUILD_GUI "Build BFF GUI" ON) +option(WITH_OPENMESH_INTERFACE "Build with OpenMesh interface" OFF) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -36,9 +37,33 @@ file(GLOB BFF_SOURCES "mesh/src/*.cpp" "mesh/include/*.h" "project/src/*.cpp" "project/include/*.h") +if(${WITH_OPENMESH_INTERFACE}) + find_package(OpenMesh REQUIRED) + add_library(bff-openmesh-interface INTERFACE) + target_link_libraries(bff-openmesh-interface INTERFACE + bff + ${OPENMESH_LIBRARIES} + ) + target_include_directories(bff-openmesh-interface INTERFACE + ${OPENMESH_INCLUDE_DIR} + ) +endif() + # create bff static library add_library(bff ${BFF_SOURCES}) target_link_libraries(bff ${SuiteSparse_LIBRARIES}) +if(${WITH_OPENMESH_INTERFACE}) + target_link_libraries(bff + PUBLIC + ${OPENMESH_LIBRARIES} + openmesh_structures + ) + target_include_directories(bff + PUBLIC + ${OPENMESH_INCLUDE_DIR} + ) +endif() + target_include_directories(bff PRIVATE $ @@ -101,5 +126,6 @@ install(DIRECTORY project/include/ DESTINATION include FILES_MATCHING PATTERN "* install(DIRECTORY mesh/include/ DESTINATION include FILES_MATCHING PATTERN "*.inl") install(DIRECTORY linear-algebra/include/ DESTINATION include FILES_MATCHING PATTERN "*.inl") install(DIRECTORY project/include/ DESTINATION include FILES_MATCHING PATTERN "*.inl") -install(EXPORT bff-targets FILE bffTargets.cmake DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/boundary-first-flattening/cmake) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/bffConfig.cmake DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/boundary-first-flattening/cmake) +if(${WITH_OPENMESH_INTERFACE}) + install(DIRECTORY openmesh-interface/include/ DESTINATION include FILES_MATCHING PATTERN "*.hpp") +endif() diff --git a/cmake/FindOpenMesh.cmake b/cmake/FindOpenMesh.cmake new file mode 100644 index 0000000..792123a --- /dev/null +++ b/cmake/FindOpenMesh.cmake @@ -0,0 +1,59 @@ +# - Try to find OPENMESH +# Once done this will define +# +# OPENMESH_FOUND - system has OPENMESH +# OPENMESH_INCLUDE_DIR - the OPENMESH include directory +# OPENMESH_LIBRARIES - the OPENMESH libraries +# OPENMESH_LIBRARY_DIR - the OPENMESH libraries directory +# + +IF (OPENMESH_INCLUDE_DIR) + # Already in cache, be silent + SET(OPENMESH_FIND_QUIETLY TRUE) +ENDIF (OPENMESH_INCLUDE_DIR) + +FIND_PATH(OPENMESH_INCLUDE_DIR OpenMesh/Core/Mesh/PolyMeshT.hh + PATHS /usr/local/include + /usr/include + /opt/local/include + /opt/include + ${OPENMESH_DIR}/src + ${OPENMESH_DIR}/include + $ENV{OPENMESH_DIR}/src + $ENV{OPENMESH_DIR}/include + ) + +IF (OPENMESH_INCLUDE_DIR) + IF (WIN32) + SET(OPENMESH_LIBRARY_DIR "${OPENMESH_INCLUDE_DIR}/../lib") + ELSE (WIN32) + SET(OPENMESH_LIBRARY_DIR "${OPENMESH_INCLUDE_DIR}/../lib/OpenMesh") + ENDIF (WIN32) + + FIND_LIBRARY(OPENMESH_CORE_LIBRARY_RELEASE NAMES OpenMeshCore libOpenMeshCore PATHS ${OPENMESH_LIBRARY_DIR}) + FIND_LIBRARY(OPENMESH_TOOLS_LIBRARY_RELEASE NAMES OpenMeshTools libOpenMeshTools PATHS ${OPENMESH_LIBRARY_DIR}) + SET(OPENMESH_LIBRARY_RELEASE + ${OPENMESH_CORE_LIBRARY_RELEASE} + ${OPENMESH_TOOLS_LIBRARY_RELEASE}) + + FIND_LIBRARY(OPENMESH_CORE_LIBRARY_DEBUG NAMES OpenMeshCored libOpenMeshCored PATHS ${OPENMESH_LIBRARY_DIR}) + FIND_LIBRARY(OPENMESH_TOOLS_LIBRARY_DEBUG NAMES OpenMeshToolsd libOpenMeshToolsd PATHS ${OPENMESH_LIBRARY_DIR}) + SET(OPENMESH_LIBRARY_DEBUG + ${OPENMESH_CORE_LIBRARY_DEBUG} + ${OPENMESH_TOOLS_LIBRARY_DEBUG}) +ENDIF (OPENMESH_INCLUDE_DIR) + +if(OPENMESH_LIBRARY_RELEASE) + if(OPENMESH_LIBRARY_DEBUG) + set(OPENMESH_LIBRARIES_ optimized ${OPENMESH_CORE_LIBRARY_RELEASE} optimized ${OPENMESH_TOOLS_LIBRARY_RELEASE} debug ${OPENMESH_CORE_LIBRARY_DEBUG} debug ${OPENMESH_TOOLS_LIBRARY_DEBUG}) + else() + set(OPENMESH_LIBRARIES_ ${OPENMESH_LIBRARY_RELEASE}) + endif() + + set(OPENMESH_LIBRARIES ${OPENMESH_LIBRARIES_} CACHE FILEPATH "The OpenMesh library") +endif() + +IF(OPENMESH_INCLUDE_DIR AND OPENMESH_LIBRARIES) + SET(OPENMESH_FOUND TRUE) + MESSAGE(STATUS "Found OpenMesh: ${OPENMESH_LIBRARIES}") +ENDIF(OPENMESH_INCLUDE_DIR AND OPENMESH_LIBRARIES) diff --git a/openmesh-interface/include/bffOpenMesh.hpp b/openmesh-interface/include/bffOpenMesh.hpp new file mode 100644 index 0000000..b57ff17 --- /dev/null +++ b/openmesh-interface/include/bffOpenMesh.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include + +namespace bff { + template + bff::Mesh openmesh_to_bff_mesh(const OpenMesh::TriMesh_ArrayKernelT &mesh) { + PolygonSoup soup; + bff::Mesh result; + + for(auto const vh : mesh.vertices()) { + auto p = mesh.point(vh); + soup.positions.push_back(bff::Vector(p[0], p[1], p[2])); + } + + for(auto const fh : mesh.faces()) { + // We do not handle uncuttable edges, as our mesh definition is for triangles only + for(auto v_it = mesh.cfv_ccwbegin(fh); v_it != mesh.cfv_ccwend(fh); v_it++) { + soup.indices.push_back(v_it->idx()); + } + } + + soup.table.construct(soup.positions.size(), soup.indices); + std::vector isCuttableEdge(soup.table.getSize(), 1); + + std::string error; + bff::MeshIO::buildMesh(soup, isCuttableEdge, result, error); + if(error.size() > 0) { + std::cerr << "Error converting OpenMesh to BFF-Mesh: " << error << std::endl; + } + + return result; + } + template + OpenMesh::TriMesh_ArrayKernelT bff_mesh_to_openmesh(bff::Mesh &mesh) { + typedef OpenMesh::TriMesh_ArrayKernelT TriMesh; + TriMesh result; + result.request_halfedge_texcoords2D(); + + // TODO: assign vertex UVs for inner vertices and halfedge UVs for cuts, + // so UV shells can be reconstructed. + // When the cut vertices have face-vertex UVs, the edges from a + // chart boundary vertex to the inside of the chart will be cut + // (have different UV vertices) as well. + // This probably cannot be solved by assigning UVs to vertices and (half)edges + // but needs a separate UV list. Possibly we should use two functions, one returning + // the halfedge-UV mesh and one returning a mesh, a UV list and + // a list of face_vertex->UV_index assignments. + + vector vertexHandles; + map, bff::Vector> facevertex_uvs; + + // Create vertices + for(const auto v: mesh.vertices) { + // Add all vertices, which are no duplicates + if(v.referenceIndex == -1) { + auto p = v.position * (mesh.radius != 0? mesh.radius: 1.0); + auto vh = result.add_vertex({p[0], p[1], p[2]}); + vertexHandles.push_back(vh); + } + } + + // Create UVs + for(auto w: mesh.wedges()) { + auto v = w.vertex(); + int vertexIndex = v->referenceIndex == -1 ? v->index : v->referenceIndex; + int faceIndex = w.face()->index; + facevertex_uvs[make_pair(faceIndex, vertexIndex)] = w.uv; + } + + // Create faces + int uncuttableEdges = 0; + for(auto f: mesh.faces) { + if(f.fillsHole) { continue; } + if(uncuttableEdges > 0) { + uncuttableEdges--; + continue; + } + + HalfEdgeCIter he = f.he; + while(!he->edge->isCuttable) he = he->next; + HalfEdgeCIter fhe = he; + std::unordered_map seenUncuttableEdges; + + std::array vhs; + short j = 0; + do { + assert(j < 3); + VertexCIter v = he->vertex; + int vIndex = v->referenceIndex == -1 ? v->index : v->referenceIndex; + vhs[j] = vertexHandles[vIndex]; + + he = he->next; + while(!he->edge->isCuttable) { + seenUncuttableEdges[he->edge->index] = true; + he = he->flip->next; + } + j++; + } while(he != fhe); + uncuttableEdges = (int)seenUncuttableEdges.size(); + + result.add_face(vhs.data(), 3); + } + + // assign UVs + for(auto heh: result.halfedges()) { + int f_idx = result.face_handle(heh).idx(); + int v_idx = result.to_vertex_handle(heh).idx(); + bff::Vector uv = facevertex_uvs[make_pair(f_idx, v_idx)]; + result.set_texcoord2D(heh, OpenMesh::Vec2d(uv[0], uv[1])); + } + + return result; + } +}