Merge branch 'cpp11' into 'master'

Cpp11



See merge request !23
This commit is contained in:
Jan Möbius
2015-11-23 16:47:25 +01:00
18 changed files with 1387 additions and 157 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.project
CMakeLists.txt.user

View File

@@ -88,6 +88,12 @@ add_subdirectory (src/OpenMesh/Core)
add_subdirectory (src/OpenMesh/Tools)
add_subdirectory (src/OpenMesh/Apps)
set(OPENMESH_BENCHMARK_DIR CACHE PATH "Source path of benchmark (https://github.com/google/benchmark).")
if (OPENMESH_BENCHMARK_DIR)
add_subdirectory(${OPENMESH_BENCHMARK_DIR} benchmark)
add_subdirectory(src/Benchmark)
endif()
# Do not build unit tests when build as external library
if(${PROJECT_NAME} MATCHES "OpenMesh")
add_subdirectory (src/Unittests)

View File

@@ -0,0 +1,12 @@
set (SOURCES "")
list (APPEND SOURCES
main.cpp
VectorT_new.cpp
VectorT_legacy.cpp
VectorT_dummy_data.cpp
)
add_executable(OMBenchmark ${SOURCES})
set_target_properties(OMBenchmark PROPERTIES
INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(OMBenchmark benchmark OpenMeshCore)

163
src/Benchmark/VectorT.cpp Normal file
View File

@@ -0,0 +1,163 @@
/*
* VectorT.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#ifndef BMPOSTFIX
#error "Do not compile directly."
#endif
#include <type_traits>
#define ASSEMBLE_(POSTFIX, PREFIX) PREFIX ## POSTFIX
#define ASSEMBLE(POSTFIX, PREFIX) ASSEMBLE_(POSTFIX, PREFIX)
#define MYBENCHMARK(NAME) BENCHMARK(NAME)
#define MYBENCHMARK_TEMPLATE(NAME, TYPE) BENCHMARK_TEMPLATE(NAME, TYPE)
template<class Vec>
static inline
typename std::enable_if<Vec::size_ == 3, Vec>::type
testVec() {
return Vec(1.1, 1.2, 1.3);
}
template<class Vec>
static inline
typename std::enable_if<Vec::size_ == 4, Vec>::type
testVec() {
return Vec(1.1, 1.2, 1.3, 1.4);
}
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_compare)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
if (v1 == v2) {
v1 -= v2;
v2 += v1;
}
}
// Just so nothing gets optimized away.
static double dummy;
dummy = v1.norm() + v2.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_cross_product)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
v1 = (v1 % v2);
}
// Just so nothing gets optimized away.
static double dummy;
dummy = v1.norm() + v2.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_scalar_product)(benchmark::State& state) {
Vec v1(0.0);
Vec v2(1000.0);
double acc = 0;
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v2 -= testVec<Vec>();
acc += (v1 | v2);
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = acc;
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_norm)(benchmark::State& state) {
Vec v1(0.0);
double acc = 0;
while (state.KeepRunning()) {
v1 += testVec<Vec>();
acc += v1.norm();
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = acc;
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec4f);
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_times_scalar)(benchmark::State& state) {
Vec v1(0.0);
while (state.KeepRunning()) {
v1 += testVec<Vec>();
v1 *= static_cast<decltype(v1.norm())>(1.0)/v1[0];
v1 *= v1[1];
}
// Otherwise GCC will optimize everything away.
static double dummy;
dummy = v1.norm();
static_cast<void>(dummy);
}
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3f);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4d);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec4f);
#include "VectorT_dummy_data.hpp"
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_in_place)(benchmark::State& state) {
auto v = make_dummy_vector<Vec>();
while (state.KeepRunning()) {
v += v;
}
// Otherwise GCC will optimize everything away.
static double dummy = observe_dummy_vector(v);
static_cast<void>(dummy);
}
template<class Vec>
static void ASSEMBLE(BMPOSTFIX, Vec_add_temporary)(benchmark::State& state) {
auto v = make_dummy_vector<Vec>();
while (state.KeepRunning()) {
v = v + v;
}
// Otherwise GCC will optimize everything away.
static double dummy = observe_dummy_vector(v);
static_cast<void>(dummy);
}
typedef OpenMesh::VectorT<std::valarray<double>, 3> Vec3VAd;
typedef OpenMesh::VectorT<std::complex<double>, 3> Vec3Cd;
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3VAd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3VAd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_in_place), Vec3Cd);
MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_temporary), Vec3Cd);

View File

@@ -0,0 +1,5 @@
#include "VectorT_dummy_data.hpp"
template<> std::valarray<double> make_dummy_component() {
return std::valarray<double>(128);
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include <valarray>
#include <complex>
template<typename T>
T make_dummy_component() {
return T();
}
template<> std::valarray<double> make_dummy_component();
template<typename Vec>
Vec make_dummy_vector() {
return Vec(make_dummy_component<typename Vec::value_type>());
}
template<typename Scalar>
double observe_dummy_component(const Scalar& _s) {
return _s;
}
template<typename T>
double observe_dummy_component(const std::valarray<T>& _s) {
return _s.sum();
}
template<typename T>
double observe_dummy_component(const std::complex<T>& _s) {
return _s.real() + _s.imag();
}
template<typename Vec>
double observe_dummy_vector(const Vec& _vec) {
double result = 0.0;
for (int dim = 0; dim < _vec.dim(); ++dim) {
result += observe_dummy_component(_vec[dim]);
}
return result;
}

View File

@@ -0,0 +1,14 @@
/*
* VectorT_legacy.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
#define OPENMESH_VECTOR_LEGACY
#include <OpenMesh/Core/Geometry/VectorT.hh>
#define BMPOSTFIX _Legacy
#include "VectorT.cpp"

View File

@@ -0,0 +1,12 @@
/*
* VectorT_new.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
#include <OpenMesh/Core/Geometry/VectorT.hh>
#define BMPOSTFIX _CPP11
#include "VectorT.cpp"

10
src/Benchmark/main.cpp Normal file
View File

@@ -0,0 +1,10 @@
/*
* main.cpp
*
* Created on: Nov 19, 2015
* Author: ebke
*/
#include <benchmark/benchmark_api.h>
BENCHMARK_MAIN();

View File

@@ -0,0 +1,832 @@
/* ========================================================================= *
* *
* OpenMesh *
* Copyright (c) 2001-2015, RWTH-Aachen University *
* Department of Computer Graphics and Multimedia *
* All rights reserved. *
* www.openmesh.org *
* *
*---------------------------------------------------------------------------*
* This file is part of OpenMesh. *
*---------------------------------------------------------------------------*
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* *
* 3. Neither the name of the copyright holder nor the names of its *
* contributors may be used to endorse or promote products derived from *
* this software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* *
* ========================================================================= */
#ifndef OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_
#define OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_
#include <array>
#include <utility>
#include <algorithm>
#include <numeric>
#include <type_traits>
#include <cmath>
#include <ostream>
#include <istream>
#include <cassert>
#include <cstdlib>
// This header is not needed by this file but expected by others including
// this file.
#include <OpenMesh/Core/System/config.h>
/*
* Helpers for VectorT
*/
namespace {
template<typename ... Ts>
struct are_convertible_to;
template<typename To, typename From, typename ... Froms>
struct are_convertible_to<To, From, Froms...> {
static constexpr bool value = std::is_convertible<From, To>::value
&& are_convertible_to<To, Froms...>::value;
};
template<typename To, typename From>
struct are_convertible_to<To, From> : public std::is_convertible<From, To> {
};
}
namespace OpenMesh {
template<typename Scalar, int DIM>
class VectorT {
static_assert(DIM >= 1, "VectorT requires positive dimensionality.");
private:
using container = std::array<Scalar, DIM>;
container values_;
public:
//---------------------------------------------------------------- class info
/// the type of the scalar used in this template
typedef Scalar value_type;
/// type of this vector
typedef VectorT<Scalar, DIM> vector_type;
/// returns dimension of the vector (deprecated)
static constexpr int dim() {
return DIM;
}
/// returns dimension of the vector
static constexpr size_t size() {
return DIM;
}
static constexpr const size_t size_ = DIM;
//-------------------------------------------------------------- constructors
/// default constructor creates uninitialized values.
constexpr VectorT() {}
/**
* Creates a vector with all components set to v.
*/
explicit VectorT(const Scalar &v) {
vectorize(v);
}
template<typename ... T,
typename = typename std::enable_if<sizeof...(T) == DIM>::type,
typename = typename std::enable_if<
are_convertible_to<Scalar, T...>::value>::type>
constexpr VectorT(T... vs) : values_ { {static_cast<Scalar>(vs)...} } {
static_assert(sizeof...(T) == DIM,
"Invalid number of components specified in constructor.");
static_assert(are_convertible_to<Scalar, T...>::value,
"Not all components are convertible to Scalar.");
}
VectorT(const VectorT &rhs) = default;
VectorT(VectorT &&rhs) = default;
VectorT &operator=(const VectorT &rhs) = default;
VectorT &operator=(VectorT &&rhs) = default;
/**
* Only for 4-component vectors with division operator on their
* Scalar: Dehomogenization.
*/
template<typename S = Scalar, int D = DIM>
auto homogenized() const ->
typename std::enable_if<D == 4,
VectorT<decltype(std::declval<S>()/std::declval<S>()), DIM>>::type {
static_assert(D == DIM, "D and DIM need to be identical. (Never "
"override the default template arguments.)");
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return VectorT(
values_[0]/values_[3],
values_[1]/values_[3],
values_[2]/values_[3],
1);
}
/// construct from a value array or any other iterator
template<typename Iterator,
typename = decltype(
*std::declval<Iterator&>(), void(),
++std::declval<Iterator&>(), void())>
explicit VectorT(Iterator it) {
std::copy_n(it, DIM, values_.begin());
}
/// copy & cast constructor (explicit)
template<typename otherScalarType,
typename = typename std::enable_if<
std::is_convertible<otherScalarType, Scalar>::value>>
explicit VectorT(const VectorT<otherScalarType, DIM>& _rhs) {
operator=(_rhs);
}
//--------------------------------------------------------------------- casts
/// cast from vector with a different scalar type
template<typename OtherScalar,
typename = typename std::enable_if<
std::is_convertible<OtherScalar, Scalar>::value>>
vector_type& operator=(const VectorT<OtherScalar, DIM>& _rhs) {
std::transform(_rhs.data(), _rhs.data() + DIM,
data(), [](OtherScalar rhs) {
return static_cast<Scalar>(std::move(rhs));
});
return *this;
}
/// access to Scalar array
Scalar* data() { return values_.data(); }
/// access to const Scalar array
const Scalar *data() const { return values_.data(); }
//----------------------------------------------------------- element access
/// get i'th element read-write
Scalar& operator[](size_t _i) {
assert(_i < DIM);
return values_[_i];
}
/// get i'th element read-only
const Scalar& operator[](size_t _i) const {
assert(_i < DIM);
return values_[_i];
}
//---------------------------------------------------------------- comparsion
/// component-wise comparison
bool operator==(const vector_type& _rhs) const {
return std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin());
}
/// component-wise comparison
bool operator!=(const vector_type& _rhs) const {
return !std::equal(_rhs.values_.cbegin(), _rhs.values_.cend(), values_.cbegin());
}
//---------------------------------------------------------- scalar operators
/// component-wise self-multiplication with scalar
template<typename OtherScalar>
auto operator*=(const OtherScalar& _s) ->
typename std::enable_if<std::is_convertible<
decltype(this->values_[0] * _s), Scalar>::value,
VectorT<Scalar, DIM>&>::type {
for (auto& e : *this) {
e *= _s;
}
return *this;
}
/// component-wise self-division by scalar
template<typename OtherScalar>
auto operator/=(const OtherScalar& _s) ->
typename std::enable_if<std::is_convertible<
decltype(this->values_[0] / _s), Scalar>::value,
VectorT<Scalar, DIM>&>::type {
for (auto& e : *this) {
e /= _s;
}
return *this;
}
/// component-wise multiplication with scalar
template<typename OtherScalar>
typename std::enable_if<std::is_convertible<
decltype(std::declval<Scalar>() * std::declval<OtherScalar>()),
Scalar>::value,
VectorT<Scalar, DIM>>::type
operator*(const OtherScalar& _s) const {
return vector_type(*this) *= _s;
}
/// component-wise division by with scalar
template<typename OtherScalar>
typename std::enable_if<std::is_convertible<
decltype(std::declval<Scalar>() / std::declval<OtherScalar>()),
Scalar>::value,
VectorT<Scalar, DIM>>::type
operator/(const OtherScalar& _s) const {
return vector_type(*this) /= _s;
}
//---------------------------------------------------------- vector operators
/// component-wise self-multiplication
template<typename OtherScalar>
auto operator*=(const VectorT<OtherScalar, DIM>& _rhs) ->
typename std::enable_if<
sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0,
vector_type&>::type {
for (int i = 0; i < DIM; ++i) {
data()[i] *= _rhs.data()[i];
}
return *this;
}
/// component-wise self-division
template<typename OtherScalar>
auto operator/=(const VectorT<OtherScalar, DIM>& _rhs) ->
typename std::enable_if<
sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0,
vector_type&>::type {
for (int i = 0; i < DIM; ++i) {
data()[i] /= _rhs.data()[i];
}
return *this;
}
/// vector difference from this
template<typename OtherScalar>
auto operator-=(const VectorT<OtherScalar, DIM>& _rhs) ->
typename std::enable_if<
sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0,
vector_type&>::type {
for (int i = 0; i < DIM; ++i) {
data()[i] -= _rhs.data()[i];
}
return *this;
}
/// vector self-addition
template<typename OtherScalar>
auto operator+=(const VectorT<OtherScalar, DIM>& _rhs) ->
typename std::enable_if<
sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0,
vector_type&>::type {
for (int i = 0; i < DIM; ++i) {
data()[i] += _rhs.data()[i];
}
return *this;
}
/// component-wise vector multiplication
template<typename OtherScalar>
auto operator*(const VectorT<OtherScalar, DIM>& _rhs) const ->
typename std::enable_if<
sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0,
vector_type>::type {
return vector_type(*this) *= _rhs;
}
/// component-wise vector division
template<typename OtherScalar>
auto operator/(const VectorT<OtherScalar, DIM>& _rhs) const ->
typename std::enable_if<
sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0,
vector_type>::type {
return vector_type(*this) /= _rhs;
}
/// component-wise vector addition
template<typename OtherScalar>
auto operator+(const VectorT<OtherScalar, DIM>& _rhs) const ->
typename std::enable_if<
sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0,
vector_type>::type {
return vector_type(*this) += _rhs;
}
/// component-wise vector difference
template<typename OtherScalar>
auto operator-(const VectorT<OtherScalar, DIM>& _rhs) const ->
typename std::enable_if<
sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0,
vector_type>::type {
return vector_type(*this) -= _rhs;
}
/// unary minus
vector_type operator-(void) const {
vector_type v;
std::transform(values_.begin(), values_.end(), v.values_.begin(),
[](const Scalar &s) { return -s; });
return v;
}
/// cross product: only defined for Vec3* as specialization
/// \see OpenMesh::cross
template<typename OtherScalar>
auto operator% (const VectorT<OtherScalar, DIM> &_rhs) const ->
typename std::enable_if<DIM == 3,
VectorT<decltype(this->values_[0] * _rhs[0] -
this->values_[0] * _rhs[0]),
DIM>>::type {
return {
values_[1] * _rhs[2] - values_[2] * _rhs[1],
values_[2] * _rhs[0] - values_[0] * _rhs[2],
values_[0] * _rhs[1] - values_[1] * _rhs[0]
};
}
/// compute scalar product
/// \see OpenMesh::dot
template<typename OtherScalar>
auto operator|(const VectorT<OtherScalar, DIM>& _rhs) const ->
decltype(*this->data() * *_rhs.data()) {
return std::inner_product(data() + 1, data() + DIM, _rhs.data() + 1,
*data() * *_rhs.data());
}
//------------------------------------------------------------ euclidean norm
/// \name Euclidean norm calculations
//@{
/// compute squared euclidean norm
template<typename S = Scalar>
decltype(std::declval<S>() * std::declval<S>()) sqrnorm() const {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
typedef decltype(values_[0] * values_[0]) RESULT;
return std::accumulate(values_.cbegin() + 1, values_.cend(),
values_[0] * values_[0],
[](const RESULT &l, const Scalar &r) { return l + r * r; });
}
/// compute euclidean norm
template<typename S = Scalar>
auto norm() const ->
decltype(std::sqrt(std::declval<VectorT<S, DIM>>().sqrnorm())) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return std::sqrt(sqrnorm());
}
template<typename S = Scalar>
auto length() const ->
decltype(std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return norm();
}
/** normalize vector, return normalized vector
*/
template<typename S = Scalar>
auto normalize() ->
decltype(*this /= std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return *this /= norm();
}
/** return normalized vector
*/
template<typename S = Scalar>
auto normalized() const ->
decltype(*this / std::declval<VectorT<S, DIM>>().norm()) {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
return *this / norm();
}
/** normalize vector, return normalized vector and avoids div by zero
*/
template<typename S = Scalar>
typename std::enable_if<
sizeof(decltype(
static_cast<S>(0),
std::declval<VectorT<S, DIM>>().norm())) >= 0,
vector_type&>::type
normalize_cond() {
static_assert(std::is_same<S, Scalar>::value, "S and Scalar need "
"to be the same type. (Never override the default template "
"arguments.)");
auto n = norm();
if (n != static_cast<decltype(norm())>(0)) {
*this /= n;
}
return *this;
}
//@}
//------------------------------------------------------------ euclidean norm
/// \name Non-Euclidean norm calculations
//@{
/// compute L1 (Manhattan) norm
Scalar l1_norm() const {
return std::accumulate(
values_.cbegin() + 1, values_.end(), values_[0]);
}
/// compute l8_norm
Scalar l8_norm() const {
return max_abs();
}
//@}
//------------------------------------------------------------ max, min, mean
/// \name Minimum maximum and mean
//@{
/// return the maximal component
Scalar max() const {
return *std::max_element(values_.cbegin(), values_.cend());
}
/// return the maximal absolute component
Scalar max_abs() const {
return std::abs(
*std::max_element(values_.cbegin(), values_.cend(),
[](const Scalar &a, const Scalar &b) {
return std::abs(a) < std::abs(b);
}));
}
/// return the minimal component
Scalar min() const {
return *std::min_element(values_.cbegin(), values_.cend());
}
/// return the minimal absolute component
Scalar min_abs() const {
return std::abs(
*std::min_element(values_.cbegin(), values_.cend(),
[](const Scalar &a, const Scalar &b) {
return std::abs(a) < std::abs(b);
}));
}
/// return arithmetic mean
Scalar mean() const {
return l1_norm()/DIM;
}
/// return absolute arithmetic mean
Scalar mean_abs() const {
return std::accumulate(values_.cbegin() + 1, values_.end(),
std::abs(values_[0]),
[](const Scalar &l, const Scalar &r) {
return l + std::abs(r);
}) / DIM;
}
/// minimize values: same as *this = min(*this, _rhs), but faster
vector_type& minimize(const vector_type& _rhs) {
std::transform(values_.cbegin(), values_.cend(),
_rhs.values_.cbegin(),
values_.begin(),
[](const Scalar &l, const Scalar &r) {
return std::min(l, r);
});
return *this;
}
/// minimize values and signalize coordinate minimization
bool minimized(const vector_type& _rhs) {
bool result = false;
std::transform(values_.cbegin(), values_.cend(),
_rhs.values_.cbegin(),
values_.begin(),
[&result](const Scalar &l, const Scalar &r) {
if (l < r) {
return l;
} else {
result = true;
return r;
}
});
return result;
}
/// maximize values: same as *this = max(*this, _rhs), but faster
vector_type& maximize(const vector_type& _rhs) {
std::transform(values_.cbegin(), values_.cend(),
_rhs.values_.cbegin(),
values_.begin(),
[](const Scalar &l, const Scalar &r) {
return std::max(l, r);
});
return *this;
}
/// maximize values and signalize coordinate maximization
bool maximized(const vector_type& _rhs) {
bool result = false;
std::transform(values_.cbegin(), values_.cend(),
_rhs.values_.cbegin(),
values_.begin(),
[&result](const Scalar &l, const Scalar &r) {
if (l > r) {
return l;
} else {
result = true;
return r;
}
});
return result;
}
/// component-wise min
inline vector_type min(const vector_type& _rhs) const {
return vector_type(*this).minimize(_rhs);
}
/// component-wise max
inline vector_type max(const vector_type& _rhs) const {
return vector_type(*this).maximize(_rhs);
}
//@}
//------------------------------------------------------------ misc functions
/// component-wise apply function object with Scalar operator()(Scalar).
template<typename Functor>
inline vector_type apply(const Functor& _func) const {
vector_type result;
std::transform(result.values_.begin(), result.values_.end(),
result.values_.begin(), _func);
return result;
}
/// store the same value in each component (e.g. to clear all entries)
vector_type& vectorize(const Scalar& _s) {
std::fill(values_.begin(), values_.end(), _s);
return *this;
}
/// store the same value in each component
static vector_type vectorized(const Scalar& _s) {
return vector_type().vectorize(_s);
}
/// lexicographical comparison
bool operator<(const vector_type& _rhs) const {
return std::lexicographical_compare(
values_.begin(), values_.end(),
_rhs.values_.begin(), _rhs.values_.end());
}
//------------------------------------------------------------ component iterators
/// \name Component iterators
//@{
using iterator = typename container::iterator;
using const_iterator = typename container::const_iterator;
using reverse_iterator = typename container::reverse_iterator;
using const_reverse_iterator = typename container::const_reverse_iterator;
iterator begin() noexcept { return values_.begin(); }
const_iterator begin() const noexcept { return values_.cbegin(); }
const_iterator cbegin() const noexcept { return values_.cbegin(); }
iterator end() noexcept { return values_.end(); }
const_iterator end() const noexcept { return values_.cend(); }
const_iterator cend() const noexcept { return values_.cend(); }
reverse_iterator rbegin() noexcept { return values_.rbegin(); }
const_reverse_iterator rbegin() const noexcept { return values_.crbegin(); }
const_reverse_iterator crbegin() const noexcept { return values_.crbegin(); }
reverse_iterator rend() noexcept { return values_.rend(); }
const_reverse_iterator rend() const noexcept { return values_.crend(); }
const_reverse_iterator crend() const noexcept { return values_.crend(); }
//@}
};
/// Component wise multiplication from the left
template<typename Scalar, int DIM, typename OtherScalar>
auto operator*(const OtherScalar& _s, const VectorT<Scalar, DIM> &rhs) ->
decltype(rhs.operator*(_s)) {
return rhs * _s;
}
/// output a vector by printing its space-separated compontens
template<typename Scalar, int DIM>
auto operator<<(std::ostream& os, const VectorT<Scalar, DIM> &_vec) ->
typename std::enable_if<
sizeof(decltype(os << _vec[0])) >= 0, std::ostream&>::type {
os << _vec[0];
for (int i = 1; i < DIM; ++i) {
os << " " << _vec[i];
}
return os;
}
/// read the space-separated components of a vector from a stream
template<typename Scalar, int DIM>
auto operator>> (std::istream& is, VectorT<Scalar, DIM> &_vec) ->
typename std::enable_if<
sizeof(decltype(is >> _vec[0])) >= 0, std::istream &>::type {
for (int i = 0; i < DIM; ++i)
is >> _vec[i];
return is;
}
/// \relates OpenMesh::VectorT
/// symmetric version of the dot product
template<typename Scalar, int DIM>
Scalar dot(const VectorT<Scalar, DIM>& _v1, const VectorT<Scalar, DIM>& _v2) {
return (_v1 | _v2);
}
/// \relates OpenMesh::VectorT
/// symmetric version of the cross product
template<typename LScalar, typename RScalar, int DIM>
auto
cross(const VectorT<LScalar, DIM>& _v1, const VectorT<RScalar, DIM>& _v2) ->
decltype(_v1 % _v2) {
return (_v1 % _v2);
}
//== TYPEDEFS =================================================================
/** 1-byte signed vector */
typedef VectorT<signed char,1> Vec1c;
/** 1-byte unsigned vector */
typedef VectorT<unsigned char,1> Vec1uc;
/** 1-short signed vector */
typedef VectorT<signed short int,1> Vec1s;
/** 1-short unsigned vector */
typedef VectorT<unsigned short int,1> Vec1us;
/** 1-int signed vector */
typedef VectorT<signed int,1> Vec1i;
/** 1-int unsigned vector */
typedef VectorT<unsigned int,1> Vec1ui;
/** 1-float vector */
typedef VectorT<float,1> Vec1f;
/** 1-double vector */
typedef VectorT<double,1> Vec1d;
/** 2-byte signed vector */
typedef VectorT<signed char,2> Vec2c;
/** 2-byte unsigned vector */
typedef VectorT<unsigned char,2> Vec2uc;
/** 2-short signed vector */
typedef VectorT<signed short int,2> Vec2s;
/** 2-short unsigned vector */
typedef VectorT<unsigned short int,2> Vec2us;
/** 2-int signed vector */
typedef VectorT<signed int,2> Vec2i;
/** 2-int unsigned vector */
typedef VectorT<unsigned int,2> Vec2ui;
/** 2-float vector */
typedef VectorT<float,2> Vec2f;
/** 2-double vector */
typedef VectorT<double,2> Vec2d;
/** 3-byte signed vector */
typedef VectorT<signed char,3> Vec3c;
/** 3-byte unsigned vector */
typedef VectorT<unsigned char,3> Vec3uc;
/** 3-short signed vector */
typedef VectorT<signed short int,3> Vec3s;
/** 3-short unsigned vector */
typedef VectorT<unsigned short int,3> Vec3us;
/** 3-int signed vector */
typedef VectorT<signed int,3> Vec3i;
/** 3-int unsigned vector */
typedef VectorT<unsigned int,3> Vec3ui;
/** 3-float vector */
typedef VectorT<float,3> Vec3f;
/** 3-double vector */
typedef VectorT<double,3> Vec3d;
/** 3-bool vector */
typedef VectorT<bool,3> Vec3b;
/** 4-byte signed vector */
typedef VectorT<signed char,4> Vec4c;
/** 4-byte unsigned vector */
typedef VectorT<unsigned char,4> Vec4uc;
/** 4-short signed vector */
typedef VectorT<signed short int,4> Vec4s;
/** 4-short unsigned vector */
typedef VectorT<unsigned short int,4> Vec4us;
/** 4-int signed vector */
typedef VectorT<signed int,4> Vec4i;
/** 4-int unsigned vector */
typedef VectorT<unsigned int,4> Vec4ui;
/** 4-float vector */
typedef VectorT<float,4> Vec4f;
/** 4-double vector */
typedef VectorT<double,4> Vec4d;
/** 5-byte signed vector */
typedef VectorT<signed char, 5> Vec5c;
/** 5-byte unsigned vector */
typedef VectorT<unsigned char, 5> Vec5uc;
/** 5-short signed vector */
typedef VectorT<signed short int, 5> Vec5s;
/** 5-short unsigned vector */
typedef VectorT<unsigned short int, 5> Vec5us;
/** 5-int signed vector */
typedef VectorT<signed int, 5> Vec5i;
/** 5-int unsigned vector */
typedef VectorT<unsigned int, 5> Vec5ui;
/** 5-float vector */
typedef VectorT<float, 5> Vec5f;
/** 5-double vector */
typedef VectorT<double, 5> Vec5d;
/** 6-byte signed vector */
typedef VectorT<signed char,6> Vec6c;
/** 6-byte unsigned vector */
typedef VectorT<unsigned char,6> Vec6uc;
/** 6-short signed vector */
typedef VectorT<signed short int,6> Vec6s;
/** 6-short unsigned vector */
typedef VectorT<unsigned short int,6> Vec6us;
/** 6-int signed vector */
typedef VectorT<signed int,6> Vec6i;
/** 6-int unsigned vector */
typedef VectorT<unsigned int,6> Vec6ui;
/** 6-float vector */
typedef VectorT<float,6> Vec6f;
/** 6-double vector */
typedef VectorT<double,6> Vec6d;
} // namespace OpenMesh
/**
* Literal operator for inline specification of colors in HTML syntax.
*
* Example:
* \code{.cpp}
* OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
* \endcode
*/
constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) {
return OpenMesh::Vec4f(
((raw_color >> 24) & 0xFF) / 255.0f,
((raw_color >> 16) & 0xFF) / 255.0f,
((raw_color >> 8) & 0xFF) / 255.0f,
((raw_color >> 0) & 0xFF) / 255.0f);
}
#endif /* OPENMESH_SRC_OPENMESH_CORE_GEOMETRY_VECTOR11T_HH_ */

