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