mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
562 lines
27 KiB
562 lines
27 KiB
#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. |
|
|
|
Cubic Hermite splines are fully interchangeable with cubic Bézier curves, use |
|
@ref fromBezier() and @ref Bezier::fromCubicHermite() for the conversion. |
|
|
|
@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 Create cubic Hermite spline point from adjacent Bézier curve segments |
|
* |
|
* Given two adjacent cubic Bézier curve segments defined by points |
|
* @f$ \boldsymbol{a}_i @f$ and @f$ \boldsymbol{b}_i @f$, |
|
* @f$ i \in \{ 0, 1, 2, 3 \} @f$, the corresponding cubic Hermite |
|
* spline point @f$ \boldsymbol{p} @f$, in-tangent @f$ \boldsymbol{m} @f$ |
|
* and out-tangent @f$ \boldsymbol{n} @f$ is defined as: @f[ |
|
* \begin{array}{rcl} |
|
* \boldsymbol{m} & = & 3 (\boldsymbol{a}_3 - \boldsymbol{a}_2) |
|
* = 3 (\boldsymbol{b}_0 - \boldsymbol{a}_2) \\ |
|
* \boldsymbol{p} & = & \boldsymbol{a}_3 = \boldsymbol{b}_0 \\ |
|
* \boldsymbol{n} & = & 3 (\boldsymbol{b}_1 - \boldsymbol{a}_3) |
|
* = 3 (\boldsymbol{b}_1 - \boldsymbol{b}_0) |
|
* \end{array} |
|
* @f] |
|
* |
|
* Expects that the two segments are adjacent (i.e., the endpoint of |
|
* first segment is the start point of the second). If you need to |
|
* create a cubic Hermite spline point that's at the beginning or at |
|
* the end of a curve, simply pass a dummy Bézier segment that |
|
* satisfies this constraint as the other parameter: |
|
* |
|
* @snippet MagnumMath.cpp CubicHermite-fromBezier |
|
* |
|
* Enabled only on vector underlying types. See |
|
* @ref Bezier::fromCubicHermite() for the inverse operation. |
|
*/ |
|
template<UnsignedInt dimensions, class U> static |
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
|
CubicHermite<T> |
|
#else |
|
typename std::enable_if<std::is_base_of<Vector<dimensions, U>, T>::value, CubicHermite<T>>::type |
|
#endif |
|
fromBezier(const CubicBezier<dimensions, U>& a, const CubicBezier<dimensions, U>& b) { |
|
return CORRADE_CONSTEXPR_ASSERT(a[3] == b[0], |
|
"Math::CubicHermite::fromBezier(): segments are not adjacent"), |
|
CubicHermite<T>{3*(a[3] - a[2]), a[3], 3*(b[1] - a[3])}; |
|
} |
|
|
|
/** |
|
* @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 Raw data |
|
* @return One-dimensional array of three elements |
|
* |
|
* @see @ref inTangent(), @ref point(), @ref outTangent() |
|
*/ |
|
T* data() { return &_inTangent; } |
|
constexpr const T* data() const { return &_inTangent; } /**< @overload */ |
|
|
|
/** @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 anything */ |
|
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 spline point |
|
@param b Second spline point |
|
@param t Interpolation phase (from range @f$ [0; 1] @f$) |
|
|
|
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 (from range @f$ [0; 1] @f$) |
|
|
|
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 lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
|
@ref slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
|
@ref slerpShortestPath(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 |
|
|
|
Equivalent to calling @ref lerp(const Complex<T>&, const Complex<T>&, T) on |
|
@ref CubicHermite::point() extracted from @p a and @p b. Compared to |
|
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds a |
|
normalization step after. 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 slerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
|
@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 |
|
|
|
Equivalent to calling @ref lerp(const Quaternion<T>&, const Quaternion<T>&, T) |
|
on @ref CubicHermite::point() extracted from @p a and @p b. Compared to |
|
@ref lerp(const CubicHermite<T>&, const CubicHermite<T>&, U) this adds a |
|
normalization step after. Expects that @ref CubicHermite::point() is a |
|
normalized quaternion in both @p a and @p b. |
|
@see @ref Quaternion::isNormalized(), |
|
@ref lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
|
@ref lerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T), |
|
@ref select(const CubicHermite<T>&, const CubicHermite<T>&, U), |
|
@ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
|
@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 Linear shortest-path interpolation of two cubic Hermite quaternions |
|
|
|
Equivalent to calling @ref lerpShortestPath(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. |
|
|
|
Note that rotations interpolated with this function may go along a completely |
|
different path compared to @ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T). |
|
Use @ref lerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
|
for behavior that is consistent with spline interpolation. |
|
@see @ref Quaternion::isNormalized(), |
|
@ref slerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
|
*/ |
|
template<class T> Quaternion<T> lerpShortestPath(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) { |
|
return lerpShortestPath(a.point(), b.point(), t); |
|
} |
|
|
|
/** @relatesalso CubicHermite |
|
@brief Spherical linear interpolation of two cubic Hermite complex numbers |
|
|
|
Equivalent to calling @ref slerp(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 slerp(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), |
|
@ref splerp(const CubicHermiteComplex<T>&, const CubicHermiteComplex<T>&, T) |
|
*/ |
|
template<class T> inline Complex<T> slerp(const CubicHermiteComplex<T>& a, const CubicHermiteComplex<T>& b, T t) { |
|
return slerp(a.point(), b.point(), t); |
|
} |
|
|
|
/** @relatesalso CubicHermite |
|
@brief Spherical linear interpolation of two cubic Hermite quaternions |
|
|
|
Equivalent to calling @ref slerp(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 complex number in both @p a and @p b. |
|
@see @ref Quaternion::isNormalized(), |
|
@ref slerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T), |
|
@ref slerp(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), |
|
@ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
|
*/ |
|
template<class T> inline Quaternion<T> slerp(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) { |
|
return slerp(a.point(), b.point(), t); |
|
} |
|
|
|
/** @relatesalso CubicHermite |
|
@brief Spherical linear shortest-path interpolation of two cubic Hermite quaternions |
|
|
|
Equivalent to calling @ref slerpShortestPath(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. |
|
|
|
Note that rotations interpolated with this function may go along a completely |
|
different path compared to @ref splerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T). |
|
Use @ref slerp(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
|
for spherical linear interpolation with behavior that is consistent with spline |
|
interpolation. |
|
@see @ref Quaternion::isNormalized(), |
|
@ref lerpShortestPath(const CubicHermiteQuaternion<T>&, const CubicHermiteQuaternion<T>&, T) |
|
*/ |
|
template<class T> Quaternion<T> slerpShortestPath(const CubicHermiteQuaternion<T>& a, const CubicHermiteQuaternion<T>& b, T t) { |
|
return slerpShortestPath(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), |
|
@ref slerp(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" << a.point() << "and" << b.point() << "are not 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), |
|
@ref slerp(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" << a.point() << "and" << b.point() << "are not 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); |
|
} |
|
|
|
namespace Implementation { |
|
|
|
template<class T> struct StrictWeakOrdering<CubicHermite<T>> { |
|
bool operator()(const CubicHermite<T>& a, const CubicHermite<T>& b) const { |
|
StrictWeakOrdering<T> o; |
|
if(o(a.inTangent(), b.inTangent())) |
|
return true; |
|
if(o(b.inTangent(), a.inTangent())) |
|
return false; |
|
if(o(a.point(), b.point())) |
|
return true; |
|
if(o(b.point(), a.point())) |
|
return false; |
|
return o(a.outTangent(), b.outTangent()); |
|
} |
|
}; |
|
|
|
} |
|
|
|
}} |
|
|
|
#endif
|
|
|