Merge branch 'PropertyManagerRefactoring' into SmartRanges

# Conflicts:
#	src/OpenMesh/Core/Mesh/PolyConnectivity.hh
This commit is contained in:
Max Lyon
2019-11-05 13:09:07 +01:00
32 changed files with 2327 additions and 689 deletions

View File

@@ -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: stages:
- build - build
- test
- deploy - deploy
gcc-c++11: variables:
stage: build GIT_SUBMODULE_STRATEGY: recursive
script: "CI/ci-linux.sh gcc C++11"
tags:
- Linux
- stretch
clang-c++11: # -----------------
stage: build # Linux tasks
script: "CI/ci-linux.sh clang C++11" # -----------------
tags:
- Linux
- stretch
gcc-c++14: cppcheck:
stage: build stage: build
script: "CI/ci-linux.sh gcc C++14" script: "CI/ci-cppcheck.sh"
tags: image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container
- Linux tags: [Docker]
- stretch artifacts:
paths:
- cppcheck.log
clang-c++14: gcc-c++11-test-debug:
stage: build stage: test
script: "CI/ci-linux.sh clang C++14" script: "CI/ci-linux-test.sh gcc C++11 debug"
tags: image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container
- Linux tags: [Docker]
- stretch
macos-cpp11:
gcc-c++11-test-release:
stage: test
script: "CI/ci-linux-test.sh gcc C++11 release"
image: graphics.rwth-aachen.de:4567/docker/docker/docker-openmesh-container
tags: [Docker]
gcc-c++11-build-debug:
stage: build stage: build
script: "CI/ci-mac.sh C++11" script: "CI/ci-linux-build.sh gcc C++11 debug"
image: graphics.rwth-aachen.de:4567/docker/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/docker/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/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/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/docker/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/docker/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/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/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/docker/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/docker/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/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/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/docker/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/docker/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:
- 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: tags:
- Apple - Apple
artifacts: artifacts:
@@ -40,9 +177,9 @@ macos-cpp11:
- build-release-cpp11/*.dmg - build-release-cpp11/*.dmg
- build-release-cpp11/*.tar.gz - build-release-cpp11/*.tar.gz
macos-cpp14: macos-cpp14-release:
stage: build 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: tags:
- Apple - Apple
artifacts: artifacts:
@@ -50,15 +187,9 @@ macos-cpp14:
- build-release-cpp14/*.dmg - build-release-cpp14/*.dmg
- build-release-cpp14/*.tar.gz - build-release-cpp14/*.tar.gz
cppcheck: # -----------------
stage: build # Windows tasks
script: "CI/ci-cppcheck.sh" # -----------------
tags:
- Linux
- stretch
artifacts:
paths:
- cppcheck.log
VS2017-64-bit-shared-apps: VS2017-64-bit-shared-apps:
stage: build stage: build
@@ -286,3 +417,4 @@ Sources:
- OpenMesh*.tar.bz2 - OpenMesh*.tar.bz2
- OpenMesh*.tar.gz - OpenMesh*.tar.gz

View File

@@ -119,6 +119,8 @@ unittests.exe --gtest_output=xml
unittests_customvec.exe --gtest_output=xml unittests_customvec.exe --gtest_output=xml
unittests_doublevec.exe --gtest_output=xml
cd .. cd ..
cd .. cd ..
@@ -147,6 +149,8 @@ unittests.exe --gtest_output=xml
unittests_customvec.exe --gtest_output=xml unittests_customvec.exe --gtest_output=xml
unittests_doublevec.exe --gtest_output=xml
IF %errorlevel% NEQ 0 exit /b %errorlevel% IF %errorlevel% NEQ 0 exit /b %errorlevel%
cd .. cd ..

View File

@@ -3,6 +3,8 @@
# Exit script on any error # Exit script on any error
set -e set -e
CPU_COUNT=$(grep -c processor /proc/cpuinfo)
#===================================== #=====================================
# Color Settings: # Color Settings:
#===================================== #=====================================

View File

@@ -11,4 +11,4 @@ cmake -DCMAKE_BUILD_TYPE=Release -DOPENMESH_BUILD_UNIT_TESTS=FALSE ../
make doc make doc
# Copy to webserver # 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/

37
CI/ci-linux-build.sh Executable file
View File

@@ -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 ..

59
CI/ci-linux-prepare.sh Executable file
View File

@@ -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

67
CI/ci-linux-test.sh Executable file
View File

@@ -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 ..

View File

@@ -1,159 +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
echo -e "${OUTPUT}"
echo ""
echo "======================================================================"
echo "Running unittests Release 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 Release version with custom vector type"
echo "======================================================================"
echo -e "${NC}"
./unittests_customvec --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
echo -e "${OUTPUT}"
echo ""
echo "======================================================================"
echo "Running unittests Debug 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 Debug version with custom vector type"
echo "======================================================================"
echo -e "${NC}"
./unittests_customvec --gtest_color=yes --gtest_output=xml
cd ..
cd ..

61
CI/ci-mac-build.sh Executable file
View File

@@ -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

43
CI/ci-mac-prepare.sh Executable file
View File

@@ -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

65
CI/ci-mac-test.sh Executable file
View File

@@ -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 ..

View File

@@ -1,161 +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
echo -e "${OUTPUT}"
echo ""
echo "======================================================================"
echo "Running unittests Release 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 Release version with minimal vector type"
echo "======================================================================"
echo -e "${NC}"
./unittests_customvec --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
echo -e "${OUTPUT}"
echo ""
echo "======================================================================"
echo "Running unittests Debug 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 Debug version with minimal vector type"
echo "======================================================================"
echo -e "${NC}"
./unittests_customvec --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

View File

@@ -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()

View File

@@ -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

133
CI/gitlab-ci/linux.yml Normal file
View File

@@ -0,0 +1,133 @@
# -----------------
# Linux tasks
# -----------------
cppcheck:
stage: build
script: "CI/ci-cppcheck.sh"
image: graphics.rwth-aachen.de:4567/docker/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/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/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/docker/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/docker/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/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/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/docker/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/docker/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/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/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/docker/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/docker/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/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/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/docker/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/docker/docker/docker-openmesh-container
tags: [Docker]
artifacts:
paths:
- build-release-clang-cpp14-Vector-Checks/

35
CI/gitlab-ci/mac.yml Normal file
View File

@@ -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

206
CI/gitlab-ci/windows.yml Normal file
View File

@@ -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

View File

@@ -1,11 +1,11 @@
#include <OpenMesh/Core/IO/MeshIO.hh> #include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> #include <OpenMesh/Core/Mesh/DefaultTriMesh.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh> #include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>; using MyMesh = OpenMesh::TriMesh;
int main(int argc, char** argv) 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 // Add a vertex property storing the computed centers of gravity
auto cog = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, MyMesh::Point>(mesh); auto cog = OpenMesh::VProp<MyMesh::Point>(mesh);
// Smooth the mesh several times // Smooth the mesh several times
for (int i = 0; i < iterations; ++i) { for (int i = 0; i < iterations; ++i) {

View File

@@ -11,6 +11,9 @@
<b>Core</b> <b>Core</b>
<ul> <ul>
<li>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. </li> <li>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. </li>
<li>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. </li>
<li>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. </li>
<li>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.
</ul> </ul>
@@ -25,6 +28,7 @@
<ul> <ul>
<li>Change PropertyManager::operator* to access the property value for mesh properties</li> <li>Change PropertyManager::operator* to access the property value for mesh properties</li>
<li>PropertyManager: add hasProperty function</li> <li>PropertyManager: add hasProperty function</li>
<li>PropertyManager rework: The behavior of the PropertyManager has been changed, hoepfully making it more usable. See tutoial.
</ul> </ul>
<b>IO</b> <b>IO</b>

View File

@@ -11,34 +11,33 @@ let %OpenMesh manage the data.
It would be even more helpful if we could attach such properties It would be even more helpful if we could attach such properties
dynamically to the mesh. dynamically to the mesh.
Custom properties can be conveniently created and attached to meshes with the following functions: 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.
- 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.
All three functions take two template arguments: 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.).
- First, the type of the mesh element that the property is attached to (i.e. OpenMesh::VertexHandle, OpenMesh::HalfedgeHandle, OpenMesh::EdgeHandle, or OpenMesh::FaceHandle). <em>Mesh properties</em> (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.). We differentiate between two kinds of properties. <em>Named</em> and <em>temporary</em> 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: Here are a few examples of how to create and access mesh properties:
\code \code
// Add a temporary mesh property that stores a double value for every vertex // Add a temporary mesh property that stores a double value for every vertex
auto temperature = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, double>(mesh, "temperature"); auto temperature = OpenMesh::VProp<double>(mesh);
OpenMesh::VertexHandle vh = ...; OpenMesh::VertexHandle vh = ...;
temperature[vh] = 1.0; temperature[vh] = 1.0;
// The temperature property will be removed from the mesh when the handle reaches the end of the scope. // 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 // Obtain an existing property that stores a 2D vector for every halfedge
// (Beware: the next line might throw if the expected property doesn't exist.) // (or create that property if it does not exist already) and initilize it with the Vector(1,1))
auto uv = OpenMesh::getProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh, "uv"); auto uv = OpenMesh::HProp<OpenMesh::Vec2d>(mesh, "uv", OpenMesh::Vec2d(1,1));
OpenMesh::VertexHandle heh = ...; OpenMesh::VertexHandle heh = ...;
std::cout << temperature[heh][0] << " " << temperature[heh][1] << std::endl; std::cout << temperature[heh][0] << " " << temperature[heh][1] << std::endl;
// Add a permanent mesh property containing a description string // Obtain an existing mesh property (or create that property if it does not exist already)
auto desc = OpenMesh::getOrMakeProperty<void, std::string>(mesh, "desc"); // containing a description string
auto desc = OpenMesh::MProp<std::string>(mesh, "desc");
*desc = "This is a very nice mesh."; *desc = "This is a very nice mesh.";
\endcode \endcode

View File

@@ -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.
<em>Note that this is an old style of using properties. Nowadays you should use the OpenMesh::PropertyManager instead.</em>
When you want to add an additional properties you have to attach it to a primitive of the 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 mesh. You can attach to verticies, halfedges, edges, faces or to the mesh itself. Use the

View File

@@ -110,6 +110,22 @@ public:
typedef EPropHandleT<EdgeData> DataEPropHandle; typedef EPropHandleT<EdgeData> DataEPropHandle;
typedef FPropHandleT<FaceData> DataFPropHandle; typedef FPropHandleT<FaceData> DataFPropHandle;
typedef VPropHandleT<Point> PointsPropertyHandle;
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
public: public:
//-------------------------------------------------- constructor / destructor //-------------------------------------------------- constructor / destructor
@@ -240,6 +256,9 @@ public:
void set_point(VertexHandle _vh, const Point& _p) void set_point(VertexHandle _vh, const Point& _p)
{ this->property(points_, _vh) = _p; } { this->property(points_, _vh) = _p; }
PointsPropertyHandle& points_property_handle()
{ return points_; }
//------------------------------------------------------------ vertex normals //------------------------------------------------------------ vertex normals
@@ -592,24 +611,6 @@ public:
bool has_face_colors() const { return face_colors_.is_valid(); } bool has_face_colors() const { return face_colors_.is_valid(); }
bool has_face_texture_index() const { return face_texture_index_.is_valid(); } bool has_face_texture_index() const { return face_texture_index_.is_valid(); }
public:
typedef VPropHandleT<Point> PointsPropertyHandle;
typedef VPropHandleT<Normal> VertexNormalsPropertyHandle;
typedef VPropHandleT<Color> VertexColorsPropertyHandle;
typedef VPropHandleT<TexCoord1D> VertexTexCoords1DPropertyHandle;
typedef VPropHandleT<TexCoord2D> VertexTexCoords2DPropertyHandle;
typedef VPropHandleT<TexCoord3D> VertexTexCoords3DPropertyHandle;
typedef HPropHandleT<TexCoord1D> HalfedgeTexCoords1DPropertyHandle;
typedef HPropHandleT<TexCoord2D> HalfedgeTexCoords2DPropertyHandle;
typedef HPropHandleT<TexCoord3D> HalfedgeTexCoords3DPropertyHandle;
typedef EPropHandleT<Color> EdgeColorsPropertyHandle;
typedef HPropHandleT<Normal> HalfedgeNormalsPropertyHandle;
typedef HPropHandleT<Color> HalfedgeColorsPropertyHandle;
typedef FPropHandleT<Normal> FaceNormalsPropertyHandle;
typedef FPropHandleT<Color> FaceColorsPropertyHandle;
typedef FPropHandleT<TextureIndex> FaceTextureIndexPropertyHandle;
public: public:
//standard vertex properties //standard vertex properties
PointsPropertyHandle points_pph() const PointsPropertyHandle points_pph() const

View File

@@ -516,7 +516,7 @@ public:
// Copy all properties, if build in is true // Copy all properties, if build in is true
// Otherwise, copy only properties without build in specifier // Otherwise, copy only properties without build in specifier
if ( *p_it && ( _copyBuildIn || (*p_it)->name().substr(0,2) != "v:" ) ) 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<size_t>(_vh_from.idx()), static_cast<size_t>(_vh_to.idx()));
} }
} }
@@ -690,6 +690,9 @@ public: //----------------------------------------------------- element numbers
virtual size_t n_edges() const { return 0; } virtual size_t n_edges() const { return 0; }
virtual size_t n_faces() const { return 0; } virtual size_t n_faces() const { return 0; }
template <typename HandleT>
size_t n_elements() const;
protected: //------------------------------------------- synchronize properties protected: //------------------------------------------- synchronize properties
@@ -814,6 +817,16 @@ private:
}; };
template <>
inline size_t BaseKernel::n_elements<VertexHandle>() const { return n_vertices(); }
template <>
inline size_t BaseKernel::n_elements<HalfedgeHandle>() const { return n_halfedges(); }
template <>
inline size_t BaseKernel::n_elements<EdgeHandle>() const { return n_edges(); }
template <>
inline size_t BaseKernel::n_elements<FaceHandle>() const { return n_faces(); }
//============================================================================= //=============================================================================
} // namespace OpenMesh } // namespace OpenMesh
//============================================================================= //=============================================================================

View File

@@ -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_DEFAULTPOLYMESH_HH
#define OPENMESH_DEFAULTPOLYMESH_HH
//== INCLUDES =================================================================
#include <OpenMesh/Core/Mesh/Traits.hh>
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
//== NAMESPACES ===============================================================
namespace OpenMesh {
//== TYPEDEFS =================================================================
typedef PolyMesh_ArrayKernelT<DefaultTraitsDouble> PolyMesh;
//=============================================================================
} // namespace OpenMesh
//=============================================================================
//=============================================================================
#endif // OPENMESH_DEFAULTPOLYMESH_HH defined
//=============================================================================

View File

@@ -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 <OpenMesh/Core/Mesh/Traits.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
//== NAMESPACES ===============================================================
namespace OpenMesh {
//== TYPEDEFS =================================================================
typedef TriMesh_ArrayKernelT<DefaultTraitsDouble> TriMesh;
//=============================================================================
} // namespace OpenMesh
//=============================================================================
//=============================================================================
#endif // OPENMESH_DEFAULTTRIMESH_HH defined
//=============================================================================

View File

@@ -1099,6 +1099,9 @@ public:
&PolyConnectivity::faces_end>> ConstFaceRangeSkipping; &PolyConnectivity::faces_end>> ConstFaceRangeSkipping;
template <typename HandleType>
struct ElementRange;
/** /**
* @return The vertices as a range object suitable * @return The vertices as a range object suitable
* for C++11 range based for loops. Will skip deleted vertices. * for C++11 range based for loops. Will skip deleted vertices.
@@ -1147,6 +1150,20 @@ public:
*/ */
ConstFaceRange all_faces() const; ConstFaceRange all_faces() const;
/**
* @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 HandleType>
typename ElementRange<HandleType>::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 HandleType>
typename ElementRange<HandleType>::Range all_elements() const;
typedef CirculatorRange<CirculatorRangeTraitT< typedef CirculatorRange<CirculatorRangeTraitT<
PolyConnectivity, PolyConnectivity,
@@ -1524,6 +1541,34 @@ private: // Working storage for add_face()
}; };
template <>
struct PolyConnectivity::ElementRange<VertexHandle>
{
using Range = ConstVertexRange;
using RangeSkipping = ConstVertexRangeSkipping;
};
template <>
struct PolyConnectivity::ElementRange<HalfedgeHandle>
{
using Range = ConstHalfedgeRange;
using RangeSkipping = ConstHalfedgeRangeSkipping;
};
template <>
struct PolyConnectivity::ElementRange<EdgeHandle>
{
using Range = ConstEdgeRange;
using RangeSkipping = ConstEdgeRangeSkipping;
};
template <>
struct PolyConnectivity::ElementRange<FaceHandle>
{
using Range = ConstFaceRange;
using RangeSkipping = ConstFaceRangeSkipping;
};
}//namespace OpenMesh }//namespace OpenMesh
@@ -1569,6 +1614,7 @@ class EntityRange : public SmartRangeT<EntityRange<RangeTraitT>, typename RangeT
typename RangeTraitT::CONTAINER_TYPE &container_; typename RangeTraitT::CONTAINER_TYPE &container_;
}; };
/// Generic class for iterator ranges. /// Generic class for iterator ranges.
template <typename CirculatorRangeTraitT> template <typename CirculatorRangeTraitT>
//class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT>, decltype (make_smart(std::declval<typename CirculatorRangeTraitT::TO_ENTITYE_TYPE>(), std::declval<PolyConnectivity>()))>{ //class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT>, decltype (make_smart(std::declval<typename CirculatorRangeTraitT::TO_ENTITYE_TYPE>(), std::declval<PolyConnectivity>()))>{
@@ -1592,7 +1638,6 @@ class CirculatorRange : public SmartRangeT<CirculatorRange<CirculatorRangeTraitT
CENTER_ENTITY_TYPE center_; CENTER_ENTITY_TYPE center_;
}; };
inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::vertices() const { return ConstVertexRangeSkipping(*this); } inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::vertices() const { return ConstVertexRangeSkipping(*this); }
inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_vertices() const { return ConstVertexRange(*this); } inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_vertices() const { return ConstVertexRange(*this); }
inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::halfedges() const { return ConstHalfedgeRangeSkipping(*this); } inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::halfedges() const { return ConstHalfedgeRangeSkipping(*this); }
@@ -1602,6 +1647,15 @@ inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_edges(
inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); } inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::faces() const { return ConstFaceRangeSkipping(*this); }
inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); } inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_faces() const { return ConstFaceRange(*this); }
template <> inline PolyConnectivity::ConstVertexRangeSkipping PolyConnectivity::elements<VertexHandle>() const { return vertices(); }
template <> inline PolyConnectivity::ConstVertexRange PolyConnectivity::all_elements<VertexHandle>() const { return all_vertices(); }
template <> inline PolyConnectivity::ConstHalfedgeRangeSkipping PolyConnectivity::elements<HalfedgeHandle>() const { return halfedges(); }
template <> inline PolyConnectivity::ConstHalfedgeRange PolyConnectivity::all_elements<HalfedgeHandle>() const { return all_halfedges(); }
template <> inline PolyConnectivity::ConstEdgeRangeSkipping PolyConnectivity::elements<EdgeHandle>() const { return edges(); }
template <> inline PolyConnectivity::ConstEdgeRange PolyConnectivity::all_elements<EdgeHandle>() const { return all_edges(); }
template <> inline PolyConnectivity::ConstFaceRangeSkipping PolyConnectivity::elements<FaceHandle>() const { return faces(); }
template <> inline PolyConnectivity::ConstFaceRange PolyConnectivity::all_elements<FaceHandle>() const { return all_faces(); }
inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const { inline PolyConnectivity::ConstVertexVertexRange PolyConnectivity::vv_range(VertexHandle _vh) const {
return ConstVertexVertexRange(*this, _vh); return ConstVertexVertexRange(*this, _vh);
} }

View File

@@ -152,6 +152,24 @@ struct DefaultTraits
FaceAttributes(0); FaceAttributes(0);
}; };
/** \class DefaultTraitsDouble Traits.hh <OpenMesh/Mesh/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 ========================================================= //== CLASS DEFINITION =========================================================

View File

@@ -485,6 +485,7 @@ struct VPropHandleT : public BasePropHandleT<T>
{ {
typedef T Value; typedef T Value;
typedef T value_type; typedef T value_type;
typedef VertexHandle Handle;
explicit VPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {} explicit VPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
explicit VPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {} explicit VPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
@@ -499,6 +500,7 @@ struct HPropHandleT : public BasePropHandleT<T>
{ {
typedef T Value; typedef T Value;
typedef T value_type; typedef T value_type;
typedef HalfedgeHandle Handle;
explicit HPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {} explicit HPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
explicit HPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {} explicit HPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
@@ -513,6 +515,7 @@ struct EPropHandleT : public BasePropHandleT<T>
{ {
typedef T Value; typedef T Value;
typedef T value_type; typedef T value_type;
typedef EdgeHandle Handle;
explicit EPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {} explicit EPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
explicit EPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {} explicit EPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
@@ -527,6 +530,7 @@ struct FPropHandleT : public BasePropHandleT<T>
{ {
typedef T Value; typedef T Value;
typedef T value_type; typedef T value_type;
typedef FaceHandle Handle;
explicit FPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {} explicit FPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
explicit FPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {} explicit FPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
@@ -541,11 +545,39 @@ struct MPropHandleT : public BasePropHandleT<T>
{ {
typedef T Value; typedef T Value;
typedef T value_type; typedef T value_type;
typedef void Handle;
explicit MPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {} explicit MPropHandleT(int _idx=-1) : BasePropHandleT<T>(_idx) {}
explicit MPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {} explicit MPropHandleT(const BasePropHandleT<T>& _b) : BasePropHandleT<T>(_b) {}
}; };
template <typename HandleT>
struct PropHandle;
template <>
struct PropHandle<VertexHandle> {
template <typename T>
using type = VPropHandleT<T>;
};
template <>
struct PropHandle<HalfedgeHandle> {
template <typename T>
using type = HPropHandleT<T>;
};
template <>
struct PropHandle<EdgeHandle> {
template <typename T>
using type = EPropHandleT<T>;
};
template <>
struct PropHandle<FaceHandle> {
template <typename T>
using type = FPropHandleT<T>;
};
} // namespace OpenMesh } // namespace OpenMesh
//============================================================================= //=============================================================================
#endif // OPENMESH_PROPERTY_HH defined #endif // OPENMESH_PROPERTY_HH defined

View File

@@ -44,6 +44,7 @@
#include <OpenMesh/Core/System/config.h> #include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/Utils/HandleToPropHandle.hh> #include <OpenMesh/Core/Utils/HandleToPropHandle.hh>
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
@@ -59,6 +60,8 @@ namespace OpenMesh {
* makeTemporaryProperty(), getProperty(), and getOrMakeProperty() * makeTemporaryProperty(), getProperty(), and getOrMakeProperty()
* to construct a PropertyManager, e.g. * to construct a PropertyManager, e.g.
* *
* Note that the second template parameter is depcretated.
*
* \code * \code
* { * {
* TriMesh mesh; * TriMesh mesh;
@@ -73,27 +76,54 @@ namespace OpenMesh {
* } * }
* \endcode * \endcode
*/ */
template<typename PROPTYPE, typename MeshT> template<typename PROPTYPE, typename MeshT = int>
class PropertyManager { class PropertyManager {
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
public: public:
PropertyManager(const PropertyManager&) = delete; using Value = typename PROPTYPE::Value;
PropertyManager& operator=(const PropertyManager&) = delete; using value_type = typename PROPTYPE::value_type;
#else using Handle = typename PROPTYPE::Handle;
using Self = PropertyManager<PROPTYPE, MeshT>;
private: private:
/** // Mesh properties (MPropHandleT<...>) are stored differently than the other properties.
* Noncopyable because there aren't no straightforward copy semantics. // This class implements different behavior when copying or swapping data from one
*/ // property manager to a another one.
PropertyManager(const PropertyManager&); template <typename PropertyManager2, typename PropHandleT>
struct StorageT;
/** // specialization for Mesh Properties
* Noncopyable because there aren't no straightforward copy semantics. template <typename PropertyManager2>
*/ struct StorageT<PropertyManager2, MPropHandleT<Value>> {
PropertyManager& operator=(const PropertyManager&); static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
#endif *to = *from;
}
static void swap(PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
std::swap(*to, *from);
}
};
// definition for other Mesh Properties
template <typename PropertyManager2, typename PropHandleT>
struct StorageT {
static void copy(const PropertyManager<PROPTYPE, MeshT>& from, PropertyManager2& to) {
from.copy_to(from.mesh_.template all_elements<Handle>(), to, to.mesh_.template all_elements<Handle>());
}
static void swap(PropertyManager<PROPTYPE, MeshT>& 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<Handle>());
rhs.mesh_.property(rhs.prop_).resize(rhs.mesh_.template n_elements<Handle>());
}
};
using Storage = StorageT<Self, PROPTYPE>;
public: public:
/** /**
* @deprecated Use a constructor without \p existing and check existance with hasProperty() instead.
*
* Constructor. * Constructor.
* *
* Throws an \p std::runtime_error if \p existing is true and * Throws an \p std::runtime_error if \p existing is true and
@@ -107,22 +137,114 @@ class PropertyManager {
* the instance merely acts as a convenience wrapper around an existing property with no * the instance merely acts as a convenience wrapper around an existing property with no
* lifecycle management whatsoever. * lifecycle management whatsoever.
* *
* @see PropertyManager::createIfNotExists, makePropertyManagerFromNew, * @see PropertyManager::getOrMakeProperty, PropertyManager::getProperty,
* makePropertyManagerFromExisting, makePropertyManagerFromExistingOrNew * PropertyManager::makeTemporaryProperty
*/ */
PropertyManager(MeshT &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") // 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 (existing) {
if (!mesh_->get_property_handle(prop_, propname)) { if (!mesh_.get_property_handle(prop_, propname)) {
std::ostringstream oss; std::ostringstream oss;
oss << "Requested property handle \"" << propname << "\" does not exist."; oss << "Requested property handle \"" << propname << "\" does not exist.";
throw std::runtime_error(oss.str()); throw std::runtime_error(oss.str());
} }
} else { } 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.
*
* @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 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<Handle>(), 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.
*
* @param initial_value The property will be initialized with intial_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<Handle>(), 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_);
Storage::copy(rhs, *this);
}
}
PropertyManager& operator=(const PropertyManager& rhs)
{
if (&mesh_ == &rhs.mesh_ && prop_ == rhs.prop_)
; // nothing to do
else
Storage::copy(rhs, *this);
return *this;
} }
~PropertyManager() { ~PropertyManager() {
@@ -130,49 +252,75 @@ class PropertyManager {
} }
void swap(PropertyManager &rhs) { void swap(PropertyManager &rhs) {
std::swap(mesh_, rhs.mesh_); // swap the data stored in the properties
std::swap(prop_, rhs.prop_); Storage::swap(rhs, *this);
std::swap(retain_, rhs.retain_);
std::swap(name_, rhs.name_);
} }
static bool propertyExists(MeshT &mesh, const char *propname) { static bool propertyExists(PolyConnectivity &mesh, const char *propname) {
PROPTYPE dummy; PROPTYPE dummy;
return mesh.get_property_handle(dummy, propname); 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(); } operator bool() const { return isValid(); }
const PROPTYPE &getRawProperty() const { return prop_; } const PROPTYPE &getRawProperty() const { return prop_; }
const std::string &getName() const { return name_; } 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<bool>(mesh);
* TriMesh& mesh_ref = visited.getMesh<TriMesh>();
* }
*
*/
template <typename MeshType >
MeshType& getMesh() const { return dynamic_cast<MeshType&>(mesh_); }
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) MeshT& getMesh() const { return dynamic_cast<MeshT&>(mesh_); }
/// Only for pre C++11 compatibility.
typedef PropertyManager<PROPTYPE, MeshT> Proxy;
/** /**
* Move constructor. Transfers ownership (delete responsibility). * Move constructor. Transfers ownership (delete responsibility).
*/ */
PropertyManager(PropertyManager &&rhs) : mesh_(rhs.mesh_), prop_(rhs.prop_), retain_(rhs.retain_), name_(rhs.name_) { PropertyManager(PropertyManager &&rhs)
rhs.retain_ = true; :
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). * Move assignment. Transfers ownership (delete responsibility).
*/ */
PropertyManager &operator=(PropertyManager &&rhs) { PropertyManager& operator=(PropertyManager&& rhs)
if (&rhs != this) { {
deleteProperty(); if ((&mesh_ != &rhs.mesh_) || (prop_ != rhs.prop_))
mesh_ = rhs.mesh_; {
prop_ = rhs.prop_; if (rhs.retain_)
retain_ = rhs.retain_; {
name_ = rhs.name_; // retained properties cannot be invalidated. Copy instead
rhs.retain_ = true; Storage::copy(rhs, *this);
}
else
{
// swap the data stored in the properties
Storage::swap(rhs, *this);
// remove the property from rhs
rhs.mesh_.remove_property(rhs.prop_);
// invalidate prop_
rhs.prop_.invalidate();
}
} }
return *this; return *this;
} }
@@ -184,11 +332,8 @@ class PropertyManager {
* *
* @see makePropertyManagerFromExistingOrNew * @see makePropertyManagerFromExistingOrNew
*/ */
static PropertyManager createIfNotExists(MeshT &mesh, const char *propname) { static PropertyManager createIfNotExists(PolyConnectivity &mesh, const char *propname) {
PROPTYPE dummy_prop; return PropertyManager(mesh, propname);
PropertyManager pm(mesh, propname, mesh.get_property_handle(dummy_prop, propname));
pm.retain();
return std::move(pm);
} }
/** /**
@@ -201,7 +346,7 @@ class PropertyManager {
* @see makePropertyManagerFromExistingOrNew * @see makePropertyManagerFromExistingOrNew
*/ */
template<typename PROP_VALUE, typename ITERATOR_TYPE> template<typename PROP_VALUE, typename ITERATOR_TYPE>
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 ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
const PROP_VALUE &init_value) { const PROP_VALUE &init_value) {
const bool exists = propertyExists(mesh, propname); const bool exists = propertyExists(mesh, propname);
@@ -222,15 +367,15 @@ class PropertyManager {
* @see makePropertyManagerFromExistingOrNew * @see makePropertyManagerFromExistingOrNew
*/ */
template<typename PROP_VALUE, typename ITERATOR_RANGE> template<typename PROP_VALUE, typename ITERATOR_RANGE>
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) { const ITERATOR_RANGE &range, const PROP_VALUE &init_value) {
return createIfNotExists( return createIfNotExists(
mesh, propname, range.begin(), range.end(), init_value); mesh, propname, range.begin(), range.end(), init_value);
} }
PropertyManager duplicate(const char *clone_name) { PropertyManager duplicate(const char *clone_name) {
PropertyManager pm(*mesh_, clone_name, false); PropertyManager pm(mesh_, clone_name, false);
pm.mesh_->property(pm.prop_) = mesh_->property(prop_); pm.mesh_.property(pm.prop_) = mesh_.property(prop_);
return pm; return pm;
} }
@@ -241,89 +386,6 @@ class PropertyManager {
return std::move(*this); return std::move(*this);
} }
#else
class Proxy {
private:
Proxy(MeshT *mesh_, PROPTYPE prop_, bool retain_, const std::string &name_) :
mesh_(mesh_), prop_(prop_), retain_(retain_), name_(name_) {}
MeshT *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(MeshT &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<typename PROP_VALUE, typename ITERATOR_TYPE>
static Proxy createIfNotExists(MeshT &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
/**
* \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. * Access the value of the encapsulated mesh property.
* *
@@ -337,7 +399,7 @@ class PropertyManager {
* @note This method is only used for mesh properties. * @note This method is only used for mesh properties.
*/ */
typename PROPTYPE::reference& operator*() { typename PROPTYPE::reference& operator*() {
return mesh_->mproperty(prop_)[0]; return mesh_.mproperty(prop_)[0];
} }
/** /**
@@ -353,7 +415,7 @@ class PropertyManager {
* @note This method is only used for mesh properties. * @note This method is only used for mesh properties.
*/ */
typename PROPTYPE::const_reference& operator*() const { typename PROPTYPE::const_reference& operator*() const {
return mesh_->mproperty(prop_)[0]; return mesh_.mproperty(prop_)[0];
} }
/** /**
@@ -365,7 +427,7 @@ class PropertyManager {
*/ */
template<typename HandleType> template<typename HandleType>
inline typename PROPTYPE::reference operator[] (const HandleType &handle) { inline typename PROPTYPE::reference operator[] (const HandleType &handle) {
return mesh_->property(prop_, handle); return mesh_.property(prop_, handle);
} }
/** /**
@@ -377,7 +439,7 @@ class PropertyManager {
*/ */
template<typename HandleType> template<typename HandleType>
inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const { inline typename PROPTYPE::const_reference operator[] (const HandleType &handle) const {
return mesh_->property(prop_, handle); return mesh_.property(prop_, handle);
} }
/** /**
@@ -389,7 +451,7 @@ class PropertyManager {
*/ */
template<typename HandleType> template<typename HandleType>
inline typename PROPTYPE::reference operator() (const HandleType &handle) { inline typename PROPTYPE::reference operator() (const HandleType &handle) {
return mesh_->property(prop_, handle); return mesh_.property(prop_, handle);
} }
/** /**
@@ -401,7 +463,7 @@ class PropertyManager {
*/ */
template<typename HandleType> template<typename HandleType>
inline typename PROPTYPE::const_reference operator() (const HandleType &handle) const { inline typename PROPTYPE::const_reference operator() (const HandleType &handle) const {
return mesh_->property(prop_, handle); return mesh_.property(prop_, handle);
} }
/** /**
@@ -410,7 +472,7 @@ class PropertyManager {
* Examples: * Examples:
* \code * \code
* MeshT mesh; * MeshT mesh;
* PropertyManager<VPropHandleT<double>, MeshT> distance( * PropertyManager<VPropHandleT<double>> distance(
* mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de"); * mesh, "distance.plugin-example.i8.informatik.rwth-aachen.de");
* distance.set_range( * distance.set_range(
* mesh.vertices_begin(), mesh.vertices_end(), * mesh.vertices_begin(), mesh.vertices_end(),
@@ -458,9 +520,9 @@ class PropertyManager {
* Will be used with dst_propmanager. Used to double check the bounds. * Will be used with dst_propmanager. Used to double check the bounds.
*/ */
template<typename HandleTypeIterator, typename PROPTYPE_2, template<typename HandleTypeIterator, typename PROPTYPE_2,
typename MeshT_2, typename HandleTypeIterator_2> typename HandleTypeIterator_2>
void copy_to(HandleTypeIterator begin, HandleTypeIterator end, void copy_to(HandleTypeIterator begin, HandleTypeIterator end,
PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager, PropertyManager<PROPTYPE_2> &dst_propmanager,
HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const { HandleTypeIterator_2 dst_begin, HandleTypeIterator_2 dst_end) const {
for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) { for (; begin != end && dst_begin != dst_end; ++begin, ++dst_begin) {
@@ -469,14 +531,15 @@ class PropertyManager {
} }
template<typename RangeType, typename PROPTYPE_2, template<typename RangeType, typename PROPTYPE_2,
typename MeshT_2, typename RangeType_2> typename RangeType_2>
void copy_to(const RangeType &range, void copy_to(const RangeType &range,
PropertyManager<PROPTYPE_2, MeshT_2> &dst_propmanager, PropertyManager<PROPTYPE_2> &dst_propmanager,
const RangeType_2 &dst_range) const { const RangeType_2 &dst_range) const {
copy_to(range.begin(), range.end(), dst_propmanager, copy_to(range.begin(), range.end(), dst_propmanager,
dst_range.begin(), dst_range.end()); dst_range.begin(), dst_range.end());
} }
/** /**
* Copy the values of a property from a source range to * Copy the values of a property from a source range to
* a target range. The source range must not be smaller than the * a target range. The source range must not be smaller than the
@@ -491,15 +554,15 @@ class PropertyManager {
* @param dst_mesh Destination mesh on which to copy. * @param dst_mesh Destination mesh on which to copy.
* @param dst_range Destination range. * @param dst_range Destination range.
*/ */
template<typename RangeType, typename MeshT_2, typename RangeType_2> template<typename RangeType, typename RangeType_2>
static void copy(const char *prop_name, static void copy(const char *prop_name,
MeshT &src_mesh, const RangeType &src_range, PolyConnectivity &src_mesh, const RangeType &src_range,
MeshT_2 &dst_mesh, const RangeType_2 &dst_range) { PolyConnectivity &dst_mesh, const RangeType_2 &dst_range) {
typedef OpenMesh::PropertyManager<PROPTYPE, MeshT> DstPM; typedef OpenMesh::PropertyManager<PROPTYPE> DstPM;
DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name)); DstPM dst(DstPM::createIfNotExists(dst_mesh, prop_name));
typedef OpenMesh::PropertyManager<PROPTYPE, MeshT_2> SrcPM; typedef OpenMesh::PropertyManager<PROPTYPE> SrcPM;
SrcPM src(src_mesh, prop_name, true); SrcPM src(src_mesh, prop_name, true);
src.copy_to(src_range, dst, dst_range); src.copy_to(src_range, dst, dst_range);
@@ -507,18 +570,20 @@ class PropertyManager {
private: private:
void deleteProperty() { void deleteProperty() {
if (!retain_) if (!retain_ && prop_.is_valid())
mesh_->remove_property(prop_); mesh_.remove_property(prop_);
} }
private: private:
MeshT *mesh_; PolyConnectivity& mesh_;
PROPTYPE prop_; PROPTYPE prop_;
bool retain_; bool retain_;
std::string name_; std::string name_;
}; };
/** @relates PropertyManager /** @relates PropertyManager
*
* @deprecated Temporary properties should not have a name.
* *
* Creates a new property whose lifetime is limited to the current scope. * Creates a new property whose lifetime is limited to the current scope.
* *
@@ -541,13 +606,72 @@ class PropertyManager {
* @param propname (optional) The name of the created property * @param propname (optional) The name of the created property
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @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 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 * @returns A PropertyManager handling the lifecycle of the property
*/ */
template<typename ElementT, typename T, typename MeshT> template<typename ElementT, typename T>
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT> PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
makeTemporaryProperty(MeshT &mesh, const char *propname = "") { OM_DEPRECATED("Named temporary properties are deprecated. Either create a temporary without name or a non-temporary with name")
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>(mesh, propname, false); makeTemporaryProperty(PolyConnectivity &mesh, const char *propname) {
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname, false);
}
/** @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<FaceHandle, bool>(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<typename ElementT, typename T>
PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
makeTemporaryProperty(PolyConnectivity &mesh) {
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh);
}
/** @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<FaceHandle, bool>(m, "is_quad")) {
* // We now know the property exists: getProperty won't throw.
* auto is_quad = getProperty<FaceHandle, bool>(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<typename ElementT, typename T>
bool
hasProperty(const PolyConnectivity &mesh, const char *propname) {
typename HandleToPropHandle<ElementT, T>::type ph;
return mesh.get_property_handle(ph, propname);
} }
/** @relates PropertyManager /** @relates PropertyManager
@@ -575,13 +699,18 @@ makeTemporaryProperty(MeshT &mesh, const char *propname = "") {
* @param propname The name of the created property * @param propname The name of the created property
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @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 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 * @returns A PropertyManager wrapping the property
*/ */
template<typename ElementT, typename T, typename MeshT> template<typename ElementT, typename T>
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT> PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
getProperty(MeshT &mesh, const char *propname) { getProperty(PolyConnectivity &mesh, const char *propname) {
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>(mesh, propname, true); if (!hasProperty<ElementT, T>(mesh, propname))
{
std::ostringstream oss;
oss << "Requested property handle \"" << propname << "\" does not exist.";
throw std::runtime_error(oss.str());
}
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type>(mesh, propname);
} }
/** @relates PropertyManager /** @relates PropertyManager
@@ -611,41 +740,12 @@ getProperty(MeshT &mesh, const char *propname) {
* @param propname The name of the created property * @param propname The name of the created property
* @tparam ElementT Element type of the created property, e.g. VertexHandle, HalfedgeHandle, etc. * @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 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 * @returns A PropertyManager wrapping the property
*/ */
template<typename ElementT, typename T, typename MeshT> template<typename ElementT, typename T>
PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT> PropertyManager<typename HandleToPropHandle<ElementT, T>::type>
getOrMakeProperty(MeshT &mesh, const char *propname) { getOrMakeProperty(PolyConnectivity &mesh, const char *propname) {
return PropertyManager<typename HandleToPropHandle<ElementT, T>::type, MeshT>::createIfNotExists(mesh, propname); return PropertyManager<typename HandleToPropHandle<ElementT, T>::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<FaceHandle, bool>(m, "is_quad")) {
* // We now know the property exists: getProperty won't throw.
* auto is_quad = getProperty<FaceHandle, bool>(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<typename ElementT, typename T, typename MeshT>
bool
hasProperty(const MeshT &mesh, const char *propname) {
typename HandleToPropHandle<ElementT, T>::type ph;
return mesh.get_property_handle(ph, propname);
} }
/** @relates PropertyManager /** @relates PropertyManager
@@ -657,11 +757,11 @@ hasProperty(const MeshT &mesh, const char *propname) {
* Intended for temporary properties. Shadows any existing properties of * Intended for temporary properties. Shadows any existing properties of
* matching name and type. * matching name and type.
*/ */
template<typename PROPTYPE, typename MeshT> template<typename PROPTYPE>
OM_DEPRECATED("Use makeTemporaryProperty instead.") OM_DEPRECATED("Use makeTemporaryProperty instead.")
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const char *propname) PropertyManager<PROPTYPE> makePropertyManagerFromNew(PolyConnectivity &mesh, const char *propname)
{ {
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, false); return PropertyManager<PROPTYPE>(mesh, propname, false);
} }
/** \relates PropertyManager /** \relates PropertyManager
@@ -676,11 +776,11 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromNew(MeshT &mesh, const c
* @throws std::runtime_error if no property with the name \p propname of * @throws std::runtime_error if no property with the name \p propname of
* matching type exists. * matching type exists.
*/ */
template<typename PROPTYPE, typename MeshT> template<typename PROPTYPE>
OM_DEPRECATED("Use getProperty instead.") OM_DEPRECATED("Use getProperty instead.")
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, const char *propname) PropertyManager<PROPTYPE> makePropertyManagerFromExisting(PolyConnectivity &mesh, const char *propname)
{ {
return PropertyManager<PROPTYPE, MeshT>(mesh, propname, true); return PropertyManager<PROPTYPE>(mesh, propname, true);
} }
/** @relates PropertyManager /** @relates PropertyManager
@@ -691,11 +791,11 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExisting(MeshT &mesh, co
* *
* Intended for creating or accessing persistent properties. * Intended for creating or accessing persistent properties.
*/ */
template<typename PROPTYPE, typename MeshT> template<typename PROPTYPE>
OM_DEPRECATED("Use getOrMakeProperty instead.") OM_DEPRECATED("Use getOrMakeProperty instead.")
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mesh, const char *propname) PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(PolyConnectivity &mesh, const char *propname)
{ {
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists(mesh, propname); return PropertyManager<PROPTYPE>::createIfNotExists(mesh, propname);
} }
/** @relates PropertyManager /** @relates PropertyManager
@@ -709,14 +809,14 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(MeshT &mes
* *
* Intended for creating or accessing persistent properties. * Intended for creating or accessing persistent properties.
*/ */
template<typename PROPTYPE, typename MeshT, template<typename PROPTYPE,
typename ITERATOR_TYPE, typename PROP_VALUE> typename ITERATOR_TYPE, typename PROP_VALUE>
OM_DEPRECATED("Use getOrMakeProperty instead.") OM_DEPRECATED("Use getOrMakeProperty instead.")
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew( PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
MeshT &mesh, const char *propname, PolyConnectivity &mesh, const char *propname,
const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end, const ITERATOR_TYPE &begin, const ITERATOR_TYPE &end,
const PROP_VALUE &init_value) { const PROP_VALUE &init_value) {
return PropertyManager<PROPTYPE, MeshT>::createIfNotExists( return PropertyManager<PROPTYPE>::createIfNotExists(
mesh, propname, begin, end, init_value); mesh, propname, begin, end, init_value);
} }
@@ -731,16 +831,45 @@ PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew(
* *
* Intended for creating or accessing persistent properties. * Intended for creating or accessing persistent properties.
*/ */
template<typename PROPTYPE, typename MeshT, template<typename PROPTYPE,
typename ITERATOR_RANGE, typename PROP_VALUE> typename ITERATOR_RANGE, typename PROP_VALUE>
OM_DEPRECATED("Use getOrMakeProperty instead.") OM_DEPRECATED("Use getOrMakeProperty instead.")
PropertyManager<PROPTYPE, MeshT> makePropertyManagerFromExistingOrNew( PropertyManager<PROPTYPE> makePropertyManagerFromExistingOrNew(
MeshT &mesh, const char *propname, PolyConnectivity &mesh, const char *propname,
const ITERATOR_RANGE &range, const ITERATOR_RANGE &range,
const PROP_VALUE &init_value) { const PROP_VALUE &init_value) {
return makePropertyManagerFromExistingOrNew<PROPTYPE, MeshT>( return makePropertyManagerFromExistingOrNew<PROPTYPE>(
mesh, propname, range.begin(), range.end(), init_value); mesh, propname, range.begin(), range.end(), init_value);
} }
/** @relates PropertyManager
* Returns a convenience wrapper around the points property of a mesh.
*/
template<typename MeshT>
PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>
getPointsProperty(MeshT &mesh) {
return PropertyManager<OpenMesh::VPropHandleT<typename MeshT::Point>>(mesh, mesh.points_property_handle());
}
template <typename HandleT, typename T>
using Prop = PropertyManager<typename PropHandle<HandleT>::template type<T>>;
template <typename T>
using VProp = PropertyManager<OpenMesh::VPropHandleT<T>>;
template <typename T>
using HProp = PropertyManager<OpenMesh::HPropHandleT<T>>;
template <typename T>
using EProp = PropertyManager<OpenMesh::EPropHandleT<T>>;
template <typename T>
using FProp = PropertyManager<OpenMesh::FPropHandleT<T>>;
template <typename T>
using MProp = PropertyManager<OpenMesh::MPropHandleT<T>>;
} /* namespace OpenMesh */ } /* namespace OpenMesh */
#endif /* PROPERTYMANAGER_HH_ */ #endif /* PROPERTYMANAGER_HH_ */

View File

@@ -51,8 +51,8 @@ protected: // SubdividerT interface
_m.request_edge_status(); _m.request_edge_status();
_m.request_vertex_status(); _m.request_vertex_status();
_m.request_face_status(); _m.request_face_status();
PropertyManager<EPropHandleT<typename mesh_t::VertexHandle>, mesh_t> edge_midpoint(_m, "edge_midpoint"); PropertyManager<EPropHandleT<typename mesh_t::VertexHandle>> edge_midpoint(_m, "edge_midpoint");
PropertyManager<VPropHandleT<bool>, mesh_t> is_original_vertex(_m, "is_original_vertex"); PropertyManager<VPropHandleT<bool>> is_original_vertex(_m, "is_original_vertex");
for (size_t iteration = 0; iteration < _n; ++iteration) { for (size_t iteration = 0; iteration < _n; ++iteration) {
is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true); is_original_vertex.set_range(_m.vertices_begin(), _m.vertices_end(), true);

View File

@@ -41,20 +41,25 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
# Create unittest executable # Create unittest executable
acg_add_executable(unittests ${UNITTEST_SRC}) acg_add_executable(unittests ${UNITTEST_SRC})
acg_add_executable(unittests_customvec ${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_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 # 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_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 directory to ${BINARY_DIR}/Unittests
set (OUTPUT_DIR "${CMAKE_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_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES}) foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${CONFIG} UPCONFIG) string(TOUPPER ${CONFIG} UPCONFIG)
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR}) 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_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
endforeach() endforeach()
@@ -62,6 +67,7 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
# Link against all necessary libraries # Link against all necessary libraries
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread) 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_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
@@ -73,6 +79,7 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
endif() 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_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
endif() endif()
@@ -81,10 +88,12 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
# Set compiler flags # Set compiler flags
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long") 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_customvec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
else() else()
# Set compiler flags # Set compiler flags
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "" ) set_target_properties(unittests PROPERTIES COMPILE_FLAGS "" )
set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "" ) set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "" )
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "" )
endif() endif()
if ( OPENMESH_BUILD_SHARED ) if ( OPENMESH_BUILD_SHARED )
@@ -103,14 +112,21 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
"$<TARGET_FILE:${TAR}>" "$<TARGET_FILE:${TAR}>"
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>" "${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
COMMENT "Copying OpenMesh targets to unittests directory") COMMENT "Copying OpenMesh targets to unittests directory")
add_custom_command(TARGET unittests_doublevec POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${TAR}>"
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
COMMENT "Copying OpenMesh targets to unittests directory")
endforeach(TAR) endforeach(TAR)
endif() endif()
acg_copy_after_build(unittests ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/) 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_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 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_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) else(GTEST_FOUND)
message(STATUS "Google testing framework was not found, unittests disabled.") message(STATUS "Google testing framework was not found, unittests disabled.")

