diff --git a/cmake/FindEIGEN3.cmake b/cmake/FindEIGEN3.cmake new file mode 100644 index 0000000000000000000000000000000000000000..fa8fc4f73619df7456ab1b96937eca5ea5471283 --- /dev/null +++ b/cmake/FindEIGEN3.cmake @@ -0,0 +1,70 @@ +# - Try to find EIGEN3 +# Once done this will define +# EIGEN3_FOUND - System has EIGEN3 +# EIGEN3_INCLUDE_DIRS - The EIGEN3 include directories + +if (EIGEN3_INCLUDE_DIR) + # in cache already + set(EIGEN3_FOUND TRUE) + set(EIGEN3_INCLUDE_DIRS "${EIGEN3_INCLUDE_DIR}" ) +else (EIGEN3_INCLUDE_DIR) + +# Check if the base path is set +if ( NOT CMAKE_WINDOWS_LIBS_DIR ) + # This is the base directory for windows library search used in the finders we shipp. + set(CMAKE_WINDOWS_LIBS_DIR "c:/libs" CACHE STRING "Default Library search dir on windows." ) +endif() + +if ( CMAKE_GENERATOR MATCHES "^Visual Studio 11.*Win64" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2012/x64/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 11.*" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2012/x32/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 12.*Win64" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2013/x64/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 12.*" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2013/x32/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 14.*Win64" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2015/x64/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 14.*" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2015/x32/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 15.*Win64" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2017/x64/") +elseif ( CMAKE_GENERATOR MATCHES "^Visual Studio 15.*" ) + SET(VS_SEARCH_PATH "${CMAKE_WINDOWS_LIBS_DIR}/vs2017/x32/") +endif() + + +find_path( EIGEN3_INCLUDE_DIR + NAMES Eigen/Dense + PATHS $ENV{EIGEN_DIR} + /usr/include/eigen3 + /usr/local/include + /usr/local/include/eigen3/ + /opt/local/include/eigen3/ + "${CMAKE_WINDOWS_LIBS_DIR}/general/Eigen-3.3.4" + "${CMAKE_WINDOWS_LIBS_DIR}/general/Eigen-3.2.8" + "${CMAKE_WINDOWS_LIBS_DIR}/general/Eigen-3.2.6" + "${CMAKE_WINDOWS_LIBS_DIR}/Eigen-3.2.6" + "${CMAKE_WINDOWS_LIBS_DIR}/Eigen-3.2.6/include" + "${CMAKE_WINDOWS_LIBS_DIR}/Eigen-3.2.1" + "${CMAKE_WINDOWS_LIBS_DIR}/Eigen-3.2.1/include" + "${CMAKE_WINDOWS_LIBS_DIR}/Eigen-3.2/include" + "${CMAKE_WINDOWS_LIBS_DIR}/eigen3/include" + "${CMAKE_WINDOWS_LIBS_DIR}/eigen/include" + ${PROJECT_SOURCE_DIR}/MacOS/Libs/eigen3/include + ../../External/include + ${module_file_path}/../../../External/include + ) + +set(EIGEN3_INCLUDE_DIRS "${EIGEN3_INCLUDE_DIR}" ) + + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set LIBCPLEX_FOUND to TRUE +# if all listed variables are TRUE +find_package_handle_standard_args(EIGEN3 DEFAULT_MSG + EIGEN3_INCLUDE_DIR) + +mark_as_advanced(EIGEN3_INCLUDE_DIR) + +endif(EIGEN3_INCLUDE_DIR) diff --git a/src/OpenMesh/Core/Geometry/EigenVectorT.hh b/src/OpenMesh/Core/Geometry/EigenVectorT.hh new file mode 100644 index 0000000000000000000000000000000000000000..237ef906f1adb2a3f634b492431618d4ebb59ea5 --- /dev/null +++ b/src/OpenMesh/Core/Geometry/EigenVectorT.hh @@ -0,0 +1,106 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +/** This file contains all code required to use Eigen3 vectors as Mesh + * vectors + */ +#pragma once + +#include +#include +#include + + +namespace OpenMesh { + template + struct vector_traits> { + static_assert(_Rows != Eigen::Dynamic && _Cols != Eigen::Dynamic, + "Should not use dynamic vectors."); + static_assert(_Rows == 1 || _Cols == 1, "Should not use matrices."); + + using vector_type = Eigen::Matrix<_Scalar, _Rows, _Cols, _Options>; + using value_type = _Scalar; + static const size_t size_ = _Rows * _Cols; + static size_t size() { return size_; } +}; + +} // namespace OpenMesh + +namespace Eigen { + + template + typename Derived::Scalar dot(const MatrixBase &x, + const MatrixBase &y) { + return x.dot(y); + } + + template + typename MatrixBase< Derived >::PlainObject cross(const MatrixBase &x, const MatrixBase &y) { + return x.cross(y); + } + + template + typename Derived::Scalar norm(const MatrixBase &x) { + return x.norm(); + } + + template + typename Derived::Scalar sqrnorm(const MatrixBase &x) { + return x.dot(x); + } + + template + MatrixBase normalize(MatrixBase &x) { + std::cerr << "Norm : " << x.norm() << std::endl; + x /= x.norm(); + std::cerr << "Norm : " << x << std::endl; + return x; + } + + template + MatrixBase &vectorize(MatrixBase &x, + typename Derived::Scalar const &val) { + x.fill(val); + return x; + } + +} // namespace Eigen + diff --git a/src/Unittests/CMakeLists.txt b/src/Unittests/CMakeLists.txt index f73e4ddd36c936ce83cb34c0b455255e29506f61..1b9e58cff8a0e2be6ce4befd10f51f7c57d93de8 100644 --- a/src/Unittests/CMakeLists.txt +++ b/src/Unittests/CMakeLists.txt @@ -17,25 +17,32 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) enable_testing() + find_package(EIGEN3) + # Set correct include paths so that the compiler can find the headers - include_directories(${GTEST_INCLUDE_DIRS}) + include_directories(${GTEST_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIR}) # set additional link directories link_directories(${GTEST_LIBRARY_DIR} ) + + if (EIGEN3_FOUND) + add_definitions( -DENABLE_EIGEN3_TEST ) + endif() + if ( CMAKE_GENERATOR MATCHES "^Visual Studio 11.*" ) add_definitions( /D _VARIADIC_MAX=10 ) endif() # Create new target named unittests_hexmeshing FILE(GLOB UNITTEST_SRC *.cc) - # Create unittest executable - acg_add_executable(unittests ${UNITTEST_SRC}) - acg_add_executable(unittests_customvec ${UNITTEST_SRC}) - target_compile_definitions(unittests_customvec PRIVATE TEST_CUSTOM_TRAITS) + # Create unittest executable + acg_add_executable(unittests ${UNITTEST_SRC}) + acg_add_executable(unittests_customvec ${UNITTEST_SRC}) + target_compile_definitions(unittests_customvec PRIVATE TEST_CUSTOM_TRAITS) - # For the unittest we don't want the install rpath as set by acg_add_executable - set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) - set_target_properties ( unittests_customvec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) + # For the unittest we don't want the install rpath as set by acg_add_executable + set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) + set_target_properties ( unittests_customvec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) # Set output directory to ${BINARY_DIR}/Unittests set (OUTPUT_DIR "${CMAKE_BINARY_DIR}/Unittests") diff --git a/src/Unittests/unittests_eigen3_type.cc b/src/Unittests/unittests_eigen3_type.cc new file mode 100644 index 0000000000000000000000000000000000000000..f96ce7aaffaa5310d82af9015a929bec69a2c73c --- /dev/null +++ b/src/Unittests/unittests_eigen3_type.cc @@ -0,0 +1,213 @@ + +#ifdef ENABLE_EIGEN3_TEST + +#include +#include +#include + +#include +#include + +#include + +struct EigenTraits : OpenMesh::DefaultTraits { + using Point = Eigen::Vector3d; + using Normal = Eigen::Vector3d; + + using TexCoord2D = Eigen::Vector2d; +}; + +using EigenTriMesh = OpenMesh::TriMesh_ArrayKernelT; + + + +template +Eigen::Matrix +transformPoint(Eigen::Matrix const &trans, + Eigen::Matrix const &point) { + return trans.leftCols(3) * point + trans.col(3); +} + +namespace { + + +class OpenMeshEigenTest : public testing::Test { + + protected: + + // This function is called before each test is run + virtual void SetUp() { + + // Do some initial stuff with the member data here... + } + + // This function is called after all tests are through + virtual void TearDown() { + + + } + + EigenTriMesh mesh_; +}; + +TEST_F(OpenMeshEigenTest, Test_external_norm) { + + + EigenTriMesh::Normal normal(1,0,0); + + EigenTriMesh::Scalar result = norm(normal); + + EXPECT_EQ(result,1.0f ) << "Wrong norm"; + + normal = EigenTriMesh::Normal(2,0,0); + + result = norm(normal); + + EXPECT_EQ(result,2.0f ) << "Wrong norm"; +} + +TEST_F(OpenMeshEigenTest, Test_external_sqrnorm) { + + + EigenTriMesh::Normal normal(1,0,0); + + EigenTriMesh::Scalar result = sqrnorm(normal); + + EXPECT_EQ(result,1.0f ) << "Wrong norm"; + + normal = EigenTriMesh::Normal(2,0,0); + + result = sqrnorm(normal); + + EXPECT_EQ(result,4.0f ) << "Wrong norm"; +} + +TEST_F(OpenMeshEigenTest, Test_external_normalize) { + + + EigenTriMesh::Normal normal(2,0,0); + + EigenTriMesh::Normal normalized = normalize(normal); + + EXPECT_EQ(norm(normalized),1.0f ) << "Wrong norm after normalization"; + + normal = EigenTriMesh::Normal(2,6,9); + + normalized = normalize(normal); + + EXPECT_EQ(norm(normalized),1.0f ) << "Wrong norm after normalization"; + +} + +TEST_F(OpenMeshEigenTest, Test_external_cross_Product) { + + + EigenTriMesh::Normal normal1(1,0,0); + EigenTriMesh::Normal normal2(1,1,0); + + EigenTriMesh::Normal result = cross(normal1,normal2); + + EXPECT_EQ(result[0],0.0f ) << "Wrong result x direction"; + EXPECT_EQ(result[1],0.0f ) << "Wrong result y direction"; + EXPECT_EQ(result[2],1.0f ) << "Wrong result z direction"; +} + +TEST_F(OpenMeshEigenTest, Test_external_dot_Product) { + + + EigenTriMesh::Normal normal1(1,0,0); + EigenTriMesh::Normal normal2(1,1,0); + EigenTriMesh::Normal normal3(1,1,1); + EigenTriMesh::Normal normal4(2,4,6); + + EigenTriMesh::Scalar result = dot(normal1,normal2); + EigenTriMesh::Scalar result1 = dot(normal3,normal4); + + EXPECT_EQ(result,1.0f ) << "Wrong dot product"; + EXPECT_EQ(result1,12.0f ) << "Wrong dot product"; + +} + + +TEST_F(OpenMeshEigenTest, Test_Basic_setup) { + + // Add some vertices + EigenTriMesh::VertexHandle vhandle[4]; + + vhandle[0] = mesh_.add_vertex(EigenTriMesh::Point(0, 0, 0)); + vhandle[1] = mesh_.add_vertex(EigenTriMesh::Point(0, 1, 0)); + vhandle[2] = mesh_.add_vertex(EigenTriMesh::Point(1, 1, 0)); + vhandle[3] = mesh_.add_vertex(EigenTriMesh::Point(1, 0, 0)); + + // Add two faces + std::vector face_vhandles; + + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[0]); + + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[3]); + mesh_.add_face(face_vhandles); + + + EXPECT_EQ(mesh_.n_faces(),2) << "Wrong number of faces"; + +} + +TEST_F(OpenMeshEigenTest, test_normal_computation) { + + // Add some vertices + EigenTriMesh::VertexHandle vhandle[4]; + + mesh_.request_vertex_normals(); + mesh_.request_face_normals(); + + vhandle[0] = mesh_.add_vertex(EigenTriMesh::Point(0, 0, 0)); + vhandle[1] = mesh_.add_vertex(EigenTriMesh::Point(0, 1, 0)); + vhandle[2] = mesh_.add_vertex(EigenTriMesh::Point(1, 1, 0)); + vhandle[3] = mesh_.add_vertex(EigenTriMesh::Point(1, 0, 0)); + + // Add two faces + std::vector face_vhandles; + + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[0]); + + EigenTriMesh::FaceHandle face1 = mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[3]); + EigenTriMesh::FaceHandle face2 = mesh_.add_face(face_vhandles); + + mesh_.update_face_normals(); + + + EXPECT_EQ(mesh_.n_faces(),2) << "Wrong number of faces"; + + EigenTriMesh::Normal normal = mesh_.normal(face1); + + EXPECT_EQ(normal[0],0.0f ) << "Wrong normal x direction"; + EXPECT_EQ(normal[1],0.0f ) << "Wrong normal y direction"; + EXPECT_EQ(normal[2],1.0f ) << "Wrong normal z direction"; + + normal = mesh_.normal(face2); + + EXPECT_EQ(normal[0],0.0f ) << "Wrong normal x direction"; + EXPECT_EQ(normal[1],0.0f ) << "Wrong normal y direction"; + EXPECT_EQ(normal[2],1.0f ) << "Wrong normal z direction"; + +} + +} + +#endif