mirror of https://github.com/mosra/magnum.git
12 changed files with 1416 additions and 12 deletions
@ -0,0 +1,422 @@
|
||||
#ifndef Magnum_Math_CubicHermiteSpline_h |
||||
#define Magnum_Math_CubicHermiteSpline_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Class @ref Magnum::Math::CubicHermite, alias @ref Magnum::Math::CubicHermite2D, @ref Magnum::Math::CubicHermite3D, function @ref Magnum::Math::select(), @ref Magnum::Math::lerp(), @ref Magnum::Math::splerp() |
||||
*/ |
||||
|
||||
#include "Magnum/Math/Complex.h" |
||||
#include "Magnum/Math/Quaternion.h" |
||||
|
||||
namespace Magnum { namespace Math { |
||||
|
||||
/**
|
||||
@brief Cubic Hermite spline point |
||||
|
||||
Represents a point on a [cubic Hermite spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline).
|
||||
|
||||
Unlike @ref Bezier, which describes a curve segment, this structure describes |
||||
a spline point @f$ \boldsymbol{p} @f$, with in-tangent @f$ \boldsymbol{m} @f$ |
||||
and out-tangent @f$ \boldsymbol{n} @f$. This form is more suitable for |
||||
animation keyframe representation. The structure assumes the in/out tangents |
||||
to be in their final form, i.e. already normalized by length of their adjacent |
||||
segments. |
||||
|
||||
@see @ref CubicHermite2D, @ref CubicHermite3D, |
||||
@ref Magnum::CubicHermite2D, @ref Magnum::CubicHermite2Dd, |
||||
@ref Magnum::CubicHermite3D, @ref Magnum::CubicHermite3Dd, |
||||
@ref CubicBezier |
||||
@experimental |
||||
*/ |
||||
template<class T> class CubicHermite { |
||||
public: |
||||
typedef T Type; /**< @brief Underlying data type */ |
||||
|
||||
/**
|
||||
* @brief Default constructor |
||||
* |
||||
* Equivalent to @ref CubicHermite(ZeroInitT) for vector types and to |
||||
* @ref CubicHermite(IdentityInitT) for complex and quaternion types. |
||||
*/ |
||||
constexpr /*implicit*/ CubicHermite() noexcept: CubicHermite{typename std::conditional<std::is_constructible<T, IdentityInitT>::value, IdentityInitT, ZeroInitT>::type{typename std::conditional<std::is_constructible<T, IdentityInitT>::value, IdentityInitT, ZeroInitT>::type::Init{}}} {} |
||||
|
||||
/**
|
||||
* @brief Default constructor |
||||
* |
||||
* Construct cubic Hermite spline point with all control points being |
||||
* zero. |
||||
*/ |
||||
constexpr explicit CubicHermite(ZeroInitT) noexcept: CubicHermite{ZeroInit, typename std::conditional<std::is_constructible<T, ZeroInitT>::value, ZeroInitT*, void*>::type{}} {} |
||||
|
||||
/**
|
||||
* @brief Identity constructor |
||||
* |
||||
* The @ref point() is constructed as identity in order to have |
||||
* interpolation working correctly; @ref inTangent() and |
||||
* @ref outTangent() is constructed as zero. Enabled only for complex |
||||
* and quaternion types. |
||||
*/ |
||||
template<class U = T, class = typename std::enable_if<std::is_constructible<U, IdentityInitT>::value>::type> constexpr explicit CubicHermite(IdentityInitT) noexcept: _inTangent{ZeroInit}, _point{IdentityInit}, _outTangent{ZeroInit} {} |
||||
|
||||
/** @brief Construct cubic Hermite spline point without initializing its contents */ |
||||
explicit CubicHermite(NoInitT) noexcept: CubicHermite{NoInit, typename std::conditional<std::is_constructible<T, NoInitT>::value, NoInitT*, void*>::type{}} {} |
||||
|
||||
/**
|
||||
* @brief Construct cubic Hermite spline point with given control points |
||||
* @param inTangent In-tangent @f$ \boldsymbol{m} @f$ |
||||
* @param point Point @f$ \boldsymbol{p} @f$ |
||||
* @param outTangent Out-tangent @f$ \boldsymbol{n} @f$ |
||||
*/ |
||||
constexpr /*implicit*/ CubicHermite(const T& inTangent, const T& point, const T& outTangent) noexcept: _inTangent{inTangent}, _point{point}, _outTangent{outTangent} {} |
||||
|
||||
/**
|
||||
* @brief Construct subic Hermite spline point from another of different type |
||||
* |
||||
* Performs only default casting on the values, no rounding or |
||||
* anything else. |
||||
*/ |
||||
template<class U> constexpr explicit CubicHermite(const CubicHermite<U>& other) noexcept: _inTangent{T(other._inTangent)}, _point{T(other._point)}, _outTangent{T(other._outTangent)} {} |
||||
|
||||
/** @brief Equality comparison */ |
||||
bool operator==(const CubicHermite<T>& other) const; |
||||
|
||||
/** @brief Non-equality comparison */ |
||||
bool operator!=(const CubicHermite<T>& other) const { |
||||
return !operator==(other); |
||||
} |
||||
|
||||
/** @brief In-tangent @f$ \boldsymbol{m} @f$ */ |
||||
T& inTangent() { return _inTangent; } |
||||
/* returns const& so [] operations are also constexpr */ |
||||
constexpr const T& inTangent() const { return _inTangent; } /**< @overload */ |
||||
|
||||
/** @brief Point @f$ \boldsymbol{p} @f$ */ |
||||
T& point() { return _point; } |
||||
/* returns const& so [] operations are also constexpr */ |
||||
constexpr const T& point() const { return _point; } /**< @overload */ |
||||
|
||||
/** @brief Out-tangent @f$ \boldsymbol{n} @f$ */ |
||||
T& outTangent() { return _outTangent; } |
||||
/* returns const& so [] operations are also constexpr */ |
||||
constexpr const T& outTangent() const { return _outTangent; } /**< @overload */ |
||||
|
||||
private: |
||||
template<class> friend class CubicHermite; |
||||
|
||||
/* Called from CubicHermite(ZeroInit), either using the ZeroInit
|
||||
constructor (if available) or passing zero directly (for scalar |
||||
types) */ |
||||
constexpr explicit CubicHermite(ZeroInitT, ZeroInitT*) noexcept: _inTangent{ZeroInit}, _point{ZeroInit}, _outTangent{ZeroInit} {} |
||||
constexpr explicit CubicHermite(ZeroInitT, void*) noexcept: _inTangent{T(0)}, _point{T(0)}, _outTangent{T(0)} {} |
||||
|
||||
/* Called from CubicHermite(NoInit), either using the NoInit
|
||||
constructor (if available) or not doing oanything */ |
||||
explicit CubicHermite(NoInitT, NoInitT*) noexcept: _inTangent{NoInit}, _point{NoInit}, _outTangent{NoInit} {} |
||||
explicit CubicHermite(NoInitT, void*) noexcept {} |
||||
|
||||
T _inTangent; |
||||
T _point; |
||||
T _outTangent; |
||||
}; |
||||
|
||||
/**
|
||||
@brief Scalar cubic Hermite spline point |
||||
|
||||
Convenience alternative to @cpp CubicHermite<T> @ce. See @ref CubicHermite for |
||||
more information. |
||||
@see @ref CubicHermite2D, @ref CubicHermite3D, @ref CubicHermiteComplex, |
||||
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite1D, |
||||
@ref Magnum::CubicHermite1Dd |
||||
*/ |
||||
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */ |
||||
template<class T> using CubicHermite1D = CubicHermite<T>; |
||||
#endif |
||||
|
||||
/**
|
||||
@brief Two-dimensional cubic Hermite spline point |
||||
|
||||
Convenience alternative to @cpp CubicHermite<Vector2<T>> @ce. See |
||||
@ref CubicHermite for more information. |
||||
@see @ref CubicHermite1D, @ref CubicHermite3D, @ref CubicHermiteComplex, |
||||
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite2D, |
||||
@ref Magnum::CubicHermite2Dd |
||||
*/ |
||||
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */ |
||||
template<class T> using CubicHermite2D = CubicHermite<Vector2<T>>; |
||||
#endif |
||||
|
||||
/**
|
||||
@brief Three-dimensional cubic Hermite spline point |
||||
|
||||
Convenience alternative to @cpp CubicHermite<Vector2<T>> @ce. See |
||||
@ref CubicHermite for more information. |
||||
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermiteComplex, |
||||
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermite3D, |
||||
@ref Magnum::CubicHermite3Dd |
||||
*/ |
||||
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */ |
||||
template<class T> using CubicHermite3D = CubicHermite<Vector3<T>>; |
||||
#endif |
||||
|
||||
/**
|
||||
@brief Cubic Hermite spline complex number |
||||
|
||||
Convenience alternative to @cpp CubicHermite<Complex<T>> @ce. See |
||||
@ref CubicHermite for more information. |
||||
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermite3D, |
||||
@ref CubicHermiteQuaternion, @ref Magnum::CubicHermiteComplex, |
||||
@ref Magnum::CubicHermiteComplexd |
||||
*/ |
||||
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */ |
||||
template<class T> using CubicHermiteComplex = CubicHermite<Complex<T>>; |
||||
#endif |
||||
|
||||
/**
|
||||
@brief Cubic Hermite spline quaternion |
||||
|
||||
Convenience alternative to @cpp CubicHermite<Quaternion<T>> @ce. See |
||||
@ref CubicHermite for more information. |
||||
@see @ref CubicHermite1D, @ref CubicHermite2D, @ref CubicHermite3D, |
||||
@ref CubicHermiteComplex, @ref Magnum::CubicHermiteQuaternion, |
||||
@ref Magnum::CubicHermiteQuaterniond |
||||
*/ |
||||
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */ |
||||
template<class T> using CubicHermiteQuaternion = CubicHermite<Quaternion<T>>; |
||||
#endif |
||||
|
||||
/** @debugoperator{CubicHermite} */ |
||||
template<class T> Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const CubicHermite<T>& value) { |
||||
return debug << "CubicHermite(" << Corrade::Utility::Debug::nospace |
||||
<< value.inTangent() << Corrade::Utility::Debug::nospace << "," |
||||
<< value.point() << Corrade::Utility::Debug::nospace << "," |
||||
<< value.outTangent() << Corrade::Utility::Debug::nospace << ")"; |
||||
} |
||||
|
||||
/* Explicit instantiation for commonly used types */ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Float>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Double>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector2<Float>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector3<Float>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector4<Float>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector2<Double>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector3<Double>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Vector4<Double>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Complex<Float>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Complex<Double>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Quaternion<Float>>&); |
||||
extern template MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug&, const CubicHermite<Quaternion<Double>>&); |
||||
#endif |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Constant interpolation of two cubic Hermite spline points |
||||
@param a First value |
||||
@param b Second value |
||||
@param t Interpolation phase |
||||
|
||||
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$ |
||||
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$ |
||||
at phase @f$ t @f$ is: @f[ |
||||
\boldsymbol{p}(t) = \begin{cases} |
||||
\boldsymbol{p}_a, & t < 1 \\
|
||||
\boldsymbol{p}_b, & t \ge 1 |
||||
\end{cases} |
||||
@f] |
||||
|
||||
Equivalent to calling @ref select(const T&, const T&, U) on |
||||
@ref CubicHermite::point() extracted from both @p a and @p b. |
||||
@see @ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) |
||||
*/ |
||||
template<class T, class U> T select(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) { |
||||
/* Not using select() from Functions.h to avoid the header dependency */ |
||||
return t < U(1) ? a.point() : b.point(); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Linear interpolation of two cubic Hermite points |
||||
@param a First spline point |
||||
@param b Second spline point |
||||
@param t Interpolation phase |
||||
|
||||
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$ |
||||
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$ |
||||
at phase @f$ t @f$ is: @f[ |
||||
\boldsymbol{p}(t) = (1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b |
||||
@f] |
||||
|
||||
Equivalent to calling @ref lerp(const T&, const T&, U) on |
||||
@ref CubicHermite::point() extracted from both @p a and @p b. |
||||
@see @ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
||||
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
||||
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
||||
*/ |
||||
template<class T, class U> T lerp(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) { |
||||
/* To avoid dependency on Functions.h */ |
||||
return Implementation::lerp(a.point(), b.point(), t); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Linear interpolation of two cubic Hermite complex numbers |
||||
|
||||
Unlike @ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds |
||||
a normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$, |
||||
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$, |
||||
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[ |
||||
\boldsymbol{p}(t) = \frac{(1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b}{|(1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b|} |
||||
@f] |
||||
|
||||
Equivalent to calling @ref lerp(const Complex<T>&, const Complex<T>&, T) on |
||||
@ref CubicHermite::point() extracted from @p a and @p b. Expects that |
||||
@ref CubicHermite::point() is a normalized complex number in both @p a and @p b. |
||||
@see @ref Complex::isNormalized(), |
||||
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) |
||||
*/ |
||||
template<class T> Complex<T> lerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) { |
||||
return lerp(a.point(), b.point(), t); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Linear interpolation of two cubic Hermite quaternions |
||||
|
||||
Unlike @ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds a |
||||
normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$, |
||||
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$, |
||||
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[ |
||||
\boldsymbol{p}(t) = \frac{(1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b}{|(1 - t) \boldsymbol{p}_a + t \boldsymbol{p}_b|} |
||||
@f] |
||||
|
||||
Equivalent to calling @ref lerp(const Quaternion<T>&, const Quaternion<T>&, T) |
||||
on @ref CubicHermite::point() extracted from @p a and @p b. Expects that |
||||
@ref CubicHermite::point() is a normalized quaternion in both @p a and @p b. |
||||
@see @ref Quaternion::isNormalized(), |
||||
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
||||
*/ |
||||
template<class T> Quaternion<T> lerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) { |
||||
return lerp(a.point(), b.point(), t); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Spline interpolation of two cubic Hermite points |
||||
@param a First spline point |
||||
@param b Second spline point |
||||
@param t Interpolation phase |
||||
|
||||
Given segment points @f$ \boldsymbol{p}_i @f$, in-tangents @f$ \boldsymbol{m}_i @f$ |
||||
and out-tangents @f$ \boldsymbol{n}_i @f$, the interpolated value @f$ \boldsymbol{p} @f$ |
||||
at phase @f$ t @f$ is: @f[ |
||||
\boldsymbol{p}(t) = (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b |
||||
@f] |
||||
|
||||
@see @ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
||||
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
*/ |
||||
template<class T, class U> T splerp(const CubicHermite<T>& a, const CubicHermite<T>& b, U t) { |
||||
return (U(2)*t*t*t - U(3)*t*t + U(1))*a.point() + |
||||
(t*t*t - U(2)*t*t + t)*a.outTangent() + |
||||
(U(-2)*t*t*t + U(3)*t*t)*b.point() + |
||||
(t*t*t - t*t)*b.inTangent(); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Spline interpolation of two cubic Hermite complex numbers |
||||
|
||||
Unlike @ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds |
||||
a normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$, |
||||
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$, |
||||
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[ |
||||
\begin{array}{rcl} |
||||
\boldsymbol{p'}(t) & = & (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b \\
|
||||
\boldsymbol{p}(t) & = & \cfrac{\boldsymbol{p'}(t)}{|\boldsymbol{p'}(t)|} |
||||
\end{array} |
||||
@f] |
||||
|
||||
Expects that @ref CubicHermite::point() is a normalized complex number in both |
||||
@p a and @p b. |
||||
@see @ref Complex::isNormalized(), |
||||
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) |
||||
*/ |
||||
template<class T> Complex<T> splerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) { |
||||
CORRADE_ASSERT(a.point().isNormalized() && b.point().isNormalized(), |
||||
"Math::splerp(): complex spline points must be normalized", {}); |
||||
return ((T(2)*t*t*t - T(3)*t*t + T(1))*a.point() + |
||||
(t*t*t - T(2)*t*t + t)*a.outTangent() + |
||||
(T(-2)*t*t*t + T(3)*t*t)*b.point() + |
||||
(t*t*t - t*t)*b.inTangent()).normalized(); |
||||
} |
||||
|
||||
/** @relatesalso CubicHermite
|
||||
@brief Spline interpolation of two cubic Hermite quaternions |
||||
|
||||
Unlike @ref splerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds |
||||
a normalization step after. Given segment points @f$ \boldsymbol{p}_i @f$, |
||||
in-tangents @f$ \boldsymbol{m}_i @f$ and out-tangents @f$ \boldsymbol{n}_i @f$, |
||||
the interpolated value @f$ \boldsymbol{p} @f$ at phase @f$ t @f$ is: @f[ |
||||
\begin{array}{rcl} |
||||
\boldsymbol{p'}(t) & = & (2 t^3 - 3 t^2 + 1) \boldsymbol{p}_a + (t^3 - 2 t^2 + t) \boldsymbol{n}_a + (-2 t^3 + 3 t^2) \boldsymbol{p}_b + (t^3 - t^2)\boldsymbol{m}_b \\
|
||||
\boldsymbol{p}(t) & = & \cfrac{\boldsymbol{p'}(t)}{|\boldsymbol{p'}(t)|} |
||||
\end{array} |
||||
@f] |
||||
|
||||
Expects that @ref CubicHermite::point() is a normalized quaternion in both @p a |
||||
and @p b. |
||||
@see @ref Quaternion::isNormalized(), |
||||
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
||||
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
||||
@ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
||||
*/ |
||||
template<class T> Quaternion<T> splerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) { |
||||
CORRADE_ASSERT(a.point().isNormalized() && b.point().isNormalized(), |
||||
"Math::splerp(): quaternion spline points must be normalized", {}); |
||||
return ((T(2)*t*t*t - T(3)*t*t + T(1))*a.point() + |
||||
(t*t*t - T(2)*t*t + t)*a.outTangent() + |
||||
(T(-2)*t*t*t + T(3)*t*t)*b.point() + |
||||
(t*t*t - t*t)*b.inTangent()).normalized(); |
||||
} |
||||
|
||||
template<class T> inline bool CubicHermite<T>::operator==(const CubicHermite<T>& other) const { |
||||
/* For non-scalar types default implementation of TypeTraits would be used,
|
||||
which is just operator== */ |
||||
return TypeTraits<T>::equals(_inTangent, other._inTangent) && |
||||
TypeTraits<T>::equals(_point, other._point) && |
||||
TypeTraits<T>::equals(_outTangent, other._outTangent); |
||||
} |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,915 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
Vladimír Vondruš <mosra@centrum.cz> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a |
||||
copy of this software and associated documentation files (the "Software"), |
||||
to deal in the Software without restriction, including without limitation |
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||
and/or sell copies of the Software, and to permit persons to whom the |
||||
Software is furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included |
||||
in all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||
DEALINGS IN THE SOFTWARE. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Math/CubicHermite.h" |
||||
#include "Magnum/Math/Functions.h" |
||||
#include "Magnum/Math/Vector2.h" |
||||
|
||||
namespace Magnum { namespace Math { namespace Test { |
||||
|
||||
struct CubicHermiteTest: Corrade::TestSuite::Tester { |
||||
explicit CubicHermiteTest(); |
||||
|
||||
void constructScalar(); |
||||
void constructVector(); |
||||
void constructComplex(); |
||||
void constructQuaternion(); |
||||
|
||||
void constructDefaultScalar(); |
||||
void constructDefaultVector(); |
||||
void constructDefaultComplex(); |
||||
void constructDefaultQuaternion(); |
||||
|
||||
void constructZeroScalar(); |
||||
void constructZeroVector(); |
||||
void constructZeroComplex(); |
||||
void constructZeroQuaternion(); |
||||
|
||||
void constructIdentityScalar(); |
||||
void constructIdentityVector(); |
||||
void constructIdentityComplex(); |
||||
void constructIdentityQuaternion(); |
||||
|
||||
void constructNoInitScalar(); |
||||
void constructNoInitVector(); |
||||
void constructNoInitComplex(); |
||||
void constructNoInitQuaternion(); |
||||
|
||||
void constructConversionScalar(); |
||||
void constructConversionVector(); |
||||
void constructConversionComplex(); |
||||
void constructConversionQuaternion(); |
||||
|
||||
void constructCopyScalar(); |
||||
void constructCopyVector(); |
||||
void constructCopyComplex(); |
||||
void constructCopyQuaternion(); |
||||
|
||||
void dataScalar(); |
||||
void dataVector(); |
||||
void dataComplex(); |
||||
void dataQuaternion(); |
||||
|
||||
void compareScalar(); |
||||
void compareVector(); |
||||
void compareComplex(); |
||||
void compareQuaternion(); |
||||
|
||||
void selectScalar(); |
||||
void selectVector(); |
||||
void selectComplex(); |
||||
void selectQuaternion(); |
||||
|
||||
void lerpScalar(); |
||||
void lerpVector(); |
||||
void lerpComplex(); |
||||
void lerpComplexNotNormalized(); |
||||
void lerpQuaternion(); |
||||
void lerpQuaternionNotNormalized(); |
||||
|
||||
void splerpScalar(); |
||||
void splerpVector(); |
||||
void splerpComplex(); |
||||
void splerpComplexNotNormalized(); |
||||
void splerpQuaternion(); |
||||
void splerpQuaternionNotNormalized(); |
||||
|
||||
void debugScalar(); |
||||
void debugVector(); |
||||
void debugComplex(); |
||||
void debugQuaternion(); |
||||
}; |
||||
|
||||
CubicHermiteTest::CubicHermiteTest() { |
||||
addTests({&CubicHermiteTest::constructScalar, |
||||
&CubicHermiteTest::constructVector, |
||||
&CubicHermiteTest::constructComplex, |
||||
&CubicHermiteTest::constructQuaternion, |
||||
|
||||
&CubicHermiteTest::constructDefaultScalar, |
||||
&CubicHermiteTest::constructDefaultVector, |
||||
&CubicHermiteTest::constructDefaultComplex, |
||||
&CubicHermiteTest::constructDefaultQuaternion, |
||||
|
||||
&CubicHermiteTest::constructZeroScalar, |
||||
&CubicHermiteTest::constructZeroVector, |
||||
&CubicHermiteTest::constructZeroComplex, |
||||
&CubicHermiteTest::constructZeroQuaternion, |
||||
|
||||
&CubicHermiteTest::constructIdentityScalar, |
||||
&CubicHermiteTest::constructIdentityVector, |
||||
&CubicHermiteTest::constructIdentityComplex, |
||||
&CubicHermiteTest::constructIdentityQuaternion, |
||||
|
||||
&CubicHermiteTest::constructNoInitScalar, |
||||
&CubicHermiteTest::constructNoInitVector, |
||||
&CubicHermiteTest::constructNoInitComplex, |
||||
&CubicHermiteTest::constructNoInitQuaternion, |
||||
|
||||
&CubicHermiteTest::constructConversionScalar, |
||||
&CubicHermiteTest::constructConversionVector, |
||||
&CubicHermiteTest::constructConversionComplex, |
||||
&CubicHermiteTest::constructConversionQuaternion, |
||||
|
||||
&CubicHermiteTest::constructCopyScalar, |
||||
&CubicHermiteTest::constructCopyVector, |
||||
&CubicHermiteTest::constructCopyComplex, |
||||
&CubicHermiteTest::constructCopyQuaternion, |
||||
|
||||
&CubicHermiteTest::dataScalar, |
||||
&CubicHermiteTest::dataVector, |
||||
&CubicHermiteTest::dataComplex, |
||||
&CubicHermiteTest::dataQuaternion, |
||||
|
||||
&CubicHermiteTest::compareScalar, |
||||
&CubicHermiteTest::compareVector, |
||||
&CubicHermiteTest::compareComplex, |
||||
&CubicHermiteTest::compareQuaternion, |
||||
|
||||
&CubicHermiteTest::selectScalar, |
||||
&CubicHermiteTest::selectVector, |
||||
&CubicHermiteTest::selectComplex, |
||||
&CubicHermiteTest::selectQuaternion, |
||||
|
||||
&CubicHermiteTest::lerpScalar, |
||||
&CubicHermiteTest::lerpVector, |
||||
&CubicHermiteTest::lerpComplex, |
||||
&CubicHermiteTest::lerpComplexNotNormalized, |
||||
&CubicHermiteTest::lerpQuaternion, |
||||
&CubicHermiteTest::lerpQuaternionNotNormalized, |
||||
|
||||
&CubicHermiteTest::splerpScalar, |
||||
&CubicHermiteTest::splerpVector, |
||||
&CubicHermiteTest::splerpComplex, |
||||
&CubicHermiteTest::splerpComplexNotNormalized, |
||||
&CubicHermiteTest::splerpQuaternion, |
||||
&CubicHermiteTest::splerpQuaternionNotNormalized, |
||||
|
||||
&CubicHermiteTest::debugScalar, |
||||
&CubicHermiteTest::debugVector, |
||||
&CubicHermiteTest::debugComplex, |
||||
&CubicHermiteTest::debugQuaternion}); |
||||
} |
||||
|
||||
typedef Math::Vector2<Float> Vector2; |
||||
typedef Math::Complex<Float> Complex; |
||||
typedef Math::Quaternion<Float> Quaternion; |
||||
typedef Math::CubicHermite1D<Float> CubicHermite1D; |
||||
typedef Math::CubicHermite2D<Float> CubicHermite2D; |
||||
typedef Math::CubicHermiteComplex<Float> CubicHermiteComplex; |
||||
typedef Math::CubicHermiteQuaternion<Float> CubicHermiteQuaternion; |
||||
|
||||
void CubicHermiteTest::constructScalar() { |
||||
constexpr CubicHermite1D a{2.0f, -2.0f, -0.5f}; |
||||
CubicHermite1D b{2.0f, -2.0f, -0.5f}; |
||||
|
||||
CORRADE_COMPARE(a.inTangent(), 2.0f); |
||||
CORRADE_COMPARE(b.inTangent(), 2.0f); |
||||
CORRADE_COMPARE(a.point(), -2.0f); |
||||
CORRADE_COMPARE(b.point(), -2.0f); |
||||
CORRADE_COMPARE(a.outTangent(), -0.5f); |
||||
CORRADE_COMPARE(b.outTangent(), -0.5f); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite1D, Float, Float, Float>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructVector() { |
||||
constexpr CubicHermite2D a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
CubicHermite2D b{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
|
||||
CORRADE_COMPARE(a.inTangent(), (Vector2{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(b.inTangent(), (Vector2{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(a.point(), (Vector2{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(b.point(), (Vector2{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(a.outTangent(), (Vector2{3.0f, -0.5f})); |
||||
CORRADE_COMPARE(b.outTangent(), (Vector2{3.0f, -0.5f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite2D, Vector2, Vector2, Vector2>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructComplex() { |
||||
constexpr CubicHermiteComplex a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
CubicHermiteComplex b{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
|
||||
CORRADE_COMPARE(a.inTangent(), (Complex{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(b.inTangent(), (Complex{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(a.point(), (Complex{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(b.point(), (Complex{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(a.outTangent(), (Complex{3.0f, -0.5f})); |
||||
CORRADE_COMPARE(b.outTangent(), (Complex{3.0f, -0.5f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, Complex, Complex, Complex>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructQuaternion() { |
||||
constexpr CubicHermiteQuaternion a{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
CubicHermiteQuaternion b{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(a.inTangent(), (Quaternion{{1.0f, 2.0f, -1.0f}, 3.0f})); |
||||
CORRADE_COMPARE(b.inTangent(), (Quaternion{{1.0f, 2.0f, -1.0f}, 3.0f})); |
||||
CORRADE_COMPARE(a.point(), (Quaternion{{1.5f, -2.0f, 0.1f}, 1.1f})); |
||||
CORRADE_COMPARE(b.point(), (Quaternion{{1.5f, -2.0f, 0.1f}, 1.1f})); |
||||
CORRADE_COMPARE(a.outTangent(), (Quaternion{{3.0f, -0.5f, 1.2f}, 0.3f})); |
||||
CORRADE_COMPARE(b.outTangent(), (Quaternion{{3.0f, -0.5f, 1.2f}, 0.3f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteQuaternion, Quaternion, Quaternion, Quaternion>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructDefaultScalar() { |
||||
constexpr CubicHermite1D a; |
||||
CubicHermite1D b; |
||||
|
||||
/* Equivalent to ZeroInit constructor */ |
||||
CORRADE_COMPARE(a, (CubicHermite1D{0.0f, 0.0f, 0.0f})); |
||||
CORRADE_COMPARE(b, (CubicHermite1D{0.0f, 0.0f, 0.0f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_default_constructible<CubicHermite1D>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructDefaultVector() { |
||||
constexpr CubicHermite2D a; |
||||
CubicHermite2D b; |
||||
|
||||
/* Equivalent to ZeroInit constructor */ |
||||
CORRADE_COMPARE(a, (CubicHermite2D{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermite2D{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_default_constructible<CubicHermite2D>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructDefaultComplex() { |
||||
constexpr CubicHermiteComplex a; |
||||
CubicHermiteComplex b; |
||||
|
||||
/* Equivalent to IdentityInit constructor */ |
||||
CORRADE_COMPARE(a, (CubicHermiteComplex{{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteComplex{{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_default_constructible<CubicHermiteComplex>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructDefaultQuaternion() { |
||||
constexpr CubicHermiteQuaternion a; |
||||
CubicHermiteQuaternion b; |
||||
|
||||
/* Equivalent to IdentityInit constructor */ |
||||
CORRADE_COMPARE(a, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 1.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 1.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_default_constructible<CubicHermiteQuaternion>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructZeroScalar() { |
||||
constexpr CubicHermite1D a{ZeroInit}; |
||||
CubicHermite1D b{ZeroInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermite1D{0.0f, 0.0f, 0.0f})); |
||||
CORRADE_COMPARE(b, (CubicHermite1D{0.0f, 0.0f, 0.0f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite1D, ZeroInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructZeroVector() { |
||||
constexpr CubicHermite2D a{ZeroInit}; |
||||
CubicHermite2D b{ZeroInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermite2D{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermite2D{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite2D, ZeroInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructZeroComplex() { |
||||
constexpr CubicHermiteComplex a{ZeroInit}; |
||||
CubicHermiteComplex b{ZeroInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermiteComplex{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteComplex{{0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, ZeroInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructZeroQuaternion() { |
||||
constexpr CubicHermiteQuaternion a{ZeroInit}; |
||||
CubicHermiteQuaternion b{ZeroInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteQuaternion, ZeroInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructIdentityScalar() { |
||||
CORRADE_VERIFY(!(std::is_constructible<CubicHermite1D, IdentityInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructIdentityVector() { |
||||
CORRADE_VERIFY(!(std::is_constructible<CubicHermite2D, IdentityInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructIdentityComplex() { |
||||
constexpr CubicHermiteComplex a{IdentityInit}; |
||||
CubicHermiteComplex b{IdentityInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermiteComplex{{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteComplex{{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, IdentityInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructIdentityQuaternion() { |
||||
constexpr CubicHermiteQuaternion a{IdentityInit}; |
||||
CubicHermiteQuaternion b{IdentityInit}; |
||||
|
||||
CORRADE_COMPARE(a, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 1.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
CORRADE_COMPARE(b, (CubicHermiteQuaternion{ |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 1.0f}, |
||||
{{0.0f, 0.0f, 0.0f}, 0.0f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, IdentityInitT>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructNoInitScalar() { |
||||
CubicHermite1D spline{2.0f, -2.0f, -0.5f}; |
||||
new(&spline) CubicHermite1D{NoInit}; |
||||
|
||||
CORRADE_COMPARE(spline, (CubicHermite1D{2.0f, -2.0f, -0.5f})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite1D, NoInitT>::value)); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CubicHermite1D>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructNoInitVector() { |
||||
CubicHermite2D spline{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
new(&spline) CubicHermite2D{NoInit}; |
||||
|
||||
CORRADE_COMPARE(spline, (CubicHermite2D{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite2D, NoInitT>::value)); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CubicHermite2D>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructNoInitComplex() { |
||||
CubicHermiteComplex spline{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
new(&spline) CubicHermiteComplex{NoInit}; |
||||
|
||||
CORRADE_COMPARE(spline, (CubicHermiteComplex{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, NoInitT>::value)); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CubicHermiteComplex>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructNoInitQuaternion() { |
||||
CubicHermiteQuaternion spline{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
new(&spline) CubicHermiteQuaternion{NoInit}; |
||||
|
||||
CORRADE_COMPARE(spline, (CubicHermiteQuaternion{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}})); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteQuaternion, NoInitT>::value)); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CubicHermiteQuaternion>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructConversionScalar() { |
||||
typedef Math::CubicHermite1D<Int> CubicHermite1Di; |
||||
|
||||
constexpr CubicHermite1D a{2.0f, -2.0f, -0.5f}; |
||||
constexpr CubicHermite1Di b{a}; |
||||
CubicHermite1Di c{a}; |
||||
CORRADE_COMPARE(b, (CubicHermite1Di{2, -2, 0})); |
||||
CORRADE_COMPARE(c, (CubicHermite1Di{2, -2, 0})); |
||||
|
||||
/* Implicit conversion is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<CubicHermite1D, CubicHermite1Di>::value)); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite1D, CubicHermite1Di>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructConversionVector() { |
||||
typedef Math::CubicHermite2D<Int> CubicHermite2Di; |
||||
|
||||
constexpr CubicHermite2D a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr CubicHermite2Di b{a}; |
||||
CubicHermite2Di c{a}; |
||||
CORRADE_COMPARE(b, (CubicHermite2Di{{1, 2}, {1, -2}, {3, 0}})); |
||||
CORRADE_COMPARE(c, (CubicHermite2Di{{1, 2}, {1, -2}, {3, 0}})); |
||||
|
||||
/* Implicit conversion is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<CubicHermite2D, CubicHermite2Di>::value)); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermite2D, CubicHermite2Di>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructConversionComplex() { |
||||
typedef Math::CubicHermiteComplex<Int> CubicHermiteComplexi; |
||||
|
||||
constexpr CubicHermiteComplex a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr CubicHermiteComplexi b{a}; |
||||
CubicHermiteComplexi c{a}; |
||||
CORRADE_COMPARE(b, (CubicHermiteComplexi{{1, 2}, {1, -2}, {3, 0}})); |
||||
CORRADE_COMPARE(c, (CubicHermiteComplexi{{1, 2}, {1, -2}, {3, 0}})); |
||||
|
||||
/* Implicit conversion is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<CubicHermiteComplex, CubicHermiteComplexi>::value)); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteComplex, CubicHermiteComplexi>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructConversionQuaternion() { |
||||
typedef Math::CubicHermiteQuaternion<Int> CubicHermiteQuaternioni; |
||||
|
||||
constexpr CubicHermiteQuaternion a{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
constexpr CubicHermiteQuaternioni b{a}; |
||||
CubicHermiteQuaternioni c{a}; |
||||
CORRADE_COMPARE(b, (CubicHermiteQuaternioni{ |
||||
{{1, 2, -1}, 3}, |
||||
{{1, -2, 0}, 1}, |
||||
{{3, 0, 1}, 0}})); |
||||
CORRADE_COMPARE(c, (CubicHermiteQuaternioni{ |
||||
{{1, 2, -1}, 3}, |
||||
{{1, -2, 0}, 1}, |
||||
{{3, 0, 1}, 0}})); |
||||
|
||||
/* Implicit conversion is not allowed */ |
||||
CORRADE_VERIFY(!(std::is_convertible<CubicHermiteQuaternion, CubicHermiteQuaternioni>::value)); |
||||
|
||||
CORRADE_VERIFY((std::is_nothrow_constructible<CubicHermiteQuaternion, CubicHermiteQuaternioni>::value)); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructCopyScalar() { |
||||
constexpr CubicHermite1D a{2.0f, -2.0f, -0.5f}; |
||||
constexpr CubicHermite1D b{a}; |
||||
|
||||
CORRADE_COMPARE(b, (CubicHermite1D{2.0f, -2.0f, -0.5f})); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_copy_constructible<CubicHermite1D>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_copy_assignable<CubicHermite1D>::value); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructCopyVector() { |
||||
constexpr CubicHermite2D a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr CubicHermite2D b{a}; |
||||
|
||||
CORRADE_COMPARE(b, (CubicHermite2D{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}})); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_copy_constructible<CubicHermite2D>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_copy_assignable<CubicHermite2D>::value); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructCopyComplex() { |
||||
constexpr CubicHermiteComplex a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr CubicHermiteComplex b{a}; |
||||
|
||||
CORRADE_COMPARE(b, (CubicHermiteComplex{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}})); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_copy_constructible<CubicHermiteComplex>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_copy_assignable<CubicHermiteComplex>::value); |
||||
} |
||||
|
||||
void CubicHermiteTest::constructCopyQuaternion() { |
||||
constexpr CubicHermiteQuaternion a{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
constexpr CubicHermiteQuaternion b{a}; |
||||
|
||||
CORRADE_COMPARE(b, (CubicHermiteQuaternion{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}})); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_copy_constructible<CubicHermiteComplex>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_copy_assignable<CubicHermiteComplex>::value); |
||||
} |
||||
|
||||
void CubicHermiteTest::dataScalar() { |
||||
constexpr CubicHermite1D ca{2.0f, -2.0f, -0.5f}; |
||||
constexpr Float inTangent = ca.inTangent(); |
||||
constexpr Float point = ca.point(); |
||||
constexpr Float outTangent = ca.outTangent(); |
||||
CORRADE_COMPARE(inTangent, 2.0f); |
||||
CORRADE_COMPARE(point, -2.0f); |
||||
CORRADE_COMPARE(outTangent, -0.5f); |
||||
|
||||
CubicHermite1D a{2.0f, -2.0f, -0.5f}; |
||||
a.inTangent() = 3.0f; |
||||
a.point() = 1.0f; |
||||
a.outTangent() = 2.0f; |
||||
CORRADE_COMPARE(a, (CubicHermite1D{3.0f, 1.0f, 2.0f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::dataVector() { |
||||
constexpr CubicHermite2D ca{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr Vector2 inTangent = ca.inTangent(); |
||||
constexpr Vector2 point = ca.point(); |
||||
constexpr Vector2 outTangent = ca.outTangent(); |
||||
CORRADE_COMPARE(inTangent, (Vector2{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(point, (Vector2{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(outTangent, (Vector2{3.0f, -0.5f})); |
||||
|
||||
CubicHermite2D a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
a.inTangent().y() = 3.0f; |
||||
a.point().x() = 1.0f; |
||||
a.outTangent().y() = 2.0f; |
||||
CORRADE_COMPARE(a, (CubicHermite2D{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::dataComplex() { |
||||
constexpr CubicHermiteComplex ca{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
constexpr Complex inTangent = ca.inTangent(); |
||||
constexpr Complex point = ca.point(); |
||||
constexpr Complex outTangent = ca.outTangent(); |
||||
CORRADE_COMPARE(inTangent, (Complex{1.0f, 2.0f})); |
||||
CORRADE_COMPARE(point, (Complex{1.5f, -2.0f})); |
||||
CORRADE_COMPARE(outTangent, (Complex{3.0f, -0.5f})); |
||||
|
||||
CubicHermiteComplex a{{1.0f, 2.0f}, {1.5f, -2.0f}, {3.0f, -0.5f}}; |
||||
a.inTangent().imaginary() = 3.0f; |
||||
a.point().real() = 1.0f; |
||||
a.outTangent().imaginary() = 2.0f; |
||||
CORRADE_COMPARE(a, (CubicHermiteComplex{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::dataQuaternion() { |
||||
constexpr CubicHermiteQuaternion ca{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
constexpr Quaternion inTangent = ca.inTangent(); |
||||
constexpr Quaternion point = ca.point(); |
||||
constexpr Quaternion outTangent = ca.outTangent(); |
||||
|
||||
CORRADE_COMPARE(inTangent, (Quaternion{{1.0f, 2.0f, -1.0f}, 3.0f})); |
||||
CORRADE_COMPARE(point, (Quaternion{{1.5f, -2.0f, 0.1f}, 1.1f})); |
||||
CORRADE_COMPARE(outTangent, (Quaternion{{3.0f, -0.5f, 1.2f}, 0.3f})); |
||||
|
||||
CubicHermiteQuaternion a{ |
||||
{{1.0f, 2.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.1f}, |
||||
{{3.0f, -0.5f, 1.2f}, 0.3f}}; |
||||
a.inTangent().vector().y() = 3.0f; |
||||
a.point().scalar() = 1.0f; |
||||
a.outTangent().vector().z() = 2.0f; |
||||
CORRADE_COMPARE(a, (CubicHermiteQuaternion{ |
||||
{{1.0f, 3.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.0f}, |
||||
{{3.0f, -0.5f, 2.0f}, 0.3f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::compareScalar() { |
||||
CORRADE_VERIFY((CubicHermite1D{3.0f, 1.0f, 2.0f} == CubicHermite1D{3.0f, 1.0f + TypeTraits<Float>::epsilon()/2, 2.0f})); |
||||
CORRADE_VERIFY((CubicHermite1D{3.0f, 1.0f, 2.0f} != CubicHermite1D{3.0f + TypeTraits<Float>::epsilon()*6, 1.0f, 2.0f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::compareVector() { |
||||
CORRADE_VERIFY((CubicHermite2D{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}}) == (CubicHermite2D{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f + TypeTraits<Float>::epsilon()/2}})); |
||||
CORRADE_VERIFY((CubicHermite2D{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}}) != (CubicHermite2D{{1.0f + TypeTraits<Float>::epsilon()*2, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::compareComplex() { |
||||
CORRADE_VERIFY((CubicHermiteComplex{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}}) == (CubicHermiteComplex{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f + TypeTraits<Float>::epsilon()/2}})); |
||||
CORRADE_VERIFY((CubicHermiteComplex{{1.0f, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}}) != (CubicHermiteComplex{{1.0f + TypeTraits<Float>::epsilon()*2, 3.0f}, {1.0f, -2.0f}, {3.0f, 2.0f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::compareQuaternion() { |
||||
CORRADE_VERIFY((CubicHermiteQuaternion{ |
||||
{{1.0f, 3.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.0f}, |
||||
{{3.0f, -0.5f, 2.0f}, 0.3f}}) == (CubicHermiteQuaternion{ |
||||
{{1.0f, 3.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.0f + TypeTraits<Float>::epsilon()/2}, |
||||
{{3.0f, -0.5f, 2.0f}, 0.3f}})); |
||||
CORRADE_VERIFY((CubicHermiteQuaternion{ |
||||
{{1.0f, 3.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.0f}, |
||||
{{3.0f, -0.5f, 2.0f}, 0.3f}}) != (CubicHermiteQuaternion{ |
||||
{{1.0f + TypeTraits<Float>::epsilon()*2, 3.0f, -1.0f}, 3.0f}, |
||||
{{1.5f, -2.0f, 0.1f}, 1.0f}, |
||||
{{3.0f, -0.5f, 2.0f}, 0.3f}})); |
||||
} |
||||
|
||||
void CubicHermiteTest::selectScalar() { |
||||
CubicHermite1D a{2.0f, 3.0f, -1.0f}; |
||||
CubicHermite1D b{5.0f, -2.0f, 1.5f}; |
||||
|
||||
CORRADE_COMPARE(Math::select(a, b, 0.0f), 3.0f); |
||||
CORRADE_COMPARE(Math::select(a, b, 0.8f), 3.0f); |
||||
CORRADE_COMPARE(Math::select(a, b, 1.0f), -2.0f); |
||||
} |
||||
|
||||
void CubicHermiteTest::selectVector() { |
||||
CubicHermite2D a{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CubicHermite2D b{{5.0f, 0.3f}, {-2.0f, 1.1f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::select(a, b, 0.0f), (Vector2{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 0.8f), (Vector2{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 1.0f), (Vector2{-2.0f, 1.1f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::selectComplex() { |
||||
CubicHermiteComplex a{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CubicHermiteComplex b{{5.0f, 0.3f}, {-2.0f, 1.1f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::select(a, b, 0.0f), (Complex{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 0.8f), (Complex{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 1.0f), (Complex{-2.0f, 1.1f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::selectQuaternion() { |
||||
CubicHermiteQuaternion a{ |
||||
{{2.0f, 1.5f, 0.3f}, 1.1f}, |
||||
{{3.0f, 0.1f, 2.3f}, 0.7f}, |
||||
{{-1.0f, 0.0f, 0.3f}, 0.4f}}; |
||||
CubicHermiteQuaternion b{ |
||||
{{5.0f, 0.3f, 1.1f}, 0.5f}, |
||||
{{-2.0f, 1.1f, 1.0f}, 1.3f}, |
||||
{{1.5f, 0.3f, 17.0f}, -7.0f}}; |
||||
|
||||
CORRADE_COMPARE(Math::select(a, b, 0.0f), (Quaternion{{3.0f, 0.1f, 2.3f}, 0.7f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 0.8f), (Quaternion{{3.0f, 0.1f, 2.3f}, 0.7f})); |
||||
CORRADE_COMPARE(Math::select(a, b, 1.0f), (Quaternion{{-2.0f, 1.1f, 1.0f}, 1.3f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpScalar() { |
||||
CubicHermite1D a{2.0f, 3.0f, -1.0f}; |
||||
CubicHermite1D b{5.0f, -2.0f, 1.5f}; |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.0f), 3.0f); |
||||
CORRADE_COMPARE(Math::lerp(a, b, 1.0f), -2.0f); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.35f), 1.25f); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.35f), 1.25f); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.8f), -1.0f); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.8f), -1.0f); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpVector() { |
||||
CubicHermite2D a{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CubicHermite2D b{{5.0f, 0.3f}, {-2.0f, 1.1f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.0f), (Vector2{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::lerp(a, b, 1.0f), (Vector2{-2.0f, 1.1f})); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.35f), (Vector2{1.25f, 0.45f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.35f), (Vector2{1.25f, 0.45f})); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.8f), (Vector2{-1.0f, 0.9f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.8f), (Vector2{-1.0f, 0.9f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpComplex() { |
||||
CubicHermiteComplex a{{2.0f, 1.5f}, {0.999445f, 0.0333148f}, {-1.0f, 0.0f}}; |
||||
CubicHermiteComplex b{{5.0f, 0.3f}, {-0.876216f, 0.481919f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.0f), (Complex{0.999445f, 0.0333148f})); |
||||
CORRADE_COMPARE(Math::lerp(a, b, 1.0f), (Complex{-0.876216f, 0.481919f})); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.35f), (Complex{0.874384f, 0.485235f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.35f), (Complex{0.874384f, 0.485235f})); |
||||
CORRADE_VERIFY(Math::lerp(a, b, 0.35f).isNormalized()); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.8f), (Complex{-0.78747f, 0.616353f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.8f), (Complex{-0.78747f, 0.616353f})); |
||||
CORRADE_VERIFY(Math::lerp(a, b, 0.8f).isNormalized()); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpComplexNotNormalized() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
/* This one should not assert as the default constructor should create
|
||||
identity point */ |
||||
CORRADE_COMPARE(Math::lerp(CubicHermiteComplex{}, {}, 0.3f), Complex{}); |
||||
|
||||
/* These will, tho */ |
||||
CubicHermiteComplex a{{}, Complex{}*2.0f, {}}; |
||||
Math::lerp({}, a, 0.3f); |
||||
Math::lerp(a, {}, 0.3f); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Math::lerp(): complex numbers must be normalized\n" |
||||
"Math::lerp(): complex numbers must be normalized\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpQuaternion() { |
||||
CubicHermiteQuaternion a{ |
||||
{{2.0f, 1.5f, 0.3f}, 1.1f}, |
||||
{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f}, |
||||
{{-1.0f, 0.0f, 0.3f}, 0.4f}}; |
||||
CubicHermiteQuaternion b{ |
||||
{{5.0f, 0.3f, 1.1f}, 0.5f}, |
||||
{{-0.711568f, 0.391362f, 0.355784f}, 0.462519f}, |
||||
{{1.5f, 0.3f, 17.0f}, -7.0f}}; |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.0f), (Quaternion{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f})); |
||||
CORRADE_COMPARE(Math::lerp(a, b, 1.0f), (Quaternion{{-0.711568f, 0.391362f, 0.355784f}, 0.462519f})); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.35f), (Quaternion{{0.392449f, 0.234067f, 0.780733f}, 0.426207f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.35f), (Quaternion{{0.392449f, 0.234067f, 0.780733f}, 0.426207f})); |
||||
CORRADE_VERIFY(Math::lerp(a, b, 0.35f).isNormalized()); |
||||
|
||||
CORRADE_COMPARE(Math::lerp(a, b, 0.8f), (Quaternion{{-0.533196f, 0.410685f, 0.521583f}, 0.524396f})); |
||||
CORRADE_COMPARE(Math::lerp(a.point(), b.point(), 0.8f), (Quaternion{{-0.533196f, 0.410685f, 0.521583f}, 0.524396f})); |
||||
CORRADE_VERIFY(Math::lerp(a, b, 0.8f).isNormalized()); |
||||
} |
||||
|
||||
void CubicHermiteTest::lerpQuaternionNotNormalized() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
/* This one should not assert as the default constructor should create
|
||||
identity point */ |
||||
Math::lerp(CubicHermiteQuaternion{}, {}, 0.3f); |
||||
|
||||
/* These will, tho */ |
||||
CubicHermiteQuaternion a{{}, Quaternion{}*2.0f, {}}; |
||||
Math::lerp({}, a, 0.3f); |
||||
Math::lerp(a, {}, 0.3f); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Math::lerp(): quaternions must be normalized\n" |
||||
"Math::lerp(): quaternions must be normalized\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpScalar() { |
||||
CubicHermite1D a{2.0f, 3.0f, -1.0f}; |
||||
CubicHermite1D b{5.0f, -2.0f, 1.5f}; |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.0f), 3.0f); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 1.0f), -2.0f); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.35f), 1.04525f); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.8f), -2.152f); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpVector() { |
||||
CubicHermite2D a{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CubicHermite2D b{{5.0f, 0.3f}, {-2.0f, 1.1f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.0f), (Vector2{3.0f, 0.1f})); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 1.0f), (Vector2{-2.0f, 1.1f})); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.35f), (Vector2{1.04525f, 0.357862f})); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.8f), (Vector2{-2.152f, 0.9576f})); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpComplex() { |
||||
CubicHermiteComplex a{{2.0f, 1.5f}, {0.999445f, 0.0333148f}, {-1.0f, 0.0f}}; |
||||
CubicHermiteComplex b{{5.0f, 0.3f}, {-0.876216f, 0.481919f}, {1.5f, 0.3f}}; |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.0f), (Complex{0.999445f, 0.0333148f})); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 1.0f), (Complex{-0.876216f, 0.481919f})); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.35f), (Complex{-0.483504f, 0.875342f})); |
||||
CORRADE_VERIFY(Math::splerp(a, b, 0.35f).isNormalized()); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.8f), (Complex{-0.95958f, 0.281435f})); |
||||
CORRADE_VERIFY(Math::splerp(a, b, 0.8f).isNormalized()); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpComplexNotNormalized() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
/* This one should not assert as the default constructor should create
|
||||
identity point */ |
||||
CORRADE_COMPARE(Math::splerp(CubicHermiteComplex{}, {}, 0.3f), Complex{}); |
||||
|
||||
/* These will, tho */ |
||||
CubicHermiteComplex a{{}, Complex{}*2.0f, {}}; |
||||
Math::splerp({}, a, 0.3f); |
||||
Math::splerp(a, {}, 0.3f); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Math::splerp(): complex spline points must be normalized\n" |
||||
"Math::splerp(): complex spline points must be normalized\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpQuaternion() { |
||||
CubicHermiteQuaternion a{ |
||||
{{2.0f, 1.5f, 0.3f}, 1.1f}, |
||||
{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f}, |
||||
{{-1.0f, 0.0f, 0.3f}, 0.4f}}; |
||||
CubicHermiteQuaternion b{ |
||||
{{5.0f, 0.3f, 1.1f}, 0.5f}, |
||||
{{-0.711568f, 0.391362f, 0.355784f}, 0.462519f}, |
||||
{{1.5f, 0.3f, 17.0f}, -7.0f}}; |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.0f), (Quaternion{{0.780076f, 0.0260025f, 0.598059f}, 0.182018f})); |
||||
CORRADE_COMPARE(Math::splerp(a, b, 1.0f), (Quaternion{{-0.711568f, 0.391362f, 0.355784f}, 0.462519f})); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.35f), (Quaternion{{-0.309862f, 0.174831f, 0.809747f}, 0.466615f})); |
||||
CORRADE_VERIFY(Math::splerp(a, b, 0.35f).isNormalized()); |
||||
|
||||
CORRADE_COMPARE(Math::splerp(a, b, 0.8f), (Quaternion{{-0.911408f, 0.23368f, 0.185318f}, 0.283524f})); |
||||
CORRADE_VERIFY(Math::splerp(a, b, 0.8f).isNormalized()); |
||||
} |
||||
|
||||
void CubicHermiteTest::splerpQuaternionNotNormalized() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
/* This one should not assert as the default constructor should create
|
||||
identity point */ |
||||
Math::splerp(CubicHermiteQuaternion{}, {}, 0.3f); |
||||
|
||||
/* These will, tho */ |
||||
CubicHermiteQuaternion a{{}, Quaternion{}*2.0f, {}}; |
||||
Math::splerp({}, a, 0.3f); |
||||
Math::splerp(a, {}, 0.3f); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Math::splerp(): quaternion spline points must be normalized\n" |
||||
"Math::splerp(): quaternion spline points must be normalized\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::debugScalar() { |
||||
std::ostringstream out; |
||||
Debug{&out} << CubicHermite1D{2.0f, 3.0f, -1.0f}; |
||||
CORRADE_COMPARE(out.str(), "CubicHermite(2, 3, -1)\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::debugVector() { |
||||
std::ostringstream out; |
||||
Debug{&out} << CubicHermite2D{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CORRADE_COMPARE(out.str(), "CubicHermite(Vector(2, 1.5), Vector(3, 0.1), Vector(-1, 0))\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::debugComplex() { |
||||
std::ostringstream out; |
||||
Debug{&out} << CubicHermiteComplex{{2.0f, 1.5f}, {3.0f, 0.1f}, {-1.0f, 0.0f}}; |
||||
CORRADE_COMPARE(out.str(), "CubicHermite(Complex(2, 1.5), Complex(3, 0.1), Complex(-1, 0))\n"); |
||||
} |
||||
|
||||
void CubicHermiteTest::debugQuaternion() { |
||||
std::ostringstream out; |
||||
Debug{&out} << CubicHermiteQuaternion{ |
||||
{{2.0f, 1.5f, 0.3f}, 1.1f}, |
||||
{{3.0f, 0.1f, 2.3f}, 0.7f}, |
||||
{{-1.0f, 0.0f, 0.3f}, 0.4f}}; |
||||
CORRADE_COMPARE(out.str(), "CubicHermite(Quaternion({2, 1.5, 0.3}, 1.1), Quaternion({3, 0.1, 2.3}, 0.7), Quaternion({-1, 0, 0.3}, 0.4))\n"); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Math::Test::CubicHermiteTest) |
||||
Loading…
Reference in new issue