From 7a608b1e04cafb169085da7c6f9e4c727cf16691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Wed, 25 Sep 2019 09:46:47 +0200 Subject: [PATCH 01/22] Fixed web upload user --- CI/ci-doc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/ci-doc.sh b/CI/ci-doc.sh index 631df011..73505753 100755 --- a/CI/ci-doc.sh +++ b/CI/ci-doc.sh @@ -11,4 +11,4 @@ cmake -DCMAKE_BUILD_TYPE=Release -DOPENMESH_BUILD_UNIT_TESTS=FALSE ../ make doc # Copy to webserver -scp -r -P 2222 Build/share/OpenMesh/Doc/html/* hudson@web4-info8:OpenMesh-Daily/Doc/ +scp -r -P 2222 Build/share/OpenMesh/Doc/html/* gitlab@web4-info8:OpenMesh-Daily/Doc/ From 651e8cf966bca253a974d420a67b613a3acf0787 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 22 Oct 2019 10:08:22 +0200 Subject: [PATCH 02/22] add default trait that uses double precision --- src/OpenMesh/Core/Mesh/Traits.hh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/OpenMesh/Core/Mesh/Traits.hh b/src/OpenMesh/Core/Mesh/Traits.hh index d6db2d3e..5768286a 100644 --- a/src/OpenMesh/Core/Mesh/Traits.hh +++ b/src/OpenMesh/Core/Mesh/Traits.hh @@ -152,6 +152,24 @@ struct DefaultTraits FaceAttributes(0); }; +/** \class DefaultTraitsDouble Traits.hh + + Version of Default Traits that uses double precision for points and + normals as well as floating point vectors for colors + + \see The Mesh docu section on \ref mesh_type. + \see Traits.hh for a list of macros for traits classes. +*/ +struct DefaultTraitsDouble : public DefaultTraits +{ + /// Use double precision points + typedef OpenMesh::Vec3d Point; + /// Use double precision Normals + typedef OpenMesh::Vec3d Normal; + /// Use RGBA Color + typedef OpenMesh::Vec4f Color; +}; + //== CLASS DEFINITION ========================================================= From a15f247a6fd8d4534b664924f029cc2a61463146 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 22 Oct 2019 10:08:40 +0200 Subject: [PATCH 03/22] add default mesh types using default doublet traits --- src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh | 66 +++++++++++++++++++++++ src/OpenMesh/Core/Mesh/DefaultTriMesh.hh | 66 +++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh create mode 100644 src/OpenMesh/Core/Mesh/DefaultTriMesh.hh diff --git a/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh b/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh new file mode 100644 index 00000000..59e31ee3 --- /dev/null +++ b/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2019, 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. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTTRIMESH_HH +#define OPENMESH_DEFAULTTRIMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef PolyMesh_ArrayKernelT PolyMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTTRIMESH_HH defined +//============================================================================= diff --git a/src/OpenMesh/Core/Mesh/DefaultTriMesh.hh b/src/OpenMesh/Core/Mesh/DefaultTriMesh.hh new file mode 100644 index 00000000..94fb4039 --- /dev/null +++ b/src/OpenMesh/Core/Mesh/DefaultTriMesh.hh @@ -0,0 +1,66 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2019, 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. * + * * + * ========================================================================= */ + + +#ifndef OPENMESH_DEFAULTTRIMESH_HH +#define OPENMESH_DEFAULTTRIMESH_HH + + +//== INCLUDES ================================================================= + +#include +#include + +//== NAMESPACES =============================================================== + +namespace OpenMesh { + +//== TYPEDEFS ================================================================= + +typedef TriMesh_ArrayKernelT TriMesh; + +//============================================================================= +} // namespace OpenMesh +//============================================================================= + +//============================================================================= +#endif // OPENMESH_DEFAULTTRIMESH_HH defined +//============================================================================= From 2343577636174a1e603bc2f4f7d91ebc9c5aaacb Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 22 Oct 2019 10:17:12 +0200 Subject: [PATCH 04/22] add unittests for default double vec type --- CI/Windows.bat | 4 ++++ CI/ci-linux.sh | 31 ++++++++++++++++++++++++++----- CI/ci-mac.sh | 31 ++++++++++++++++++++++++++----- src/Unittests/CMakeLists.txt | 22 +++++++++++++++++++--- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/CI/Windows.bat b/CI/Windows.bat index d4f44307..36f18285 100644 --- a/CI/Windows.bat +++ b/CI/Windows.bat @@ -119,6 +119,8 @@ unittests.exe --gtest_output=xml unittests_customvec.exe --gtest_output=xml +unittests_doublevec.exe --gtest_output=xml + cd .. cd .. @@ -147,6 +149,8 @@ unittests.exe --gtest_output=xml unittests_customvec.exe --gtest_output=xml +unittests_doublevec.exe --gtest_output=xml + IF %errorlevel% NEQ 0 exit /b %errorlevel% cd .. diff --git a/CI/ci-linux.sh b/CI/ci-linux.sh index fe75b847..468a7872 100755 --- a/CI/ci-linux.sh +++ b/CI/ci-linux.sh @@ -87,6 +87,8 @@ make $MAKE_OPTIONS #build the unit tests make $MAKE_OPTIONS unittests +cd Unittests + echo -e "${OUTPUT}" echo "" echo "======================================================================" @@ -94,8 +96,6 @@ echo "Running unittests Release version with vectorchecks enabled" echo "======================================================================" echo -e "${NC}" -cd Unittests - #execute tests ./unittests --gtest_color=yes --gtest_output=xml @@ -106,8 +106,19 @@ echo "Running unittests Release version with custom vector type" echo "======================================================================" echo -e "${NC}" +#execute tests ./unittests_customvec --gtest_color=yes --gtest_output=xml +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests Release version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + cd .. cd .. @@ -133,6 +144,8 @@ make $MAKE_OPTIONS #build the unit tests make $MAKE_OPTIONS unittests +cd Unittests + echo -e "${OUTPUT}" echo "" echo "======================================================================" @@ -140,9 +153,6 @@ echo "Running unittests Debug version with vectorchecks enabled" echo "======================================================================" echo -e "${NC}" - -cd Unittests - #execute tests ./unittests --gtest_color=yes --gtest_output=xml @@ -153,7 +163,18 @@ echo "Running unittests Debug version with custom vector type" echo "======================================================================" echo -e "${NC}" +#execute tests ./unittests_customvec --gtest_color=yes --gtest_output=xml +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests Debug version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + cd .. cd .. diff --git a/CI/ci-mac.sh b/CI/ci-mac.sh index c3d454cd..493214b2 100755 --- a/CI/ci-mac.sh +++ b/CI/ci-mac.sh @@ -69,6 +69,8 @@ make #build the unit tests make unittests +cd Unittests + echo -e "${OUTPUT}" echo "" echo "======================================================================" @@ -76,8 +78,6 @@ echo "Running unittests Release version with vectorchecks enabled" echo "======================================================================" echo -e "${NC}" -cd Unittests - #execute tests ./unittests --gtest_color=yes --gtest_output=xml @@ -88,8 +88,19 @@ echo "Running unittests Release version with minimal vector type" echo "======================================================================" echo -e "${NC}" +#execute tests ./unittests_customvec --gtest_color=yes --gtest_output=xml +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests Release version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + cd .. cd .. @@ -115,6 +126,8 @@ make #build the unit tests make unittests +cd Unittests + echo -e "${OUTPUT}" echo "" echo "======================================================================" @@ -122,9 +135,6 @@ echo "Running unittests Debug version with vectorchecks enabled" echo "======================================================================" echo -e "${NC}" - -cd Unittests - #execute tests ./unittests --gtest_color=yes --gtest_output=xml @@ -135,8 +145,19 @@ echo "Running unittests Debug version with minimal vector type" echo "======================================================================" echo -e "${NC}" +#execute tests ./unittests_customvec --gtest_color=yes --gtest_output=xml +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests Debug version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + cd .. cd .. diff --git a/src/Unittests/CMakeLists.txt b/src/Unittests/CMakeLists.txt index 7173ddde..e11060cf 100644 --- a/src/Unittests/CMakeLists.txt +++ b/src/Unittests/CMakeLists.txt @@ -41,20 +41,25 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) # Create unittest executable acg_add_executable(unittests ${UNITTEST_SRC}) acg_add_executable(unittests_customvec ${UNITTEST_SRC}) + acg_add_executable(unittests_doublevec ${UNITTEST_SRC}) target_compile_definitions(unittests_customvec PRIVATE TEST_CUSTOM_TRAITS) + target_compile_definitions(unittests_doublevec PRIVATE TEST_DOUBLE_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 PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) set_target_properties ( unittests_customvec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) + set_target_properties ( unittests_doublevec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 ) # Set output directory to ${BINARY_DIR}/Unittests set (OUTPUT_DIR "${CMAKE_BINARY_DIR}/Unittests") - set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) + set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) + set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}) foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${CONFIG} UPCONFIG) set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR}) set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR}) + set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR}) endforeach() @@ -62,6 +67,7 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) # Link against all necessary libraries target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread) target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread) + target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread) @@ -71,8 +77,9 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) add_definitions( -DOPENMESHDLL ) endif() - target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) + target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) + target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES}) endif() @@ -81,10 +88,12 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) # Set compiler flags set_target_properties(unittests PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long") set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long") + set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long") else() # Set compiler flags set_target_properties(unittests PROPERTIES COMPILE_FLAGS "" ) set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "" ) + set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "" ) endif() if ( OPENMESH_BUILD_SHARED ) @@ -103,14 +112,21 @@ if ( OPENMESH_BUILD_UNIT_TESTS ) "$" "${CMAKE_BINARY_DIR}/Unittests/$" COMMENT "Copying OpenMesh targets to unittests directory") + add_custom_command(TARGET unittests_doublevec POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "${CMAKE_BINARY_DIR}/Unittests/$" + COMMENT "Copying OpenMesh targets to unittests directory") endforeach(TAR) endif() acg_copy_after_build(unittests ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/) acg_copy_after_build(unittests_customvec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/) + acg_copy_after_build(unittests_doublevec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/) add_test(NAME AllTestsIn_OpenMesh_tests WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests") add_test(NAME AllTestsIn_OpenMesh_tests_with_minimal_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_customvec") + add_test(NAME AllTestsIn_OpenMesh_tests_with_double_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_doublevec") else(GTEST_FOUND) message(STATUS "Google testing framework was not found, unittests disabled.") From ef65cf870d473b49e1c81bf55060fbc509faddfd Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 22 Oct 2019 10:37:35 +0200 Subject: [PATCH 05/22] fix copy paste error --- src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh b/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh index 59e31ee3..56bdda9d 100644 --- a/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh +++ b/src/OpenMesh/Core/Mesh/DefaultPolyMesh.hh @@ -40,8 +40,8 @@ * ========================================================================= */ -#ifndef OPENMESH_DEFAULTTRIMESH_HH -#define OPENMESH_DEFAULTTRIMESH_HH +#ifndef OPENMESH_DEFAULTPOLYMESH_HH +#define OPENMESH_DEFAULTPOLYMESH_HH //== INCLUDES ================================================================= @@ -62,5 +62,5 @@ typedef PolyMesh_ArrayKernelT PolyMesh; //============================================================================= //============================================================================= -#endif // OPENMESH_DEFAULTTRIMESH_HH defined +#endif // OPENMESH_DEFAULTPOLYMESH_HH defined //============================================================================= From 627a9b770eaf05664c135b1fb38edbad1cc15610 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 22 Oct 2019 15:39:10 +0200 Subject: [PATCH 06/22] add default mesh types to changelog --- Doc/changelog.docu | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/changelog.docu b/Doc/changelog.docu index 60ec3095..ff45eb22 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -11,12 +11,14 @@ Core
  • Property System: Get rid of the OM_FORCE_STATIC_CAST defines. We use the type ids to check if the cast is valid or not. This will add more type safety.
  • +
  • Default Traits: Added DefaultTraitsDouble as a version of the default traits that uses double precision for positions and normals as well as float for colors.
  • +
  • Default Mesh Types: Added typdefs for a Triangle Mesh and a PolyMesh which use DefaultTraitsDouble and can be used as default mesh type be the user.
Tools
    -
  • Subdivider: Fixed crash in Loop subdivider
  • +
  • Subdivider: Fixed crash in Loop subdivider
  • Subdivider: Fixed crash in ModifiedButterfly subdivider
