/* * Copyright 2013 The Android Open Source Project * * 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. */ #pragma once #include #include #include #include #include #define PURE __attribute__((pure)) namespace android { namespace details { // ------------------------------------------------------------------------------------- /* * No user serviceable parts here. * * Don't use this file directly, instead include ui/quat.h */ /* * TQuatProductOperators implements basic arithmetic and basic compound assignment * operators on a quaternion of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TQuatProductOperators BASE will automatically * get all the functionality here. */ template class QUATERNION, typename T> class TQuatProductOperators { public: /* compound assignment from a another quaternion of the same size but different * element type. */ template QUATERNION& operator *= (const QUATERNION& r) { QUATERNION& q = static_cast&>(*this); q = q * r; return q; } /* compound assignment products by a scalar */ QUATERNION& operator *= (T v) { QUATERNION& lhs = static_cast&>(*this); for (size_t i = 0; i < QUATERNION::size(); i++) { lhs[i] *= v; } return lhs; } QUATERNION& operator /= (T v) { QUATERNION& lhs = static_cast&>(*this); for (size_t i = 0; i < QUATERNION::size(); i++) { lhs[i] /= v; } return lhs; } /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ /* The operators below handle operation between quaternion of the same size * but of a different element type. */ template friend inline constexpr QUATERNION PURE operator *(const QUATERNION& q, const QUATERNION& r) { // could be written as: // return QUATERNION( // q.w*r.w - dot(q.xyz, r.xyz), // q.w*r.xyz + r.w*q.xyz + cross(q.xyz, r.xyz)); return QUATERNION( q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z, q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y, q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x, q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w); } template friend inline constexpr TVec3 PURE operator *(const QUATERNION& q, const TVec3& v) { // note: if q is known to be a unit quaternion, then this simplifies to: // TVec3 t = 2 * cross(q.xyz, v) // return v + (q.w * t) + cross(q.xyz, t) return imaginary(q * QUATERNION(v, 0) * inverse(q)); } /* For quaternions, we use explicit "by a scalar" products because it's much faster * than going (implicitly) through the quaternion multiplication. * For reference: we could use the code below instead, but it would be a lot slower. * friend inline * constexpr BASE PURE operator *(const BASE& q, const BASE& r) { * return BASE( * q.w*r.w - q.x*r.x - q.y*r.y - q.z*r.z, * q.w*r.x + q.x*r.w + q.y*r.z - q.z*r.y, * q.w*r.y - q.x*r.z + q.y*r.w + q.z*r.x, * q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w); * */ friend inline constexpr QUATERNION PURE operator *(QUATERNION q, T scalar) { // don't pass q by reference because we need a copy anyways return q *= scalar; } friend inline constexpr QUATERNION PURE operator *(T scalar, QUATERNION q) { // don't pass q by reference because we need a copy anyways return q *= scalar; } friend inline constexpr QUATERNION PURE operator /(QUATERNION q, T scalar) { // don't pass q by reference because we need a copy anyways return q /= scalar; } }; /* * TQuatFunctions implements functions on a quaternion of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TQuatFunctions BASE will automatically * get all the functionality here. */ template class QUATERNION, typename T> class TQuatFunctions { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline constexpr T PURE dot(const QUATERNION& p, const QUATERNION& q) { return p.x * q.x + p.y * q.y + p.z * q.z + p.w * q.w; } friend inline constexpr T PURE norm(const QUATERNION& q) { return std::sqrt( dot(q, q) ); } friend inline constexpr T PURE length(const QUATERNION& q) { return norm(q); } friend inline constexpr T PURE length2(const QUATERNION& q) { return dot(q, q); } friend inline constexpr QUATERNION PURE normalize(const QUATERNION& q) { return length(q) ? q / length(q) : QUATERNION(1); } friend inline constexpr QUATERNION PURE conj(const QUATERNION& q) { return QUATERNION(q.w, -q.x, -q.y, -q.z); } friend inline constexpr QUATERNION PURE inverse(const QUATERNION& q) { return conj(q) * (1 / dot(q, q)); } friend inline constexpr T PURE real(const QUATERNION& q) { return q.w; } friend inline constexpr TVec3 PURE imaginary(const QUATERNION& q) { return q.xyz; } friend inline constexpr QUATERNION PURE unreal(const QUATERNION& q) { return QUATERNION(q.xyz, 0); } friend inline constexpr QUATERNION PURE cross(const QUATERNION& p, const QUATERNION& q) { return unreal(p*q); } friend inline QUATERNION PURE exp(const QUATERNION& q) { const T nq(norm(q.xyz)); return std::exp(q.w)*QUATERNION((sin(nq)/nq)*q.xyz, cos(nq)); } friend inline QUATERNION PURE log(const QUATERNION& q) { const T nq(norm(q)); return QUATERNION((std::acos(q.w/nq)/norm(q.xyz))*q.xyz, log(nq)); } friend inline QUATERNION PURE pow(const QUATERNION& q, T a) { // could also be computed as: exp(a*log(q)); const T nq(norm(q)); const T theta(a*std::acos(q.w / nq)); return std::pow(nq, a) * QUATERNION(normalize(q.xyz) * std::sin(theta), std::cos(theta)); } friend inline QUATERNION PURE slerp(const QUATERNION& p, const QUATERNION& q, T t) { // could also be computed as: pow(q * inverse(p), t) * p; const T d = dot(p, q); const T npq = sqrt(dot(p, p) * dot(q, q)); // ||p|| * ||q|| const T a = std::acos(std::abs(d) / npq); const T a0 = a * (1 - t); const T a1 = a * t; const T isina = 1 / sin(a); const T s0 = std::sin(a0) * isina; const T s1 = std::sin(a1) * isina; // ensure we're taking the "short" side return normalize(s0 * p + ((d < 0) ? (-s1) : (s1)) * q); } friend inline constexpr QUATERNION PURE lerp(const QUATERNION& p, const QUATERNION& q, T t) { return ((1 - t) * p) + (t * q); } friend inline constexpr QUATERNION PURE nlerp(const QUATERNION& p, const QUATERNION& q, T t) { return normalize(lerp(p, q, t)); } friend inline constexpr QUATERNION PURE positive(const QUATERNION& q) { return q.w < 0 ? -q : q; } }; /* * TQuatDebug implements functions on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TQuatDebug BASE will automatically * get all the functionality here. */ template class QUATERNION, typename T> class TQuatDebug { public: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ friend std::ostream& operator<< (std::ostream& stream, const QUATERNION& q) { return stream << "< " << q.w << " + " << q.x << "i + " << q.y << "j + " << q.z << "k >"; } }; #undef PURE // ------------------------------------------------------------------------------------- } // namespace details } // namespace android