From 287da209120062603022f0e4e3ca11ae310cb842 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Wed, 18 Nov 2015 15:11:48 +0100 Subject: [PATCH 01/33] C++11: Reimplemented VectorT without macros. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 757 ++++++++++++++++++++++ src/OpenMesh/Core/Geometry/VectorT.hh | 71 +- src/Unittests/unittests_trimesh_others.cc | 2 +- 3 files changed, 763 insertions(+), 67 deletions(-) create mode 100644 src/OpenMesh/Core/Geometry/Vector11T.hh diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh new file mode 100644 index 00000000..6c60166f --- /dev/null +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -0,0 +1,757 @@ +/* ========================================================================= * + * * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +// This header is not needed by this file but expected by others including +// this file. +#include + + +/* + * Helpers for VectorT + */ +namespace { + +template +struct are_convertible_to; + +template +struct are_convertible_to { + static constexpr bool value = std::is_convertible::value + && are_convertible_to::value; +}; + +template +struct are_convertible_to : public std::is_convertible { +}; +} + +namespace OpenMesh { + +template +class VectorT { + private: + std::array values_; + + public: + + //---------------------------------------------------------------- class info + + /// the type of the scalar used in this template + typedef Scalar value_type; + + /// type of this vector + typedef VectorT vector_type; + + /// returns dimension of the vector (deprecated) + static inline int dim() { + return DIM; + } + + /// returns dimension of the vector + static inline size_t size() { + return DIM; + } + + static 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::type, + typename = typename std::enable_if< + are_convertible_to::value>::type> + constexpr VectorT(T... vs) : values_ { {static_cast(vs)...} } + {} + + /** + * Only for 4-component vectors with division operator on their + * Scalar: Dehomogenization. + */ + template::type, + typename = decltype(values_[0]/values_[3])> + typename std::enable_if::type + homogenized() const { + return VectorT( + values_[0]/values_[3], + values_[1]/values_[3], + values_[2]/values_[3], + 1); + } + + /// construct from a value array (explicit) + explicit inline VectorT(const Scalar _values[DIM]) { + std::copy(_values, _values + DIM, values_.begin()); + } + + /// copy & cast constructor (explicit) + template::value>> + explicit inline VectorT(const VectorT& _rhs) { + operator=(_rhs); + } + + //--------------------------------------------------------------------- casts + + /// cast from vector with a different scalar type + template::value>> + vector_type& operator=(const VectorT& _rhs) { + std::transform(_rhs.data(), _rhs.data() + DIM, + data(), [](OtherScalar rhs) { + return static_cast(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 std::enable_if() * std::declval()), + Scalar>::value, + VectorT&>::type + operator*=(const OtherScalar& _s) { + std::transform(values_.begin(), values_.end(), values_.begin(), + [&_s](const Scalar & c) { return c * _s; }); + return *this; + } + + /** component-wise self-division by scalar + \attention v *= (1/_s) is much faster than this */ + template + typename std::enable_if() / std::declval()), + Scalar>::value, + VectorT&>::type + operator/=(const OtherScalar& _s) { + std::transform(values_.begin(), values_.end(), values_.begin(), + [&_s](const Scalar & c) { return c / _s; }); + return *this; + } + + /// component-wise multiplication with scalar + //template() * + // std::declval())> + //VectorT operator*(const OtherScalar& _s) const { + // return vector_type(*this) *= _s; + //} + template + typename std::enable_if() * std::declval()), + Scalar>::value, + VectorT>::type + operator*(const OtherScalar& _s) const { + return vector_type(*this) *= _s; + } + + /// component-wise division by with scalar + template + typename std::enable_if() / std::declval()), + Scalar>::value, + VectorT>::type + operator/(const OtherScalar& _s) const { + return vector_type(*this) /= _s; + } + + //---------------------------------------------------------- vector operators + + /// component-wise self-multiplication + template() * + std::declval())> + vector_type& operator*=(const VectorT& _rhs) { + std::transform(data(), data() + DIM, + _rhs.data(), data(), + [](const Scalar &l, const OtherScalar &r) { return l * r; }); + return *this; + } + + /// component-wise self-division + template() / + std::declval())> + vector_type& operator/=(const VectorT& _rhs) { + std::transform(data(), data() + DIM, + _rhs.data(), data(), + [](const Scalar &l, const OtherScalar &r) { return l / r; }); + return *this; + } + + /// vector difference from this + template() - + std::declval())> + vector_type& operator-=(const VectorT& _rhs) { + std::transform(data(), data() + DIM, + _rhs.data(), data(), + [](const Scalar &l, const OtherScalar &r) { return l - r; }); + return *this; + } + + /// vector self-addition + template() + + std::declval())> + vector_type& operator+=(const VectorT& _rhs) { + std::transform(data(), data() + DIM, + _rhs.data(), data(), + [](const Scalar &l, const OtherScalar &r) { return l + r; }); + return *this; + } + + /// component-wise vector multiplication + template() *= + std::declval&>())> + vector_type operator*(const VectorT& _rhs) const { + return vector_type(*this) *= _rhs; + } + + /// component-wise vector division + template() /= + std::declval&>())> + vector_type operator/(const VectorT& _rhs) const { + return vector_type(*this) /= _rhs; + } + + /// component-wise vector addition + template() += + std::declval&>())> + vector_type operator+(const VectorT& _rhs) const { + return vector_type(*this) += _rhs; + } + + /// component-wise vector difference + template() -= + std::declval&>())> + vector_type operator-(const VectorT& _rhs) const { + return vector_type(*this) -= _rhs; + } + + /// unary minus + vector_type operator-(void) const { + vector_type v; + std::transform(v.values_.begin(), v.values_.end(), v.values_.begin(), + [](const Scalar &s) { return -s; }); + return v; + } + + /// cross product: only defined for Vec3* as specialization + /// \see OpenMesh::cross + template() * std::declval() - + std::declval() * std::declval())> + typename std::enable_if>::type + operator% (const VectorT &_rhs) const { + return VectorT( + values_[1] * _rhs.values_[2] - values_[2] * _rhs.values_[1], + values_[2] * _rhs.values_[0] - values_[0] * _rhs.values_[2], + values_[0] * _rhs.values_[1] - values_[1] * _rhs.values_[0]); + } + + /// compute scalar product + /// \see OpenMesh::dot + template() * std::declval())> + typename std::enable_if::type + operator|(const VectorT& _rhs) const { + ResultScalar p = values_[0] * _rhs[0]; + for (int i = 1; i < DIM; ++i) { + p += values_[i] * _rhs[i]; + } + return p; + } + + //------------------------------------------------------------ euclidean norm + + /// \name Euclidean norm calculations + //@{ + + /// compute squared euclidean norm + decltype(values_[0] * values_[0]) sqrnorm() const { + 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 + decltype(std::sqrt(std::declval().sqrnorm())) norm() const { + return std::sqrt(sqrnorm()); + } + + decltype(std::declval().norm()) length() const { + return norm(); + } + + /** normalize vector, return normalized vector + */ + vector_type& normalize() { + *this /= norm(); + return *this; + } + + /** return normalized vector + */ + decltype(std::declval() / std::declval().norm()) + normalized() const { + return *this / norm(); + } + + /** normalize vector, return normalized vector and avoids div by zero + */ + vector_type& normalize_cond() { + Scalar n = norm(); + if (n != (Scalar)0.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 + 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()); + } + + public: + /// Component wise multiplication from the left + template + friend + decltype(std::declval().operator*(std::declval())) + operator*(const OtherScalar& _s, const vector_type &rhs) { + return rhs * _s; + } +}; + +/// output a vector by printing its space-separated compontens +template +typename std::enable_if() << + std::declval())) >= 0, std::ostream&>::type +operator<<(std::ostream& os, const VectorT &_vec) { + 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 std::enable_if() >> + std::declval())) >= 0, std::istream&>::type +operator>> (std::istream& is, VectorT &_vec) { + for (int i = 0; i < DIM; ++i) + is >> _vec[i]; + return is; +} + +/// \relates OpenMesh::VectorT +/// symmetric version of the dot product +template +Scalar +dot(const VectorT& _v1, const VectorT& _v2) { + return (_v1 | _v2); +} + + +/// \relates OpenMesh::VectorT +/// symmetric version of the cross product +template +decltype(std::declval&>() % + std::declval&>()) +cross(const VectorT& _v1, const VectorT& _v2) { + return (_v1 % _v2); +} + + +//== TYPEDEFS ================================================================= + +/** 1-byte signed vector */ +typedef VectorT Vec1c; +/** 1-byte unsigned vector */ +typedef VectorT Vec1uc; +/** 1-short signed vector */ +typedef VectorT Vec1s; +/** 1-short unsigned vector */ +typedef VectorT Vec1us; +/** 1-int signed vector */ +typedef VectorT Vec1i; +/** 1-int unsigned vector */ +typedef VectorT Vec1ui; +/** 1-float vector */ +typedef VectorT Vec1f; +/** 1-double vector */ +typedef VectorT Vec1d; + +/** 2-byte signed vector */ +typedef VectorT Vec2c; +/** 2-byte unsigned vector */ +typedef VectorT Vec2uc; +/** 2-short signed vector */ +typedef VectorT Vec2s; +/** 2-short unsigned vector */ +typedef VectorT Vec2us; +/** 2-int signed vector */ +typedef VectorT Vec2i; +/** 2-int unsigned vector */ +typedef VectorT Vec2ui; +/** 2-float vector */ +typedef VectorT Vec2f; +/** 2-double vector */ +typedef VectorT Vec2d; + +/** 3-byte signed vector */ +typedef VectorT Vec3c; +/** 3-byte unsigned vector */ +typedef VectorT Vec3uc; +/** 3-short signed vector */ +typedef VectorT Vec3s; +/** 3-short unsigned vector */ +typedef VectorT Vec3us; +/** 3-int signed vector */ +typedef VectorT Vec3i; +/** 3-int unsigned vector */ +typedef VectorT Vec3ui; +/** 3-float vector */ +typedef VectorT Vec3f; +/** 3-double vector */ +typedef VectorT Vec3d; +/** 3-bool vector */ +typedef VectorT Vec3b; + +/** 4-byte signed vector */ +typedef VectorT Vec4c; +/** 4-byte unsigned vector */ +typedef VectorT Vec4uc; +/** 4-short signed vector */ +typedef VectorT Vec4s; +/** 4-short unsigned vector */ +typedef VectorT Vec4us; +/** 4-int signed vector */ +typedef VectorT Vec4i; +/** 4-int unsigned vector */ +typedef VectorT Vec4ui; +/** 4-float vector */ +typedef VectorT Vec4f; +/** 4-double vector */ +typedef VectorT Vec4d; + +/** 5-byte signed vector */ +typedef VectorT Vec5c; +/** 5-byte unsigned vector */ +typedef VectorT Vec5uc; +/** 5-short signed vector */ +typedef VectorT Vec5s; +/** 5-short unsigned vector */ +typedef VectorT Vec5us; +/** 5-int signed vector */ +typedef VectorT Vec5i; +/** 5-int unsigned vector */ +typedef VectorT Vec5ui; +/** 5-float vector */ +typedef VectorT Vec5f; +/** 5-double vector */ +typedef VectorT Vec5d; + +/** 6-byte signed vector */ +typedef VectorT Vec6c; +/** 6-byte unsigned vector */ +typedef VectorT Vec6uc; +/** 6-short signed vector */ +typedef VectorT Vec6s; +/** 6-short unsigned vector */ +typedef VectorT Vec6us; +/** 6-int signed vector */ +typedef VectorT Vec6i; +/** 6-int unsigned vector */ +typedef VectorT Vec6ui; +/** 6-float vector */ +typedef VectorT Vec6f; +/** 6-double vector */ +typedef VectorT 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_ */ diff --git a/src/OpenMesh/Core/Geometry/VectorT.hh b/src/OpenMesh/Core/Geometry/VectorT.hh index 433120a0..a582d194 100644 --- a/src/OpenMesh/Core/Geometry/VectorT.hh +++ b/src/OpenMesh/Core/Geometry/VectorT.hh @@ -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__) +#include "Vector11T.hh" +#else #ifndef DOXYGEN #ifndef OPENMESH_VECTOR_HH @@ -77,12 +81,6 @@ #include #endif -#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) -#include -#include -#include -#endif - //== NAMESPACES =============================================================== @@ -92,24 +90,6 @@ namespace OpenMesh { //== CLASS DEFINITION ========================================================= -#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) -/* - * Helpers for VectorT - */ -namespace { -template -struct are_convertible_to; - -template -struct are_convertible_to { - static constexpr bool value = std::is_convertible::value && are_convertible_to::value; -}; -template -struct are_convertible_to : public std::is_convertible {}; -} -#endif - - /** The N values of the template Scalar type are the only data members of the class VectorT. 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 : public std::is_convertible {}; */ template class VectorDataT { public: -#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) - VectorDataT() {} - - template - constexpr VectorDataT(T... vs) : values_ {{vs...}} { - static_assert(sizeof...(vs) == N, - "Incorrect number of vector components supplied."); - } - std::array values_; -#else Scalar values_[N]; -#endif }; @@ -141,22 +110,9 @@ template class VectorDataT { /// This specialization enables us to use aligned SSE instructions. template<> class VectorDataT { public: -#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) - VectorDataT() {} - - template - 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 values_; -#else float values_[4]; -#endif }; }; @@ -432,24 +388,7 @@ typedef VectorT 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 diff --git a/src/Unittests/unittests_trimesh_others.cc b/src/Unittests/unittests_trimesh_others.cc index 03b056e7..14d96e37 100644 --- a/src/Unittests/unittests_trimesh_others.cc +++ b/src/Unittests/unittests_trimesh_others.cc @@ -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; } } From b0f7f8b0f3017d5c7b84225ff3d62dea348333e7 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Wed, 18 Nov 2015 15:52:20 +0100 Subject: [PATCH 02/33] Fixed VectorT::operator| and operator>>. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 6c60166f..8df3fafe 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -357,8 +357,7 @@ class VectorT { template() * std::declval())> - typename std::enable_if::type - operator|(const VectorT& _rhs) const { + ResultScalar operator|(const VectorT& _rhs) const { ResultScalar p = values_[0] * _rhs[0]; for (int i = 1; i < DIM; ++i) { p += values_[i] * _rhs[i]; @@ -603,7 +602,7 @@ operator<<(std::ostream& os, const VectorT &_vec) { /// read the space-separated components of a vector from a stream template typename std::enable_if() >> + std::declval() >> std::declval())) >= 0, std::istream&>::type operator>> (std::istream& is, VectorT &_vec) { for (int i = 0; i < DIM; ++i) From e966c351b4bddcb02d213e5ce2522c6afe22a1ba Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Wed, 18 Nov 2015 15:52:32 +0100 Subject: [PATCH 03/33] Fixed VectorT python wrapper. --- src/Python/Vector.hh | 116 ++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 50 deletions(-) diff --git a/src/Python/Vector.hh b/src/Python/Vector.hh index f43cd14b..759a6638 100644 --- a/src/Python/Vector.hh +++ b/src/Python/Vector.hh @@ -38,6 +38,71 @@ Scalar get_item(Vector& _vec, int _index) { return 0.0; } +namespace { +template +struct Factory { + typedef OpenMesh::VectorT Vector2; + typedef OpenMesh::VectorT Vector3; + typedef OpenMesh::VectorT 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 +void defInitMod(class_> &classVector); + +template +void defInitMod(class_> &classVector) { + classVector + .def("__init__", make_constructor(&Factory::vec2_default)) + .def("__init__", make_constructor(&Factory::vec2_user_defined)) + ; + + typedef OpenMesh::VectorT Vector; + def("dot", &Vector::operator|); +} +template +void defInitMod(class_> &classVector) { + classVector + .def("__init__", make_constructor(&Factory::vec3_default)) + .def("__init__", make_constructor(&Factory::vec3_user_defined)) + .def("__mod__", &Factory::Vector3::operator%) + ; + + def("cross", &Factory::Vector3::operator%); + + typedef OpenMesh::VectorT Vector; + def("dot", &Vector::operator|); +} +template +void defInitMod(class_> &classVector) { + classVector + .def("__init__", make_constructor(&Factory::vec4_default)) + .def("__init__", make_constructor(&Factory::vec4_user_defined)) + ; + + typedef OpenMesh::VectorT Vector; + def("dot", &Vector::operator|); +} + /** * Expose a vector type to %Python. * @@ -115,56 +180,7 @@ void expose_vec(const char *_name) { .staticmethod("vectorized") ; - typedef OpenMesh::VectorT Vector2; - typedef OpenMesh::VectorT Vector3; - typedef OpenMesh::VectorT 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(classVector); } } // namespace OpenMesh From 9bac315198c7ba325b104f63187129810e1248ea Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 10:26:45 +0100 Subject: [PATCH 04/33] C++11: Fixed VectorT so it compiles with clang as well. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 179 ++++++++++++------------ 1 file changed, 89 insertions(+), 90 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 8df3fafe..3f3b212d 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -203,11 +204,10 @@ class VectorT { /// component-wise self-multiplication with scalar template - typename std::enable_if() * std::declval()), - Scalar>::value, - VectorT&>::type - operator*=(const OtherScalar& _s) { + auto operator*=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] * _s), Scalar>::value, + VectorT&>::type { std::transform(values_.begin(), values_.end(), values_.begin(), [&_s](const Scalar & c) { return c * _s; }); return *this; @@ -216,23 +216,16 @@ class VectorT { /** component-wise self-division by scalar \attention v *= (1/_s) is much faster than this */ template - typename std::enable_if() / std::declval()), - Scalar>::value, - VectorT&>::type - operator/=(const OtherScalar& _s) { + auto operator/=(const OtherScalar& _s) -> + typename std::enable_ifvalues_[0] / _s), Scalar>::value, + VectorT&>::type { std::transform(values_.begin(), values_.end(), values_.begin(), [&_s](const Scalar & c) { return c / _s; }); return *this; } /// component-wise multiplication with scalar - //template() * - // std::declval())> - //VectorT operator*(const OtherScalar& _s) const { - // return vector_type(*this) *= _s; - //} template typename std::enable_if() * std::declval()), @@ -255,10 +248,12 @@ class VectorT { //---------------------------------------------------------- vector operators /// component-wise self-multiplication - template() * - std::declval())> - vector_type& operator*=(const VectorT& _rhs) { + template + auto operator*=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, + vector_type&>::type { + std::transform(data(), data() + DIM, _rhs.data(), data(), [](const Scalar &l, const OtherScalar &r) { return l * r; }); @@ -266,10 +261,11 @@ class VectorT { } /// component-wise self-division - template() / - std::declval())> - vector_type& operator/=(const VectorT& _rhs) { + template + auto operator/=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, + vector_type&>::type { std::transform(data(), data() + DIM, _rhs.data(), data(), [](const Scalar &l, const OtherScalar &r) { return l / r; }); @@ -277,10 +273,11 @@ class VectorT { } /// vector difference from this - template() - - std::declval())> - vector_type& operator-=(const VectorT& _rhs) { + template + auto operator-=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, + vector_type&>::type { std::transform(data(), data() + DIM, _rhs.data(), data(), [](const Scalar &l, const OtherScalar &r) { return l - r; }); @@ -288,10 +285,11 @@ class VectorT { } /// vector self-addition - template() + - std::declval())> - vector_type& operator+=(const VectorT& _rhs) { + template + auto operator+=(const VectorT& _rhs) -> + typename std::enable_if< + sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, + vector_type&>::type { std::transform(data(), data() + DIM, _rhs.data(), data(), [](const Scalar &l, const OtherScalar &r) { return l + r; }); @@ -299,66 +297,71 @@ class VectorT { } /// component-wise vector multiplication - template() *= - std::declval&>())> - vector_type operator*(const VectorT& _rhs) const { + template + auto operator*(const VectorT& _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() /= - std::declval&>())> - vector_type operator/(const VectorT& _rhs) const { + template + auto operator/(const VectorT& _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() += - std::declval&>())> - vector_type operator+(const VectorT& _rhs) const { + template + auto operator+(const VectorT& _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() -= - std::declval&>())> - vector_type operator-(const VectorT& _rhs) const { + template + auto operator-(const VectorT& _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(v.values_.begin(), v.values_.end(), v.values_.begin(), + 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() * std::declval() - - std::declval() * std::declval())> - typename std::enable_if>::type - operator% (const VectorT &_rhs) const { - return VectorT( - values_[1] * _rhs.values_[2] - values_[2] * _rhs.values_[1], - values_[2] * _rhs.values_[0] - values_[0] * _rhs.values_[2], - values_[0] * _rhs.values_[1] - values_[1] * _rhs.values_[0]); + template + auto operator% (const VectorT &_rhs) const -> + typename std::enable_ifvalues_[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() * std::declval())> - ResultScalar operator|(const VectorT& _rhs) const { - ResultScalar p = values_[0] * _rhs[0]; + template + auto operator|(const VectorT& _rhs) const -> + decltype(this->values_[0] * _rhs[0]) { + + auto p = values_[0] * _rhs[0]; for (int i = 1; i < DIM; ++i) { p += values_[i] * _rhs[i]; } @@ -379,11 +382,11 @@ class VectorT { } /// compute euclidean norm - decltype(std::sqrt(std::declval().sqrnorm())) norm() const { + auto norm() const -> decltype(std::sqrt(this->sqrnorm())) { return std::sqrt(sqrnorm()); } - decltype(std::declval().norm()) length() const { + auto length() const -> decltype(this->norm()) { return norm(); } @@ -396,8 +399,7 @@ class VectorT { /** return normalized vector */ - decltype(std::declval() / std::declval().norm()) - normalized() const { + auto normalized() const -> decltype((*this) / this->norm()) { return *this / norm(); } @@ -575,23 +577,22 @@ class VectorT { values_.begin(), values_.end(), _rhs.values_.begin(), _rhs.values_.end()); } - - public: - /// Component wise multiplication from the left - template - friend - decltype(std::declval().operator*(std::declval())) - operator*(const OtherScalar& _s, const vector_type &rhs) { - return rhs * _s; - } }; +/// Component wise multiplication from the left +template +auto operator*(const OtherScalar& _s, const VectorT &rhs) -> + decltype(rhs.operator*(_s)) { + + return rhs * _s; +} + /// output a vector by printing its space-separated compontens template -typename std::enable_if() << - std::declval())) >= 0, std::ostream&>::type -operator<<(std::ostream& os, const VectorT &_vec) { +auto operator<<(std::ostream& os, const VectorT &_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]; @@ -601,10 +602,9 @@ operator<<(std::ostream& os, const VectorT &_vec) { /// read the space-separated components of a vector from a stream template -typename std::enable_if() >> - std::declval())) >= 0, std::istream&>::type -operator>> (std::istream& is, VectorT &_vec) { +auto operator>> (std::istream& is, VectorT &_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; @@ -613,8 +613,7 @@ operator>> (std::istream& is, VectorT &_vec) { /// \relates OpenMesh::VectorT /// symmetric version of the dot product template -Scalar -dot(const VectorT& _v1, const VectorT& _v2) { +Scalar dot(const VectorT& _v1, const VectorT& _v2) { return (_v1 | _v2); } @@ -622,9 +621,9 @@ dot(const VectorT& _v1, const VectorT& _v2) { /// \relates OpenMesh::VectorT /// symmetric version of the cross product template -decltype(std::declval&>() % - std::declval&>()) -cross(const VectorT& _v1, const VectorT& _v2) { +auto +cross(const VectorT& _v1, const VectorT& _v2) -> + decltype(_v1 % _v2) { return (_v1 % _v2); } From d511f657395af57f504216c936d7f45778da26e7 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 10:27:11 +0100 Subject: [PATCH 05/33] Added some more basic linear algebra unit tests for VectorT. --- src/Unittests/unittests_vector_type.cc | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 82e7793b..1986ce22 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -127,4 +127,31 @@ TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) { } #endif + +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); +} + } From 21cc0acab5ccf6aea1efca8582fdff0384709a98 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 11:09:53 +0100 Subject: [PATCH 06/33] C++11: Explicitly defined default copy/move c'tor and operator=. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 3f3b212d..bdc9db25 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -125,6 +125,11 @@ class VectorT { constexpr VectorT(T... vs) : values_ { {static_cast(vs)...} } {} + 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. From 687da4e08f339f735b56f71c3ba32b831ba18059 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 11:10:28 +0100 Subject: [PATCH 07/33] C++11: Added static_asserts to component-wise constructor. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index bdc9db25..1a5fcf23 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -122,8 +122,12 @@ class VectorT { typename = typename std::enable_if::type, typename = typename std::enable_if< are_convertible_to::value>::type> - constexpr VectorT(T... vs) : values_ { {static_cast(vs)...} } - {} + constexpr VectorT(T... vs) : values_ { {static_cast(vs)...} } { + static_assert(sizeof...(T) == DIM, + "Invalid number of components specified in constructor."); + static_assert(are_convertible_to::value, + "Not all components are convertible to Scalar."); + } VectorT(const VectorT &rhs) = default; VectorT(VectorT &&rhs) = default; From 784adb97449615a11cd8ca451c68448372d59453 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 14:08:42 +0100 Subject: [PATCH 08/33] C++11: Made VectorT::size() and VectorT::dim() constexpr. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 1a5fcf23..796a9e9b 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -95,12 +95,12 @@ class VectorT { typedef VectorT vector_type; /// returns dimension of the vector (deprecated) - static inline int dim() { + static constexpr int dim() { return DIM; } /// returns dimension of the vector - static inline size_t size() { + static constexpr size_t size() { return DIM; } From 07fa145057396151666594bab5ad5952eaa87be9 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 14:09:03 +0100 Subject: [PATCH 09/33] C++11: Fixed VectorT::normalize_cond() implementation. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 15 +++++++++++---- src/Unittests/unittests_vector_type.cc | 9 +++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 796a9e9b..978e5408 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -414,10 +414,17 @@ class VectorT { /** normalize vector, return normalized vector and avoids div by zero */ - vector_type& normalize_cond() { - Scalar n = norm(); - if (n != (Scalar)0.0) - { + template::type> + typename std::enable_if< + sizeof(static_cast(0)) >= 0, + vector_type&>::type + normalize_cond() { + static_assert(sizeof(static_cast(0)) >= 0, + "normalize_cond() only works with Scalar types that can " + "be statically casted from 0."); + auto n = norm(); + if (n != static_cast(0)) { *this /= n; } return *this; diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 1986ce22..ce845091 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -154,4 +154,13 @@ TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) { EXPECT_NEAR(14, OpenMesh::Vec3d(-1, -2, -3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6); } +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 auto r1 = OpenMesh::Vec3d(0.2672612419124244, -0.5345224838248488, 0.8017837257372732) - v1.normalize_cond(); + EXPECT_NEAR(r1[0], 0.0, 1e-6); + EXPECT_NEAR(r1[1], 0.0, 1e-6); + EXPECT_NEAR(r1[2], 0.0, 1e-6); +} + } From 4c36fcfee8c5a40832930da804059d20073b2916 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 14:11:44 +0100 Subject: [PATCH 10/33] Added more unit tests to VectorT. --- src/Unittests/unittests_vector_type.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index ce845091..762998dd 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -158,9 +158,22 @@ 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 auto r1 = OpenMesh::Vec3d(0.2672612419124244, -0.5345224838248488, 0.8017837257372732) - v1.normalize_cond(); - EXPECT_NEAR(r1[0], 0.0, 1e-6); - EXPECT_NEAR(r1[1], 0.0, 1e-6); - EXPECT_NEAR(r1[2], 0.0, 1e-6); + 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()); } } From 580e5526d8ec9ad80cdb278e6e586ae74344f007 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 15:20:41 +0100 Subject: [PATCH 11/33] C++11: VectorT now also accepts non-arithmetic types as Scalar. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 64 ++++++++++++++++++------- src/Unittests/unittests_vector_type.cc | 42 ++++++++++++++++ 2 files changed, 88 insertions(+), 18 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 978e5408..e29f5013 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -138,11 +138,15 @@ class VectorT { * Only for 4-component vectors with division operator on their * Scalar: Dehomogenization. */ - template::type, - typename = decltype(values_[0]/values_[3])> - typename std::enable_if::type - homogenized() const { + template + auto homogenized() const -> + typename std::enable_if()/std::declval()), DIM>>::type { + static_assert(D == DIM, "D and DIM need to be identical. (Never " + "override the default template arguments.)"); + static_assert(std::is_same::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], @@ -383,7 +387,11 @@ class VectorT { //@{ /// compute squared euclidean norm - decltype(values_[0] * values_[0]) sqrnorm() const { + template + decltype(std::declval() * std::declval()) sqrnorm() const { + static_assert(std::is_same::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], @@ -391,38 +399,58 @@ class VectorT { } /// compute euclidean norm - auto norm() const -> decltype(std::sqrt(this->sqrnorm())) { + template + auto norm() const -> + decltype(std::sqrt(std::declval>().sqrnorm())) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return std::sqrt(sqrnorm()); } - auto length() const -> decltype(this->norm()) { + template + auto length() const -> + decltype(std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); return norm(); } /** normalize vector, return normalized vector */ - vector_type& normalize() { - *this /= norm(); - return *this; + template + auto normalize() -> + decltype(*this /= std::declval>().norm()) { + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); + return *this /= norm(); } /** return normalized vector */ - auto normalized() const -> decltype((*this) / this->norm()) { + template + auto normalized() const -> + decltype(*this / std::declval>().norm()) { + static_assert(std::is_same::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::type> + template typename std::enable_if< - sizeof(static_cast(0)) >= 0, + sizeof(decltype( + static_cast(0), + std::declval>().norm())) >= 0, vector_type&>::type normalize_cond() { - static_assert(sizeof(static_cast(0)) >= 0, - "normalize_cond() only works with Scalar types that can " - "be statically casted from 0."); + static_assert(std::is_same::value, "S and Scalar need " + "to be the same type. (Never override the default template " + "arguments.)"); auto n = norm(); if (n != static_cast(0)) { *this /= n; diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 762998dd..a5882431 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -176,4 +176,46 @@ TEST_F(OpenMeshVectorTest, size_dim) { EXPECT_EQ(2, v2i.dim()); } +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 x, y; + x = std::move(y); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(0, C::copy_con); + + // Test move constructing. + OpenMesh::VectorT z(std::move(x)); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(3, C::copy_con); +} + } From 498e4d033f653d6be59a745da1075b5da3b37dd8 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 15:21:00 +0100 Subject: [PATCH 12/33] Purged warnings in unit tests. --- src/Unittests/unittests_cpp_11_features.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Unittests/unittests_cpp_11_features.cc b/src/Unittests/unittests_cpp_11_features.cc index ec3cb64b..72915491 100644 --- a/src/Unittests/unittests_cpp_11_features.cc +++ b/src/Unittests/unittests_cpp_11_features.cc @@ -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 From 54d14e54c395c70d2a95c042c97db0e5401061df Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 15:23:43 +0100 Subject: [PATCH 13/33] Purged another warning in unit tests. --- src/Unittests/unittests_vector_type.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index a5882431..941c0f46 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -115,6 +115,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); From 2899984ed90cbdeb429935da880737d9a40878ad Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 15:42:39 +0100 Subject: [PATCH 14/33] C++11: Fixed OpenMesh Python bindings. --- src/Python/Vector.hh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Python/Vector.hh b/src/Python/Vector.hh index 759a6638..68cfaf94 100644 --- a/src/Python/Vector.hh +++ b/src/Python/Vector.hh @@ -151,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) + .def("length", &Vector::template length) + .def("sqrnorm", &Vector::template sqrnorm) + .def("normalize", &Vector::template normalize, return_internal_reference<>()) + .def("normalized", &Vector::template normalized) + .def("normalize_cond", &Vector::template normalize_cond, return_internal_reference<>()) .def("l1_norm", &Vector::l1_norm) .def("l8_norm", &Vector::l8_norm) From 8d24e6bb67a43733bcd8ed50cfbebcbac993c199 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 16:44:14 +0100 Subject: [PATCH 15/33] C++11: Moved C++11 specific unit test into #ifdef. --- src/Unittests/unittests_vector_type.cc | 88 +++++++++++++------------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 941c0f46..eca9d6ec 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -127,7 +127,51 @@ 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 x, y; + x = std::move(y); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(0, C::copy_con); + + // Test move constructing. + OpenMesh::VectorT z(std::move(x)); + EXPECT_EQ(3, C::copy_ass); + EXPECT_EQ(3, C::copy_con); +} + +#endif // C++11 TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) { @@ -178,46 +222,4 @@ TEST_F(OpenMeshVectorTest, size_dim) { EXPECT_EQ(2, v2i.dim()); } -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 x, y; - x = std::move(y); - EXPECT_EQ(3, C::copy_ass); - EXPECT_EQ(0, C::copy_con); - - // Test move constructing. - OpenMesh::VectorT z(std::move(x)); - EXPECT_EQ(3, C::copy_ass); - EXPECT_EQ(3, C::copy_con); -} - } From c8b5dea2498fbb10e9432e269c30625b84c79917 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 16:56:23 +0100 Subject: [PATCH 16/33] C++11: Made a unit test C++98 compatible. --- src/Unittests/unittests_vector_type.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index eca9d6ec..e6bf0176 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -203,7 +203,11 @@ TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) { 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 auto r1 = OpenMesh::Vec3d(0.2672612419124244, -0.5345224838248488, 0.8017837257372732) - v1.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); From 14dffb83ce3f604097213cce00940371e1fd398c Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 17:31:54 +0100 Subject: [PATCH 17/33] C++11: Made VectorT's constructor from array more general. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 10 +++++++--- src/Unittests/unittests_vector_type.cc | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index e29f5013..4d8792aa 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -81,6 +81,9 @@ namespace OpenMesh { template class VectorT { + + static_assert(DIM >= 1, "VectorT requires positive dimensionality."); + private: std::array values_; @@ -154,9 +157,10 @@ class VectorT { 1); } - /// construct from a value array (explicit) - explicit inline VectorT(const Scalar _values[DIM]) { - std::copy(_values, _values + DIM, values_.begin()); + /// construct from a value array or any other iterator + template + explicit inline VectorT(Iterator it) { + std::copy_n(it, DIM, values_.begin()); } /// copy & cast constructor (explicit) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index e6bf0176..bb27754d 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -1,6 +1,7 @@ #include #include #include +#include namespace { @@ -171,6 +172,15 @@ TEST_F(OpenMeshVectorTest, move_constructor_assignment) { EXPECT_EQ(3, C::copy_con); } +TEST_F(OpenMeshVectorTest, iterator_init) { + std::list 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 @@ -200,6 +210,12 @@ TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) { 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); +} + 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()); From cdfd266cab08b866624123cca7c5b203026854cd Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 17:32:11 +0100 Subject: [PATCH 18/33] C++11: Using std::inner_product for VectorT::operator|. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 4d8792aa..fe0b92b2 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -376,13 +376,10 @@ class VectorT { /// \see OpenMesh::dot template auto operator|(const VectorT& _rhs) const -> - decltype(this->values_[0] * _rhs[0]) { + decltype(*data() * *_rhs.data()) { - auto p = values_[0] * _rhs[0]; - for (int i = 1; i < DIM; ++i) { - p += values_[i] * _rhs[i]; - } - return p; + return std::inner_product(data() + 1, data() + DIM, _rhs.data() + 1, + *data() * *_rhs.data()); } //------------------------------------------------------------ euclidean norm From 61fe9dabefe1169eeb6e09867f3f9adc674e0b6f Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 17:59:37 +0100 Subject: [PATCH 19/33] C++11: Making sure VectorT construction from iterator is only instantiated for actual iterators. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 11 +++++++---- src/Unittests/unittests_vector_type.cc | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index fe0b92b2..b8382bd6 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -158,8 +158,11 @@ class VectorT { } /// construct from a value array or any other iterator - template - explicit inline VectorT(Iterator it) { + template(), void(), + ++std::declval(), void())> + explicit VectorT(Iterator it) { std::copy_n(it, DIM, values_.begin()); } @@ -167,7 +170,7 @@ class VectorT { template::value>> - explicit inline VectorT(const VectorT& _rhs) { + explicit VectorT(const VectorT& _rhs) { operator=(_rhs); } @@ -376,7 +379,7 @@ class VectorT { /// \see OpenMesh::dot template auto operator|(const VectorT& _rhs) const -> - decltype(*data() * *_rhs.data()) { + decltype(*this->data() * *_rhs.data()) { return std::inner_product(data() + 1, data() + DIM, _rhs.data() + 1, *data() * *_rhs.data()); diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index bb27754d..8d6cced1 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -214,6 +214,9 @@ 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) { From 3ed7079cb82f84cf730bf4c1c8a0824bfb3e9198 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 19:53:36 +0100 Subject: [PATCH 20/33] C++11: Laid foundation for benchmark tests. We need more of them! --- CMakeLists.txt | 6 +++++ src/Benchmark/CMakeLists.txt | 11 ++++++++ src/Benchmark/VectorT.cpp | 29 ++++++++++++++++++++ src/Benchmark/VectorT_legacy.cpp | 14 ++++++++++ src/Benchmark/VectorT_new.cpp | 12 +++++++++ src/Benchmark/main.cpp | 10 +++++++ src/OpenMesh/Core/Geometry/VectorT.hh | 2 +- src/OpenMesh/Core/Geometry/VectorT_inc.hh | 33 ----------------------- 8 files changed, 83 insertions(+), 34 deletions(-) create mode 100644 src/Benchmark/CMakeLists.txt create mode 100644 src/Benchmark/VectorT.cpp create mode 100644 src/Benchmark/VectorT_legacy.cpp create mode 100644 src/Benchmark/VectorT_new.cpp create mode 100644 src/Benchmark/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b8eb0f39..08e6fb63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/Benchmark/CMakeLists.txt b/src/Benchmark/CMakeLists.txt new file mode 100644 index 00000000..9332e561 --- /dev/null +++ b/src/Benchmark/CMakeLists.txt @@ -0,0 +1,11 @@ +set (SOURCES "") +list (APPEND SOURCES + main.cpp + VectorT_new.cpp + VectorT_legacy.cpp +) + +add_executable(OMBenchmark ${SOURCES}) +set_target_properties(OMBenchmark PROPERTIES + INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/..") +target_link_libraries(OMBenchmark benchmark OpenMeshCore) \ No newline at end of file diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp new file mode 100644 index 00000000..0d70ab59 --- /dev/null +++ b/src/Benchmark/VectorT.cpp @@ -0,0 +1,29 @@ +/* + * VectorT.cpp + * + * Created on: Nov 19, 2015 + * Author: ebke + */ + +#ifndef BMPREFIX +#error "Do not compile directly." +#endif + +#define ASSEMBLE_(PREFIX, SUFFIX) PREFIX ## SUFFIX +#define ASSEMBLE(PREFIX, SUFFIX) ASSEMBLE_(PREFIX, SUFFIX) +#define MYBENCHMARK(NAME) BENCHMARK(NAME) + +static void ASSEMBLE(BMPREFIX, Vec3f_add_compare)(benchmark::State& state) { + OpenMesh::Vec3f v1(0, 0, 0); + OpenMesh::Vec3f v2(1000, 1000, 1000); + while (state.KeepRunning()) { + v1 += OpenMesh::Vec3f(1.1, 1.2, 1.3); + v2 -= OpenMesh::Vec3f(1.1, 1.2, 1.3); + if (v1 == v2) { + v1 -= v2; + v2 += v1; + } + } +} + +MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3f_add_compare)); diff --git a/src/Benchmark/VectorT_legacy.cpp b/src/Benchmark/VectorT_legacy.cpp new file mode 100644 index 00000000..9d8aa288 --- /dev/null +++ b/src/Benchmark/VectorT_legacy.cpp @@ -0,0 +1,14 @@ +/* + * VectorT_legacy.cpp + * + * Created on: Nov 19, 2015 + * Author: ebke + */ + +#include + +#define OPENMESH_VECTOR_LEGACY +#include + +#define BMPREFIX Legacy_ +#include "VectorT.cpp" diff --git a/src/Benchmark/VectorT_new.cpp b/src/Benchmark/VectorT_new.cpp new file mode 100644 index 00000000..ae303634 --- /dev/null +++ b/src/Benchmark/VectorT_new.cpp @@ -0,0 +1,12 @@ +/* + * VectorT_new.cpp + * + * Created on: Nov 19, 2015 + * Author: ebke + */ + +#include +#include + +#define BMPREFIX CPP11_ +#include "VectorT.cpp" diff --git a/src/Benchmark/main.cpp b/src/Benchmark/main.cpp new file mode 100644 index 00000000..eb0427bb --- /dev/null +++ b/src/Benchmark/main.cpp @@ -0,0 +1,10 @@ +/* + * main.cpp + * + * Created on: Nov 19, 2015 + * Author: ebke + */ + +#include + +BENCHMARK_MAIN(); diff --git a/src/OpenMesh/Core/Geometry/VectorT.hh b/src/OpenMesh/Core/Geometry/VectorT.hh index a582d194..5e2aca6f 100644 --- a/src/OpenMesh/Core/Geometry/VectorT.hh +++ b/src/OpenMesh/Core/Geometry/VectorT.hh @@ -60,7 +60,7 @@ // macro expansion and preprocessor defines // don't work properly. -#if __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__) +#if (__cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY) #include "Vector11T.hh" #else #ifndef DOXYGEN diff --git a/src/OpenMesh/Core/Geometry/VectorT_inc.hh b/src/OpenMesh/Core/Geometry/VectorT_inc.hh index 97bc055f..96b6c100 100644 --- a/src/OpenMesh/Core/Geometry/VectorT_inc.hh +++ b/src/OpenMesh/Core/Geometry/VectorT_inc.hh @@ -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::type, - typename = typename std::enable_if::value>::type> - constexpr VectorT(T... vs) : Base { static_cast(vs)...} - { } - - template::type> - typename std::enable_if::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 From c9d2e4f15f1fc0bd89b52567cc2073fb0ca144fb Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 20:02:50 +0100 Subject: [PATCH 21/33] Added another tiny benchmark. --- src/Benchmark/VectorT.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 0d70ab59..b8330d0a 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -27,3 +27,18 @@ static void ASSEMBLE(BMPREFIX, Vec3f_add_compare)(benchmark::State& state) { } MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3f_add_compare)); + +static void ASSEMBLE(BMPREFIX, Vec3d_add_compare)(benchmark::State& state) { + OpenMesh::Vec3d v1(0, 0, 0); + OpenMesh::Vec3d v2(1000, 1000, 1000); + while (state.KeepRunning()) { + v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); + v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); + if (v1 == v2) { + v1 -= v2; + v2 += v1; + } + } +} + +MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_add_compare)); From 0c093941791f94eb2274933b9004e04599633079 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 20:08:36 +0100 Subject: [PATCH 22/33] Added two more benchmarks. --- src/Benchmark/VectorT.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index b8330d0a..855fe6e2 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -42,3 +42,33 @@ static void ASSEMBLE(BMPREFIX, Vec3d_add_compare)(benchmark::State& state) { } MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_add_compare)); + +static void ASSEMBLE(BMPREFIX, Vec3d_cross_product)(benchmark::State& state) { + OpenMesh::Vec3d v1(0, 0, 0); + OpenMesh::Vec3d v2(1000, 1000, 1000); + while (state.KeepRunning()) { + v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); + v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); + if ((v1 % v2) == (v2 % v1)) { + v1 -= v2; + v2 += v1; + } + } +} + +MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_cross_product)); + +static void ASSEMBLE(BMPREFIX, Vec3d_scalar_product)(benchmark::State& state) { + OpenMesh::Vec3d v1(0, 0, 0); + OpenMesh::Vec3d v2(1000, 1000, 1000); + while (state.KeepRunning()) { + v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); + v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); + if ((v1 | v2) > 0) { + v1 -= v2; + v2 += v1; + } + } +} + +MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_scalar_product)); From 733b6ddadcbf1a04b325e87d679f715219cda832 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 22:46:17 +0100 Subject: [PATCH 23/33] Added more benchmarks and templatized them. --- src/Benchmark/VectorT.cpp | 84 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 855fe6e2..6ee3c143 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -12,63 +12,75 @@ #define ASSEMBLE_(PREFIX, SUFFIX) PREFIX ## SUFFIX #define ASSEMBLE(PREFIX, SUFFIX) ASSEMBLE_(PREFIX, SUFFIX) #define MYBENCHMARK(NAME) BENCHMARK(NAME) +#define MYBENCHMARK_TEMPLATE(NAME, TYPE) BENCHMARK_TEMPLATE(NAME, TYPE) -static void ASSEMBLE(BMPREFIX, Vec3f_add_compare)(benchmark::State& state) { - OpenMesh::Vec3f v1(0, 0, 0); - OpenMesh::Vec3f v2(1000, 1000, 1000); +template +static void ASSEMBLE(BMPREFIX, Vec_add_compare)(benchmark::State& state) { + Vec v1(0, 0, 0); + Vec v2(1000, 1000, 1000); while (state.KeepRunning()) { - v1 += OpenMesh::Vec3f(1.1, 1.2, 1.3); - v2 -= OpenMesh::Vec3f(1.1, 1.2, 1.3); + v1 += Vec(1.1, 1.2, 1.3); + v2 -= Vec(1.1, 1.2, 1.3); if (v1 == v2) { v1 -= v2; v2 += v1; } } + // Just so nothing gets optimized away. + static double dummy; + dummy = v1.norm() + v2.norm(); } -MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3f_add_compare)); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3f); -static void ASSEMBLE(BMPREFIX, Vec3d_add_compare)(benchmark::State& state) { - OpenMesh::Vec3d v1(0, 0, 0); - OpenMesh::Vec3d v2(1000, 1000, 1000); +template +static void ASSEMBLE(BMPREFIX, Vec_cross_product)(benchmark::State& state) { + Vec v1(0, 0, 0); + Vec v2(1000, 1000, 1000); while (state.KeepRunning()) { - v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); - v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); - if (v1 == v2) { - v1 -= v2; - v2 += v1; - } + v1 += Vec(1.1, 1.2, 1.3); + v2 -= Vec(1.1, 1.2, 1.3); + v1 = (v1 % v2); } + // Just so nothing gets optimized away. + static double dummy; + dummy = v1.norm() + v2.norm(); } -MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_add_compare)); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_cross_product), OpenMesh::Vec3d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_cross_product), OpenMesh::Vec3f); -static void ASSEMBLE(BMPREFIX, Vec3d_cross_product)(benchmark::State& state) { - OpenMesh::Vec3d v1(0, 0, 0); - OpenMesh::Vec3d v2(1000, 1000, 1000); +template +static void ASSEMBLE(BMPREFIX, Vec_scalar_product)(benchmark::State& state) { + Vec v1(0, 0, 0); + Vec v2(1000, 1000, 1000); + double acc = 0; while (state.KeepRunning()) { - v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); - v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); - if ((v1 % v2) == (v2 % v1)) { - v1 -= v2; - v2 += v1; - } + v1 += Vec(1.1, 1.2, 1.3); + v2 -= Vec(1.1, 1.2, 1.3); + acc += (v1 | v2); } + // Otherwise GCC will optimize everything away. + static double dummy; + dummy = acc; } -MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_cross_product)); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3f); -static void ASSEMBLE(BMPREFIX, Vec3d_scalar_product)(benchmark::State& state) { - OpenMesh::Vec3d v1(0, 0, 0); - OpenMesh::Vec3d v2(1000, 1000, 1000); +template +static void ASSEMBLE(BMPREFIX, Vec_norm)(benchmark::State& state) { + Vec v1(0, 0, 0); + double acc = 0; while (state.KeepRunning()) { - v1 += OpenMesh::Vec3d(1.1, 1.2, 1.3); - v2 -= OpenMesh::Vec3d(1.1, 1.2, 1.3); - if ((v1 | v2) > 0) { - v1 -= v2; - v2 += v1; - } + v1 += Vec(1.1, 1.2, 1.3); + acc += v1.norm(); } + // Otherwise GCC will optimize everything away. + static double dummy; + dummy = acc; } -MYBENCHMARK (ASSEMBLE(BMPREFIX, Vec3d_scalar_product)); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3f); From fe3dfade1329d259213dc04ee052cccc82622ff4 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 22:58:42 +0100 Subject: [PATCH 24/33] C++11: Made VectorT::size_ constexpr. --- src/OpenMesh/Core/Geometry/Vector11T.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index b8382bd6..785d85bd 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -107,7 +107,7 @@ class VectorT { return DIM; } - static const size_t size_ = DIM; + static constexpr const size_t size_ = DIM; //-------------------------------------------------------------- constructors From dbb4cf4db3e9adf7b761990e8ffd6be55a88fdbd Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 22:58:58 +0100 Subject: [PATCH 25/33] Further templatized benchmarks. Testing Vec4* now as well. --- src/Benchmark/VectorT.cpp | 48 +++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 6ee3c143..aef6cea1 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -14,13 +14,27 @@ #define MYBENCHMARK(NAME) BENCHMARK(NAME) #define MYBENCHMARK_TEMPLATE(NAME, TYPE) BENCHMARK_TEMPLATE(NAME, TYPE) +template +static inline +typename std::enable_if::type +testVec() { + return Vec(1.1, 1.2, 1.3); +} + +template +static inline +typename std::enable_if::type +testVec() { + return Vec(1.1, 1.2, 1.3, 1.4); +} + template static void ASSEMBLE(BMPREFIX, Vec_add_compare)(benchmark::State& state) { - Vec v1(0, 0, 0); - Vec v2(1000, 1000, 1000); + Vec v1(0.0); + Vec v2(1000.0); while (state.KeepRunning()) { - v1 += Vec(1.1, 1.2, 1.3); - v2 -= Vec(1.1, 1.2, 1.3); + v1 += testVec(); + v2 -= testVec(); if (v1 == v2) { v1 -= v2; v2 += v1; @@ -33,14 +47,16 @@ static void ASSEMBLE(BMPREFIX, Vec_add_compare)(benchmark::State& state) { MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3d); MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3f); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec4d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec4f); template static void ASSEMBLE(BMPREFIX, Vec_cross_product)(benchmark::State& state) { - Vec v1(0, 0, 0); - Vec v2(1000, 1000, 1000); + Vec v1(0.0); + Vec v2(1000.0); while (state.KeepRunning()) { - v1 += Vec(1.1, 1.2, 1.3); - v2 -= Vec(1.1, 1.2, 1.3); + v1 += testVec(); + v2 -= testVec(); v1 = (v1 % v2); } // Just so nothing gets optimized away. @@ -53,12 +69,12 @@ MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_cross_product), OpenMesh::Vec3f); template static void ASSEMBLE(BMPREFIX, Vec_scalar_product)(benchmark::State& state) { - Vec v1(0, 0, 0); - Vec v2(1000, 1000, 1000); + Vec v1(0.0); + Vec v2(1000.0); double acc = 0; while (state.KeepRunning()) { - v1 += Vec(1.1, 1.2, 1.3); - v2 -= Vec(1.1, 1.2, 1.3); + v1 += testVec(); + v2 -= testVec(); acc += (v1 | v2); } // Otherwise GCC will optimize everything away. @@ -68,13 +84,15 @@ static void ASSEMBLE(BMPREFIX, Vec_scalar_product)(benchmark::State& state) { MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3d); MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3f); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec4d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec4f); template static void ASSEMBLE(BMPREFIX, Vec_norm)(benchmark::State& state) { - Vec v1(0, 0, 0); + Vec v1(0.0); double acc = 0; while (state.KeepRunning()) { - v1 += Vec(1.1, 1.2, 1.3); + v1 += testVec(); acc += v1.norm(); } // Otherwise GCC will optimize everything away. @@ -84,3 +102,5 @@ static void ASSEMBLE(BMPREFIX, Vec_norm)(benchmark::State& state) { MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3d); MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3f); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec4d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec4f); From 6a43753fed563db89ec0293f064a1dbebe30bfe9 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 23:05:24 +0100 Subject: [PATCH 26/33] Benchmark: Made CPP11/Legacy a postfix for better sortability. --- src/Benchmark/VectorT.cpp | 44 +++++++++++++++++--------------- src/Benchmark/VectorT_legacy.cpp | 2 +- src/Benchmark/VectorT_new.cpp | 2 +- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index aef6cea1..7d385a44 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -5,12 +5,14 @@ * Author: ebke */ -#ifndef BMPREFIX +#ifndef BMPOSTFIX #error "Do not compile directly." #endif -#define ASSEMBLE_(PREFIX, SUFFIX) PREFIX ## SUFFIX -#define ASSEMBLE(PREFIX, SUFFIX) ASSEMBLE_(PREFIX, SUFFIX) +#include + +#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) @@ -29,7 +31,7 @@ testVec() { } template -static void ASSEMBLE(BMPREFIX, Vec_add_compare)(benchmark::State& state) { +static void ASSEMBLE(BMPOSTFIX, Vec_add_compare)(benchmark::State& state) { Vec v1(0.0); Vec v2(1000.0); while (state.KeepRunning()) { @@ -45,13 +47,13 @@ static void ASSEMBLE(BMPREFIX, Vec_add_compare)(benchmark::State& state) { dummy = v1.norm() + v2.norm(); } -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec3f); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec4d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_add_compare), OpenMesh::Vec4f); +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 -static void ASSEMBLE(BMPREFIX, Vec_cross_product)(benchmark::State& state) { +static void ASSEMBLE(BMPOSTFIX, Vec_cross_product)(benchmark::State& state) { Vec v1(0.0); Vec v2(1000.0); while (state.KeepRunning()) { @@ -64,11 +66,11 @@ static void ASSEMBLE(BMPREFIX, Vec_cross_product)(benchmark::State& state) { dummy = v1.norm() + v2.norm(); } -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_cross_product), OpenMesh::Vec3d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_cross_product), OpenMesh::Vec3f); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3d); +MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3f); template -static void ASSEMBLE(BMPREFIX, Vec_scalar_product)(benchmark::State& state) { +static void ASSEMBLE(BMPOSTFIX, Vec_scalar_product)(benchmark::State& state) { Vec v1(0.0); Vec v2(1000.0); double acc = 0; @@ -82,13 +84,13 @@ static void ASSEMBLE(BMPREFIX, Vec_scalar_product)(benchmark::State& state) { dummy = acc; } -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec3f); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec4d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_scalar_product), OpenMesh::Vec4f); +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 -static void ASSEMBLE(BMPREFIX, Vec_norm)(benchmark::State& state) { +static void ASSEMBLE(BMPOSTFIX, Vec_norm)(benchmark::State& state) { Vec v1(0.0); double acc = 0; while (state.KeepRunning()) { @@ -100,7 +102,7 @@ static void ASSEMBLE(BMPREFIX, Vec_norm)(benchmark::State& state) { dummy = acc; } -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec3f); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec4d); -MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPREFIX, Vec_norm), OpenMesh::Vec4f); +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); diff --git a/src/Benchmark/VectorT_legacy.cpp b/src/Benchmark/VectorT_legacy.cpp index 9d8aa288..8063fa44 100644 --- a/src/Benchmark/VectorT_legacy.cpp +++ b/src/Benchmark/VectorT_legacy.cpp @@ -10,5 +10,5 @@ #define OPENMESH_VECTOR_LEGACY #include -#define BMPREFIX Legacy_ +#define BMPOSTFIX _Legacy #include "VectorT.cpp" diff --git a/src/Benchmark/VectorT_new.cpp b/src/Benchmark/VectorT_new.cpp index ae303634..ff3e7093 100644 --- a/src/Benchmark/VectorT_new.cpp +++ b/src/Benchmark/VectorT_new.cpp @@ -8,5 +8,5 @@ #include #include -#define BMPREFIX CPP11_ +#define BMPOSTFIX _CPP11 #include "VectorT.cpp" From fab8a9cf61a059ee02ddf6e991f526d34e34b2a5 Mon Sep 17 00:00:00 2001 From: Hans-Christian Ebke Date: Thu, 19 Nov 2015 23:23:56 +0100 Subject: [PATCH 27/33] Added another benchmark. --- src/Benchmark/VectorT.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 7d385a44..87c00454 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -106,3 +106,21 @@ 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 +static void ASSEMBLE(BMPOSTFIX, Vec_times_scalar)(benchmark::State& state) { + Vec v1(0.0); + while (state.KeepRunning()) { + v1 += testVec(); + v1 *= static_cast(1.0)/v1[0]; + v1 *= v1[1]; + } + // Otherwise GCC will optimize everything away. + static double dummy; + dummy = v1.norm(); +} + +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); From 37fc29b59b49eca1a420e8e35d3de6294c6b34d2 Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 09:37:08 +0100 Subject: [PATCH 28/33] add begin / end iterators for Vector11T component access --- src/OpenMesh/Core/Geometry/Vector11T.hh | 31 ++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 785d85bd..214d004b 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -85,7 +85,8 @@ class VectorT { static_assert(DIM >= 1, "VectorT requires positive dimensionality."); private: - std::array values_; + using container = std::array; + container values_; public: @@ -625,6 +626,34 @@ class VectorT { 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 From 8ce8d00bf311533576ca1fd5911515603d5f9b2c Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 09:49:36 +0100 Subject: [PATCH 29/33] suppress 'unused variable' warnings for benchmark dummy variables --- src/Benchmark/VectorT.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 87c00454..348915b5 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -45,6 +45,7 @@ static void ASSEMBLE(BMPOSTFIX, Vec_add_compare)(benchmark::State& state) { // Just so nothing gets optimized away. static double dummy; dummy = v1.norm() + v2.norm(); + static_cast(dummy); } MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_add_compare), OpenMesh::Vec3d); @@ -64,6 +65,7 @@ static void ASSEMBLE(BMPOSTFIX, Vec_cross_product)(benchmark::State& state) { // Just so nothing gets optimized away. static double dummy; dummy = v1.norm() + v2.norm(); + static_cast(dummy); } MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_cross_product), OpenMesh::Vec3d); @@ -82,6 +84,7 @@ static void ASSEMBLE(BMPOSTFIX, Vec_scalar_product)(benchmark::State& state) { // Otherwise GCC will optimize everything away. static double dummy; dummy = acc; + static_cast(dummy); } MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_scalar_product), OpenMesh::Vec3d); @@ -100,6 +103,7 @@ static void ASSEMBLE(BMPOSTFIX, Vec_norm)(benchmark::State& state) { // Otherwise GCC will optimize everything away. static double dummy; dummy = acc; + static_cast(dummy); } MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_norm), OpenMesh::Vec3d); @@ -118,6 +122,7 @@ static void ASSEMBLE(BMPOSTFIX, Vec_times_scalar)(benchmark::State& state) { // Otherwise GCC will optimize everything away. static double dummy; dummy = v1.norm(); + static_cast(dummy); } MYBENCHMARK_TEMPLATE (ASSEMBLE(BMPOSTFIX, Vec_times_scalar), OpenMesh::Vec3d); From 797e83f2c00291c1edf7026a77d56d0801a6a76a Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 11:38:33 +0100 Subject: [PATCH 30/33] add benchmarks for non-fundamental Scalar types for VectorT --- src/Benchmark/CMakeLists.txt | 1 + src/Benchmark/VectorT.cpp | 32 ++++++++++++++++++++++ src/Benchmark/VectorT_dummy_data.cpp | 5 ++++ src/Benchmark/VectorT_dummy_data.hpp | 40 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 src/Benchmark/VectorT_dummy_data.cpp create mode 100644 src/Benchmark/VectorT_dummy_data.hpp diff --git a/src/Benchmark/CMakeLists.txt b/src/Benchmark/CMakeLists.txt index 9332e561..59ae3c00 100644 --- a/src/Benchmark/CMakeLists.txt +++ b/src/Benchmark/CMakeLists.txt @@ -3,6 +3,7 @@ list (APPEND SOURCES main.cpp VectorT_new.cpp VectorT_legacy.cpp + VectorT_dummy_data.cpp ) add_executable(OMBenchmark ${SOURCES}) diff --git a/src/Benchmark/VectorT.cpp b/src/Benchmark/VectorT.cpp index 348915b5..54989d54 100644 --- a/src/Benchmark/VectorT.cpp +++ b/src/Benchmark/VectorT.cpp @@ -129,3 +129,35 @@ 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 +static void ASSEMBLE(BMPOSTFIX, Vec_add_in_place)(benchmark::State& state) { + auto v = make_dummy_vector(); + while (state.KeepRunning()) { + v += v; + } + // Otherwise GCC will optimize everything away. + static double dummy = observe_dummy_vector(v); + static_cast(dummy); +} + +template +static void ASSEMBLE(BMPOSTFIX, Vec_add_temporary)(benchmark::State& state) { + auto v = make_dummy_vector(); + while (state.KeepRunning()) { + v = v + v; + } + // Otherwise GCC will optimize everything away. + static double dummy = observe_dummy_vector(v); + static_cast(dummy); +} + +typedef OpenMesh::VectorT, 3> Vec3VAd; +typedef OpenMesh::VectorT, 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); diff --git a/src/Benchmark/VectorT_dummy_data.cpp b/src/Benchmark/VectorT_dummy_data.cpp new file mode 100644 index 00000000..cb2ca113 --- /dev/null +++ b/src/Benchmark/VectorT_dummy_data.cpp @@ -0,0 +1,5 @@ +#include "VectorT_dummy_data.hpp" + +template<> std::valarray make_dummy_component() { + return std::valarray(128); +} diff --git a/src/Benchmark/VectorT_dummy_data.hpp b/src/Benchmark/VectorT_dummy_data.hpp new file mode 100644 index 00000000..62211c9d --- /dev/null +++ b/src/Benchmark/VectorT_dummy_data.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +template +T make_dummy_component() { + return T(); +} + +template<> std::valarray make_dummy_component(); + +template +Vec make_dummy_vector() { + return Vec(make_dummy_component()); +} + +template +double observe_dummy_component(const Scalar& _s) { + return _s; +} + +template +double observe_dummy_component(const std::valarray& _s) { + return _s.sum(); +} + +template +double observe_dummy_component(const std::complex& _s) { + return _s.real() + _s.imag(); +} + +template +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; +} From 4e9330a87d54e066438c460e20fb9eb2a76d2f78 Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 12:22:11 +0100 Subject: [PATCH 31/33] add unit tests for basic vector arithmetic --- src/Unittests/unittests_vector_type.cc | 78 ++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/Unittests/unittests_vector_type.cc b/src/Unittests/unittests_vector_type.cc index 8d6cced1..8ca929ca 100644 --- a/src/Unittests/unittests_vector_type.cc +++ b/src/Unittests/unittests_vector_type.cc @@ -184,6 +184,84 @@ TEST_F(OpenMeshVectorTest, iterator_init) { #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); From cf54f40e3e1d931125545f8ee6e8a1a70ed887d9 Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 12:25:07 +0100 Subject: [PATCH 32/33] implement VectorT in-place arithmetic operators based on Scalar in-place arithmetic operators --- src/OpenMesh/Core/Geometry/Vector11T.hh | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/OpenMesh/Core/Geometry/Vector11T.hh b/src/OpenMesh/Core/Geometry/Vector11T.hh index 214d004b..eefac1fb 100644 --- a/src/OpenMesh/Core/Geometry/Vector11T.hh +++ b/src/OpenMesh/Core/Geometry/Vector11T.hh @@ -229,20 +229,21 @@ class VectorT { typename std::enable_ifvalues_[0] * _s), Scalar>::value, VectorT&>::type { - std::transform(values_.begin(), values_.end(), values_.begin(), - [&_s](const Scalar & c) { return c * _s; }); + for (auto& e : *this) { + e *= _s; + } return *this; } - /** component-wise self-division by scalar - \attention v *= (1/_s) is much faster than this */ + /// component-wise self-division by scalar template auto operator/=(const OtherScalar& _s) -> typename std::enable_ifvalues_[0] / _s), Scalar>::value, VectorT&>::type { - std::transform(values_.begin(), values_.end(), values_.begin(), - [&_s](const Scalar & c) { return c / _s; }); + for (auto& e : *this) { + e /= _s; + } return *this; } @@ -274,10 +275,9 @@ class VectorT { typename std::enable_if< sizeof(decltype(this->values_[0] * *_rhs.data())) >= 0, vector_type&>::type { - - std::transform(data(), data() + DIM, - _rhs.data(), data(), - [](const Scalar &l, const OtherScalar &r) { return l * r; }); + for (int i = 0; i < DIM; ++i) { + data()[i] *= _rhs.data()[i]; + } return *this; } @@ -287,9 +287,9 @@ class VectorT { typename std::enable_if< sizeof(decltype(this->values_[0] / *_rhs.data())) >= 0, vector_type&>::type { - std::transform(data(), data() + DIM, - _rhs.data(), data(), - [](const Scalar &l, const OtherScalar &r) { return l / r; }); + for (int i = 0; i < DIM; ++i) { + data()[i] /= _rhs.data()[i]; + } return *this; } @@ -299,9 +299,9 @@ class VectorT { typename std::enable_if< sizeof(decltype(this->values_[0] - *_rhs.data())) >= 0, vector_type&>::type { - std::transform(data(), data() + DIM, - _rhs.data(), data(), - [](const Scalar &l, const OtherScalar &r) { return l - r; }); + for (int i = 0; i < DIM; ++i) { + data()[i] -= _rhs.data()[i]; + } return *this; } @@ -311,9 +311,9 @@ class VectorT { typename std::enable_if< sizeof(decltype(this->values_[0] + *_rhs.data())) >= 0, vector_type&>::type { - std::transform(data(), data() + DIM, - _rhs.data(), data(), - [](const Scalar &l, const OtherScalar &r) { return l + r; }); + for (int i = 0; i < DIM; ++i) { + data()[i] += _rhs.data()[i]; + } return *this; } From de46a56b75e98ae7962d1d87d375bca70389cb3f Mon Sep 17 00:00:00 2001 From: Janis Born Date: Mon, 23 Nov 2015 12:30:16 +0100 Subject: [PATCH 33/33] add .gitignore entries for junk files generated by running unit tests --- .gitignore | 1 + src/Unittests/.gitignore | 7 +++++++ src/Unittests/TestFiles/.gitignore | 6 ++++++ 3 files changed, 14 insertions(+) create mode 100644 src/Unittests/.gitignore create mode 100644 src/Unittests/TestFiles/.gitignore diff --git a/.gitignore b/.gitignore index 3a4edf69..65b3b7ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .project +CMakeLists.txt.user diff --git a/src/Unittests/.gitignore b/src/Unittests/.gitignore new file mode 100644 index 00000000..868a01f9 --- /dev/null +++ b/src/Unittests/.gitignore @@ -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 diff --git a/src/Unittests/TestFiles/.gitignore b/src/Unittests/TestFiles/.gitignore new file mode 100644 index 00000000..4f6adcfd --- /dev/null +++ b/src/Unittests/TestFiles/.gitignore @@ -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