View File

@@ -62,7 +62,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
{ {
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool"); OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool");
pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false); pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
ASSERT_FALSE(pm_v_bool[vhandle[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]]); ASSERT_TRUE(pm_v_bool[vhandle[i]]);
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool"); OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool");
pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), false); 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(); for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
e_it != f_end; ++e_it) e_it != f_end; ++e_it)
@@ -82,7 +82,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_e_bool[*e_it]); ASSERT_TRUE(pm_e_bool[*e_it]);
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool"); OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool");
pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), false); 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(); for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
f_it != f_end; ++f_it) f_it != f_end; ++f_it)
@@ -98,7 +98,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
*/ */
{ {
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool2"); OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool2");
pm_v_bool.set_range(mesh_.vertices(), false); pm_v_bool.set_range(mesh_.vertices(), false);
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
ASSERT_FALSE(pm_v_bool[vhandle[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]]); ASSERT_TRUE(pm_v_bool[vhandle[i]]);
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool2"); OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool2");
pm_e_bool.set_range(mesh_.edges(), false); pm_e_bool.set_range(mesh_.edges(), false);
for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end(); for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
e_it != f_end; ++e_it) e_it != f_end; ++e_it)
@@ -118,7 +118,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_e_bool[*e_it]); ASSERT_TRUE(pm_e_bool[*e_it]);
OpenMesh::PropertyManager< OpenMesh::PropertyManager<
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool2"); OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool2");
pm_f_bool.set_range(mesh_.faces(), false); pm_f_bool.set_range(mesh_.faces(), false);
for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end(); for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
f_it != f_end; ++f_it) f_it != f_end; ++f_it)
@@ -130,62 +130,6 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
} }
} }
/*
* ====================================================================
* Factory Functions
* ====================================================================
*/
template<typename PropHandle, typename Mesh>
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<int>;
const auto prop_name = "pm_v_test_property";
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
{
auto vprop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
static_cast<void>(vprop); // Unused variable
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
}
ASSERT_FALSE(has_property<handle_type>(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
using handle_type = OpenMesh::VPropHandleT<int>;
const auto prop_name = "pm_v_test_property";
auto outer_prop = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, int>(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<OpenMesh::VertexHandle, int>(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(has_property<handle_type>(mesh_, prop_name));
ASSERT_EQ(100, outer_prop[vh]);
}
/* /*
* In sequence: * In sequence:
* - add a persistent property to a mesh * - add a persistent property to a mesh
@@ -196,10 +140,9 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) { TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
using handle_type = OpenMesh::VPropHandleT<int>;
const auto prop_name = "pm_v_test_property"; const auto prop_name = "pm_v_test_property";
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name)); ASSERT_FALSE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{ {
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name); auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
@@ -207,7 +150,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
// End of scope, property persists // End of scope, property persists
} }
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name)); ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{ {
// Since a property of the same name and type already exists, this refers to the existing property. // Since a property of the same name and type already exists, this refers to the existing property.
@@ -217,7 +160,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
// End of scope, property persists // End of scope, property persists
} }
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name)); ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{ {
// Acquire non-owning handle to the property, knowing it exists // Acquire non-owning handle to the property, knowing it exists
@@ -225,7 +168,7 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
ASSERT_EQ(200, prop[vh]); ASSERT_EQ(200, prop[vh]);
} }
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name)); ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{ {
// Attempt to acquire non-owning handle for a non-existing property // Attempt to acquire non-owning handle for a non-existing property
@@ -235,7 +178,630 @@ TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
ASSERT_THROW(code_that_throws(), std::runtime_error); ASSERT_THROW(code_that_throws(), std::runtime_error);
} }
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name)); ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(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<int>(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<int>(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<int>(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<std::chrono::milliseconds>(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<int>(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<std::chrono::milliseconds>(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<int>(3, mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
}
{
auto prop1 = OpenMesh::MProp<int>(mesh_);
*prop1 = 43;
auto prop2 = prop1;
prop2 = prop1;
prop2 = std::move(prop1);
}
}
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<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(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<int>(3, mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(copy, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
auto prop4 = OpenMesh::VProp<int>(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<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(copy, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
auto prop6 = OpenMesh::Prop<OpenMesh::VertexHandle, int>(mesh_);
prop6 = prop1;
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<std::chrono::milliseconds>(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<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
}
} }