From 00a2eac354c0a45c241f3c1ef304a31dd95e9809 Mon Sep 17 00:00:00 2001 From: Johannes Lenzen Date: Tue, 29 Oct 2019 09:30:35 +0100 Subject: [PATCH 07/22] Changed the .gitlab-ci.yml structure Beginned with new building system .gitlab-ci.yml can now be generated by the script assemble-gitlab-ci.py. Therefore the .gitlab-ci.yml configuration file can be split into several smaller files --- .gitlab-ci.yml | 206 +++++++++++++++++++++++------ CI/ci-cppcheck.sh | 2 + CI/ci-linux-build.sh | 37 ++++++ CI/ci-linux-prepare.sh | 59 +++++++++ CI/ci-linux-test.sh | 67 ++++++++++ CI/ci-linux.sh | 180 ------------------------- CI/ci-mac-build.sh | 61 +++++++++ CI/ci-mac-prepare.sh | 43 ++++++ CI/ci-mac-test.sh | 65 +++++++++ CI/ci-mac.sh | 182 ------------------------- CI/gitlab-ci/assemble-gitlab-ci.py | 111 ++++++++++++++++ CI/gitlab-ci/ci-master.yml | 37 ++++++ CI/gitlab-ci/linux.yml | 133 +++++++++++++++++++ CI/gitlab-ci/mac.yml | 35 +++++ CI/gitlab-ci/windows.yml | 206 +++++++++++++++++++++++++++++ 15 files changed, 1025 insertions(+), 399 deletions(-) create mode 100755 CI/ci-linux-build.sh create mode 100755 CI/ci-linux-prepare.sh create mode 100755 CI/ci-linux-test.sh delete mode 100755 CI/ci-linux.sh create mode 100755 CI/ci-mac-build.sh create mode 100755 CI/ci-mac-prepare.sh create mode 100755 CI/ci-mac-test.sh delete mode 100755 CI/ci-mac.sh create mode 100755 CI/gitlab-ci/assemble-gitlab-ci.py create mode 100644 CI/gitlab-ci/ci-master.yml create mode 100644 CI/gitlab-ci/linux.yml create mode 100644 CI/gitlab-ci/mac.yml create mode 100644 CI/gitlab-ci/windows.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 21314106..8fd21723 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,38 +1,175 @@ +############################################################# +# # +# This is an auto generated file. Do not make # +# changes to this file. They possible will be overriden. # +# # +# To make persistent changes changes files in # +# ./CI/gitlab-ci/ ... # +# and regenerate this file with the configuration tool # +# # +############################################################# + stages: - build + - test - deploy -gcc-c++11: +variables: + GIT_SUBMODULE_STRATEGY: recursive + +# ----------------- +# Linux tasks +# ----------------- + +cppcheck: stage: build - script: "CI/ci-linux.sh gcc C++11" + script: "CI/ci-cppcheck.sh" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - cppcheck.log + +gcc-c++11-test-debug: + stage: test + script: "CI/ci-linux-test.sh gcc C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + + +gcc-c++11-test-release: + stage: test + script: "CI/ci-linux-test.sh gcc C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++11-build-debug: + stage: build + script: "CI/ci-linux-build.sh gcc C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-gcc-cpp11-Vector-Checks/ + +gcc-c++11-build-release: + stage: build + script: "CI/ci-linux-build.sh gcc C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-gcc-cpp11-Vector-Checks/ + +clang-c++11-test-debug: + stage: test + script: "CI/ci-linux-test.sh clang C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++11-test-release: + stage: test + script: "CI/ci-linux-test.sh clang C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++11-build-debug: + stage: build + script: "CI/ci-linux-build.sh clang C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-clang-cpp11-Vector-Checks/ + +clang-c++11-build-release: + stage: build + script: "CI/ci-linux-build.sh clang C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-clang-cpp11-Vector-Checks/ + +gcc-c++14-test-debug: + stage: test + script: "CI/ci-linux-test.sh gcc C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++14-test-release: + stage: test + script: "CI/ci-linux-test.sh gcc C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++14-build-debug: + stage: build + script: "CI/ci-linux-build.sh gcc C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-gcc-cpp14-Vector-Checks/ + +gcc-c++14-build-release: + stage: build + script: "CI/ci-linux-build.sh gcc C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-gcc-cpp14-Vector-Checks/ + +clang-c++14-test-debug: + stage: test + script: "CI/ci-linux-test.sh clang C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++14-test-release: + stage: test + script: "CI/ci-linux-test.sh clang C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++14-build-debug: + stage: build + script: "CI/ci-linux-build.sh clang C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-clang-cpp14-Vector-Checks/ + +clang-c++14-build-release: + stage: build + script: "CI/ci-linux-build.sh clang C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-clang-cpp14-Vector-Checks/ + +# ----------------- +# Apple tasks +# ----------------- + +macos-cpp11-debug: + stage: build + script: "CI/ci-mac-build.sh C++11 debug ; CI/ci-mac-test.sh C++11 debug" tags: - - Linux - - stretch + - Apple -clang-c++11: +macos-cpp14-debug: stage: build - script: "CI/ci-linux.sh clang C++11" + script: "CI/ci-mac-build.sh C++14 debug ; CI/ci-mac-test.sh C++14 debug" tags: - - Linux - - stretch + - Apple -gcc-c++14: +macos-cpp11-release: stage: build - script: "CI/ci-linux.sh gcc C++14" - tags: - - Linux - - stretch - -clang-c++14: - stage: build - script: "CI/ci-linux.sh clang C++14" - tags: - - Linux - - stretch - -macos-cpp11: - stage: build - script: "CI/ci-mac.sh C++11" + script: "CI/ci-mac-build.sh C++11 release ; CI/ci-mac-test.sh C++11 release" tags: - Apple artifacts: @@ -40,9 +177,9 @@ macos-cpp11: - build-release-cpp11/*.dmg - build-release-cpp11/*.tar.gz -macos-cpp14: +macos-cpp14-release: stage: build - script: "CI/ci-mac.sh C++14" + script: "CI/ci-mac-build.sh C++14 release ; CI/ci-mac-test.sh C++14 release" tags: - Apple artifacts: @@ -50,16 +187,10 @@ macos-cpp14: - build-release-cpp14/*.dmg - build-release-cpp14/*.tar.gz -cppcheck: - stage: build - script: "CI/ci-cppcheck.sh" - tags: - - Linux - - stretch - artifacts: - paths: - - cppcheck.log - +# ----------------- +# Windows tasks +# ----------------- + VS2017-64-bit-shared-apps: stage: build variables: @@ -262,7 +393,7 @@ VS2015-32-bit-static-no-apps: artifacts: paths: - build-release/*.exe - + Doc-publish: stage: deploy only: @@ -286,3 +417,4 @@ Sources: - OpenMesh*.tar.bz2 - OpenMesh*.tar.gz + diff --git a/CI/ci-cppcheck.sh b/CI/ci-cppcheck.sh index 914376c2..fbd1c67c 100755 --- a/CI/ci-cppcheck.sh +++ b/CI/ci-cppcheck.sh @@ -3,6 +3,8 @@ # Exit script on any error set -e +CPU_COUNT=$(grep -c processor /proc/cpuinfo) + #===================================== # Color Settings: #===================================== diff --git a/CI/ci-linux-build.sh b/CI/ci-linux-build.sh new file mode 100755 index 00000000..a08d973f --- /dev/null +++ b/CI/ci-linux-build.sh @@ -0,0 +1,37 @@ +#!/bin/bash +source CI/ci-linux-prepare.sh + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Basic configuration details:" +echo "======================================================================" +echo -e "${NC}" + +echo "Compiler: $COMPILER" +echo "Options: $OPTIONS" +echo "Language: $LANGUAGE" +echo "Make Options: $OPTIONS" +echo "BuildPath: $BUILDPATH" +echo "Path: $PATH" +echo "Language: $LANGUAGE" + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Building $BUILD_TYPE version with vectorchecks enabled" +echo "======================================================================" +echo -e "${NC}" + +if [ ! -d build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks ]; then + mkdir build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks +fi + +cd build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks + +cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ + +#build it +make $MAKE_OPTIONS + +cd .. \ No newline at end of file diff --git a/CI/ci-linux-prepare.sh b/CI/ci-linux-prepare.sh new file mode 100755 index 00000000..893b06b5 --- /dev/null +++ b/CI/ci-linux-prepare.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +COMPILER=$1 +LANGUAGE=$2 +BUILD_TYPE=$3 + +# Exit script on any error +set -e + +OPTIONS="" +MAKE_OPTIONS="" +BUILDPATH="" + +# set GTEST path +OPTIONS="-DGTEST_ROOT=/usr/src/gtest/" + +if [ "$COMPILER" == "gcc" ]; then + echo "Building with GCC"; + BUILDPATH="gcc" + + # without icecc: no options required + OPTIONS="$OPTIONS -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc" + MAKE_OPTIONS="-j16" + export ICECC_CXX=/usr/bin/g++ ; export ICECC_CC=/usr/bin/gcc + +elif [ "$COMPILER" == "clang" ]; then + + OPTIONS="$OPTIONS -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang" + echo "Building with CLANG"; + BUILDPATH="clang" +fi + +if [ "$LANGUAGE" == "C++98" ]; then + echo "Building with C++98"; + BUILDPATH="$BUILDPATH-cpp98" +elif [ "$LANGUAGE" == "C++11" ]; then + echo "Building with C++11"; + OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++11' " + BUILDPATH="$BUILDPATH-cpp11" +elif [ "$LANGUAGE" == "C++14" ]; then + echo "Building with C++14"; + OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++14' " + BUILDPATH="$BUILDPATH-cpp14" +fi + +#===================================== +# Color Settings: +#===================================== +NC='\033[0m' +OUTPUT='\033[0;32m' +WARNING='\033[0;93m' + +if [ "$BUILD_TYPE" == "release" ]; then + export BUILD_TYPE=Release + export BUILD_TYPE_L=release +else + export BUILD_TYPE=Debug + export BUILD_TYPE_L=debug +fi \ No newline at end of file diff --git a/CI/ci-linux-test.sh b/CI/ci-linux-test.sh new file mode 100755 index 00000000..938605e6 --- /dev/null +++ b/CI/ci-linux-test.sh @@ -0,0 +1,67 @@ +#!/bin/bash +source CI/ci-linux-prepare.sh + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Basic configuration details:" +echo "======================================================================" +echo -e "${NC}" + +echo "Compiler: $COMPILER" +echo "Options: $OPTIONS" +echo "Language: $LANGUAGE" +echo "Make Options: $OPTIONS" +echo "BuildPath: $BUILDPATH" +echo "Path: $PATH" +echo "Language: $LANGUAGE" + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Building $BUILD_TYPE version unittests" +echo "======================================================================" +echo -e "${NC}" + +if [ ! -d build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks ]; then + mkdir build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks +fi + +cd build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks + +#build the unit tests +make $MAKE_OPTIONS unittests + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with vectorchecks enabled" +echo "======================================================================" +echo -e "${NC}" + +cd Unittests + +#execute tests +./unittests --gtest_color=yes --gtest_output=xml + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with custom vector type" +echo "======================================================================" +echo -e "${NC}" + +./unittests_customvec --gtest_color=yes --gtest_output=xml + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + +cd .. +cd .. \ No newline at end of file diff --git a/CI/ci-linux.sh b/CI/ci-linux.sh deleted file mode 100755 index 468a7872..00000000 --- a/CI/ci-linux.sh +++ /dev/null @@ -1,180 +0,0 @@ -#!/bin/bash - -COMPILER=$1 -LANGUAGE=$2 - -# Exit script on any error -set -e - -OPTIONS="" -MAKE_OPTIONS="" -BUILDPATH="" - -# set GTEST path -OPTIONS="-DGTEST_ROOT=~/sw/gtest-1.8.0/" - -if [ "$COMPILER" == "gcc" ]; then - echo "Building with GCC"; - BUILDPATH="gcc" - - # without icecc: no options required - OPTIONS="$OPTIONS -DCMAKE_CXX_COMPILER=/usr/lib/icecc/bin/g++ -DCMAKE_C_COMPILER=/usr/lib/icecc/bin/gcc" - MAKE_OPTIONS="-j16" - export ICECC_CXX=/usr/bin/g++ ; export ICECC_CC=/usr/bin/gcc - -elif [ "$COMPILER" == "clang" ]; then - - OPTIONS="$OPTIONS -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang" - echo "Building with CLANG"; - BUILDPATH="clang" -fi - -if [ "$LANGUAGE" == "C++98" ]; then - echo "Building with C++98"; - BUILDPATH="$BUILDPATH-cpp98" -elif [ "$LANGUAGE" == "C++11" ]; then - echo "Building with C++11"; - OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++11' " - BUILDPATH="$BUILDPATH-cpp11" -elif [ "$LANGUAGE" == "C++14" ]; then - echo "Building with C++14"; - OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++14' " - BUILDPATH="$BUILDPATH-cpp14" -fi - -#===================================== -# Color Settings: -#===================================== -NC='\033[0m' -OUTPUT='\033[0;32m' -WARNING='\033[0;93m' - - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Basic configuration details:" -echo "======================================================================" -echo -e "${NC}" - -echo "Compiler: $COMPILER" -echo "Options: $OPTIONS" -echo "Language: $LANGUAGE" -echo "Make Options: $OPTIONS" -echo "BuildPath: $BUILDPATH" -echo "Path: $PATH" -echo "Language: $LANGUAGE" - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Building Release version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - - -if [ ! -d build-release-$BUILDPATH-Vector-Checks ]; then - mkdir build-release-$BUILDPATH-Vector-Checks -fi - -cd build-release-$BUILDPATH-Vector-Checks - -cmake -DCMAKE_BUILD_TYPE=Release -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ - -#build it -make $MAKE_OPTIONS - -#build the unit tests -make $MAKE_OPTIONS unittests - -cd Unittests - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with custom vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_customvec --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with double vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_doublevec --gtest_color=yes --gtest_output=xml - -cd .. -cd .. - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Building Debug version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - - -if [ ! -d build-debug-$BUILDPATH-Vector-Checks ]; then - mkdir build-debug-$BUILDPATH-Vector-Checks -fi - -cd build-debug-$BUILDPATH-Vector-Checks - -cmake -DCMAKE_BUILD_TYPE=Debug -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ - -#build it -make $MAKE_OPTIONS - -#build the unit tests -make $MAKE_OPTIONS unittests - -cd Unittests - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with custom vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_customvec --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with double vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_doublevec --gtest_color=yes --gtest_output=xml - -cd .. -cd .. diff --git a/CI/ci-mac-build.sh b/CI/ci-mac-build.sh new file mode 100755 index 00000000..44773c39 --- /dev/null +++ b/CI/ci-mac-build.sh @@ -0,0 +1,61 @@ +#!/bin/bash +source CI/ci-mac-prepare.sh + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Basic configuration details:" +echo "======================================================================" +echo -e "${NC}" + +echo "Options: $OPTIONS" +echo "BuildPath: $BUILDPATH" +echo "Path: $PATH" +echo "Language: $LANGUAGE" + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Building $BUILD_TYPE version with vectorchecks enabled" +echo "======================================================================" +echo -e "${NC}" + + +if [ ! -d build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks ]; then + mkdir build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks +fi + +cd build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks + +cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ + +#build it +make + +cd .. + +if [ "$BUILD_TYPE_L" == "release" ]; then + + echo -e "${OUTPUT}" + echo "" + echo "======================================================================" + echo "Package creation (DMG and tarball)" + echo "======================================================================" + echo -e "${NC}" + + + if [ ! -d build-release-$BUILDPATH ]; then + mkdir build-release-$BUILDPATH + fi + + cd build-release-$BUILDPATH + + cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_APPS=OFF -DCPACK_BINARY_DRAGNDROP=ON $OPTIONS ../ + + #build it + make + make package + + cd .. + +fi \ No newline at end of file diff --git a/CI/ci-mac-prepare.sh b/CI/ci-mac-prepare.sh new file mode 100755 index 00000000..985171c6 --- /dev/null +++ b/CI/ci-mac-prepare.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +#Exit on any error +set -e + +LANGUAGE=$1 +BUILD_TYPE=$2 + +PATH=$PATH:/opt/local/bin +export PATH + +OPTIONS="" + +# set GTEST path +OPTIONS="$OPTIONS -DGTEST_ROOT=~/sw/gtest-1.7.0/" + +if [ "$LANGUAGE" == "C++98" ]; then + echo "Building with C++98"; + BUILDPATH="cpp98" +elif [ "$LANGUAGE" == "C++11" ]; then + echo "Building with C++11"; + OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++11' " + BUILDPATH="cpp11" +elif [ "$LANGUAGE" == "C++14" ]; then + echo "Building with C++14"; + OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++14' " + BUILDPATH="cpp14" +fi + +#===================================== +# Color Settings: +#===================================== +NC='\033[0m' +OUTPUT='\033[0;32m' +WARNING='\033[0;93m' + +if [ "$BUILD_TYPE" == "release" ]; then + export BUILD_TYPE=Release + export BUILD_TYPE_L=release +else + export BUILD_TYPE=Debug + export BUILD_TYPE_L=debug +fi diff --git a/CI/ci-mac-test.sh b/CI/ci-mac-test.sh new file mode 100755 index 00000000..de25ba39 --- /dev/null +++ b/CI/ci-mac-test.sh @@ -0,0 +1,65 @@ +#!/bin/bash +source CI/ci-mac-prepare.sh + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Basic configuration details:" +echo "======================================================================" +echo -e "${NC}" + +echo "Options: $OPTIONS" +echo "BuildPath: $BUILDPATH" +echo "Path: $PATH" +echo "Language: $LANGUAGE" + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Building $BUILD_TYPE version unittests" +echo "======================================================================" +echo -e "${NC}" + + +if [ ! -d build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks ]; then + mkdir build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks +fi + +cd build-$BUILD_TYPE_L-$BUILDPATH-Vector-Checks + +#build the unit tests +make unittests + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with vectorchecks enabled" +echo "======================================================================" +echo -e "${NC}" + +cd Unittests + +#execute tests +./unittests --gtest_color=yes --gtest_output=xml + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with minimal vector type" +echo "======================================================================" +echo -e "${NC}" + +./unittests_customvec --gtest_color=yes --gtest_output=xml + +echo -e "${OUTPUT}" +echo "" +echo "======================================================================" +echo "Running unittests $BUILD_TYPE version with double vector type" +echo "======================================================================" +echo -e "${NC}" + +#execute tests +./unittests_doublevec --gtest_color=yes --gtest_output=xml + +cd .. +cd .. \ No newline at end of file diff --git a/CI/ci-mac.sh b/CI/ci-mac.sh deleted file mode 100755 index 493214b2..00000000 --- a/CI/ci-mac.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/bash - -#Exit on any error -set -e - -LANGUAGE=$1 - - -PATH=$PATH:/opt/local/bin -export PATH - -OPTIONS="" - -# set GTEST path -OPTIONS="$OPTIONS -DGTEST_ROOT=~/sw/gtest-1.7.0/" - -if [ "$LANGUAGE" == "C++98" ]; then - echo "Building with C++98"; - BUILDPATH="cpp98" -elif [ "$LANGUAGE" == "C++11" ]; then - echo "Building with C++11"; - OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++11' " - BUILDPATH="cpp11" -elif [ "$LANGUAGE" == "C++14" ]; then - echo "Building with C++14"; - OPTIONS="$OPTIONS -DCMAKE_CXX_FLAGS='-std=c++14' " - BUILDPATH="cpp14" -fi - -#===================================== -# Color Settings: -#===================================== -NC='\033[0m' -OUTPUT='\033[0;32m' -WARNING='\033[0;93m' - - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Basic configuration details:" -echo "======================================================================" -echo -e "${NC}" - -echo "Options: $OPTIONS" -echo "BuildPath: $BUILDPATH" -echo "Path: $PATH" -echo "Language: $LANGUAGE" - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Building Release version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - - -if [ ! -d build-release-$BUILDPATH-Vector-Checks ]; then - mkdir build-release-$BUILDPATH-Vector-Checks -fi - -cd build-release-$BUILDPATH-Vector-Checks - -cmake -DCMAKE_BUILD_TYPE=Release -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ - -#build it -make - -#build the unit tests -make unittests - -cd Unittests - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with minimal vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_customvec --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Release version with double vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_doublevec --gtest_color=yes --gtest_output=xml - -cd .. -cd .. - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Building Debug version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - - -if [ ! -d build-debug-$BUILDPATH-Vector-Checks ]; then - mkdir build-debug-$BUILDPATH-Vector-Checks -fi - -cd build-debug-$BUILDPATH-Vector-Checks - -cmake -DCMAKE_BUILD_TYPE=Debug -DOPENMESH_BUILD_UNIT_TESTS=TRUE -DSTL_VECTOR_CHECKS=ON $OPTIONS ../ - -#build it -make - -#build the unit tests -make unittests - -cd Unittests - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with vectorchecks enabled" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with minimal vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_customvec --gtest_color=yes --gtest_output=xml - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Running unittests Debug version with double vector type" -echo "======================================================================" -echo -e "${NC}" - -#execute tests -./unittests_doublevec --gtest_color=yes --gtest_output=xml - -cd .. -cd .. - -echo -e "${OUTPUT}" -echo "" -echo "======================================================================" -echo "Package creation (DMG and tarball)" -echo "======================================================================" -echo -e "${NC}" - - -if [ ! -d build-release-$BUILDPATH ]; then - mkdir build-release-$BUILDPATH -fi - -cd build-release-$BUILDPATH - -cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_APPS=OFF -DCPACK_BINARY_DRAGNDROP=ON $OPTIONS ../ - -#build it -make -make package diff --git a/CI/gitlab-ci/assemble-gitlab-ci.py b/CI/gitlab-ci/assemble-gitlab-ci.py new file mode 100755 index 00000000..a7fb97de --- /dev/null +++ b/CI/gitlab-ci/assemble-gitlab-ci.py @@ -0,0 +1,111 @@ +#!/usr/bin/python3 + +import sys, os, re + +# Script for automated gitlab-ci creation +# Assembles the gitlab ci from master template file: +master_file = 'ci-master.yml' +# Lines in the master file are copied to the resulting +# assemblied gitlab ci file +target_file = '../../.gitlab-ci.yml' +# Lines containing the String {xxx} are interpreted +# as import statement. Therefore the file xxx is imported +# into that line. +error_on_path_redirection = True +# Notice that xxx can not contain path redirections +# like .. and / + + +# Prefix to prepend to master file +autogenerated_notice = """############################################################# +# # +# This is an auto generated file. Do not make # +# changes to this file. They possible will be overriden. # +# # +# To make persistent changes changes files in # +# ./CI/gitlab-ci/ ... # +# and regenerate this file with the configuration tool # +# # +############################################################# + +""" + + +# Checks if an import filename is valid - free of path redirections +def isValidImportFilename(filenameToImport): + if not error_on_path_redirection: + return True + else: + filterRegex = r"(\/|\\|\.\.+)" + filtered = re.sub(filterRegex, '', filenameToImport) + return filenameToImport == filtered + +# Returns the directory to work on +def findCIAssemblyDirectory(): + pathname = os.path.dirname(sys.argv[0]) + return os.path.abspath(pathname) + +# Returns file content as string +def readFile(filename): + file = open(filename, "r") + content = file.read() + file.close() + return content + +# Assembles the file in memory and returns file content as string +def assembleTarget(master, depth=3): + if depth < 0: + raise "Max depth reached. Possible circular import?" + + master_content = readFile(master) + regex_import_stmt = r"^\ *\{([^\}\n]+)\}\ *$" + regex_import_comp = re.compile(regex_import_stmt) + master_content_list = master_content.splitlines() + + # Walk through file looking for import statements + cur_index = 0 + while cur_index < len(master_content_list): + cur_line = master_content_list[cur_index] + match = regex_import_comp.match(cur_line) + + if match: + importFile = match.groups()[0] + if importFile: + # Found import statement + print("Importing file: "+importFile) + + if not isValidImportFilename(importFile): + raise "Invalid filename "+importFile+ ". Do not include path redirections" + + import_content = assembleTarget(importFile, depth=depth-1) + import_content_list = import_content.splitlines() + master_content_list.pop(cur_index) + for new_line in reversed(import_content_list): + master_content_list.insert(cur_index, new_line) + + cur_index += 1 + + # Assemble result + master_content = ''.join(str(e)+'\n' for e in master_content_list) + return master_content + +# Main function +def main(): + print("Starting config assembly") + os.chdir(findCIAssemblyDirectory()) + target_content = autogenerated_notice + target_content += assembleTarget(master_file) + print("Writing config to file "+target_file) + + target_file_handle = open(target_file, "w") + target_file_handle.write(target_content) + target_file_handle.write("\n") + target_file_handle.flush() + target_file_handle.close() + + print("Finished.") + + +# Execute main function +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/CI/gitlab-ci/ci-master.yml b/CI/gitlab-ci/ci-master.yml new file mode 100644 index 00000000..341375c4 --- /dev/null +++ b/CI/gitlab-ci/ci-master.yml @@ -0,0 +1,37 @@ +stages: + - build + - test + - deploy + +variables: + GIT_SUBMODULE_STRATEGY: recursive + +{linux.yml} + +{mac.yml} + +{windows.yml} + +Doc-publish: + stage: deploy + only: + - master + script: "CI/ci-doc.sh" + tags: + - Linux + - stretch + +Sources: + stage: deploy + only: + - master + script: "CI/ci-source.sh" + tags: + - Linux + - stretch + artifacts: + paths: + - OpenMesh*.zip + - OpenMesh*.tar.bz2 + - OpenMesh*.tar.gz + diff --git a/CI/gitlab-ci/linux.yml b/CI/gitlab-ci/linux.yml new file mode 100644 index 00000000..3073aa0e --- /dev/null +++ b/CI/gitlab-ci/linux.yml @@ -0,0 +1,133 @@ +# ----------------- +# Linux tasks +# ----------------- + +cppcheck: + stage: build + script: "CI/ci-cppcheck.sh" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - cppcheck.log + +gcc-c++11-test-debug: + stage: test + script: "CI/ci-linux-test.sh gcc C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + + +gcc-c++11-test-release: + stage: test + script: "CI/ci-linux-test.sh gcc C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++11-build-debug: + stage: build + script: "CI/ci-linux-build.sh gcc C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-gcc-cpp11-Vector-Checks/ + +gcc-c++11-build-release: + stage: build + script: "CI/ci-linux-build.sh gcc C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-gcc-cpp11-Vector-Checks/ + +clang-c++11-test-debug: + stage: test + script: "CI/ci-linux-test.sh clang C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++11-test-release: + stage: test + script: "CI/ci-linux-test.sh clang C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++11-build-debug: + stage: build + script: "CI/ci-linux-build.sh clang C++11 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-clang-cpp11-Vector-Checks/ + +clang-c++11-build-release: + stage: build + script: "CI/ci-linux-build.sh clang C++11 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-clang-cpp11-Vector-Checks/ + +gcc-c++14-test-debug: + stage: test + script: "CI/ci-linux-test.sh gcc C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++14-test-release: + stage: test + script: "CI/ci-linux-test.sh gcc C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +gcc-c++14-build-debug: + stage: build + script: "CI/ci-linux-build.sh gcc C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-gcc-cpp14-Vector-Checks/ + +gcc-c++14-build-release: + stage: build + script: "CI/ci-linux-build.sh gcc C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-gcc-cpp14-Vector-Checks/ + +clang-c++14-test-debug: + stage: test + script: "CI/ci-linux-test.sh clang C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++14-test-release: + stage: test + script: "CI/ci-linux-test.sh clang C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + +clang-c++14-build-debug: + stage: build + script: "CI/ci-linux-build.sh clang C++14 debug" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-debug-clang-cpp14-Vector-Checks/ + +clang-c++14-build-release: + stage: build + script: "CI/ci-linux-build.sh clang C++14 release" + image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + tags: [Docker] + artifacts: + paths: + - build-release-clang-cpp14-Vector-Checks/ \ No newline at end of file diff --git a/CI/gitlab-ci/mac.yml b/CI/gitlab-ci/mac.yml new file mode 100644 index 00000000..b385eeeb --- /dev/null +++ b/CI/gitlab-ci/mac.yml @@ -0,0 +1,35 @@ +# ----------------- +# Apple tasks +# ----------------- + +macos-cpp11-debug: + stage: build + script: "CI/ci-mac-build.sh C++11 debug ; CI/ci-mac-test.sh C++11 debug" + tags: + - Apple + +macos-cpp14-debug: + stage: build + script: "CI/ci-mac-build.sh C++14 debug ; CI/ci-mac-test.sh C++14 debug" + tags: + - Apple + +macos-cpp11-release: + stage: build + script: "CI/ci-mac-build.sh C++11 release ; CI/ci-mac-test.sh C++11 release" + tags: + - Apple + artifacts: + paths: + - build-release-cpp11/*.dmg + - build-release-cpp11/*.tar.gz + +macos-cpp14-release: + stage: build + script: "CI/ci-mac-build.sh C++14 release ; CI/ci-mac-test.sh C++14 release" + tags: + - Apple + artifacts: + paths: + - build-release-cpp14/*.dmg + - build-release-cpp14/*.tar.gz diff --git a/CI/gitlab-ci/windows.yml b/CI/gitlab-ci/windows.yml new file mode 100644 index 00000000..d8ebdf03 --- /dev/null +++ b/CI/gitlab-ci/windows.yml @@ -0,0 +1,206 @@ +# ----------------- +# Windows tasks +# ----------------- + +VS2017-64-bit-shared-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x64" + SHARED: "TRUE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2017 + - Qt5101 + artifacts: + paths: + - build-release/*.exe + +VS2017-64-bit-static-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x64" + SHARED: "FALSE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2017 + - Qt5101 + artifacts: + paths: + - build-release/*.exe + + +VS2017-64-bit-shared-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x64" + SHARED: "TRUE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2017 + artifacts: + paths: + - build-release/*.exe + + +VS2017-32-bit-shared-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x32" + SHARED: "TRUE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2017 + artifacts: + paths: + - build-release/*.exe + + +VS2017-64-bit-static-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x64" + SHARED: "FALSE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2017 + artifacts: + paths: + - build-release/*.exe + + +VS2017-32-bit-static-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2017" + ARCHITECTURE: "x32" + SHARED: "FALSE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2017 + artifacts: + paths: + - build-release/*.exe + +VS2015-64-bit-shared-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x64" + SHARED: "TRUE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + + +VS2015-64-bit-shared-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x64" + SHARED: "TRUE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-32-bit-shared-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x32" + SHARED: "TRUE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-32-bit-shared-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x32" + SHARED: "TRUE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-64-bit-static-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x64" + SHARED: "FALSE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-64-bit-static-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x64" + SHARED: "FALSE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-32-bit-static-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x32" + SHARED: "FALSE" + APPS: "ON" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe + +VS2015-32-bit-static-no-apps: + stage: build + variables: + BUILD_PLATFORM: "VS2015" + ARCHITECTURE: "x32" + SHARED: "FALSE" + APPS: "OFF" + script: "CI\\Windows.bat" + tags: + - VS2015 + artifacts: + paths: + - build-release/*.exe From 75297b11e61042342701152a0718b7070004718b Mon Sep 17 00:00:00 2001 From: Johannes Lenzen Date: Tue, 29 Oct 2019 16:15:54 +0100 Subject: [PATCH 08/22] Changed the .gitlab-ci.yml structure Beginned with new building system .gitlab-ci.yml can now be generated by the script assemble-gitlab-ci.py. Therefore the .gitlab-ci.yml configuration file can be split into several smaller files --- .gitlab-ci.yml | 34 +++++++++++++++++----------------- CI/gitlab-ci/linux.yml | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8fd21723..79a414a4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ variables: cppcheck: stage: build script: "CI/ci-cppcheck.sh" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -33,20 +33,20 @@ cppcheck: gcc-c++11-test-debug: stage: test script: "CI/ci-linux-test.sh gcc C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++11-test-release: stage: test script: "CI/ci-linux-test.sh gcc C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++11-build-debug: stage: build script: "CI/ci-linux-build.sh gcc C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -55,7 +55,7 @@ gcc-c++11-build-debug: gcc-c++11-build-release: stage: build script: "CI/ci-linux-build.sh gcc C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -64,19 +64,19 @@ gcc-c++11-build-release: clang-c++11-test-debug: stage: test script: "CI/ci-linux-test.sh clang C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++11-test-release: stage: test script: "CI/ci-linux-test.sh clang C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++11-build-debug: stage: build script: "CI/ci-linux-build.sh clang C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -85,7 +85,7 @@ clang-c++11-build-debug: clang-c++11-build-release: stage: build script: "CI/ci-linux-build.sh clang C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -94,19 +94,19 @@ clang-c++11-build-release: gcc-c++14-test-debug: stage: test script: "CI/ci-linux-test.sh gcc C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++14-test-release: stage: test script: "CI/ci-linux-test.sh gcc C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++14-build-debug: stage: build script: "CI/ci-linux-build.sh gcc C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -115,7 +115,7 @@ gcc-c++14-build-debug: gcc-c++14-build-release: stage: build script: "CI/ci-linux-build.sh gcc C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -124,19 +124,19 @@ gcc-c++14-build-release: clang-c++14-test-debug: stage: test script: "CI/ci-linux-test.sh clang C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++14-test-release: stage: test script: "CI/ci-linux-test.sh clang C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++14-build-debug: stage: build script: "CI/ci-linux-build.sh clang C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -145,7 +145,7 @@ clang-c++14-build-debug: clang-c++14-build-release: stage: build script: "CI/ci-linux-build.sh clang C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: diff --git a/CI/gitlab-ci/linux.yml b/CI/gitlab-ci/linux.yml index 3073aa0e..a3480c64 100644 --- a/CI/gitlab-ci/linux.yml +++ b/CI/gitlab-ci/linux.yml @@ -5,7 +5,7 @@ cppcheck: stage: build script: "CI/ci-cppcheck.sh" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -14,20 +14,20 @@ cppcheck: gcc-c++11-test-debug: stage: test script: "CI/ci-linux-test.sh gcc C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++11-test-release: stage: test script: "CI/ci-linux-test.sh gcc C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++11-build-debug: stage: build script: "CI/ci-linux-build.sh gcc C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -36,7 +36,7 @@ gcc-c++11-build-debug: gcc-c++11-build-release: stage: build script: "CI/ci-linux-build.sh gcc C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -45,19 +45,19 @@ gcc-c++11-build-release: clang-c++11-test-debug: stage: test script: "CI/ci-linux-test.sh clang C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++11-test-release: stage: test script: "CI/ci-linux-test.sh clang C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++11-build-debug: stage: build script: "CI/ci-linux-build.sh clang C++11 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -66,7 +66,7 @@ clang-c++11-build-debug: clang-c++11-build-release: stage: build script: "CI/ci-linux-build.sh clang C++11 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -75,19 +75,19 @@ clang-c++11-build-release: gcc-c++14-test-debug: stage: test script: "CI/ci-linux-test.sh gcc C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++14-test-release: stage: test script: "CI/ci-linux-test.sh gcc C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] gcc-c++14-build-debug: stage: build script: "CI/ci-linux-build.sh gcc C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -96,7 +96,7 @@ gcc-c++14-build-debug: gcc-c++14-build-release: stage: build script: "CI/ci-linux-build.sh gcc C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -105,19 +105,19 @@ gcc-c++14-build-release: clang-c++14-test-debug: stage: test script: "CI/ci-linux-test.sh clang C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++14-test-release: stage: test script: "CI/ci-linux-test.sh clang C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] clang-c++14-build-debug: stage: build script: "CI/ci-linux-build.sh clang C++14 debug" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: @@ -126,7 +126,7 @@ clang-c++14-build-debug: clang-c++14-build-release: stage: build script: "CI/ci-linux-build.sh clang C++14 release" - image: graphics.rwth-aachen.de:4567/moebius/docker/docker-openmesh-container + image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container tags: [Docker] artifacts: paths: From 34b2e958e13731ee8594733e067602ef835e93e4 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 13:59:54 +0100 Subject: [PATCH 09/22] add convenience function n_elements returning n_vertices, n_halfedges, n_edges, or n_faces depending on the template argument --- src/OpenMesh/Core/Mesh/BaseKernel.hh | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/Mesh/BaseKernel.hh b/src/OpenMesh/Core/Mesh/BaseKernel.hh index 0a0fee1a..0270a580 100644 --- a/src/OpenMesh/Core/Mesh/BaseKernel.hh +++ b/src/OpenMesh/Core/Mesh/BaseKernel.hh @@ -516,7 +516,7 @@ public: // Copy all properties, if build in is true // Otherwise, copy only properties without build in specifier if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) ) - (*p_it)->copy(_vh_from.idx(), _vh_to.idx()); + (*p_it)->copy(static_cast(_vh_from.idx()), static_cast(_vh_to.idx())); } } @@ -690,6 +690,9 @@ public: //----------------------------------------------------- element numbers virtual size_t n_edges() const { return 0; } virtual size_t n_faces() const { return 0; } + template + size_t n_elements() const; + protected: //------------------------------------------- synchronize properties @@ -814,6 +817,16 @@ private: }; +template <> +inline size_t BaseKernel::n_elements() const { return n_vertices(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_halfedges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_edges(); } +template <> +inline size_t BaseKernel::n_elements() const { return n_faces(); } + + //============================================================================= } // namespace OpenMesh //============================================================================= From 3d648b23b30b7e4fba12d8fb2e71ef927a84389d Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:01:50 +0100 Subject: [PATCH 10/22] add elements and all_elements methods that return the range corresponding to the template argument --- src/OpenMesh/Core/Mesh/PolyConnectivity.hh | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/OpenMesh/Core/Mesh/PolyConnectivity.hh b/src/OpenMesh/Core/Mesh/PolyConnectivity.hh index 78e8a3f9..6973f614 100644 --- a/src/OpenMesh/Core/Mesh/PolyConnectivity.hh +++ b/src/OpenMesh/Core/Mesh/PolyConnectivity.hh @@ -1169,6 +1169,9 @@ public: &PolyConnectivity::faces_sbegin, &PolyConnectivity::faces_end> ConstFaceRangeSkipping; + template + struct ElementRange; + /** * @return The vertices as a range object suitable * for C++11 range based for loops. Will skip deleted vertices. @@ -1217,6 +1220,21 @@ public: */ ConstFaceRange all_faces() const { return ConstFaceRange(*this); } + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will skip deleted faces. + */ + template + typename ElementRange::RangeSkipping elements() const; + + /** + * @return The elements corresponding to the template type as a range object suitable + * for C++11 range based for loops. Will include deleted faces. + */ + template + typename ElementRange::Range all_elements() const; + + /// Generic class for iterator ranges. template< typename CONTAINER_TYPE, @@ -1241,6 +1259,7 @@ public: CENTER_ENTITY_TYPE center_; }; + typedef CirculatorRange< PolyConnectivity, ConstVertexVertexCWIter, @@ -1625,6 +1644,52 @@ private: // Working storage for add_face() }; +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstVertexRange; + using RangeSkipping = ConstVertexRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstHalfedgeRange; + using RangeSkipping = ConstHalfedgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstEdgeRange; + using RangeSkipping = ConstEdgeRangeSkipping; +}; + +template <> +struct PolyConnectivity::ElementRange +{ + using Range = ConstFaceRange; + using RangeSkipping = ConstFaceRangeSkipping; +}; + + +template <> +inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::elements() const { return ConstVertexRangeSkipping(*this); } +template <> +inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_elements() const { return ConstVertexRange(*this); } +template <> +inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::elements() const { return ConstHalfedgeRangeSkipping(*this); } +template <> +inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_elements() const { return ConstHalfedgeRange(*this); } +template <> +inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::elements() const { return ConstEdgeRangeSkipping(*this); } +template <> +inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_elements() const { return ConstEdgeRange(*this); } +template <> +inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::elements() const { return ConstFaceRangeSkipping(*this); } +template <> +inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_elements() const { return ConstFaceRange(*this); } + }//namespace OpenMesh #endif//OPENMESH_POLYCONNECTIVITY_HH From 8bc5491c5cd623e7908f13d71ba4f56bcbcd5a3c Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:02:43 +0100 Subject: [PATCH 11/22] add Handle typedef to PropHandleT that specifies the corresponding element handle type --- src/OpenMesh/Core/Utils/Property.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/OpenMesh/Core/Utils/Property.hh b/src/OpenMesh/Core/Utils/Property.hh index 7f913ec1..cf2fdf5c 100644 --- a/src/OpenMesh/Core/Utils/Property.hh +++ b/src/OpenMesh/Core/Utils/Property.hh @@ -485,6 +485,7 @@ struct VPropHandleT : public BasePropHandleT { typedef T Value; typedef T value_type; + typedef VertexHandle Handle; explicit VPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} explicit VPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} @@ -499,6 +500,7 @@ struct HPropHandleT : public BasePropHandleT { typedef T Value; typedef T value_type; + typedef HalfedgeHandle Handle; explicit HPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} explicit HPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} @@ -513,6 +515,7 @@ struct EPropHandleT : public BasePropHandleT { typedef T Value; typedef T value_type; + typedef EdgeHandle Handle; explicit EPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} explicit EPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} @@ -527,6 +530,7 @@ struct FPropHandleT : public BasePropHandleT { typedef T Value; typedef T value_type; + typedef FaceHandle Handle; explicit FPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} explicit FPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} From de529269b508acf6638b2892435608f159640d77 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:09:08 +0100 Subject: [PATCH 12/22] remove second template argument off PropertyManager --- src/OpenMesh/Core/Utils/PropertyManager.hh | 124 ++++++++++++--------- 1 file changed, 70 insertions(+), 54 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index fb3860f5..9319184d 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,8 @@ namespace OpenMesh { * makeTemporaryProperty(), getProperty(), and getOrMakeProperty() * to construct a PropertyManager, e.g. * + * Note that the second template parameter is depcretated. + * * \code * { * TriMesh mesh; @@ -73,7 +76,7 @@ namespace OpenMesh { * } * \endcode */ -template +template class PropertyManager { #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) public: @@ -110,7 +113,7 @@ class PropertyManager { * @see PropertyManager::createIfNotExists, makePropertyManagerFromNew, * makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew */ - PropertyManager(MeshT &mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) { + PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) { if (existing) { if (!mesh_->get_property_handle(prop_, propname)) { std::ostringstream oss; @@ -136,24 +139,40 @@ class PropertyManager { std::swap(name_, rhs.name_); } - static bool propertyExists(MeshT &mesh, const char *propname) { + static bool propertyExists(PolyConnectivity &mesh, const char *propname) { PROPTYPE dummy; return mesh.get_property_handle(dummy, propname); } - bool isValid() const { return mesh_ != 0; } + bool isValid() const { return prop_.is_valid(); } operator bool() const { return isValid(); } const PROPTYPE &getRawProperty() const { return prop_; } const std::string &getName() const { return name_; } - MeshT &getMesh() const { return *mesh_; } + /** + * Get the mesh corresponding to the property. + * + * If you use PropertyManager without second template parameter (recommended) + * you need to specify the actual mesh type when using this function, e.g.: + * \code + * { + * TriMesh mesh; + * auto visited = VProp(mesh); + * TriMesh& mesh_ref = visited.getMesh(); + * } + * + */ + template + MeshType& getMesh() const { return dynamic_cast(mesh_); } + + MeshT& getMesh() const { return dynamic_cast(mesh_); } #if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) /// Only for pre C++11 compatibility. - typedef PropertyManager Proxy; + typedef PropertyManager Proxy; /** * Move constructor. Transfers ownership (delete responsibility). @@ -184,7 +203,7 @@ class PropertyManager { * * @see makePropertyManagerFromExistingOrNew */ - static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) { + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) { PROPTYPE dummy_prop; PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); pm.retain(); @@ -201,7 +220,7 @@ class PropertyManager { * @see makePropertyManagerFromExistingOrNew */ template - static PropertyManager createIfNotExists(MeshT &mesh, const char *propname, + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, const PROP_VALUE &init_value) { const bool exists = propertyExists(mesh, propname); @@ -222,7 +241,7 @@ class PropertyManager { * @see makePropertyManagerFromExistingOrNew */ template - static PropertyManager createIfNotExists(MeshT &mesh, const char *propname, + static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname, const ITERATOR_RANGE &range, const PROP_VALUE &init_value) { return createIfNotExists( mesh, propname, range.begin(), range.end(), init_value); @@ -244,9 +263,9 @@ class PropertyManager { #else class Proxy { private: - Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) : + Proxy(PolyConnectivity *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) : mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {} - MeshT *mesh_; + PolyConnectivity *mesh_; PROPTYPE prop_; bool retain_; std::string name_; @@ -279,7 +298,7 @@ class PropertyManager { * * @see makePropertyManagerFromExistingOrNew */ - static Proxy createIfNotExists(MeshT &mesh, const char *propname) { + static Proxy createIfNotExists(PolyConnectivity &mesh, const char *propname) { PROPTYPE dummy_prop; PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); pm.retain(); @@ -296,7 +315,7 @@ class PropertyManager { * @see makePropertyManagerFromExistingOrNew */ template - static Proxy createIfNotExists(MeshT &mesh, const char *propname, + static Proxy createIfNotExists(PolyConnectivity &mesh, const char *propname, const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, const PROP_VALUE &init_value) { const bool exists = propertyExists(mesh, propname); @@ -386,7 +405,7 @@ class PropertyManager { * Examples: * \code * MeshT mesh; - * PropertyManager, MeshT> distance( + * PropertyManager> distance( * mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de"); * distance.set_range( * mesh.vertices_begin(), mesh.vertices_end(), @@ -434,9 +453,9 @@ class PropertyManager { * Will be used with dst_propmanager. Used to double check the bounds. */ template + typename HandleTypeIterator_2> void copy_to(HandleTypeIterator begin, HandleTypeIterator end, - PropertyManager &dst_propmanager, + PropertyManager &dst_propmanager, HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const { for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) { @@ -445,9 +464,9 @@ class PropertyManager { } template + typename RangeType_2> void copy_to(const RangeType &range, - PropertyManager &dst_propmanager, + PropertyManager &dst_propmanager, const RangeType_2 &dst_range) const { copy_to(range.begin(), range.end(), dst_propmanager, dst_range.begin(), dst_range.end()); @@ -467,15 +486,15 @@ class PropertyManager { * @param dst_mesh Destination mesh on which to copy. * @param dst_range Destination range. */ - template + template static void copy(const char *prop_name, - MeshT &src_mesh, const RangeType &src_range, - MeshT_2 &dst_mesh, const RangeType_2 &dst_range) { + PolyConnectivity &src_mesh, const RangeType &src_range, + PolyConnectivity &dst_mesh, const RangeType_2 &dst_range) { - typedef OpenMesh::PropertyManager DstPM; + typedef OpenMesh::PropertyManager DstPM; DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name)); - typedef OpenMesh::PropertyManager SrcPM; + typedef OpenMesh::PropertyManager SrcPM; SrcPM src(src_mesh, prop_name, true); src.copy_to(src_range, dst, dst_range); @@ -488,7 +507,7 @@ class PropertyManager { } private: - MeshT *mesh_; + PolyConnectivity* mesh_; PROPTYPE prop_; bool retain_; std::string name_; @@ -517,13 +536,12 @@ class PropertyManager { * @param propname (optional) The name of the created property * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @tparam T Value type of the created property, e.g., \p double, \p int, etc. - * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh * @returns A PropertyManager handling the lifecycle of the property */ -template -PropertyManager::type, MeshT> -makeTemporaryProperty(MeshT &mesh, const char *propname = "") { - return PropertyManager::type, MeshT>(mesh, propname, false); +template +PropertyManager::type> +makeTemporaryProperty(PolyConnectivity &mesh, const char *propname = "") { + return PropertyManager::type>(mesh, propname, false); } /** @relates PropertyManager @@ -551,13 +569,12 @@ makeTemporaryProperty(MeshT &mesh, const char *propname = "") { * @param propname The name of the created property * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @tparam T Value type of the created property, e.g., \p double, \p int, etc. - * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh * @returns A PropertyManager wrapping the property */ -template -PropertyManager::type, MeshT> -getProperty(MeshT &mesh, const char *propname) { - return PropertyManager::type, MeshT>(mesh, propname, true); +template +PropertyManager::type> +getProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>(mesh, propname, true); } /** @relates PropertyManager @@ -587,13 +604,12 @@ getProperty(MeshT &mesh, const char *propname) { * @param propname The name of the created property * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @tparam T Value type of the created property, e.g., \p double, \p int, etc. - * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh * @returns A PropertyManager wrapping the property */ -template -PropertyManager::type, MeshT> -getOrMakeProperty(MeshT &mesh, const char *propname) { - return PropertyManager::type, MeshT>::createIfNotExists(mesh, propname); +template +PropertyManager::type> +getOrMakeProperty(PolyConnectivity &mesh, const char *propname) { + return PropertyManager::type>::createIfNotExists(mesh, propname); } /** @relates PropertyManager @@ -617,9 +633,9 @@ getOrMakeProperty(MeshT &mesh, const char *propname) { * @tparam T Value type of the expected property, e.g., \p double, \p int, etc. * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh */ -template +template bool -hasProperty(const MeshT &mesh, const char *propname) { +hasProperty(const PolyConnectivity &mesh, const char *propname) { typename HandleToPropHandle::type ph; return mesh.get_property_handle(ph, propname); } @@ -633,11 +649,11 @@ hasProperty(const MeshT &mesh, const char *propname) { * Intended for temporary properties. Shadows any existing properties of * matching name and type. */ -template +template OM_DEPRECATED("Use makeTemporaryProperty instead.") -PropertyManager makePropertyManagerFromNew(MeshT &mesh, const char *propname) +PropertyManager makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname) { - return PropertyManager(mesh, propname, false); + return PropertyManager(mesh, propname, false); } /** \relates PropertyManager @@ -652,11 +668,11 @@ PropertyManager makePropertyManagerFromNew(MeshT &mesh, const c * @throws std::runtime_error if no property with the name \p propname of * matching type exists. */ -template +template OM_DEPRECATED("Use getProperty instead.") -PropertyManager makePropertyManagerFromExisting(MeshT &mesh, const char *propname) +PropertyManager makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname) { - return PropertyManager(mesh, propname, true); + return PropertyManager(mesh, propname, true); } /** @relates PropertyManager @@ -667,11 +683,11 @@ PropertyManager makePropertyManagerFromExisting(MeshT &mesh, co * * Intended for creating or accessing persistent properties. */ -template +template OM_DEPRECATED("Use getOrMakeProperty instead.") -PropertyManager makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname) +PropertyManager makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname) { - return PropertyManager::createIfNotExists(mesh, propname); + return PropertyManager::createIfNotExists(mesh, propname); } /** @relates PropertyManager @@ -707,14 +723,14 @@ PropertyManager makePropertyManagerFromExistingOrNew( * * Intended for creating or accessing persistent properties. */ -template OM_DEPRECATED("Use getOrMakeProperty instead.") -PropertyManager makePropertyManagerFromExistingOrNew( - MeshT &mesh, const char *propname, +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, const ITERATOR_RANGE &range, const PROP_VALUE &init_value) { - return makePropertyManagerFromExistingOrNew( + return makePropertyManagerFromExistingOrNew( mesh, propname, range.begin(), range.end(), init_value); } From 8a8aab33e01176221696f11c6cab29f70ceb015b Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:31:00 +0100 Subject: [PATCH 13/22] remove second template argument of property manager in unittests --- src/Unittests/unittests_propertymanager.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index 2fe59654..d8f8668e 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -62,7 +62,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { { OpenMesh::PropertyManager< - OpenMesh::VPropHandleT, Mesh> pm_v_bool(mesh_, "pm_v_bool"); + OpenMesh::VPropHandleT> pm_v_bool(mesh_, "pm_v_bool"); pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false); for (int i = 0; i < 4; ++i) ASSERT_FALSE(pm_v_bool[vhandle[i]]); @@ -71,7 +71,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { ASSERT_TRUE(pm_v_bool[vhandle[i]]); OpenMesh::PropertyManager< - OpenMesh::EPropHandleT, Mesh> pm_e_bool(mesh_, "pm_e_bool"); + OpenMesh::EPropHandleT> pm_e_bool(mesh_, "pm_e_bool"); pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), false); for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end(); e_it != f_end; ++e_it) @@ -82,7 +82,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { ASSERT_TRUE(pm_e_bool[*e_it]); OpenMesh::PropertyManager< - OpenMesh::FPropHandleT, Mesh> pm_f_bool(mesh_, "pm_f_bool"); + OpenMesh::FPropHandleT> pm_f_bool(mesh_, "pm_f_bool"); pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), false); for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end(); f_it != f_end; ++f_it) @@ -98,7 +98,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { */ { OpenMesh::PropertyManager< - OpenMesh::VPropHandleT, Mesh> pm_v_bool(mesh_, "pm_v_bool2"); + OpenMesh::VPropHandleT> pm_v_bool(mesh_, "pm_v_bool2"); pm_v_bool.set_range(mesh_.vertices(), false); for (int i = 0; i < 4; ++i) ASSERT_FALSE(pm_v_bool[vhandle[i]]); @@ -107,7 +107,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { ASSERT_TRUE(pm_v_bool[vhandle[i]]); OpenMesh::PropertyManager< - OpenMesh::EPropHandleT, Mesh> pm_e_bool(mesh_, "pm_e_bool2"); + OpenMesh::EPropHandleT> pm_e_bool(mesh_, "pm_e_bool2"); pm_e_bool.set_range(mesh_.edges(), false); for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end(); e_it != f_end; ++e_it) @@ -118,7 +118,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { ASSERT_TRUE(pm_e_bool[*e_it]); OpenMesh::PropertyManager< - OpenMesh::FPropHandleT, Mesh> pm_f_bool(mesh_, "pm_f_bool2"); + OpenMesh::FPropHandleT> pm_f_bool(mesh_, "pm_f_bool2"); pm_f_bool.set_range(mesh_.faces(), false); for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end(); f_it != f_end; ++f_it) From 99632809d8c14ea54667600dbb741d09a6dbc049 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:31:55 +0100 Subject: [PATCH 14/22] in unittest replace has_property check with the one implemented in property manager --- src/Unittests/unittests_propertymanager.cc | 26 ++++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index d8f8668e..ece51b6b 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -136,27 +136,21 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { * ==================================================================== */ -template -bool has_property(const Mesh& _mesh, const std::string& _name) { - auto dummy_handle = PropHandle{}; - return _mesh.get_property_handle(dummy_handle, _name); -} - /* * Temporary property */ TEST_F(OpenMeshPropertyManager, cpp11_temp_property) { using handle_type = OpenMesh::VPropHandleT; const auto prop_name = "pm_v_test_property"; - ASSERT_FALSE(has_property(mesh_, prop_name)); + ASSERT_FALSE((OpenMesh::hasProperty(mesh_, prop_name))); { auto vprop = OpenMesh::makeTemporaryProperty(mesh_, prop_name); static_cast(vprop); // Unused variable - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); } - ASSERT_FALSE(has_property(mesh_, prop_name)); + ASSERT_FALSE((OpenMesh::hasProperty(mesh_, prop_name))); } /* @@ -166,7 +160,6 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property) { TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) { auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to - using handle_type = OpenMesh::VPropHandleT; const auto prop_name = "pm_v_test_property"; auto outer_prop = OpenMesh::makeTemporaryProperty(mesh_, prop_name); @@ -182,7 +175,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) { } // Ensure outer_prop still exists and its data has not been overwritten by inner_prop - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); ASSERT_EQ(100, outer_prop[vh]); } @@ -196,10 +189,9 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) { TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to - using handle_type = OpenMesh::VPropHandleT; const auto prop_name = "pm_v_test_property"; - ASSERT_FALSE(has_property(mesh_, prop_name)); + ASSERT_FALSE((OpenMesh::hasProperty(mesh_, prop_name))); { auto prop = OpenMesh::getOrMakeProperty(mesh_, prop_name); @@ -207,7 +199,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { // End of scope, property persists } - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); { // Since a property of the same name and type already exists, this refers to the existing property. @@ -217,7 +209,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { // End of scope, property persists } - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); { // Acquire non-owning handle to the property, knowing it exists @@ -225,7 +217,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { ASSERT_EQ(200, prop[vh]); } - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); { // Attempt to acquire non-owning handle for a non-existing property @@ -235,7 +227,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { ASSERT_THROW(code_that_throws(), std::runtime_error); } - ASSERT_TRUE(has_property(mesh_, prop_name)); + ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); } } From c861a0e84da3006243abc097f9ef86c93f132c7d Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 14:32:24 +0100 Subject: [PATCH 15/22] add method to get points property handle in AttribKernel --- src/OpenMesh/Core/Mesh/AttribKernelT.hh | 45 +++++++++++++------------ 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/OpenMesh/Core/Mesh/AttribKernelT.hh b/src/OpenMesh/Core/Mesh/AttribKernelT.hh index 90b10fe0..3d4d2046 100644 --- a/src/OpenMesh/Core/Mesh/AttribKernelT.hh +++ b/src/OpenMesh/Core/Mesh/AttribKernelT.hh @@ -105,10 +105,26 @@ public: FAttribs = MeshItems::FAttribs }; - typedef VPropHandleT DataVPropHandle; - typedef HPropHandleT DataHPropHandle; - typedef EPropHandleT DataEPropHandle; - typedef FPropHandleT DataFPropHandle; + typedef VPropHandleT DataVPropHandle; + typedef HPropHandleT DataHPropHandle; + typedef EPropHandleT DataEPropHandle; + typedef FPropHandleT DataFPropHandle; + + typedef VPropHandleT PointsPropertyHandle; + typedef VPropHandleT VertexNormalsPropertyHandle; + typedef VPropHandleT VertexColorsPropertyHandle; + typedef VPropHandleT VertexTexCoords1DPropertyHandle; + typedef VPropHandleT VertexTexCoords2DPropertyHandle; + typedef VPropHandleT VertexTexCoords3DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; + typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; + typedef EPropHandleT EdgeColorsPropertyHandle; + typedef HPropHandleT HalfedgeNormalsPropertyHandle; + typedef HPropHandleT HalfedgeColorsPropertyHandle; + typedef FPropHandleT FaceNormalsPropertyHandle; + typedef FPropHandleT FaceColorsPropertyHandle; + typedef FPropHandleT FaceTextureIndexPropertyHandle; public: @@ -240,6 +256,9 @@ public: void set_point(VertexHandle _vh, const Point& _p) { this->property(points_, _vh) = _p; } + PointsPropertyHandle& points_property_handle() + { return points_; } + //------------------------------------------------------------ vertex normals @@ -592,24 +611,6 @@ public: bool has_face_colors() const { return face_colors_.is_valid(); } bool has_face_texture_index() const { return face_texture_index_.is_valid(); } -public: - - typedef VPropHandleT PointsPropertyHandle; - typedef VPropHandleT VertexNormalsPropertyHandle; - typedef VPropHandleT VertexColorsPropertyHandle; - typedef VPropHandleT VertexTexCoords1DPropertyHandle; - typedef VPropHandleT VertexTexCoords2DPropertyHandle; - typedef VPropHandleT VertexTexCoords3DPropertyHandle; - typedef HPropHandleT HalfedgeTexCoords1DPropertyHandle; - typedef HPropHandleT HalfedgeTexCoords2DPropertyHandle; - typedef HPropHandleT HalfedgeTexCoords3DPropertyHandle; - typedef EPropHandleT EdgeColorsPropertyHandle; - typedef HPropHandleT HalfedgeNormalsPropertyHandle; - typedef HPropHandleT HalfedgeColorsPropertyHandle; - typedef FPropHandleT FaceNormalsPropertyHandle; - typedef FPropHandleT FaceColorsPropertyHandle; - typedef FPropHandleT FaceTextureIndexPropertyHandle; - public: //standard vertex properties PointsPropertyHandle points_pph() const From c79d85c3a0d14b4770cf03aaba7fa4dd0c8f94ea Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 15:24:42 +0100 Subject: [PATCH 16/22] remove second template argument of propertymanager in subdivider --- src/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh b/src/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh index 3014449c..b22b7782 100644 --- a/src/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh +++ b/src/OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh @@ -51,8 +51,8 @@ protected: // SubdividerT interface _m.request_edge_status(); _m.request_vertex_status(); _m.request_face_status(); - PropertyManager, mesh_t> edge_midpoint(_m, "edge_midpoint"); - PropertyManager, mesh_t> is_original_vertex(_m, "is_original_vertex"); + PropertyManager> edge_midpoint(_m, "edge_midpoint"); + PropertyManager> is_original_vertex(_m, "is_original_vertex"); for (size_t iteration = 0; iteration < _n; ++iteration) { is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true); From 3c52a276150574aca2e883be6e06cfb0eb37d7cb Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 15:27:34 +0100 Subject: [PATCH 17/22] rework property manager --- src/OpenMesh/Core/Utils/PropertyManager.hh | 253 +++++++-- src/Unittests/unittests_propertymanager.cc | 610 +++++++++++++++++++++ 2 files changed, 803 insertions(+), 60 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index 9319184d..183a77f5 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -78,25 +78,15 @@ namespace OpenMesh { */ template class PropertyManager { -#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) - public: - PropertyManager(const PropertyManager&) = delete; - PropertyManager& operator=(const PropertyManager&) = delete; -#else - private: - /** - * Noncopyable because there aren't no straightforward copy semantics. - */ - PropertyManager(const PropertyManager&); - - /** - * Noncopyable because there aren't no straightforward copy semantics. - */ - PropertyManager& operator=(const PropertyManager&); -#endif public: + using Value = typename PROPTYPE::Value; + using value_type = typename PROPTYPE::value_type; + using Handle = typename PROPTYPE::Handle; + /** + * @deprecated Use a constructor without \p existing and check existance with hasProperty() instead. + * * Constructor. * * Throws an \p std::runtime_error if \p existing is true and @@ -110,22 +100,114 @@ class PropertyManager { * the instance merely acts as a convenience wrapper around an existing property with no * lifecycle management whatsoever. * - * @see PropertyManager::createIfNotExists, makePropertyManagerFromNew, - * makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew + * @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty, + * PropertyManager::makeTemporaryProperty */ - PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing = false) : mesh_(&mesh), retain_(existing), name_(propname) { + OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") + PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) { if (existing) { - if (!mesh_->get_property_handle(prop_, propname)) { + if (!mesh_.get_property_handle(prop_, propname)) { std::ostringstream oss; oss << "Requested property handle \"" << propname << "\" does not exist."; throw std::runtime_error(oss.str()); } } else { - mesh_->add_property(prop_, propname); + mesh_.add_property(prop_, propname); } } - PropertyManager() : mesh_(0), retain_(false) { + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + * @param propname The name of the property. + */ + PropertyManager(PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!mesh_.get_property_handle(prop_, propname)) { + mesh_.add_property(prop_, propname); + } + } + + /** + * Constructor. + * + * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. + * If the property is created it is initialized with \p initial_value + * + * @param mesh The mesh on which to create the property. + * @param initial_value + * @param propname The name of the property. + */ + PropertyManager(const Value& intial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + if (!mesh_.get_property_handle(prop_, propname)) { + mesh_.add_property(prop_, propname); + set_range(mesh_.all_elements(), intial_value); + } + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * + * @param mesh The mesh on which to create the property. + */ + PropertyManager(PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + mesh_.add_property(prop_, name_); + } + + /** + * Constructor. + * + * Create an anonymous property. Lifetime is managed. + * If the property is created it is initialized with \p initial_value + * + * @param mesh The mesh on which to create the property. + */ + PropertyManager(const Value& intial_value, PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + mesh_.add_property(prop_, name_); + set_range(mesh_.all_elements(), intial_value); + } + + /** + * Constructor. + * + * Create a wrapper around an existing property. Lifetime is not managed. + * + * @param mesh The mesh on which to create the property. + */ + PropertyManager(PolyConnectivity& mesh, PROPTYPE property_handle) : mesh_(mesh), prop_(property_handle), retain_(true), name_() { + } + + PropertyManager() = delete; + + PropertyManager(const PropertyManager& rhs) + : + mesh_(rhs.mesh_), + prop_(), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (rhs.retain_) // named property -> create a property manager referring to the same + { + prop_ = rhs.prop_; + } + else // unnamed property -> create a property manager refering to a new property and copy the contents + { + mesh_.add_property(prop_, name_); + rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + } + } + + PropertyManager& operator=(const PropertyManager& rhs) + { + if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_) + ; // nothing to do + else + rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + return *this; } ~PropertyManager() { @@ -177,21 +259,40 @@ class PropertyManager { /** * Move constructor. Transfers ownership (delete responsibility). */ - PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) { - rhs.retain_ = true; + PropertyManager(PropertyManager &&rhs) + : + mesh_(rhs.mesh_), + prop_(rhs.prop_), + retain_(rhs.retain_), + name_(rhs.name_) + { + if (!rhs.retain_) + rhs.prop_.invalidate(); // only invalidate unnamed properties } /** * Move assignment. Transfers ownership (delete responsibility). */ - PropertyManager &operator=(PropertyManager &&rhs) { - if (&rhs != this) { - deleteProperty(); - mesh_ = rhs.mesh_; - prop_ = rhs.prop_; - retain_ = rhs.retain_; - name_ = rhs.name_; - rhs.retain_ = true; + PropertyManager& operator=(PropertyManager&& rhs) + { + if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_)) + { + if (rhs.retain_) + { + // retained properties cannot be invalidated. Copy instead + rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + } + else + { + // switch the data stored in the properties + std::swap(mesh_.property(prop_).data_vector(), rhs.mesh_.property(rhs.prop_).data_vector()); + // resize the property to the correct size + mesh_.property(prop_).resize(mesh_.n_elements()); + // remove the property from rhs + rhs.mesh_.remove_property(rhs.prop_); + // invalidate prop_ + rhs.prop_.invalidate(); + } } return *this; } @@ -204,10 +305,7 @@ class PropertyManager { * @see makePropertyManagerFromExistingOrNew */ static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) { - PROPTYPE dummy_prop; - PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); - pm.retain(); - return std::move(pm); + return PropertyManager(mesh, propname); } /** @@ -248,8 +346,8 @@ class PropertyManager { } PropertyManager duplicate(const char *clone_name) { - PropertyManager pm(*mesh_, clone_name, false); - pm.mesh_->property(pm.prop_) = mesh_->property(prop_); + PropertyManager pm(mesh_, clone_name, false); + pm.mesh_.property(pm.prop_) = mesh_.property(prop_); return pm; } @@ -328,21 +426,11 @@ class PropertyManager { Proxy duplicate(const char *clone_name) { PropertyManager pm(*mesh_, clone_name, false); - pm.mesh_->property(pm.prop_) = mesh_->property(prop_); + pm.mesh_.property(pm.prop_) = mesh_.property(prop_); return (Proxy)pm; } #endif - /** - * \brief Disable lifecycle management for this property. - * - * If this method is called, the encapsulated property will not be deleted - * upon destruction of the PropertyManager instance. - */ - inline void retain(bool doRetain = true) { - retain_ = doRetain; - } - /** * Access the value of the encapsulated mesh property. * @@ -356,7 +444,7 @@ class PropertyManager { * @note This method is only used for mesh properties. */ typename PROPTYPE::reference& operator*() { - return mesh_->mproperty(prop_)[0]; + return mesh_.mproperty(prop_)[0]; } /** @@ -372,7 +460,7 @@ class PropertyManager { * @note This method is only used for mesh properties. */ typename PROPTYPE::const_reference& operator*() const { - return mesh_->mproperty(prop_)[0]; + return mesh_.mproperty(prop_)[0]; } /** @@ -384,7 +472,7 @@ class PropertyManager { */ template inline typename PROPTYPE::reference operator[] (const HandleType &handle) { - return mesh_->property(prop_, handle); + return mesh_.property(prop_, handle); } /** @@ -396,7 +484,7 @@ class PropertyManager { */ template inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const { - return mesh_->property(prop_, handle); + return mesh_.property(prop_, handle); } /** @@ -502,12 +590,12 @@ class PropertyManager { private: void deleteProperty() { - if (!retain_) - mesh_->remove_property(prop_); + if (!retain_ && prop_.is_valid()) + mesh_.remove_property(prop_); } private: - PolyConnectivity* mesh_; + PolyConnectivity& mesh_; PROPTYPE prop_; bool retain_; std::string name_; @@ -544,6 +632,27 @@ makeTemporaryProperty(PolyConnectivity &mesh, const char *propname = "") { return PropertyManager::type>(mesh, propname, false); } +///// shortcut or makeTemporaryrProperty +//template +//PropertyManager::type, MeshT> +//makeTemporaryVertexProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } + +///// shortcut or makeTemporaryrProperty +//template +//PropertyManager::type, MeshT> +//makeTemporaryHalfedgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } + +///// shortcut or makeTemporaryrProperty +//template +//PropertyManager::type, MeshT> +//makeTemporaryEdgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } + +///// shortcut or makeTemporaryrProperty +//template +//PropertyManager::type, MeshT> +//makeTemporaryFaceProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } + + /** @relates PropertyManager * * Obtains a handle to a named property. @@ -701,14 +810,14 @@ PropertyManager makePropertyManagerFromExistingOrNew(PolyConnectivity * * Intended for creating or accessing persistent properties. */ -template OM_DEPRECATED("Use getOrMakeProperty instead.") -PropertyManager makePropertyManagerFromExistingOrNew( - MeshT &mesh, const char *propname, +PropertyManager makePropertyManagerFromExistingOrNew( + PolyConnectivity &mesh, const char *propname, const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, const PROP_VALUE &init_value) { - return PropertyManager::createIfNotExists( + return PropertyManager::createIfNotExists( mesh, propname, begin, end, init_value); } @@ -734,5 +843,29 @@ PropertyManager makePropertyManagerFromExistingOrNew( mesh, propname, range.begin(), range.end(), init_value); } + +/** @relates PropertyManager + * Returns a convenience wrapper around the points property of a mesh. + */ +template +PropertyManager> +getPointsProperty(MeshT &mesh) { + return PropertyManager>(mesh, mesh.points_property_handle()); +} + + +template +using VProp = PropertyManager>; + +template +using HProp = PropertyManager>; + +template +using EProp = PropertyManager>; + +template +using FProp = PropertyManager>; + + } /* namespace OpenMesh */ #endif /* PROPERTYMANAGER_HH_ */ diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index ece51b6b..e5046194 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -230,4 +230,614 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); } + +TEST_F(OpenMeshPropertyManager, property_copy_construction) { + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + // unnamed + { + auto prop1 = OpenMesh::VProp(mesh_); + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto prop2 = prop1; // prop1 and prop2 should be two different properties with the same content + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13); + } + + // named + { + auto prop1 = OpenMesh::VProp(mesh_, "ids"); + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto prop2 = prop1; // prop1 and prop2 should refere to the same property + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13); + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0); + } +} + +TEST_F(OpenMeshPropertyManager, property_move_construction) { + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + // unnamed + { + auto prop1 = OpenMesh::VProp(mesh_); + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + auto prop2 = std::move(prop1); + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "move constructing property from temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_FALSE(prop1.isValid()) << "prop1 should have been invalidated"; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13); + } + + // named + { + auto prop1 = OpenMesh::VProp(mesh_, "ids"); + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + auto prop2 = std::move(prop1); // prop1 and prop2 should refere to the same property + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "move constructing from named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named properties cannot be invalidated"; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "property is not valid anymore"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "did not copy property correctly"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0); + } +} + + +TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { + + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + // unnamed to unnamed + { + auto prop1 = OpenMesh::VProp(3, mesh_); + auto prop2 = OpenMesh::VProp(0, mesh_); + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // unnamed to named + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(0, mesh_, "ids"); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed"; + } + + // named to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_, "ids2"); + auto prop2 = OpenMesh::VProp(mesh_); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + } + + // named to named (different names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids3"); + auto prop2 = OpenMesh::VProp(mesh_, "ids4"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // named to named (same names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids5"); + auto prop2 = OpenMesh::VProp(mesh_, "ids5"); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; // this should be a no op + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + prop1.set_range(mesh_.vertices(), 42); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids5"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + } +} + + +TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) { + + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + // unnamed to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(mesh_); + prop2.set_range(mesh_.vertices(), 0); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // this should be cheap + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // unnamed to named + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(mesh_, "ids"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed"; + } + + // named to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_, "ids2"); + auto prop2 = OpenMesh::VProp(mesh_); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + } + + // named to named (different names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids3"); + auto prop2 = OpenMesh::VProp(mesh_, "ids4"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // named to named (same names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids5"); + auto prop2 = OpenMesh::VProp(mesh_, "ids5"); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // this should be a no op + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids5"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; + } +} + + + +TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { + + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + auto copy = mesh_; + for (int i = 0; i < 10; ++i) + copy.add_vertex(Mesh::Point()); + + // unnamed to unnamed + { + auto prop1 = OpenMesh::VProp(3, mesh_); + auto prop2 = OpenMesh::VProp(0, copy); + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized"; + } + + // unnamed to named + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(0, copy, "ids"); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(copy, "ids"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed"; + } + + // named to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_, "ids2"); + auto prop2 = OpenMesh::VProp(copy); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + } + + // named to named (different names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids3"); + auto prop2 = OpenMesh::VProp(copy, "ids4"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // named to named (same names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids5"); + auto prop2 = OpenMesh::VProp(copy, "ids5"); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = prop1; // this should be a no op + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "copying property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + prop1.set_range(mesh_.vertices(), 42); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids5"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + auto prop4 = OpenMesh::VProp(copy, "ids5"); + EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } +} + + +TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { + + for (int i = 0; i < 1000000; ++i) + mesh_.add_vertex(Mesh::Point()); + + auto copy = mesh_; + for (int i = 0; i < 10; ++i) + copy.add_vertex(Mesh::Point()); + + // unnamed to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(copy); + prop2.set_range(mesh_.vertices(), 0); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // this should be cheap + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized"; + } + + // unnamed to named + { + auto prop1 = OpenMesh::VProp(mesh_); + auto prop2 = OpenMesh::VProp(copy, "ids"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property temporary to named took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(copy, "ids"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed"; + } + + // named to unnamed + { + auto prop1 = OpenMesh::VProp(mesh_, "ids2"); + auto prop2 = OpenMesh::VProp(copy); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to temporary took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + } + + // named to named (different names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids3"); + auto prop2 = OpenMesh::VProp(copy, "ids4"); + prop2.set_range(mesh_.vertices(), 0); + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to named with different name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + prop1.set_range(mesh_.vertices(), 0); + + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } + + // named to named (same names) + { + auto prop1 = OpenMesh::VProp(mesh_, "ids5"); + auto prop2 = OpenMesh::VProp(copy, "ids5"); + + for (auto vh : mesh_.vertices()) + prop1[vh] = vh.idx()*2-13; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto t_start = std::chrono::high_resolution_clock::now(); + prop2 = std::move(prop1); // should copy + auto t_end = std::chrono::high_resolution_clock::now(); + std::cout << "moving property named to named with same name took " << std::chrono::duration_cast(t_end-t_start).count() << "ms" << std::endl; + + EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving"; + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + prop1.set_range(mesh_.vertices(), 42); + + EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + + auto prop3 = OpenMesh::VProp(mesh_, "ids5"); + EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; + auto prop4 = OpenMesh::VProp(copy, "ids5"); + EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; + } +} + + + } From 9b14efaa6dc6c36ad654e27711df30a82227b13a Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 31 Oct 2019 17:56:37 +0100 Subject: [PATCH 18/22] fix property manager for mesh properties --- src/OpenMesh/Core/Utils/Property.hh | 28 ++++ src/OpenMesh/Core/Utils/PropertyManager.hh | 172 ++++++++++++++------- src/Unittests/unittests_propertymanager.cc | 65 +------- 3 files changed, 152 insertions(+), 113 deletions(-) diff --git a/src/OpenMesh/Core/Utils/Property.hh b/src/OpenMesh/Core/Utils/Property.hh index cf2fdf5c..fb97f81c 100644 --- a/src/OpenMesh/Core/Utils/Property.hh +++ b/src/OpenMesh/Core/Utils/Property.hh @@ -545,11 +545,39 @@ struct MPropHandleT : public BasePropHandleT { typedef T Value; typedef T value_type; + typedef void Handle; explicit MPropHandleT(int _idx=-1) : BasePropHandleT(_idx) {} explicit MPropHandleT(const BasePropHandleT& _b) : BasePropHandleT(_b) {} }; +template +struct PropHandle; + +template <> +struct PropHandle { + template + using type = VPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = HPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = EPropHandleT; +}; + +template <> +struct PropHandle { + template + using type = FPropHandleT; +}; + } // namespace OpenMesh //============================================================================= #endif // OPENMESH_PROPERTY_HH defined diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index 183a77f5..cc462fd5 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -83,6 +83,43 @@ class PropertyManager { using Value = typename PROPTYPE::Value; using value_type = typename PROPTYPE::value_type; using Handle = typename PROPTYPE::Handle; + using Self = PropertyManager; + + private: + // Mesh properties (MPropHandleT<...>) are stored differently than the other properties. + // This class implements different behavior when copying or swapping data from one + // property manager to a another one. + template + struct StorageT; + + // specialization for Mesh Properties + template + struct StorageT> { + static void copy(const PropertyManager& from, PropertyManager2& to) { + *to = *from; + } + static void swap(PropertyManager& from, PropertyManager2& to) { + std::swap(*to, *from); + } + }; + + // definition for other Mesh Properties + template + struct StorageT { + static void copy(const PropertyManager& from, PropertyManager2& to) { + from.copy_to(from.mesh_.template all_elements(), to, to.mesh_.template all_elements()); + } + static void swap(PropertyManager& lhs, PropertyManager2& rhs) { + std::swap(lhs.mesh_.property(lhs.prop_).data_vector(), rhs.mesh_.property(rhs.prop_).data_vector()); + // resize the property to the correct size + lhs.mesh_.property(lhs.prop_).resize(lhs.mesh_.template n_elements()); + rhs.mesh_.property(rhs.prop_).resize(rhs.mesh_.template n_elements()); + } + }; + + using Storage = StorageT; + + public: /** * @deprecated Use a constructor without \p existing and check existance with hasProperty() instead. @@ -140,7 +177,7 @@ class PropertyManager { * @param initial_value * @param propname The name of the property. */ - PropertyManager(const Value& intial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { + PropertyManager(PolyConnectivity& mesh, const char *propname, const Value& intial_value) : mesh_(mesh), retain_(true), name_(propname) { if (!mesh_.get_property_handle(prop_, propname)) { mesh_.add_property(prop_, propname); set_range(mesh_.all_elements(), intial_value); @@ -166,7 +203,7 @@ class PropertyManager { * * @param mesh The mesh on which to create the property. */ - PropertyManager(const Value& intial_value, PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { + PropertyManager(PolyConnectivity& mesh, const Value& intial_value) : mesh_(mesh), retain_(false), name_("") { mesh_.add_property(prop_, name_); set_range(mesh_.all_elements(), intial_value); } @@ -197,7 +234,7 @@ class PropertyManager { else // unnamed property -> create a property manager refering to a new property and copy the contents { mesh_.add_property(prop_, name_); - rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + Storage::copy(rhs, *this); } } @@ -206,7 +243,7 @@ class PropertyManager { if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_) ; // nothing to do else - rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + Storage::copy(rhs, *this); return *this; } @@ -280,14 +317,12 @@ class PropertyManager { if (rhs.retain_) { // retained properties cannot be invalidated. Copy instead - rhs.copy_to(rhs.mesh_.template all_elements(), *this, mesh_.all_elements()); + Storage::copy(rhs, *this); } else { // switch the data stored in the properties - std::swap(mesh_.property(prop_).data_vector(), rhs.mesh_.property(rhs.prop_).data_vector()); - // resize the property to the correct size - mesh_.property(prop_).resize(mesh_.n_elements()); + Storage::swap(rhs, *this); // remove the property from rhs rhs.mesh_.remove_property(rhs.prop_); // invalidate prop_ @@ -560,6 +595,7 @@ class PropertyManager { dst_range.begin(), dst_range.end()); } + /** * Copy the values of a property from a source range to * a target range. The source range must not be smaller than the @@ -602,6 +638,8 @@ class PropertyManager { }; /** @relates PropertyManager + * + * @deprecated Temporary properties should not have a name. * * Creates a new property whose lifetime is limited to the current scope. * @@ -628,30 +666,69 @@ class PropertyManager { */ template PropertyManager::type> -makeTemporaryProperty(PolyConnectivity &mesh, const char *propname = "") { +OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name") +makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) { return PropertyManager::type>(mesh, propname, false); } -///// shortcut or makeTemporaryrProperty -//template -//PropertyManager::type, MeshT> -//makeTemporaryVertexProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } +/** @relates PropertyManager + * + * Creates a new property whose lifetime is limited to the current scope. + * + * Used for temporary properties. Shadows any existing properties of + * matching name and type. + * + * Example: + * @code + * PolyMesh m; + * { + * auto is_quad = makeTemporaryProperty(m); + * for (auto& fh : m.faces()) { + * is_quad[fh] = (m.valence(fh) == 4); + * } + * // The property is automatically removed from the mesh at the end of the scope. + * } + * @endcode + * + * @param mesh The mesh on which the property is created + * @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the created property, e.g., \p double, \p int, etc. + * @returns A PropertyManager handling the lifecycle of the property + */ +template +PropertyManager::type> +makeTemporaryProperty(PolyConnectivity &mesh) { + return PropertyManager::type>(mesh); +} -///// shortcut or makeTemporaryrProperty -//template -//PropertyManager::type, MeshT> -//makeTemporaryHalfedgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } - -///// shortcut or makeTemporaryrProperty -//template -//PropertyManager::type, MeshT> -//makeTemporaryEdgeProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } - -///// shortcut or makeTemporaryrProperty -//template -//PropertyManager::type, MeshT> -//makeTemporaryFaceProperty(MeshT &mesh, const char *propname) { return makeTemporaryProperty(mesh, propname); } +/** @relates PropertyManager + * + * Tests whether a property with the given element type, value type, and name is + * present on the given mesh. + * + * * Example: + * @code + * PolyMesh m; + * if (hasProperty(m, "is_quad")) { + * // We now know the property exists: getProperty won't throw. + * auto is_quad = getProperty(m, "is_quad"); + * // Use is_quad here. + * } + * @endcode + * + * @param mesh The mesh in question + * @param propname The property name of the expected property + * @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc. + * @tparam T Value type of the expected property, e.g., \p double, \p int, etc. + * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh + */ +template +bool +hasProperty(const PolyConnectivity &mesh, const char *propname) { + typename HandleToPropHandle::type ph; + return mesh.get_property_handle(ph, propname); +} /** @relates PropertyManager * @@ -683,7 +760,13 @@ makeTemporaryProperty(PolyConnectivity &mesh, const char *propname = "") { template PropertyManager::type> getProperty(PolyConnectivity &mesh, const char *propname) { - return PropertyManager::type>(mesh, propname, true); + if (!hasProperty(mesh, propname)) + { + std::ostringstream oss; + oss << "Requested property handle \"" << propname << "\" does not exist."; + throw std::runtime_error(oss.str()); + } + return PropertyManager::type>(mesh, propname); } /** @relates PropertyManager @@ -721,34 +804,6 @@ getOrMakeProperty(PolyConnectivity &mesh, const char *propname) { return PropertyManager::type>::createIfNotExists(mesh, propname); } -/** @relates PropertyManager - * - * Tests whether a property with the given element type, value type, and name is - * present on the given mesh. - * - * * Example: - * @code - * PolyMesh m; - * if (hasProperty(m, "is_quad")) { - * // We now know the property exists: getProperty won't throw. - * auto is_quad = getProperty(m, "is_quad"); - * // Use is_quad here. - * } - * @endcode - * - * @param mesh The mesh in question - * @param propname The property name of the expected property - * @tparam ElementT Element type of the expected property, e.g. VertexHandle, HalfedgeHandle, etc. - * @tparam T Value type of the expected property, e.g., \p double, \p int, etc. - * @tparam MeshT Type of the mesh. Can often be inferred from \p mesh - */ -template -bool -hasProperty(const PolyConnectivity &mesh, const char *propname) { - typename HandleToPropHandle::type ph; - return mesh.get_property_handle(ph, propname); -} - /** @relates PropertyManager * @deprecated Use makeTemporaryProperty() instead. * @@ -853,6 +908,8 @@ getPointsProperty(MeshT &mesh) { return PropertyManager>(mesh, mesh.points_property_handle()); } +template +using Prop = PropertyManager::template type>; template using VProp = PropertyManager>; @@ -866,6 +923,9 @@ using EProp = PropertyManager>; template using FProp = PropertyManager>; +template +using MProp = PropertyManager>; + } /* namespace OpenMesh */ #endif /* PROPERTYMANAGER_HH_ */ diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index e5046194..8263fcd5 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -130,55 +130,6 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) { } } -/* - * ==================================================================== - * Factory Functions - * ==================================================================== - */ - -/* - * Temporary property - */ -TEST_F(OpenMeshPropertyManager, cpp11_temp_property) { - using handle_type = OpenMesh::VPropHandleT; - const auto prop_name = "pm_v_test_property"; - ASSERT_FALSE((OpenMesh::hasProperty(mesh_, prop_name))); - - { - auto vprop = OpenMesh::makeTemporaryProperty(mesh_, prop_name); - static_cast(vprop); // Unused variable - ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); - } - - ASSERT_FALSE((OpenMesh::hasProperty(mesh_, prop_name))); -} - -/* - * Two temporary properties on a mesh using the same name and type. The second - * (inner) one shadows the first (outer) one instead of aliasing. - */ -TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) { - auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to - - const auto prop_name = "pm_v_test_property"; - - auto outer_prop = OpenMesh::makeTemporaryProperty(mesh_, prop_name); - outer_prop[vh] = 100; - ASSERT_EQ(100, outer_prop[vh]); - - { - // inner_prop uses same type and name as outer_prop - auto inner_prop = OpenMesh::makeTemporaryProperty(mesh_, prop_name); - inner_prop[vh] = 200; - ASSERT_EQ(200, inner_prop[vh]); - // End of scope: inner_prop is removed from mesh_ - } - - // Ensure outer_prop still exists and its data has not been overwritten by inner_prop - ASSERT_TRUE((OpenMesh::hasProperty(mesh_, prop_name))); - ASSERT_EQ(100, outer_prop[vh]); -} - /* * In sequence: * - add a persistent property to a mesh @@ -315,8 +266,8 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { // unnamed to unnamed { - auto prop1 = OpenMesh::VProp(3, mesh_); - auto prop2 = OpenMesh::VProp(0, mesh_); + auto prop1 = OpenMesh::VProp(mesh_, 3); + auto prop2 = OpenMesh::VProp(mesh_, 0); EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; @@ -341,7 +292,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { // unnamed to named { auto prop1 = OpenMesh::VProp(mesh_); - auto prop2 = OpenMesh::VProp(0, mesh_, "ids"); + auto prop2 = OpenMesh::VProp(mesh_, "ids", 0); EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; for (auto vh : mesh_.vertices()) @@ -579,8 +530,8 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { // unnamed to unnamed { - auto prop1 = OpenMesh::VProp(3, mesh_); - auto prop2 = OpenMesh::VProp(0, copy); + auto prop1 = OpenMesh::VProp(mesh_, 3); + auto prop2 = OpenMesh::VProp(copy, 0); EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; @@ -600,13 +551,13 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; - EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized"; + EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast(copy.n_vertices())-1)]) << "Property not correctly resized"; } // unnamed to named { auto prop1 = OpenMesh::VProp(mesh_); - auto prop2 = OpenMesh::VProp(0, copy, "ids"); + auto prop2 = OpenMesh::VProp(copy, "ids", 0); EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; for (auto vh : mesh_.vertices()) @@ -731,7 +682,7 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly"; - EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(copy.n_vertices()-1)]) << "Property not correctly resized"; + EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast(copy.n_vertices())-1)]) << "Property not correctly resized"; } // unnamed to named From fb91dead5bfa3357ab8e59600b308d2fec7ed9d2 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 5 Nov 2019 09:40:48 +0100 Subject: [PATCH 19/22] move propertymanager initial_value back to front to fix bool properties --- src/OpenMesh/Core/Utils/PropertyManager.hh | 12 +++++------ src/Unittests/unittests_propertymanager.cc | 25 ++++++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index cc462fd5..1ec4a6af 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -140,7 +140,7 @@ class PropertyManager { * @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty, * PropertyManager::makeTemporaryProperty */ - OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") + OM_DEPRECATED("Use the constructor without parameter 'existing' instead. Check for existance with hasProperty") // As long as this overload exists, initial value must be first parameter due to ambiguity for properties of type bool PropertyManager(PolyConnectivity& mesh, const char *propname, bool existing) : mesh_(mesh), retain_(existing), name_(propname) { if (existing) { if (!mesh_.get_property_handle(prop_, propname)) { @@ -171,13 +171,13 @@ class PropertyManager { * Constructor. * * Asks for a property with name propname and creates one if none exists. Lifetime is not managed. - * If the property is created it is initialized with \p initial_value * + * @param initial_value If the proeprty is newly created, it will be initialized with intial_value. + * If the property already existed, nothing is changes. * @param mesh The mesh on which to create the property. - * @param initial_value * @param propname The name of the property. */ - PropertyManager(PolyConnectivity& mesh, const char *propname, const Value& intial_value) : mesh_(mesh), retain_(true), name_(propname) { + PropertyManager(const Value& intial_value, PolyConnectivity& mesh, const char *propname) : mesh_(mesh), retain_(true), name_(propname) { if (!mesh_.get_property_handle(prop_, propname)) { mesh_.add_property(prop_, propname); set_range(mesh_.all_elements(), intial_value); @@ -199,11 +199,11 @@ class PropertyManager { * Constructor. * * Create an anonymous property. Lifetime is managed. - * If the property is created it is initialized with \p initial_value * + * @param initial_value The property will be initialized with intial_value. * @param mesh The mesh on which to create the property. */ - PropertyManager(PolyConnectivity& mesh, const Value& intial_value) : mesh_(mesh), retain_(false), name_("") { + PropertyManager(const Value& intial_value, PolyConnectivity& mesh) : mesh_(mesh), retain_(false), name_("") { mesh_.add_property(prop_, name_); set_range(mesh_.all_elements(), intial_value); } diff --git a/src/Unittests/unittests_propertymanager.cc b/src/Unittests/unittests_propertymanager.cc index 8263fcd5..ea7e82f7 100644 --- a/src/Unittests/unittests_propertymanager.cc +++ b/src/Unittests/unittests_propertymanager.cc @@ -266,8 +266,8 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { // unnamed to unnamed { - auto prop1 = OpenMesh::VProp(mesh_, 3); - auto prop2 = OpenMesh::VProp(mesh_, 0); + auto prop1 = OpenMesh::VProp(3, mesh_); + auto prop2 = OpenMesh::VProp(0, mesh_); EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; @@ -292,7 +292,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { // unnamed to named { auto prop1 = OpenMesh::VProp(mesh_); - auto prop2 = OpenMesh::VProp(mesh_, "ids", 0); + auto prop2 = OpenMesh::VProp(0, mesh_, "ids"); EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; for (auto vh : mesh_.vertices()) @@ -385,6 +385,16 @@ TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) { auto prop3 = OpenMesh::VProp(mesh_, "ids5"); EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly"; } + + { + auto prop1 = OpenMesh::MProp(mesh_); + *prop1 = 43; + auto prop2 = prop1; + + prop2 = prop1; + + prop2 = std::move(prop1); + } } @@ -530,8 +540,8 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { // unnamed to unnamed { - auto prop1 = OpenMesh::VProp(mesh_, 3); - auto prop2 = OpenMesh::VProp(copy, 0); + auto prop1 = OpenMesh::VProp(3, mesh_); + auto prop2 = OpenMesh::VProp(0, copy); EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly"; EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; @@ -557,7 +567,7 @@ TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) { // unnamed to named { auto prop1 = OpenMesh::VProp(mesh_); - auto prop2 = OpenMesh::VProp(copy, "ids", 0); + auto prop2 = OpenMesh::VProp(0, copy, "ids"); EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly"; for (auto vh : mesh_.vertices()) @@ -762,6 +772,9 @@ TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) { auto prop1 = OpenMesh::VProp(mesh_, "ids5"); auto prop2 = OpenMesh::VProp(copy, "ids5"); + auto prop6 = OpenMesh::Prop(mesh_); + prop6 = prop1; + for (auto vh : mesh_.vertices()) prop1[vh] = vh.idx()*2-13; From b813fffe8bd69c7150b235b396a9f3138cf60956 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 5 Nov 2019 09:40:57 +0100 Subject: [PATCH 20/22] remove pre c++11 code --- src/OpenMesh/Core/Utils/PropertyManager.hh | 78 ---------------------- 1 file changed, 78 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index 1ec4a6af..dbfba226 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -288,11 +288,6 @@ class PropertyManager { MeshT& getMesh() const { return dynamic_cast(mesh_); } -#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) - /// Only for pre C++11 compatibility. - - typedef PropertyManager Proxy; - /** * Move constructor. Transfers ownership (delete responsibility). */ @@ -393,79 +388,6 @@ class PropertyManager { return std::move(*this); } -#else - class Proxy { - private: - Proxy(PolyConnectivity *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) : - mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {} - PolyConnectivity *mesh_; - PROPTYPE prop_; - bool retain_; - std::string name_; - - friend class PropertyManager; - }; - - operator Proxy() { - Proxy p(mesh_, prop_, retain_, name_); - mesh_ = 0; - retain_ = true; - return p; - } - - Proxy move() { - return (Proxy)*this; - } - - PropertyManager(Proxy p) : mesh_(p.mesh_), prop_(p.prop_), retain_(p.retain_), name_(p.name_) {} - - PropertyManager &operator=(Proxy p) { - PropertyManager(p).swap(*this); - return *this; - } - - /** - * Create a property manager for the supplied property and mesh. - * If the property doesn't exist, it is created. In any case, - * lifecycle management is disabled. - * - * @see makePropertyManagerFromExistingOrNew - */ - static Proxy createIfNotExists(PolyConnectivity &mesh, const char *propname) { - PROPTYPE dummy_prop; - PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname)); - pm.retain(); - return (Proxy)pm; - } - - /** - * Like createIfNotExists() with two parameters except, if the property - * doesn't exist, it is initialized with the supplied value over - * the supplied range after creation. If the property already exists, - * this method has the exact same effect as the two parameter version. - * Lifecycle management is disabled in any case. - * - * @see makePropertyManagerFromExistingOrNew - */ - template - static Proxy createIfNotExists(PolyConnectivity &mesh, const char *propname, - const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, - const PROP_VALUE &init_value) { - const bool exists = propertyExists(mesh, propname); - PropertyManager pm(mesh, propname, exists); - pm.retain(); - if (!exists) - pm.set_range(begin, end, init_value); - return (Proxy)pm; - } - - Proxy duplicate(const char *clone_name) { - PropertyManager pm(*mesh_, clone_name, false); - pm.mesh_.property(pm.prop_) = mesh_.property(prop_); - return (Proxy)pm; - } -#endif - /** * Access the value of the encapsulated mesh property. * From 6e81f6c2db50936d2472249a5fc84403f02cf37d Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 5 Nov 2019 10:20:47 +0100 Subject: [PATCH 21/22] update documentation of new property manager --- Doc/Tutorial/03-properties/smooth.cc | 6 +++--- Doc/changelog.docu | 2 ++ Doc/tutorial_03.docu | 27 +++++++++++++-------------- Doc/tutorial_09.docu | 6 ++++-- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Doc/Tutorial/03-properties/smooth.cc b/Doc/Tutorial/03-properties/smooth.cc index 37833017..41d7ab60 100644 --- a/Doc/Tutorial/03-properties/smooth.cc +++ b/Doc/Tutorial/03-properties/smooth.cc @@ -1,11 +1,11 @@ #include -#include +#include #include #include #include -using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>; +using MyMesh = OpenMesh::TriMesh; int main(int argc, char** argv) { @@ -27,7 +27,7 @@ int main(int argc, char** argv) { // Add a vertex property storing the computed centers of gravity - auto cog = OpenMesh::makeTemporaryProperty(mesh); + auto cog = OpenMesh::VProp(mesh); // Smooth the mesh several times for (int i = 0; i < iterations; ++i) { diff --git a/Doc/changelog.docu b/Doc/changelog.docu index ff45eb22..716ce284 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -13,6 +13,7 @@
  • Property System: Get rid of the OM_FORCE_STATIC_CAST defines. We use the type ids to check if the cast is valid or not. This will add more type safety.
  • Default Traits: Added DefaultTraitsDouble as a version of the default traits that uses double precision for positions and normals as well as float for colors.
  • Default Mesh Types: Added typdefs for a Triangle Mesh and a PolyMesh which use DefaultTraitsDouble and can be used as default mesh type be the user.
  • +
  • Template Programming Convenience: Added n_elements which returns the number of elements corresponding to the handle type given as template argument. Also added elements and all_elements methods returning ranges of the elements corresponding to the handle type given as template argument. @@ -27,6 +28,7 @@
    • Change PropertyManager::operator* to access the property value for mesh properties
    • PropertyManager: add hasProperty function
    • +
    • PropertyManager rework: The behavior of the PropertyManager has been changed, hoepfully making it more usable. See tutoial.
    IO diff --git a/Doc/tutorial_03.docu b/Doc/tutorial_03.docu index ba76515c..01f8c6e3 100644 --- a/Doc/tutorial_03.docu +++ b/Doc/tutorial_03.docu @@ -11,34 +11,33 @@ let %OpenMesh manage the data. It would be even more helpful if we could attach such properties dynamically to the mesh. -Custom properties can be conveniently created and attached to meshes with the following functions: -- makeTemporaryProperty() creates a property that is temporary to the current scope. -- getOrMakeProperty() is used for creating and accessing permanent named properties on a mesh. -- getProperty() is used for accessing an existing permanent named property on a mesh. +Custom properties can be conveniently created and attached to meshes by creating an object of type OpenMesh::PropertyManager. A PropertyManager manages the lifetime of the property and provides read / write access to its values. -All three functions take two template arguments: -- First, the type of the mesh element that the property is attached to (i.e. OpenMesh::VertexHandle, OpenMesh::HalfedgeHandle, OpenMesh::EdgeHandle, or OpenMesh::FaceHandle). Mesh properties (i.e. singleton properties that are attached to an entire mesh instead of individual elements) are accessed by passing \c void instead of a handle type. -- Second, the type of the property value that is attached to each element (e.g., \p int, \p double, etc.). +You can use the typedefs VProp, HProp, EProp, FProp, and MProp in order to create a PropertyManager attached to vertices, halfedge, edges, faces and the mesh respectively. Each of these takes as template argument the type of the property value that is attached to each element (e.g., \p int, \p double, etc.). + +We differentiate between two kinds of properties. Named and temporary properties. Temporary properties are created by just providing the constructor with a mesh on which the property should be created. These properties will be removed as soon as the PropertyManager goes out of scope. If in addition to the mesh a property name is provided, a named property will be created which will stay alive even after the PropertyManager goes out of scope. If a PropertyManager is given a name of an already existing property, it will provide read and write access to the same property. + +Finally, an optional first parameter can be given containing a value that will be used to initialize the property for all elements if the property is freshly created (i.e. always for temporary properties, and only the first time a specific name is used). -All three functions return a handle object (of type OpenMesh::PropertyManager) that manages the lifetime of the property and provides read / write access to its values. Here are a few examples of how to create and access mesh properties: \code // Add a temporary mesh property that stores a double value for every vertex -auto temperature = OpenMesh::getOrMakeProperty(mesh, "temperature"); +auto temperature = OpenMesh::VProp(mesh); OpenMesh::VertexHandle vh = ...; temperature[vh] = 1.0; // The temperature property will be removed from the mesh when the handle reaches the end of the scope. -// Obtain an existing mesh property that stores a 2D vector for every halfedge -// (Beware: the next line might throw if the expected property doesn't exist.) -auto uv = OpenMesh::getProperty(mesh, "uv"); +// Obtain an existing property that stores a 2D vector for every halfedge +// (or create that property if it does not exist already) and initilize it with the Vector(1,1)) +auto uv = OpenMesh::HProp(mesh, "uv", OpenMesh::Vec2d(1,1)); OpenMesh::VertexHandle heh = ...; std::cout << temperature[heh][0] << " " << temperature[heh][1] << std::endl; -// Add a permanent mesh property containing a description string -auto desc = OpenMesh::getOrMakeProperty(mesh, "desc"); +// Obtain an existing mesh property (or create that property if it does not exist already) +// containing a description string +auto desc = OpenMesh::MProp(mesh, "desc"); *desc = "This is a very nice mesh."; \endcode diff --git a/Doc/tutorial_09.docu b/Doc/tutorial_09.docu index 3e0a6d8a..1b2d4f09 100644 --- a/Doc/tutorial_09.docu +++ b/Doc/tutorial_09.docu @@ -1,6 +1,8 @@ -/** \page tutorial_09 Using custom properties +/** \page tutorial_09 Using custom properties (old style) -This small code example shows how to attach andaccess additional properties on a mesh. +This small code example shows how to attach and access additional properties on a mesh. + +Note that this is an old style of using properties. Nowadays you should use the OpenMesh::PropertyManager instead. When you want to add an additional properties you have to attach it to a primitive of the mesh. You can attach to verticies, halfedges, edges, faces or to the mesh itself. Use the From 794b49976b57f4c26cd66c4c6aa018ae48998e98 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 5 Nov 2019 10:21:09 +0100 Subject: [PATCH 22/22] fix swap of property managers --- src/OpenMesh/Core/Utils/PropertyManager.hh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/OpenMesh/Core/Utils/PropertyManager.hh b/src/OpenMesh/Core/Utils/PropertyManager.hh index dbfba226..a48bc8b8 100644 --- a/src/OpenMesh/Core/Utils/PropertyManager.hh +++ b/src/OpenMesh/Core/Utils/PropertyManager.hh @@ -252,10 +252,8 @@ class PropertyManager { } void swap(PropertyManager &rhs) { - std::swap(mesh_, rhs.mesh_); - std::swap(prop_, rhs.prop_); - std::swap(retain_, rhs.retain_); - std::swap(name_, rhs.name_); + // swap the data stored in the properties + Storage::swap(rhs, *this); } static bool propertyExists(PolyConnectivity &mesh, const char *propname) { @@ -316,7 +314,7 @@ class PropertyManager { } else { - // switch the data stored in the properties + // swap the data stored in the properties Storage::swap(rhs, *this); // remove the property from rhs rhs.mesh_.remove_property(rhs.prop_);