quaternion: move out of coord infrastructure
This commit is contained in:
parent
b5b7ae3a9a
commit
e96ef7af32
@ -206,6 +206,7 @@ UTIL_FILES = \
|
|||||||
preprocessor.hpp \
|
preprocessor.hpp \
|
||||||
quaternion.cpp \
|
quaternion.cpp \
|
||||||
quaternion.hpp \
|
quaternion.hpp \
|
||||||
|
quaternion.ipp \
|
||||||
raii.hpp \
|
raii.hpp \
|
||||||
rand/lcg.cpp \
|
rand/lcg.cpp \
|
||||||
rand/lcg.hpp \
|
rand/lcg.hpp \
|
||||||
|
@ -21,7 +21,6 @@ namespace util {
|
|||||||
template <size_t,typename> struct colour;
|
template <size_t,typename> struct colour;
|
||||||
template <size_t,typename> struct extent;
|
template <size_t,typename> struct extent;
|
||||||
template <size_t,typename> struct point;
|
template <size_t,typename> struct point;
|
||||||
template <size_t,typename> struct quaternion;
|
|
||||||
template <size_t,typename> struct vector;
|
template <size_t,typename> struct vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,6 @@ namespace util {
|
|||||||
struct has_norm : public std::false_type { };
|
struct has_norm : public std::false_type { };
|
||||||
|
|
||||||
template <> struct has_norm<vector> : public std::true_type { };
|
template <> struct has_norm<vector> : public std::true_type { };
|
||||||
template <> struct has_norm<quaternion> : public std::true_type { };
|
|
||||||
|
|
||||||
template <template <size_t,typename> class K>
|
template <template <size_t,typename> class K>
|
||||||
constexpr auto has_norm_v = has_norm<K>::value;
|
constexpr auto has_norm_v = has_norm<K>::value;
|
||||||
@ -71,7 +70,6 @@ namespace util {
|
|||||||
template <> struct has_scalar_op<colour> : public std::true_type { };
|
template <> struct has_scalar_op<colour> : public std::true_type { };
|
||||||
template <> struct has_scalar_op<extent> : public std::true_type { };
|
template <> struct has_scalar_op<extent> : public std::true_type { };
|
||||||
template <> struct has_scalar_op<point> : public std::true_type { };
|
template <> struct has_scalar_op<point> : public std::true_type { };
|
||||||
template <> struct has_scalar_op<quaternion> : public std::true_type { };
|
|
||||||
template <> struct has_scalar_op<vector> : public std::true_type { };
|
template <> struct has_scalar_op<vector> : public std::true_type { };
|
||||||
|
|
||||||
template <template <size_t,typename> class K>
|
template <template <size_t,typename> class K>
|
||||||
@ -84,7 +82,6 @@ namespace util {
|
|||||||
template <size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
|
template <size_t S, typename T> struct is_coord<extent<S,T>> : std::true_type { };
|
||||||
template <size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
|
template <size_t S, typename T> struct is_coord<vector<S,T>> : std::true_type { };
|
||||||
template <size_t S, typename T> struct is_coord<colour<S,T>> : std::true_type { };
|
template <size_t S, typename T> struct is_coord<colour<S,T>> : std::true_type { };
|
||||||
template <size_t S, typename T> struct is_coord<quaternion<S,T>> : std::true_type { };
|
|
||||||
|
|
||||||
template <class K>
|
template <class K>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
|
127
quaternion.cpp
127
quaternion.cpp
@ -11,7 +11,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -22,19 +22,15 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
using util::quaternion;
|
using util::quaternion;
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template<> const quaternion<4, float> quaternion<4, float>::IDENTITY = { 1, 0, 0, 0 };
|
|
||||||
template<> const quaternion<4, double> quaternion<4, double>::IDENTITY = { 1, 0, 0, 0 };
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
quaternion<S,T>::angle_axis (const T radians, const vector<3,T> axis)
|
quaternion<T>::angle_axis (const T radians, const vector<3,T> axis)
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (axis));
|
CHECK (is_normalised (axis));
|
||||||
|
|
||||||
@ -48,9 +44,9 @@ quaternion<S,T>::angle_axis (const T radians, const vector<3,T> axis)
|
|||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
quaternion<S,T>::from_euler (vector<3,T> angles)
|
quaternion<T>::from_euler (vector<3,T> angles)
|
||||||
{
|
{
|
||||||
auto half = angles / 2;
|
auto half = angles / 2;
|
||||||
|
|
||||||
@ -69,9 +65,9 @@ quaternion<S,T>::from_euler (vector<3,T> angles)
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// vector-to-vector rotation algorithm from:
|
// vector-to-vector rotation algorithm from:
|
||||||
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
quaternion<S,T>::from_to (const vector<3,T> u, const vector<3,T> v)
|
quaternion<T>::from_to (const vector<3,T> u, const vector<3,T> v)
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (u));
|
CHECK (is_normalised (u));
|
||||||
CHECK (is_normalised (v));
|
CHECK (is_normalised (v));
|
||||||
@ -103,28 +99,24 @@ quaternion<S,T>::from_to (const vector<3,T> u, const vector<3,T> v)
|
|||||||
w = cross(u, v);
|
w = cross(u, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalised (util::quaternion<4,T> (real_part, w.x, w.y, w.z));
|
return normalised (util::quaternion<T> {real_part, w.x, w.y, w.z});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
quaternion<4,T>
|
quaternion<T>
|
||||||
util::conjugate (quaternion<4,T> q)
|
util::conjugate (quaternion<T> q)
|
||||||
{
|
{
|
||||||
return { q.w, -q.x, -q.y, -q.z };
|
return { q.w, -q.x, -q.y, -q.z };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template quaternion<4,float> util::conjugate (quaternion<4,float>);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
util::operator* (const quaternion<S,T> a, const quaternion<S,T> b)
|
util::operator* (const quaternion<T> a, const quaternion<T> b)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
|
||||||
@ -134,18 +126,16 @@ util::operator* (const quaternion<S,T> a, const quaternion<S,T> b)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template quaternion<4,float> util::operator* (quaternion<4,float>, quaternion<4,float>);
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
util::operator/ (const quaternion<S,T> a, const quaternion<S,T> b)
|
util::operator/ (const quaternion<T> a, const quaternion<T> b)
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (a));
|
CHECK (is_normalised (a));
|
||||||
CHECK (is_normalised (b));
|
CHECK (is_normalised (b));
|
||||||
|
|
||||||
return quaternion<S,T> {
|
return quaternion<T> {
|
||||||
a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z,
|
a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z,
|
||||||
- a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
- a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
|
||||||
- a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
- a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
|
||||||
@ -153,13 +143,11 @@ util::operator/ (const quaternion<S,T> a, const quaternion<S,T> b)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template quaternion<4,float> util::operator/ (quaternion<4,float>, quaternion<4,float>);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
util::matrix4<T>
|
util::matrix4<T>
|
||||||
quaternion<S, T>::as_matrix (void) const
|
quaternion<T>::as_matrix (void) const
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (*this));
|
CHECK (is_normalised (*this));
|
||||||
|
|
||||||
@ -180,13 +168,13 @@ quaternion<S, T>::as_matrix (void) const
|
|||||||
// https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion
|
// https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion
|
||||||
template <typename T>
|
template <typename T>
|
||||||
util::vector3<T>
|
util::vector3<T>
|
||||||
util::rotate (vector3<T> v, quaternion<4,T> q)
|
util::rotate (vector3<T> v, quaternion<T> q)
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (v));
|
CHECK (is_normalised (v));
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Naive:
|
// Naive:
|
||||||
quaternion<4,T> p { 0, v.x, v.y, v.z };
|
quaternion<T> p { 0, v.x, v.y, v.z };
|
||||||
auto p_ = q * p * conjugate (q);
|
auto p_ = q * p * conjugate (q);
|
||||||
return { p_.x, p_.y, p_.z };
|
return { p_.x, p_.y, p_.z };
|
||||||
#else
|
#else
|
||||||
@ -196,17 +184,12 @@ util::rotate (vector3<T> v, quaternion<4,T> q)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template util::vector3f util::rotate (util::vector3f, util::quaternionf);
|
|
||||||
template util::vector3d util::rotate (util::vector3d, util::quaterniond);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// based on the implementation at:
|
// based on the implementation at:
|
||||||
// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/
|
// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
quaternion<S,T>
|
quaternion<T>
|
||||||
quaternion<S,T>::look (vector<3,T> fwd, vector<3,T> up)
|
quaternion<T>::look (vector<3,T> fwd, vector<3,T> up)
|
||||||
{
|
{
|
||||||
CHECK (is_normalised (fwd));
|
CHECK (is_normalised (fwd));
|
||||||
CHECK (is_normalised (up));
|
CHECK (is_normalised (up));
|
||||||
@ -232,36 +215,50 @@ quaternion<S,T>::look (vector<3,T> fwd, vector<3,T> up)
|
|||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
|
bool
|
||||||
|
util::almost_equal (quaternion<T> a, quaternion<T> b)
|
||||||
|
{
|
||||||
|
return almost_equal (a.w, b.w) &&
|
||||||
|
almost_equal (a.x, b.x) &&
|
||||||
|
almost_equal (a.y, b.y) &&
|
||||||
|
almost_equal (a.z, b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
util::operator<< (std::ostream &os, const quaternion<S,T> q)
|
util::operator<< (std::ostream &os, const quaternion<T> q)
|
||||||
{
|
{
|
||||||
return os << "[" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << "]";
|
return os << "[" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template std::ostream& util::operator<< (std::ostream&, quaternion<4,float>);
|
|
||||||
template std::ostream& util::operator<< (std::ostream&, quaternion<4,double>);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
namespace util { namespace debug {
|
namespace util::debug {
|
||||||
template <size_t S, typename T>
|
template <typename T>
|
||||||
struct validator<quaternion<S,T>> {
|
struct validator<quaternion<T>> {
|
||||||
static bool is_valid (const quaternion<S,T> &q)
|
static constexpr
|
||||||
|
bool
|
||||||
|
is_valid (const quaternion<T> &q)
|
||||||
{
|
{
|
||||||
return is_normalised (q);
|
return is_normalised (q);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} }
|
}
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
template bool util::debug::is_valid(const quaternion<4,float>&);
|
|
||||||
template bool util::debug::is_valid(const quaternion<4,double>&);
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
template struct util::quaternion<4,float>;
|
#define INSTANTIATE(T) \
|
||||||
template struct util::quaternion<4,double>;
|
template util::vector3<T> util::rotate (util::vector3<T>, util::quaternion<T>); \
|
||||||
|
template quaternion<T> util::conjugate (quaternion<T>); \
|
||||||
|
template quaternion<T> util::operator* (quaternion<T>, quaternion<T>); \
|
||||||
|
template quaternion<T> util::operator/ (quaternion<T>, quaternion<T>); \
|
||||||
|
template bool util::almost_equal (util::quaternion<T>, util::quaternion<T>); \
|
||||||
|
template std::ostream& util::operator<< (std::ostream&, quaternion<T>); \
|
||||||
|
template bool util::debug::is_valid(const quaternion<T>&); \
|
||||||
|
template struct util::quaternion<T>;
|
||||||
|
|
||||||
|
INSTANTIATE(float)
|
||||||
|
INSTANTIATE(double)
|
||||||
|
110
quaternion.hpp
110
quaternion.hpp
@ -11,7 +11,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*
|
*
|
||||||
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UTIL_QUATERNION_HPP
|
#ifndef __UTIL_QUATERNION_HPP
|
||||||
@ -26,20 +26,17 @@
|
|||||||
|
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
// quaternions must be 4 elements, but we include a size parameter so it
|
// quaternion's are _just_ different enough to other coord types that we
|
||||||
// fits with the generic coord infrastructure more easily.
|
// special case as a distinct POD type and provide many of the same
|
||||||
|
// functions as distinct declarations.
|
||||||
//
|
//
|
||||||
// specifically:
|
// issues include:
|
||||||
// large regions of base code require a template template parameter with
|
// * strictly 4 dimensions
|
||||||
// size and type arguments, which is annoying to work around for this one
|
// * scalar operations sometimes don't make sense on the w component
|
||||||
// case.
|
// * objects must be normalised to make sense
|
||||||
//
|
template <typename T>
|
||||||
// we protect against invalid instantiations through static_assert
|
struct quaternion {
|
||||||
template <size_t S, typename T>
|
T w, x, y, z;
|
||||||
struct quaternion : public coord::base<4,T,quaternion,coord::wxyz,coord::abcd> {
|
|
||||||
static_assert (S == 4, "quaternions must be 4 elements");
|
|
||||||
|
|
||||||
using coord::base<S,T,::util::quaternion,::util::coord::wxyz,::util::coord::abcd>::base;
|
|
||||||
|
|
||||||
static quaternion angle_axis (T radians, vector<3,T> axis);
|
static quaternion angle_axis (T radians, vector<3,T> axis);
|
||||||
static quaternion from_euler (vector<3,T>);
|
static quaternion from_euler (vector<3,T>);
|
||||||
@ -49,32 +46,81 @@ namespace util {
|
|||||||
|
|
||||||
matrix4<T> as_matrix (void) const;
|
matrix4<T> as_matrix (void) const;
|
||||||
|
|
||||||
static const quaternion IDENTITY;
|
static constexpr quaternion<T> identity (void);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
quaternion<4,T>
|
|
||||||
conjugate (quaternion<4,T>);
|
|
||||||
|
|
||||||
template <size_t S, typename T>
|
|
||||||
quaternion<S,T>
|
|
||||||
operator* (const quaternion<S,T>, const quaternion<S,T>);
|
|
||||||
|
|
||||||
template <size_t S, typename T>
|
|
||||||
quaternion<S,T>
|
|
||||||
operator/ (const quaternion<S,T>, const quaternion<S,T>);
|
|
||||||
|
|
||||||
typedef quaternion<4,float> quaternionf;
|
|
||||||
typedef quaternion<4,double> quaterniond;
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
template <typename T>
|
template <typename T>
|
||||||
vector3<T>
|
vector3<T>
|
||||||
rotate (vector3<T>, quaternion<4,T>);
|
rotate (vector3<T>, quaternion<T>);
|
||||||
|
|
||||||
template <size_t S, typename T>
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
T
|
||||||
|
norm2 (quaternion<T>);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
T
|
||||||
|
norm (quaternion<T>);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
bool
|
||||||
|
is_normalised (quaternion<T>);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
quaternion<T>
|
||||||
|
normalised (quaternion<T>);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
quaternion<T>
|
||||||
|
conjugate (quaternion<T>);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
quaternion<T>
|
||||||
|
operator* (quaternion<T>, quaternion<T>);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
quaternion<T>
|
||||||
|
operator/ (quaternion<T>, quaternion<T>);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
quaternion<T>
|
||||||
|
operator/ (quaternion<T>, T);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
bool operator== (quaternion<T>, quaternion<T>);
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
bool almost_equal (quaternion<T>, quaternion<T>);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
typedef quaternion<float> quaternionf;
|
||||||
|
typedef quaternion<double> quaterniond;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
std::ostream&
|
std::ostream&
|
||||||
operator<< (std::ostream&, quaternion<S,T>);
|
operator<< (std::ostream&, quaternion<T>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "./quaternion.ipp"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
99
quaternion.ipp
Normal file
99
quaternion.ipp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* Copyright 2011-2016 Danny Robson <danny@nerdcruft.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(CRUFT_UTIL_QUATERNION_IPP)
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CRUFT_UTIL_QUATERNION_IPP
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
util::quaternion<T>
|
||||||
|
util::quaternion<T>::identity (void)
|
||||||
|
{
|
||||||
|
return { 1, 0, 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
T
|
||||||
|
util::norm2 (quaternion<T> q)
|
||||||
|
{
|
||||||
|
return q.w * q.w +
|
||||||
|
q.x * q.x +
|
||||||
|
q.y * q.y +
|
||||||
|
q.z * q.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
T
|
||||||
|
util::norm (quaternion<T> q)
|
||||||
|
{
|
||||||
|
return std::sqrt (norm2 (q));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
bool
|
||||||
|
util::is_normalised (quaternion<T> q)
|
||||||
|
{
|
||||||
|
return almost_equal (T{1}, norm2 (q));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
util::quaternion<T>
|
||||||
|
util::normalised (quaternion<T> q)
|
||||||
|
{
|
||||||
|
return q / norm (q);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
util::quaternion<T>
|
||||||
|
util::operator/ (quaternion<T> q, T t)
|
||||||
|
{
|
||||||
|
return { q.w / t, q.x / t, q.y / t, q.z / t };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
template <typename T>
|
||||||
|
constexpr
|
||||||
|
bool
|
||||||
|
util::operator== (quaternion<T> a, quaternion<T> b)
|
||||||
|
{
|
||||||
|
return exactly_equal (a.w, b.w) &&
|
||||||
|
exactly_equal (a.x, b.x) &&
|
||||||
|
exactly_equal (a.y, b.y) &&
|
||||||
|
exactly_equal (a.z, b.z);
|
||||||
|
}
|
@ -17,22 +17,22 @@ main (void)
|
|||||||
|
|
||||||
// identity relations
|
// identity relations
|
||||||
tap.expect_eq (
|
tap.expect_eq (
|
||||||
norm (quaternionf::IDENTITY), 1.f,
|
norm (quaternionf::identity ()), 1.f,
|
||||||
"identity magnitude is unit"
|
"identity magnitude is unit"
|
||||||
);
|
);
|
||||||
|
|
||||||
tap.expect_eq (
|
tap.expect_eq (
|
||||||
quaternionf::IDENTITY * quaternionf::IDENTITY,
|
quaternionf::identity () * quaternionf::identity (),
|
||||||
quaternionf::IDENTITY,
|
quaternionf::identity (),
|
||||||
"identity multiplication with identity"
|
"identity multiplication with identity"
|
||||||
);
|
);
|
||||||
|
|
||||||
// normalisation
|
// normalisation
|
||||||
{
|
{
|
||||||
auto val = normalised (quaternionf (2, 3, 4, 7));
|
auto val = normalised (quaternionf {2, 3, 4, 7});
|
||||||
|
|
||||||
tap.expect_eq (
|
tap.expect_eq (
|
||||||
val * quaternionf::IDENTITY,
|
val * quaternionf::identity (),
|
||||||
val,
|
val,
|
||||||
"identity multiplication with quaternion constant"
|
"identity multiplication with quaternion constant"
|
||||||
);
|
);
|
||||||
@ -47,9 +47,11 @@ main (void)
|
|||||||
// towards rotations than general maths).
|
// towards rotations than general maths).
|
||||||
util::vector4f a_v { 2, -11, 5, -17};
|
util::vector4f a_v { 2, -11, 5, -17};
|
||||||
util::vector4f b_v { 3, 13, -7, -19};
|
util::vector4f b_v { 3, 13, -7, -19};
|
||||||
|
a_v = normalised (a_v);
|
||||||
|
b_v = normalised (b_v);
|
||||||
|
|
||||||
auto a = normalised (a_v).as<quaternion> ();
|
auto a = quaternionf { a_v[0], a_v[1], a_v[2], a_v[3] };
|
||||||
auto b = normalised (b_v).as<quaternion> ();
|
auto b = quaternionf { b_v[0], b_v[1], b_v[2], b_v[3] };
|
||||||
auto c = quaternionf {
|
auto c = quaternionf {
|
||||||
-0.27358657116960006f,
|
-0.27358657116960006f,
|
||||||
-0.43498209092420004f,
|
-0.43498209092420004f,
|
||||||
@ -62,7 +64,7 @@ main (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tap.expect_eq (
|
tap.expect_eq (
|
||||||
quaternionf::IDENTITY.as_matrix (),
|
quaternionf::identity ().as_matrix (),
|
||||||
util::matrix4f::IDENTITY,
|
util::matrix4f::IDENTITY,
|
||||||
"identity quaternion to matrix"
|
"identity quaternion to matrix"
|
||||||
);
|
);
|
||||||
@ -90,7 +92,7 @@ main (void)
|
|||||||
tap.expect_lt (util::sum (diff), 1e-6f, "single basis rotation %zu", i);
|
tap.expect_lt (util::sum (diff), 1e-6f, "single basis rotation %zu", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto q = quaternionf::IDENTITY;
|
auto q = quaternionf::identity ();
|
||||||
auto m = util::matrix4f::IDENTITY;
|
auto m = util::matrix4f::IDENTITY;
|
||||||
|
|
||||||
for (auto r: ROTATIONS) {
|
for (auto r: ROTATIONS) {
|
||||||
|
Loading…
Reference in New Issue
Block a user