| 1 | /// @ref gtx_dual_quaternion |
| 2 | |
| 3 | #include "../geometric.hpp" |
| 4 | #include <limits> |
| 5 | |
| 6 | namespace glm |
| 7 | { |
| 8 | // -- Component accesses -- |
| 9 | |
| 10 | template<typename T, qualifier Q> |
| 11 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename tdualquat<T, Q>::part_type & tdualquat<T, Q>::operator[](typename tdualquat<T, Q>::length_type i) noexcept |
| 12 | { |
| 13 | assert(i >= 0 && i < this->length()); |
| 14 | return (&real)[i]; |
| 15 | } |
| 16 | |
| 17 | template<typename T, qualifier Q> |
| 18 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR typename tdualquat<T, Q>::part_type const& tdualquat<T, Q>::operator[](typename tdualquat<T, Q>::length_type i) const noexcept |
| 19 | { |
| 20 | assert(i >= 0 && i < this->length()); |
| 21 | return (&real)[i]; |
| 22 | } |
| 23 | |
| 24 | // -- Implicit basic constructors -- |
| 25 | |
| 26 | # if GLM_CONFIG_CTOR_INIT == GLM_ENABLE |
| 27 | template<typename T, qualifier Q> |
| 28 | GLM_DEFAULTED_DEFAULT_CTOR_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat() |
| 29 | : real(qua<T, Q>()) |
| 30 | , dual(qua<T, Q>::wxyz(0, 0, 0, 0)) |
| 31 | {} |
| 32 | # endif |
| 33 | |
| 34 | template<typename T, qualifier Q> |
| 35 | template<qualifier P> |
| 36 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(tdualquat<T, P> const& d) |
| 37 | : real(d.real) |
| 38 | , dual(d.dual) |
| 39 | {} |
| 40 | |
| 41 | // -- Explicit basic constructors -- |
| 42 | |
| 43 | template<typename T, qualifier Q> |
| 44 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& r) |
| 45 | : real(r), dual(qua<T, Q>::wxyz(0, 0, 0, 0)) |
| 46 | {} |
| 47 | |
| 48 | template<typename T, qualifier Q> |
| 49 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& q, vec<3, T, Q> const& p) |
| 50 | : real(q), dual(qua<T, Q>::wxyz( |
| 51 | T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z), |
| 52 | T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y), |
| 53 | T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x), |
| 54 | T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w))) |
| 55 | {} |
| 56 | |
| 57 | template<typename T, qualifier Q> |
| 58 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& r, qua<T, Q> const& d) |
| 59 | : real(r), dual(d) |
| 60 | {} |
| 61 | |
| 62 | // -- Conversion constructors -- |
| 63 | |
| 64 | template<typename T, qualifier Q> |
| 65 | template<typename U, qualifier P> |
| 66 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(tdualquat<U, P> const& q) |
| 67 | : real(q.real) |
| 68 | , dual(q.dual) |
| 69 | {} |
| 70 | |
| 71 | template<typename T, qualifier Q> |
| 72 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(mat<2, 4, T, Q> const& m) |
| 73 | { |
| 74 | *this = dualquat_cast(m); |
| 75 | } |
| 76 | |
| 77 | template<typename T, qualifier Q> |
| 78 | GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(mat<3, 4, T, Q> const& m) |
| 79 | { |
| 80 | *this = dualquat_cast(m); |
| 81 | } |
| 82 | |
| 83 | // -- Unary arithmetic operators -- |
| 84 | |
| 85 | template<typename T, qualifier Q> |
| 86 | template<typename U> |
| 87 | GLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator=(tdualquat<U, Q> const& q) |
| 88 | { |
| 89 | this->real = q.real; |
| 90 | this->dual = q.dual; |
| 91 | return *this; |
| 92 | } |
| 93 | |
| 94 | template<typename T, qualifier Q> |
| 95 | template<typename U> |
| 96 | GLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator*=(U s) |
| 97 | { |
| 98 | this->real *= static_cast<T>(s); |
| 99 | this->dual *= static_cast<T>(s); |
| 100 | return *this; |
| 101 | } |
| 102 | |
| 103 | template<typename T, qualifier Q> |
| 104 | template<typename U> |
| 105 | GLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator/=(U s) |
| 106 | { |
| 107 | this->real /= static_cast<T>(s); |
| 108 | this->dual /= static_cast<T>(s); |
| 109 | return *this; |
| 110 | } |
| 111 | |
| 112 | // -- Unary bit operators -- |
| 113 | |
| 114 | template<typename T, qualifier Q> |
| 115 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator+(tdualquat<T, Q> const& q) |
| 116 | { |
| 117 | return q; |
| 118 | } |
| 119 | |
| 120 | template<typename T, qualifier Q> |
| 121 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator-(tdualquat<T, Q> const& q) |
| 122 | { |
| 123 | return tdualquat<T, Q>(-q.real, -q.dual); |
| 124 | } |
| 125 | |
| 126 | // -- Binary operators -- |
| 127 | |
| 128 | template<typename T, qualifier Q> |
| 129 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator+(tdualquat<T, Q> const& q, tdualquat<T, Q> const& p) |
| 130 | { |
| 131 | return tdualquat<T, Q>(q.real + p.real,q.dual + p.dual); |
| 132 | } |
| 133 | |
| 134 | template<typename T, qualifier Q> |
| 135 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(tdualquat<T, Q> const& p, tdualquat<T, Q> const& o) |
| 136 | { |
| 137 | return tdualquat<T, Q>(p.real * o.real,p.real * o.dual + p.dual * o.real); |
| 138 | } |
| 139 | |
| 140 | template<typename T, qualifier Q> |
| 141 | GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat<T, Q> const& q, vec<3, T, Q> const& v) |
| 142 | { |
| 143 | vec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z); |
| 144 | vec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z); |
| 145 | return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v; |
| 146 | } |
| 147 | |
| 148 | template<typename T, qualifier Q> |
| 149 | GLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat<T, Q> const& q) |
| 150 | { |
| 151 | return glm::inverse(q) * v; |
| 152 | } |
| 153 | |
| 154 | template<typename T, qualifier Q> |
| 155 | GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat<T, Q> const& q, vec<4, T, Q> const& v) |
| 156 | { |
| 157 | return vec<4, T, Q>(q * vec<3, T, Q>(v), v.w); |
| 158 | } |
| 159 | |
| 160 | template<typename T, qualifier Q> |
| 161 | GLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat<T, Q> const& q) |
| 162 | { |
| 163 | return glm::inverse(q) * v; |
| 164 | } |
| 165 | |
| 166 | template<typename T, qualifier Q> |
| 167 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(tdualquat<T, Q> const& q, T const& s) |
| 168 | { |
| 169 | return tdualquat<T, Q>(q.real * s, q.dual * s); |
| 170 | } |
| 171 | |
| 172 | template<typename T, qualifier Q> |
| 173 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(T const& s, tdualquat<T, Q> const& q) |
| 174 | { |
| 175 | return q * s; |
| 176 | } |
| 177 | |
| 178 | template<typename T, qualifier Q> |
| 179 | GLM_FUNC_QUALIFIER tdualquat<T, Q> operator/(tdualquat<T, Q> const& q, T const& s) |
| 180 | { |
| 181 | return tdualquat<T, Q>(q.real / s, q.dual / s); |
| 182 | } |
| 183 | |
| 184 | // -- Boolean operators -- |
| 185 | |
| 186 | template<typename T, qualifier Q> |
| 187 | GLM_FUNC_QUALIFIER bool operator==(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2) |
| 188 | { |
| 189 | return (q1.real == q2.real) && (q1.dual == q2.dual); |
| 190 | } |
| 191 | |
| 192 | template<typename T, qualifier Q> |
| 193 | GLM_FUNC_QUALIFIER bool operator!=(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2) |
| 194 | { |
| 195 | return (q1.real != q2.real) || (q1.dual != q2.dual); |
| 196 | } |
| 197 | |
| 198 | // -- Operations -- |
| 199 | |
| 200 | template<typename T, qualifier Q> |
| 201 | GLM_FUNC_QUALIFIER tdualquat<T, Q> dual_quat_identity() |
| 202 | { |
| 203 | return tdualquat<T, Q>( |
| 204 | qua<T, Q>::wxyz(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0)), |
| 205 | qua<T, Q>::wxyz(static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0))); |
| 206 | } |
| 207 | |
| 208 | template<typename T, qualifier Q> |
| 209 | GLM_FUNC_QUALIFIER tdualquat<T, Q> normalize(tdualquat<T, Q> const& q) |
| 210 | { |
| 211 | return q / length(q.real); |
| 212 | } |
| 213 | |
| 214 | template<typename T, qualifier Q> |
| 215 | GLM_FUNC_QUALIFIER tdualquat<T, Q> lerp(tdualquat<T, Q> const& x, tdualquat<T, Q> const& y, T const& a) |
| 216 | { |
| 217 | // Dual Quaternion Linear blend aka DLB: |
| 218 | // Lerp is only defined in [0, 1] |
| 219 | assert(a >= static_cast<T>(0)); |
| 220 | assert(a <= static_cast<T>(1)); |
| 221 | T const k = dot(x.real,y.real) < static_cast<T>(0) ? -a : a; |
| 222 | T const one(1); |
| 223 | return tdualquat<T, Q>(x * (one - a) + y * k); |
| 224 | } |
| 225 | |
| 226 | template<typename T, qualifier Q> |
| 227 | GLM_FUNC_QUALIFIER tdualquat<T, Q> inverse(tdualquat<T, Q> const& q) |
| 228 | { |
| 229 | const glm::qua<T, Q> real = conjugate(q.real); |
| 230 | const glm::qua<T, Q> dual = conjugate(q.dual); |
| 231 | return tdualquat<T, Q>(real, dual + (real * (-2.0f * dot(real,dual)))); |
| 232 | } |
| 233 | |
| 234 | template<typename T, qualifier Q> |
| 235 | GLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat<T, Q> const& x) |
| 236 | { |
| 237 | return mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w ); |
| 238 | } |
| 239 | |
| 240 | template<typename T, qualifier Q> |
| 241 | GLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat<T, Q> const& x) |
| 242 | { |
| 243 | qua<T, Q> r = x.real / length2(x.real); |
| 244 | |
| 245 | qua<T, Q> const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z); |
| 246 | r *= static_cast<T>(2); |
| 247 | |
| 248 | T const xy = r.x * x.real.y; |
| 249 | T const xz = r.x * x.real.z; |
| 250 | T const yz = r.y * x.real.z; |
| 251 | T const wx = r.w * x.real.x; |
| 252 | T const wy = r.w * x.real.y; |
| 253 | T const wz = r.w * x.real.z; |
| 254 | |
| 255 | vec<4, T, Q> const a( |
| 256 | rr.w + rr.x - rr.y - rr.z, |
| 257 | xy - wz, |
| 258 | xz + wy, |
| 259 | -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y)); |
| 260 | |
| 261 | vec<4, T, Q> const b( |
| 262 | xy + wz, |
| 263 | rr.w + rr.y - rr.x - rr.z, |
| 264 | yz - wx, |
| 265 | -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x)); |
| 266 | |
| 267 | vec<4, T, Q> const c( |
| 268 | xz - wy, |
| 269 | yz + wx, |
| 270 | rr.w + rr.z - rr.x - rr.y, |
| 271 | -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w)); |
| 272 | |
| 273 | return mat<3, 4, T, Q>(a, b, c); |
| 274 | } |
| 275 | |
| 276 | template<typename T, qualifier Q> |
| 277 | GLM_FUNC_QUALIFIER tdualquat<T, Q> dualquat_cast(mat<2, 4, T, Q> const& x) |
| 278 | { |
| 279 | return tdualquat<T, Q>( |
| 280 | qua<T, Q>::wxyz( x[0].w, x[0].x, x[0].y, x[0].z ), |
| 281 | qua<T, Q>::wxyz( x[1].w, x[1].x, x[1].y, x[1].z )); |
| 282 | } |
| 283 | |
| 284 | template<typename T, qualifier Q> |
| 285 | GLM_FUNC_QUALIFIER tdualquat<T, Q> dualquat_cast(mat<3, 4, T, Q> const& x) |
| 286 | { |
| 287 | qua<T, Q> real; |
| 288 | |
| 289 | T const trace = x[0].x + x[1].y + x[2].z; |
| 290 | if(trace > static_cast<T>(0)) |
| 291 | { |
| 292 | T const r = sqrt(T(1) + trace); |
| 293 | T const invr = static_cast<T>(0.5) / r; |
| 294 | real.w = static_cast<T>(0.5) * r; |
| 295 | real.x = (x[2].y - x[1].z) * invr; |
| 296 | real.y = (x[0].z - x[2].x) * invr; |
| 297 | real.z = (x[1].x - x[0].y) * invr; |
| 298 | } |
| 299 | else if(x[0].x > x[1].y && x[0].x > x[2].z) |
| 300 | { |
| 301 | T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z); |
| 302 | T const invr = static_cast<T>(0.5) / r; |
| 303 | real.x = static_cast<T>(0.5)*r; |
| 304 | real.y = (x[1].x + x[0].y) * invr; |
| 305 | real.z = (x[0].z + x[2].x) * invr; |
| 306 | real.w = (x[2].y - x[1].z) * invr; |
| 307 | } |
| 308 | else if(x[1].y > x[2].z) |
| 309 | { |
| 310 | T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z); |
| 311 | T const invr = static_cast<T>(0.5) / r; |
| 312 | real.x = (x[1].x + x[0].y) * invr; |
| 313 | real.y = static_cast<T>(0.5) * r; |
| 314 | real.z = (x[2].y + x[1].z) * invr; |
| 315 | real.w = (x[0].z - x[2].x) * invr; |
| 316 | } |
| 317 | else |
| 318 | { |
| 319 | T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y); |
| 320 | T const invr = static_cast<T>(0.5) / r; |
| 321 | real.x = (x[0].z + x[2].x) * invr; |
| 322 | real.y = (x[2].y + x[1].z) * invr; |
| 323 | real.z = static_cast<T>(0.5) * r; |
| 324 | real.w = (x[1].x - x[0].y) * invr; |
| 325 | } |
| 326 | |
| 327 | qua<T, Q> dual; |
| 328 | dual.x = static_cast<T>(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y); |
| 329 | dual.y = static_cast<T>(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x); |
| 330 | dual.z = static_cast<T>(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w); |
| 331 | dual.w = -static_cast<T>(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z); |
| 332 | return tdualquat<T, Q>(real, dual); |
| 333 | } |
| 334 | }//namespace glm |