Browse Source

Math: disable floating-point vector ops on integral types.

Avoids accidents.
pull/272/head
Vladimír Vondruš 8 years ago
parent
commit
04f4917f7b
  1. 6
      doc/changelog.dox
  2. 74
      src/Magnum/Math/Vector.h
  3. 10
      src/Magnum/Math/Vector2.h

6
doc/changelog.dox

@ -140,6 +140,12 @@ See also:
- @ref Math::Matrix3::rotation() const and @ref Math::Matrix4::rotation() const
now allow non-uniform scaling, but expect the roation/scaling part to be
orthogonal after normalization
- @ref Math::angle(), @ref Math::Vector::lengthInverted(),
@ref Math::Vector::normalized(), @ref Math::Vector::resized(),
@ref Math::Vector::projected(), @ref Math::Vector::projectedOntoNormalized()
and @ref Math::Vector2::aspectRatio() are now enabled only for
floating-point types to avoid errors when using these functions
accidentally on integral vectors
@subsubsection changelog-latest-changes-meshtools MeshTools library

74
src/Magnum/Math/Vector.h

@ -84,17 +84,24 @@ template<std::size_t size, class T> inline T dot(const Vector<size, T>& a, const
/** @relatesalso Vector
@brief Angle between normalized vectors
Expects that both vectors are normalized. @f[
Expects that both vectors are normalized. Enabled only for floating-point
types. @f[
\theta = acos \left( \frac{\boldsymbol a \cdot \boldsymbol b}{|\boldsymbol a| |\boldsymbol b|} \right) = acos (\boldsymbol a \cdot \boldsymbol b)
@f]
@see @ref Vector::isNormalized(),
@ref angle(const Complex<T>&, const Complex<T>&),
@ref angle(const Quaternion<T>&, const Quaternion<T>&)
*/
template<std::size_t size, class T> inline Rad<T> angle(const Vector<size, T>& normalizedA, const Vector<size, T>& normalizedB) {
template<std::size_t size, class FloatingPoint> inline
#ifdef DOXYGEN_GENERATING_OUTPUT
Rad<FloatingPoint>
#else
typename std::enable_if<std::is_floating_point<FloatingPoint>::value, Rad<FloatingPoint>>::type
#endif
angle(const Vector<size, FloatingPoint>& normalizedA, const Vector<size, FloatingPoint>& normalizedB) {
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
"Math::angle(): vectors must be normalized", {});
return Rad<T>(std::acos(dot(normalizedA, normalizedB)));
return Rad<FloatingPoint>(std::acos(dot(normalizedA, normalizedB)));
}
/**
@ -468,28 +475,39 @@ template<std::size_t size, class T> class Vector {
/**
* @brief Inverse vector length
*
* @f[
* Enabled only for floating-point types. @f[
* \frac{1}{|\boldsymbol a|} = \frac{1}{\sqrt{\boldsymbol a \cdot \boldsymbol a}}
* @f]
* @see @ref length(), @ref Math::sqrtInverted(), @ref normalized(),
* @ref resized()
*/
T lengthInverted() const { return T(1)/length(); }
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
#endif
lengthInverted() const { return T(1)/length(); }
/**
* @brief Normalized vector (of unit length)
*
* Enabled only for floating-point types.
* @see @ref isNormalized(), @ref lengthInverted(), @ref resized()
* @m_keyword{normalize(),GLSL normalize(),}
*/
Vector<size, T> normalized() const { return *this*lengthInverted(); }
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
normalized() const { return *this*lengthInverted(); }
/**
* @brief Resized vector
*
* Convenience equivalent to the following code. Due to operation order
* this function is faster than the obvious way of sizing
* @ref normalized() vector.
* a @ref normalized() vector. Enabled only for floating-point types.
*
* @code{.cpp}
* vec*(vec.lengthInverted()*length) // the parentheses are important
@ -497,19 +515,30 @@ template<std::size_t size, class T> class Vector {
*
* @see @ref normalized()
*/
Vector<size, T> resized(T length) const {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
resized(T length) const {
return *this*(lengthInverted()*length);
}
/**
* @brief Vector projected onto line
*
* Returns vector projected onto @p line. @f[
* Returns a vector projected onto @p line. Enabled only for
* floating-point types. @f[
* \operatorname{proj}_{\boldsymbol{b}}\,(\boldsymbol{a}) = \frac{\boldsymbol a \cdot \boldsymbol b}{\boldsymbol b \cdot \boldsymbol b} \boldsymbol b
* @f]
* @see @ref Math::dot(), @ref projectedOntoNormalized()
*/
Vector<size, T> projected(const Vector<size, T>& line) const {
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
projected(const Vector<size, T>& line) const {
return line*Math::dot(*this, line)/line.dot();
}
@ -517,13 +546,18 @@ template<std::size_t size, class T> class Vector {
* @brief Vector projected onto normalized line
*
* Slightly faster alternative to @ref projected(), expects @p line to
* be normalized. @f[
* be normalized. Enabled only for floating-point types. @f[
* \operatorname{proj}_{\boldsymbol{b}}\,(\boldsymbol{a}) = \frac{\boldsymbol a \cdot \boldsymbol b}{\boldsymbol b \cdot \boldsymbol b} \boldsymbol b =
* (\boldsymbol a \cdot \boldsymbol b) \boldsymbol b
* @f]
* @see @ref Math::dot()
*/
Vector<size, T> projectedOntoNormalized(const Vector<size, T>& line) const;
#ifdef DOXYGEN_GENERATING_OUTPUT
Vector<size, T>
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
projectedOntoNormalized(const Vector<size, T>& line) const;
/**
* @brief Flipped vector
@ -1159,16 +1193,16 @@ extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utili
return Math::Vector<size, T>::operator/(other); \
} \
\
Type<T> normalized() const { \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type normalized() const { \
return Math::Vector<size, T>::normalized(); \
} \
Type<T> resized(T length) const { \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type resized(T length) const { \
return Math::Vector<size, T>::resized(length); \
} \
Type<T> projected(const Math::Vector<size, T>& other) const { \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projected(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projected(other); \
} \
Type<T> projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, Type<T>>::type projectedOntoNormalized(const Math::Vector<size, T>& other) const { \
return Math::Vector<size, T>::projectedOntoNormalized(other); \
} \
constexpr Type<T> flipped() const { \
@ -1318,7 +1352,13 @@ template<std::size_t size, class T> inline Vector<size, T> Vector<size, T>::oper
return out;
}
template<std::size_t size, class T> inline Vector<size, T> Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
template<std::size_t size, class T>
#ifdef DOXYGEN_GENERATING_OUTPUT
inline Vector<size, T>
#else
template<class U> inline typename std::enable_if<std::is_floating_point<U>::value, Vector<size, T>>::type
#endif
Vector<size, T>::projectedOntoNormalized(const Vector<size, T>& line) const {
CORRADE_ASSERT(line.isNormalized(), "Math::Vector::projectedOntoNormalized(): line must be normalized", {});
return line*Math::dot(*this, line);
}

10
src/Magnum/Math/Vector2.h

@ -168,11 +168,17 @@ template<class T> class Vector2: public Vector<2, T> {
/**
* @brief Aspect ratio
*
* Returns quotient of the two elements. @f[
* Returns quotient of the two elements. Enabled only for
* floating-point types. @f[
* a = \frac{v_x}{v_y}
* @f]
*/
T aspectRatio() const { return x()/y(); }
#ifdef DOXYGEN_GENERATING_OUTPUT
T
#else
template<class U = T> typename std::enable_if<std::is_floating_point<U>::value, T>::type
#endif
aspectRatio() const { return x()/y(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(2, Vector2)
};

Loading…
Cancel
Save