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; } }