View File

@@ -59,6 +59,10 @@
// bugreport: https://bugzilla.gnome.org/show_bug.cgi?id=629182)
// macro expansion and preprocessor defines
// don't work properly.
#if (__cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
#include "Vector11T.hh"
#else
#ifndef DOXYGEN
#ifndef OPENMESH_VECTOR_HH
@@ -77,12 +81,6 @@
#include <xmmintrin.h>
#endif
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#include <array>
#include <initializer_list>
#include <type_traits>
#endif
//== NAMESPACES ===============================================================
@@ -92,24 +90,6 @@ namespace OpenMesh {
//== CLASS DEFINITION =========================================================
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/*
* Helpers for VectorT
*/
namespace {
template<typename... Ts>
struct are_convertible_to;
template<typename To, typename From, typename... Froms>
struct are_convertible_to<To, From, Froms...> {
static constexpr bool value = std::is_convertible<From, To>::value && are_convertible_to<To, Froms...>::value;
};
template<typename To, typename From>
struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
}
#endif
/** The N values of the template Scalar type are the only data members
of the class VectorT<Scalar,N>. This guarantees 100% compatibility
with arrays of type Scalar and size N, allowing us to define the
@@ -121,18 +101,7 @@ struct are_convertible_to<To, From> : public std::is_convertible<From, To> {};
*/
template<typename Scalar, int N> class VectorDataT {
public:
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
VectorDataT() {}
template<typename... T>
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
static_assert(sizeof...(vs) == N,
"Incorrect number of vector components supplied.");
}
std::array<Scalar, N> values_;
#else
Scalar values_[N];
#endif
};
@@ -141,22 +110,9 @@ template<typename Scalar, int N> class VectorDataT {
/// This specialization enables us to use aligned SSE instructions.
template<> class VectorDataT<float, 4> {
public:
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
VectorDataT() {}
template<typename... T>
constexpr VectorDataT(T... vs) : values_ {{vs...}} {
static_assert(sizeof...(vs) == 4,
"Incorrect number of vector components supplied.");
}
#endif
union {
__m128 m128;
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
std::array<float, 4> values_;
#else
float values_[4];
#endif
};
};
@@ -432,24 +388,7 @@ typedef VectorT<double,6> Vec6d;
//=============================================================================
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/**
* Literal operator for inline specification of colors in HTML syntax.
*
* Example:
* \code{.cpp}
* OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
* \endcode
*/
constexpr OpenMesh::Vec4f operator"" _htmlColor(unsigned long long raw_color) {
return OpenMesh::Vec4f(
((raw_color >> 24) & 0xFF) / 255.0f,
((raw_color >> 16) & 0xFF) / 255.0f,
((raw_color >> 8) & 0xFF) / 255.0f,
((raw_color >> 0) & 0xFF) / 255.0f);
}
#endif
#endif // OPENMESH_VECTOR_HH defined
//=============================================================================
#endif // DOXYGEN
#endif // C++11

View File

@@ -97,28 +97,6 @@ public:
/// default constructor creates uninitialized values.
inline VectorT() {}
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
explicit inline VectorT(const Scalar &v) {
vectorize(v);
}
template<typename... T,
typename = typename std::enable_if<sizeof...(T) == DIM>::type,
typename = typename std::enable_if<are_convertible_to<Scalar, T...>::value>::type>
constexpr VectorT(T... vs) : Base { static_cast<Scalar>(vs)...}
{ }
template<int D = DIM, typename = typename std::enable_if<D == DIM>::type>
typename std::enable_if<D==4, VectorT>::type
homogenized() const {
return VectorT(
Base::values_[0]/Base::values_[3],
Base::values_[1]/Base::values_[3],
Base::values_[2]/Base::values_[3],
1);
}
#else
/// special constructor for 1D vectors
explicit inline VectorT(const Scalar& v) {
// assert(DIM==1);
@@ -165,7 +143,6 @@ public:
Base::values_[0]=v0; Base::values_[1]=v1; Base::values_[2]=v2;
Base::values_[3]=v3; Base::values_[4]=v4; Base::values_[5]=v5;
}
#endif
#endif
/// construct from a value array (explicit)
@@ -210,21 +187,11 @@ public:
// /// cast to const Scalar array
// inline operator const Scalar*() const { return Base::values_; }
#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/// access to Scalar array
inline Scalar* data() { return Base::values_.data(); }
/// access to const Scalar array
inline const Scalar*data() const { return Base::values_.data(); }
#else
/// access to Scalar array
inline Scalar* data() { return Base::values_; }
/// access to const Scalar array
inline const Scalar*data() const { return Base::values_; }
#endif
//----------------------------------------------------------- element access

View File

@@ -38,6 +38,71 @@ Scalar get_item(Vector& _vec, int _index) {
return 0.0;
}
namespace {
template<class Scalar>
struct Factory {
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
static Vector2 *vec2_default() {
return new Vector2(Scalar(), Scalar());
}
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
return new Vector2(_v0, _v1);
}
static Vector3 *vec3_default() {
return new Vector3(Scalar(), Scalar(), Scalar());
}
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
return new Vector3(_v0, _v1, _v2);
}
static Vector4 *vec4_default() {
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
}
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
return new Vector4(_v0, _v1, _v2, _v3);
}
};
}
template<class Scalar, int N>
void defInitMod(class_<OpenMesh::VectorT<Scalar, N>> &classVector);
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 2>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec2_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec2_user_defined))
;
typedef OpenMesh::VectorT<Scalar, 2> Vector;
def("dot", &Vector::operator|);
}
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 3>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec3_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec3_user_defined))
.def("__mod__", &Factory<Scalar>::Vector3::operator%)
;
def("cross", &Factory<Scalar>::Vector3::operator%);
typedef OpenMesh::VectorT<Scalar, 3> Vector;
def("dot", &Vector::operator|);
}
template<class Scalar>
void defInitMod(class_<OpenMesh::VectorT<Scalar, 4>> &classVector) {
classVector
.def("__init__", make_constructor(&Factory<Scalar>::vec4_default))
.def("__init__", make_constructor(&Factory<Scalar>::vec4_user_defined))
;
typedef OpenMesh::VectorT<Scalar, 4> Vector;
def("dot", &Vector::operator|);
}
/**
* Expose a vector type to %Python.
*
@@ -86,12 +151,12 @@ void expose_vec(const char *_name) {
.def("vectorize", &Vector::vectorize, return_internal_reference<>())
.def(self < self)
.def("norm", &Vector::norm)
.def("length", &Vector::length)
.def("sqrnorm", &Vector::sqrnorm)
.def("normalize", &Vector::normalize, return_internal_reference<>())
.def("normalized", &Vector::normalized)
.def("normalize_cond", &Vector::normalize_cond, return_internal_reference<>())
.def("norm", &Vector::template norm<Scalar>)
.def("length", &Vector::template length<Scalar>)
.def("sqrnorm", &Vector::template sqrnorm<Scalar>)
.def("normalize", &Vector::template normalize<Scalar>, return_internal_reference<>())
.def("normalized", &Vector::template normalized<Scalar>)
.def("normalize_cond", &Vector::template normalize_cond<Scalar>, return_internal_reference<>())
.def("l1_norm", &Vector::l1_norm)
.def("l8_norm", &Vector::l8_norm)
@@ -115,56 +180,7 @@ void expose_vec(const char *_name) {
.staticmethod("vectorized")
;
typedef OpenMesh::VectorT<Scalar, 2> Vector2;
typedef OpenMesh::VectorT<Scalar, 3> Vector3;
typedef OpenMesh::VectorT<Scalar, 4> Vector4;
struct Factory {
static Vector2 *vec2_default() {
return new Vector2(Scalar(), Scalar());
}
static Vector2 *vec2_user_defined(const Scalar& _v0, const Scalar& _v1) {
return new Vector2(_v0, _v1);
}
static Vector3 *vec3_default() {
return new Vector3(Scalar(), Scalar(), Scalar());
}
static Vector3 *vec3_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2) {
return new Vector3(_v0, _v1, _v2);
}
static Vector4 *vec4_default() {
return new Vector4(Scalar(), Scalar(), Scalar(), Scalar());
}
static Vector4 *vec4_user_defined(const Scalar& _v0, const Scalar& _v1, const Scalar& _v2, const Scalar& _v3) {
return new Vector4(_v0, _v1, _v2, _v3);
}
};
if (N == 2) {
classVector
.def("__init__", make_constructor(&Factory::vec2_default))
.def("__init__", make_constructor(&Factory::vec2_user_defined))
;
}
if (N == 3) {
classVector
.def("__init__", make_constructor(&Factory::vec3_default))
.def("__init__", make_constructor(&Factory::vec3_user_defined))
.def("__mod__", &Vector3::operator%)
;
def("cross", &Vector3::operator%);
}
if (N == 4) {
classVector
.def("__init__", make_constructor(&Factory::vec4_default))
.def("__init__", make_constructor(&Factory::vec4_user_defined))
;
}
def("dot", &Vector::operator|);
defInitMod<Scalar, N>(classVector);
}
} // namespace OpenMesh

7
src/Unittests/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
deleted_output.off
output.off
persistence-check.om
smoothed_STL_output.off
smoothed_custom_properties_output.off
smoothed_extended_output.off
smoothed_output.off

6
src/Unittests/TestFiles/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
cube-minimal-customprops_openmeshOutputTestfileBinary.ply
cube_floating.off
cube_floating_binary.off
meshlab_binary.ply
meshlab_binary_float.ply
meshlab_float.ply

View File

@@ -82,6 +82,7 @@ TEST_F(OpenMesh_Triangle, cpp11_vertexrange_test) {
for(Mesh::VertexHandle t : mesh_.vertices())
{
FAIL() << "The Vertexrange for an empty Mesh is not empty";
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
}
//add vertices to mesh
@@ -110,6 +111,7 @@ TEST_F(OpenMesh_Poly, cpp11_vertexrange_test) {
for(PolyMesh::VertexHandle t : mesh_.vertices())
{
FAIL() << "The Vertexrange for an empty Mesh is not empty";
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
}
//add vertices to mesh
@@ -140,6 +142,7 @@ TEST_F(OpenMesh_Triangle, cpp11_vvrange_test) {
for(Mesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
{
FAIL() << "The vvrange for a single vertex in a TriMesh is not empty";
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
}
//add more vertices
@@ -198,6 +201,7 @@ TEST_F(OpenMesh_Poly, cpp11_vvrange_test) {
for(PolyMesh::VertexHandle t : mesh_.vv_range(vhandle[0]))
{
FAIL() << "The vvrange for a single vertex in a PolyMesh is not empty";
EXPECT_TRUE(t.is_valid()); // Just so we don't get an unused variable warning.
}
//add more vertices

View File

@@ -169,7 +169,7 @@ TEST_F(OpenMeshOthers, CalcDihedralAngre ) {
double difference = fabs( 1.36944 - mesh_.calc_dihedral_angle(eh) );
EXPECT_TRUE( (difference < 0.00001 ) ) << "Wrong Dihedral angle, Difference is to big!" << std::endl;
EXPECT_LT(difference, 0.00001) << "Wrong Dihedral angle, Difference is to big!" << std::endl;
}
}

View File

@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <list>
namespace {
@@ -115,6 +116,8 @@ TEST_F(OpenMeshVectorTest, cpp11_constructors) {
TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
static constexpr OpenMesh::Vec4f rose = 0xFFC7F1FF_htmlColor;
EXPECT_EQ(0xFFC7F1FF_htmlColor, rose);
const OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
EXPECT_LE((OpenMesh::Vec4f(0.1215686274f, 0.8117647058f, 1.0f, 1.0f)
- light_blue).sqrnorm(), 1e-10);
@@ -125,6 +128,199 @@ TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
::value, "Bad type deduced from _htmlColor literal.");
EXPECT_EQ(light_blue, light_blue_2);
}
#endif
namespace {
class C {
public:
C() {}
C(const C &rhs) { ADD_FAILURE() << "Copy constructor used."; }
C(C &&rhs) { ++copy_con; }
C &operator= (const C &rhs) {
ADD_FAILURE() << "Copy assignemnt used.";
return *this;
}
C &operator= (C &&rhs) { ++copy_ass; return *this; }
static int copy_con;
static int copy_ass;
};
int C::copy_con = 0;
int C::copy_ass = 0;
}
/**
* Checks two things:
* 1) Whether VectorT works with a non-arithmetic type.
* 2) Whether move construction and assignment works.
*/
TEST_F(OpenMeshVectorTest, move_constructor_assignment) {
C::copy_con = 0;
C::copy_ass = 0;
// Test move assigning.
OpenMesh::VectorT<C, 3> x, y;
x = std::move(y);
EXPECT_EQ(3, C::copy_ass);
EXPECT_EQ(0, C::copy_con);
// Test move constructing.
OpenMesh::VectorT<C, 3> z(std::move(x));
EXPECT_EQ(3, C::copy_ass);
EXPECT_EQ(3, C::copy_con);
}
TEST_F(OpenMeshVectorTest, iterator_init) {
std::list<float> a;
a.push_back(1.0);
a.push_back(2.0);
a.push_back(3.0);
OpenMesh::Vec3f v(a.begin());
EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
}
#endif // C++11
TEST_F(OpenMeshVectorTest, BasicArithmeticInPlace) {
OpenMesh::Vec3d v1(1, 2, 3);
double s1 = 2;
const double epsilon = 1e-6;
OpenMesh::Vec3d v2add (3, 4, 6); v2add += v1;
OpenMesh::Vec3d v2sub (3, 4, 6); v2sub -= v1;
OpenMesh::Vec3d v2cmul(3, 4, 6); v2cmul *= v1;
OpenMesh::Vec3d v2cdiv(3, 4, 6); v2cdiv /= v1;
OpenMesh::Vec3d v2smul(3, 4, 6); v2smul *= s1;
OpenMesh::Vec3d v2sdiv(3, 4, 6); v2sdiv /= s1;
EXPECT_NEAR(4, v2add[0], epsilon);
EXPECT_NEAR(6, v2add[1], epsilon);
EXPECT_NEAR(9, v2add[2], epsilon);
EXPECT_NEAR(2, v2sub[0], epsilon);
EXPECT_NEAR(2, v2sub[1], epsilon);
EXPECT_NEAR(3, v2sub[2], epsilon);
EXPECT_NEAR( 3, v2cmul[0], epsilon);
EXPECT_NEAR( 8, v2cmul[1], epsilon);
EXPECT_NEAR(18, v2cmul[2], epsilon);
EXPECT_NEAR(3, v2cdiv[0], epsilon);
EXPECT_NEAR(2, v2cdiv[1], epsilon);
EXPECT_NEAR(2, v2cdiv[2], epsilon);
EXPECT_NEAR( 6, v2smul[0], epsilon);
EXPECT_NEAR( 8, v2smul[1], epsilon);
EXPECT_NEAR(12, v2smul[2], epsilon);
EXPECT_NEAR(1.5, v2sdiv[0], epsilon);
EXPECT_NEAR(2.0, v2sdiv[1], epsilon);
EXPECT_NEAR(3.0, v2sdiv[2], epsilon);
}
TEST_F(OpenMeshVectorTest, BasicArithmeticImmutable) {
OpenMesh::Vec3d v1(1, 2, 3);
const double epsilon = 1e-6;
OpenMesh::Vec3d v2add = v1 + OpenMesh::Vec3d(2, 4, 6);
OpenMesh::Vec3d v2sub = v1 - OpenMesh::Vec3d(2, 4, 6);
OpenMesh::Vec3d v2cmul = v1 * OpenMesh::Vec3d(2, 4, 6);
OpenMesh::Vec3d v2cdiv = v1 / OpenMesh::Vec3d(2, 4, 6);
OpenMesh::Vec3d v2smul = v1 * 2.0;
OpenMesh::Vec3d v2sdiv = v1 / 2.0;
OpenMesh::Vec3d v2neg = -v1;
EXPECT_NEAR(3, v2add[0], epsilon);
EXPECT_NEAR(6, v2add[1], epsilon);
EXPECT_NEAR(9, v2add[2], epsilon);
EXPECT_NEAR(-1, v2sub[0], epsilon);
EXPECT_NEAR(-2, v2sub[1], epsilon);
EXPECT_NEAR(-3, v2sub[2], epsilon);
EXPECT_NEAR( 2, v2cmul[0], epsilon);
EXPECT_NEAR( 8, v2cmul[1], epsilon);
EXPECT_NEAR(18, v2cmul[2], epsilon);
EXPECT_NEAR(0.5, v2cdiv[0], epsilon);
EXPECT_NEAR(0.5, v2cdiv[1], epsilon);
EXPECT_NEAR(0.5, v2cdiv[2], epsilon);
EXPECT_NEAR(2, v2smul[0], epsilon);
EXPECT_NEAR(4, v2smul[1], epsilon);
EXPECT_NEAR(6, v2smul[2], epsilon);
EXPECT_NEAR(0.5, v2sdiv[0], epsilon);
EXPECT_NEAR(1.0, v2sdiv[1], epsilon);
EXPECT_NEAR(1.5, v2sdiv[2], epsilon);
EXPECT_NEAR(-1, v2neg[0], epsilon);
EXPECT_NEAR(-2, v2neg[1], epsilon);
EXPECT_NEAR(-3, v2neg[2], epsilon);
}
TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
OpenMesh::Vec3d v(1, 2, 3);
EXPECT_EQ(v[0], 1.0);
EXPECT_EQ(v[1], 2.0);
EXPECT_EQ(v[2], 3.0);
EXPECT_EQ(OpenMesh::Vec3d(-1, -2, -3), -v);
EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, 2).max());
EXPECT_EQ(3, OpenMesh::Vec3d(1, 2, 3).max());
EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, -4).max());
EXPECT_EQ(3, OpenMesh::Vec3d(-4, 2, 3).max());
EXPECT_EQ(4, OpenMesh::Vec3d(1, 3, -4).max_abs());
EXPECT_EQ(4, OpenMesh::Vec3d(-4, 2, 3).max_abs());
EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, 2).min());
EXPECT_EQ(1, OpenMesh::Vec3d(1, 2, 3).min());
EXPECT_EQ(-4, OpenMesh::Vec3d(1, 3, -4).min());
EXPECT_EQ(-4, OpenMesh::Vec3d(-4, 2, 3).min());
EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, -4).min_abs());
EXPECT_EQ(2, OpenMesh::Vec3d(-4, 2, 3).min_abs());
EXPECT_NEAR(14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(1, 2, 3), 1e-6);
EXPECT_NEAR(-14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
EXPECT_NEAR(14, OpenMesh::Vec3d(-1, -2, -3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
}
TEST_F(OpenMeshVectorTest, array_init) {
float a[3]; a[0] = 1.0; a[1] = 2.0; a[2] = 3.0;
OpenMesh::Vec3f v(a);
EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
// This should not invoke the array constructor.
OpenMesh::Vec3d v2(3.0f);
}
TEST_F(OpenMeshVectorTest, normalized_cond) {
OpenMesh::Vec3d v1(1, -2, 3), v2(0, 0, 0);
EXPECT_EQ(OpenMesh::Vec3d(0, 0, 0), v2.normalize_cond());
const OpenMesh::Vec3d r1 =
OpenMesh::Vec3d(
0.2672612419124244,
-0.5345224838248488,
0.8017837257372732) - v1.normalize_cond();
EXPECT_NEAR(r1[0], 0.0, 1e-12);
EXPECT_NEAR(r1[1], 0.0, 1e-12);
EXPECT_NEAR(r1[2], 0.0, 1e-12);
}
TEST_F(OpenMeshVectorTest, size_dim) {
OpenMesh::Vec3d v3d(1, 2, 3);
OpenMesh::Vec3f v3f(1, 2, 3);
OpenMesh::Vec2i v2i(1, 2);
EXPECT_EQ(3u, v3d.size());
EXPECT_EQ(3, v3d.dim());
EXPECT_EQ(3u, v3f.size());
EXPECT_EQ(3, v3f.dim());
EXPECT_EQ(2u, v2i.size());
EXPECT_EQ(2, v2i.dim());
}
}