/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //////////////////////////////////////////////////////////////////////////////// // XMath 1.0 // Vector - Matrix library for 3D visualisation and // physics modeling. // // (C) 1999 KDV Games // Author: Alexandre Kotliar // // //////////////////////////////////////////////////////////////////////////////// #include "qdengine/xmath.h" namespace QDEngine { /////////////////////////////////////////////////////////////////////////////// // // Constants // /////////////////////////////////////////////////////////////////////////////// const Vect3f Vect3f::ZERO(0, 0, 0); const QuatF QuatF::ID(1, 0, 0, 0); const QuatD QuatD::ID(1, 0, 0, 0); /////////////////////////////////////////////////////////////////////////////// // // class Vect2f // /////////////////////////////////////////////////////////////////////////////// float Vect2f::angle(const Vect2f &other) const { return acosf(dot(other) * invSqrtFast(norm2() * other.norm2() * 1.0000001f)); } /////////////////////////////////////////////////////////////////////////////// // // class Vect3f // /////////////////////////////////////////////////////////////////////////////// float Vect3f::angle(const Vect3f &other) const { return acosf(dot(other) * invSqrtFast(norm2() * other.norm2() * 1.0000001f)); } /////////////////////////////////////////////////////////////////////////////// // // class Mat3d // /////////////////////////////////////////////////////////////////////////////// Mat3d &Mat3d::set(const Vect3d &axis, double angle, int normalizeAxis) { QuatD q; q.set(angle, axis, normalizeAxis); set(q); return *this; } Mat3d &Mat3d::set(const QuatD &q) { xx = 2.0 * (q.s_ * q.s_ + q.x_ * q.x_ - 0.5); yy = 2.0 * (q.s_ * q.s_ + q.y_ * q.y_ - 0.5); zz = 2.0 * (q.s_ * q.s_ + q.z_ * q.z_ - 0.5); xy = 2.0 * (q.y_ * q.x_ - q.z_ * q.s_); yx = 2.0 * (q.x_ * q.y_ + q.z_ * q.s_); yz = 2.0 * (q.z_ * q.y_ - q.x_ * q.s_); zy = 2.0 * (q.y_ * q.z_ + q.x_ * q.s_); zx = 2.0 * (q.x_ * q.z_ - q.y_ * q.s_); xz = 2.0 * (q.z_ * q.x_ + q.y_ * q.s_); return *this; } Mat3d &Mat3d::set(const Vect3d &x_from, const Vect3d &y_from, const Vect3d &z_from, const Vect3d &x_to, const Vect3d &y_to, const Vect3d &z_to) { xx = dot(x_from, x_to); xy = dot(y_from, x_to); xz = dot(z_from, x_to); yx = dot(x_from, y_to); yy = dot(y_from, y_to); yz = dot(z_from, y_to); zx = dot(x_from, z_to); zy = dot(y_from, z_to); zz = dot(z_from, z_to); return *this; } int Mat3d::invert(const Mat3d &M) { double D, oneOverDet; if (fabs(D = M.det()) < 1.0e-12) return 1; // not invertible oneOverDet = 1 / D; xx = (M.yy * M.zz - M.yz * M.zy) * oneOverDet; xy = (M.xz * M.zy - M.xy * M.zz) * oneOverDet; xz = (M.xy * M.yz - M.xz * M.yy) * oneOverDet; yx = (M.yz * M.zx - M.yx * M.zz) * oneOverDet; yy = (M.xx * M.zz - M.xz * M.zx) * oneOverDet; yz = (M.xz * M.yx - M.xx * M.yz) * oneOverDet; zx = (M.yx * M.zy - M.yy * M.zx) * oneOverDet; zy = (M.xy * M.zx - M.xx * M.zy) * oneOverDet; zz = (M.xx * M.yy - M.xy * M.yx) * oneOverDet; return 0; } int Mat3d::invert() { double D, oneOverDet; double oxy, oyz, ozx, oyx, ozy, oxz, oxx, oyy; if (fabs(D = det()) < 1.0e-12) return 1; // not invertible oneOverDet = 1 / D; oxx = xx; oyy = yy; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = (oxz * ozy - zz * oxy) * oneOverDet; yz = (oxz * oyx - xx * oyz) * oneOverDet; zx = (oyx * ozy - yy * ozx) * oneOverDet; yx = (oyz * ozx - oyx * zz) * oneOverDet; zy = (oxy * ozx - ozy * xx) * oneOverDet; xz = (oxy * oyz - oxz * yy) * oneOverDet; xx = (oyy * zz - oyz * ozy) * oneOverDet; yy = (oxx * zz - oxz * ozx) * oneOverDet; zz = (oxx * oyy - oxy * oyx) * oneOverDet; return 0; } Mat3d &Mat3d::mult(const Mat3d &M, const Mat3d &N) { xx = M.xx * N.xx + M.xy * N.yx + M.xz * N.zx; xy = M.xx * N.xy + M.xy * N.yy + M.xz * N.zy; xz = M.xx * N.xz + M.xy * N.yz + M.xz * N.zz; yx = M.yx * N.xx + M.yy * N.yx + M.yz * N.zx; yy = M.yx * N.xy + M.yy * N.yy + M.yz * N.zy; yz = M.yx * N.xz + M.yy * N.yz + M.yz * N.zz; zx = M.zx * N.xx + M.zy * N.yx + M.zz * N.zx; zy = M.zx * N.xy + M.zy * N.yy + M.zz * N.zy; zz = M.zx * N.xz + M.zy * N.yz + M.zz * N.zz; return *this; } Mat3d &Mat3d::premult(const Mat3d &M) { double oxy, oyz, ozx, oyx, ozy, oxz; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = M.xx * oxy + M.xy * yy + M.xz * ozy; xz = M.xx * oxz + M.xy * oyz + M.xz * zz; yx = M.yx * xx + M.yy * oyx + M.yz * ozx; yz = M.yx * oxz + M.yy * oyz + M.yz * zz; zx = M.zx * xx + M.zy * oyx + M.zz * ozx; zy = M.zx * oxy + M.zy * yy + M.zz * ozy; xx = M.xx * xx + M.xy * oyx + M.xz * ozx; yy = M.yx * oxy + M.yy * yy + M.yz * ozy; zz = M.zx * oxz + M.zy * oyz + M.zz * zz; return *this; } Mat3d &Mat3d::postmult(const Mat3d &M) { double oxy, oyz, ozx, oyx, ozy, oxz; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = xx * M.xy + oxy * M.yy + oxz * M.zy; xz = xx * M.xz + oxy * M.yz + oxz * M.zz; yx = oyx * M.xx + yy * M.yx + oyz * M.zx; yz = oyx * M.xz + yy * M.yz + oyz * M.zz; zx = ozx * M.xx + ozy * M.yx + zz * M.zx; zy = ozx * M.xy + ozy * M.yy + zz * M.zy; xx = xx * M.xx + oxy * M.yx + oxz * M.zx; yy = oyx * M.xy + yy * M.yy + oyz * M.zy; zz = ozx * M.xz + ozy * M.yz + zz * M.zz; return *this; } /////////////////////////////////////////////////////////////////////////////// // // class Mat3f // /////////////////////////////////////////////////////////////////////////////// Mat3f &Mat3f::set(const Vect3f &axis, float angle, int normalizeAxis) { QuatF q; q.set(angle, axis, normalizeAxis); set(q); return *this; } Mat3f &Mat3f::set(const QuatF &q) { xx = 2.f * (q.s_ * q.s_ + q.x_ * q.x_ - 0.5f); yy = 2.f * (q.s_ * q.s_ + q.y_ * q.y_ - 0.5f); zz = 2.f * (q.s_ * q.s_ + q.z_ * q.z_ - 0.5f); xy = 2.f * (q.y_ * q.x_ - q.z_ * q.s_); yx = 2.f * (q.x_ * q.y_ + q.z_ * q.s_); yz = 2.f * (q.z_ * q.y_ - q.x_ * q.s_); zy = 2.f * (q.y_ * q.z_ + q.x_ * q.s_); zx = 2.f * (q.x_ * q.z_ - q.y_ * q.s_); xz = 2.f * (q.z_ * q.x_ + q.y_ * q.s_); return *this; } Mat3f &Mat3f::set(const Vect3f &x_from, const Vect3f &y_from, const Vect3f &z_from, const Vect3f &x_to, const Vect3f &y_to, const Vect3f &z_to) { xx = dot(x_from, x_to); xy = dot(y_from, x_to); xz = dot(z_from, x_to); yx = dot(x_from, y_to); yy = dot(y_from, y_to); yz = dot(z_from, y_to); zx = dot(x_from, z_to); zy = dot(y_from, z_to); zz = dot(z_from, z_to); return *this; } int Mat3f::invert(const Mat3f &M) { float D, oneOverDet; if (fabs(D = M.det()) < 1.0e-12) return 1; // not invertible oneOverDet = 1 / D; xx = (M.yy * M.zz - M.yz * M.zy) * oneOverDet; xy = (M.xz * M.zy - M.xy * M.zz) * oneOverDet; xz = (M.xy * M.yz - M.xz * M.yy) * oneOverDet; yx = (M.yz * M.zx - M.yx * M.zz) * oneOverDet; yy = (M.xx * M.zz - M.xz * M.zx) * oneOverDet; yz = (M.xz * M.yx - M.xx * M.yz) * oneOverDet; zx = (M.yx * M.zy - M.yy * M.zx) * oneOverDet; zy = (M.xy * M.zx - M.xx * M.zy) * oneOverDet; zz = (M.xx * M.yy - M.xy * M.yx) * oneOverDet; return 0; } int Mat3f::invert() { float D, oneOverDet; float oxy, oyz, ozx, oyx, ozy, oxz, oxx, oyy; if (fabs(D = det()) < 1.0e-12) return 1; // not invertible oneOverDet = 1 / D; oxx = xx; oyy = yy; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = (oxz * ozy - zz * oxy) * oneOverDet; yz = (oxz * oyx - xx * oyz) * oneOverDet; zx = (oyx * ozy - yy * ozx) * oneOverDet; yx = (oyz * ozx - oyx * zz) * oneOverDet; zy = (oxy * ozx - ozy * xx) * oneOverDet; xz = (oxy * oyz - oxz * yy) * oneOverDet; xx = (oyy * zz - oyz * ozy) * oneOverDet; yy = (oxx * zz - oxz * ozx) * oneOverDet; zz = (oxx * oyy - oxy * oyx) * oneOverDet; return 0; } Mat3f &Mat3f::mult(const Mat3f &M, const Mat3f &N) { xx = M.xx * N.xx + M.xy * N.yx + M.xz * N.zx; xy = M.xx * N.xy + M.xy * N.yy + M.xz * N.zy; xz = M.xx * N.xz + M.xy * N.yz + M.xz * N.zz; yx = M.yx * N.xx + M.yy * N.yx + M.yz * N.zx; yy = M.yx * N.xy + M.yy * N.yy + M.yz * N.zy; yz = M.yx * N.xz + M.yy * N.yz + M.yz * N.zz; zx = M.zx * N.xx + M.zy * N.yx + M.zz * N.zx; zy = M.zx * N.xy + M.zy * N.yy + M.zz * N.zy; zz = M.zx * N.xz + M.zy * N.yz + M.zz * N.zz; return *this; } Mat3f &Mat3f::premult(const Mat3f &M) { float oxy, oyz, ozx, oyx, ozy, oxz; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = M.xx * oxy + M.xy * yy + M.xz * ozy; xz = M.xx * oxz + M.xy * oyz + M.xz * zz; yx = M.yx * xx + M.yy * oyx + M.yz * ozx; yz = M.yx * oxz + M.yy * oyz + M.yz * zz; zx = M.zx * xx + M.zy * oyx + M.zz * ozx; zy = M.zx * oxy + M.zy * yy + M.zz * ozy; xx = M.xx * xx + M.xy * oyx + M.xz * ozx; yy = M.yx * oxy + M.yy * yy + M.yz * ozy; zz = M.zx * oxz + M.zy * oyz + M.zz * zz; return *this; } Mat3f &Mat3f::postmult(const Mat3f &M) { float oxy, oyz, ozx, oyx, ozy, oxz; oxy = xy; oyx = yx; oyz = yz; ozy = zy; ozx = zx; oxz = xz; xy = xx * M.xy + oxy * M.yy + oxz * M.zy; xz = xx * M.xz + oxy * M.yz + oxz * M.zz; yx = oyx * M.xx + yy * M.yx + oyz * M.zx; yz = oyx * M.xz + yy * M.yz + oyz * M.zz; zx = ozx * M.xx + ozy * M.yx + zz * M.zx; zy = ozx * M.xy + ozy * M.yy + zz * M.zy; xx = xx * M.xx + oxy * M.yx + oxz * M.zx; yy = oyx * M.xy + yy * M.yy + oyz * M.zy; zz = ozx * M.xz + ozy * M.yz + zz * M.zz; return *this; } /////////////////////////////////////////////////////////////////////////////// // // class MatXd // /////////////////////////////////////////////////////////////////////////////// MatXd &MatXd::mult(const MatXd &M, const MatXd &N) { // multiply rotation matrices R.xx = M.R.xx * N.R.xx + M.R.xy * N.R.yx + M.R.xz * N.R.zx; R.xy = M.R.xx * N.R.xy + M.R.xy * N.R.yy + M.R.xz * N.R.zy; R.xz = M.R.xx * N.R.xz + M.R.xy * N.R.yz + M.R.xz * N.R.zz; R.yx = M.R.yx * N.R.xx + M.R.yy * N.R.yx + M.R.yz * N.R.zx; R.yy = M.R.yx * N.R.xy + M.R.yy * N.R.yy + M.R.yz * N.R.zy; R.yz = M.R.yx * N.R.xz + M.R.yy * N.R.yz + M.R.yz * N.R.zz; R.zx = M.R.zx * N.R.xx + M.R.zy * N.R.yx + M.R.zz * N.R.zx; R.zy = M.R.zx * N.R.xy + M.R.zy * N.R.yy + M.R.zz * N.R.zy; R.zz = M.R.zx * N.R.xz + M.R.zy * N.R.yz + M.R.zz * N.R.zz; // d = M.R * N.d + M.d d.x = M.R.xx * N.d.x + M.R.xy * N.d.y + M.R.xz * N.d.z + M.d.x; d.y = M.R.yx * N.d.x + M.R.yy * N.d.y + M.R.yz * N.d.z + M.d.y; d.z = M.R.zx * N.d.x + M.R.zy * N.d.y + M.R.zz * N.d.z + M.d.z; return *this; } MatXd &MatXd::premult(const MatXd &M) { double oxy, oyz, ozx, oyx, ozy, oxz, odx, ody; // multiply rotation matrices oxy = R.xy; oyx = R.yx; oyz = R.yz; ozy = R.zy; ozx = R.zx; oxz = R.xz; R.xy = M.R.xx * oxy + M.R.xy * R.yy + M.R.xz * ozy; R.xz = M.R.xx * oxz + M.R.xy * oyz + M.R.xz * R.zz; R.yx = M.R.yx * R.xx + M.R.yy * oyx + M.R.yz * ozx; R.yz = M.R.yx * oxz + M.R.yy * oyz + M.R.yz * R.zz; R.zx = M.R.zx * R.xx + M.R.zy * oyx + M.R.zz * ozx; R.zy = M.R.zx * oxy + M.R.zy * R.yy + M.R.zz * ozy; R.xx = M.R.xx * R.xx + M.R.xy * oyx + M.R.xz * ozx; R.yy = M.R.yx * oxy + M.R.yy * R.yy + M.R.yz * ozy; R.zz = M.R.zx * oxz + M.R.zy * oyz + M.R.zz * R.zz; // d = M.R * d + M.d odx = d.x; ody = d.y; d.x = M.R.xx * odx + M.R.xy * ody + M.R.xz * d.z + M.d.x; d.y = M.R.yx * odx + M.R.yy * ody + M.R.yz * d.z + M.d.y; d.z = M.R.zx * odx + M.R.zy * ody + M.R.zz * d.z + M.d.z; return *this; } MatXd &MatXd::postmult(const MatXd &M) { double oxy, oyz, ozx, oyx, ozy, oxz; Vect3d v; // d = R * M.d + d d.x += R.xx * M.d.x + R.xy * M.d.y + R.xz * M.d.z; d.y += R.yx * M.d.x + R.yy * M.d.y + R.yz * M.d.z; d.z += R.zx * M.d.x + R.zy * M.d.y + R.zz * M.d.z; // multiply rotation matrices oxy = R.xy; oyx = R.yx; oyz = R.yz; ozy = R.zy; ozx = R.zx; oxz = R.xz; R.xy = R.xx * M.R.xy + oxy * M.R.yy + oxz * M.R.zy; R.xz = R.xx * M.R.xz + oxy * M.R.yz + oxz * M.R.zz; R.yx = oyx * M.R.xx + R.yy * M.R.yx + oyz * M.R.zx; R.yz = oyx * M.R.xz + R.yy * M.R.yz + oyz * M.R.zz; R.zx = ozx * M.R.xx + ozy * M.R.yx + R.zz * M.R.zx; R.zy = ozx * M.R.xy + ozy * M.R.yy + R.zz * M.R.zy; R.xx = R.xx * M.R.xx + oxy * M.R.yx + oxz * M.R.zx; R.yy = oyx * M.R.xy + R.yy * M.R.yy + oyz * M.R.zy; R.zz = ozx * M.R.xz + ozy * M.R.yz + R.zz * M.R.zz; return *this; } MatXd &MatXd::invert(const MatXd &M) { // invert the rotation part by transposing it R.xx = M.R.xx; R.xy = M.R.yx; R.xz = M.R.zx; R.yx = M.R.xy; R.yy = M.R.yy; R.yz = M.R.zy; R.zx = M.R.xz; R.zy = M.R.yz; R.zz = M.R.zz; // new displacement vector given by: d' = -(R^-1) * d d.x = - (R.xx * M.d.x + R.xy * M.d.y + R.xz * M.d.z); d.y = - (R.yx * M.d.x + R.yy * M.d.y + R.yz * M.d.z); d.z = - (R.zx * M.d.x + R.zy * M.d.y + R.zz * M.d.z); return *this; } MatXd &MatXd::invert() { double tmp, odx, ody; // invert the rotation part by transposing it tmp = R.xy; R.xy = R.yx; R.yx = tmp; tmp = R.yz; R.yz = R.zy; R.zy = tmp; tmp = R.zx; R.zx = R.xz; R.xz = tmp; // new displacement vector given by: d' = -(R^T) * d odx = d.x; ody = d.y; d.x = - (R.xx * odx + R.xy * ody + R.xz * d.z); d.y = - (R.yx * odx + R.yy * ody + R.yz * d.z); d.z = - (R.zx * odx + R.zy * ody + R.zz * d.z); return *this; } MatXd &MatXd::Invert(const MatXd &M) { // invert the rotation part R.invert(M.R); // new displacement vector given by: d' = -(R^-1) * d R.xform(M.d, d); d.negate(); return *this; } MatXd &MatXd::Invert() { // invert the rotation part R.invert(); // new displacement vector given by: d' = -(R^-1) * d R.xform(d); d.negate(); return *this; } /////////////////////////////////////////////////////////////////////////////// // // class MatXf // /////////////////////////////////////////////////////////////////////////////// MatXf &MatXf::mult(const MatXf &M, const MatXf &N) { // multiply rotation matrices R.xx = M.R.xx * N.R.xx + M.R.xy * N.R.yx + M.R.xz * N.R.zx; R.xy = M.R.xx * N.R.xy + M.R.xy * N.R.yy + M.R.xz * N.R.zy; R.xz = M.R.xx * N.R.xz + M.R.xy * N.R.yz + M.R.xz * N.R.zz; R.yx = M.R.yx * N.R.xx + M.R.yy * N.R.yx + M.R.yz * N.R.zx; R.yy = M.R.yx * N.R.xy + M.R.yy * N.R.yy + M.R.yz * N.R.zy; R.yz = M.R.yx * N.R.xz + M.R.yy * N.R.yz + M.R.yz * N.R.zz; R.zx = M.R.zx * N.R.xx + M.R.zy * N.R.yx + M.R.zz * N.R.zx; R.zy = M.R.zx * N.R.xy + M.R.zy * N.R.yy + M.R.zz * N.R.zy; R.zz = M.R.zx * N.R.xz + M.R.zy * N.R.yz + M.R.zz * N.R.zz; // d = M.R * N.d + M.d d.x = M.R.xx * N.d.x + M.R.xy * N.d.y + M.R.xz * N.d.z + M.d.x; d.y = M.R.yx * N.d.x + M.R.yy * N.d.y + M.R.yz * N.d.z + M.d.y; d.z = M.R.zx * N.d.x + M.R.zy * N.d.y + M.R.zz * N.d.z + M.d.z; return *this; } MatXf &MatXf::premult(const MatXf &M) { float oxy, oyz, ozx, oyx, ozy, oxz, odx, ody; // multiply rotation matrices oxy = R.xy; oyx = R.yx; oyz = R.yz; ozy = R.zy; ozx = R.zx; oxz = R.xz; R.xy = M.R.xx * oxy + M.R.xy * R.yy + M.R.xz * ozy; R.xz = M.R.xx * oxz + M.R.xy * oyz + M.R.xz * R.zz; R.yx = M.R.yx * R.xx + M.R.yy * oyx + M.R.yz * ozx; R.yz = M.R.yx * oxz + M.R.yy * oyz + M.R.yz * R.zz; R.zx = M.R.zx * R.xx + M.R.zy * oyx + M.R.zz * ozx; R.zy = M.R.zx * oxy + M.R.zy * R.yy + M.R.zz * ozy; R.xx = M.R.xx * R.xx + M.R.xy * oyx + M.R.xz * ozx; R.yy = M.R.yx * oxy + M.R.yy * R.yy + M.R.yz * ozy; R.zz = M.R.zx * oxz + M.R.zy * oyz + M.R.zz * R.zz; // d = M.R * d + M.d odx = d.x; ody = d.y; d.x = M.R.xx * odx + M.R.xy * ody + M.R.xz * d.z + M.d.x; d.y = M.R.yx * odx + M.R.yy * ody + M.R.yz * d.z + M.d.y; d.z = M.R.zx * odx + M.R.zy * ody + M.R.zz * d.z + M.d.z; return *this; } MatXf &MatXf::postmult(const MatXf &M) { float oxy, oyz, ozx, oyx, ozy, oxz; Vect3d v; // d = R * M.d + d d.x += R.xx * M.d.x + R.xy * M.d.y + R.xz * M.d.z; d.y += R.yx * M.d.x + R.yy * M.d.y + R.yz * M.d.z; d.z += R.zx * M.d.x + R.zy * M.d.y + R.zz * M.d.z; // multiply rotation matrices oxy = R.xy; oyx = R.yx; oyz = R.yz; ozy = R.zy; ozx = R.zx; oxz = R.xz; R.xy = R.xx * M.R.xy + oxy * M.R.yy + oxz * M.R.zy; R.xz = R.xx * M.R.xz + oxy * M.R.yz + oxz * M.R.zz; R.yx = oyx * M.R.xx + R.yy * M.R.yx + oyz * M.R.zx; R.yz = oyx * M.R.xz + R.yy * M.R.yz + oyz * M.R.zz; R.zx = ozx * M.R.xx + ozy * M.R.yx + R.zz * M.R.zx; R.zy = ozx * M.R.xy + ozy * M.R.yy + R.zz * M.R.zy; R.xx = R.xx * M.R.xx + oxy * M.R.yx + oxz * M.R.zx; R.yy = oyx * M.R.xy + R.yy * M.R.yy + oyz * M.R.zy; R.zz = ozx * M.R.xz + ozy * M.R.yz + R.zz * M.R.zz; return *this; } MatXf &MatXf::invert(const MatXf &M) { // invert the rotation part by transposing it R.xx = M.R.xx; R.xy = M.R.yx; R.xz = M.R.zx; R.yx = M.R.xy; R.yy = M.R.yy; R.yz = M.R.zy; R.zx = M.R.xz; R.zy = M.R.yz; R.zz = M.R.zz; // new displacement vector given by: d' = -(R^-1) * d d.x = - (R.xx * M.d.x + R.xy * M.d.y + R.xz * M.d.z); d.y = - (R.yx * M.d.x + R.yy * M.d.y + R.yz * M.d.z); d.z = - (R.zx * M.d.x + R.zy * M.d.y + R.zz * M.d.z); return *this; } MatXf &MatXf::invert() { float tmp, odx, ody; // invert the rotation part by transposing it tmp = R.xy; R.xy = R.yx; R.yx = tmp; tmp = R.yz; R.yz = R.zy; R.zy = tmp; tmp = R.zx; R.zx = R.xz; R.xz = tmp; // new displacement vector given by: d' = -(R^T) * d odx = d.x; ody = d.y; d.x = - (R.xx * odx + R.xy * ody + R.xz * d.z); d.y = - (R.yx * odx + R.yy * ody + R.yz * d.z); d.z = - (R.zx * odx + R.zy * ody + R.zz * d.z); return *this; } MatXf &MatXf::Invert(const MatXf &M) { // invert the rotation part R.invert(M.R); // new displacement vector given by: d' = -(R^-1) * d R.xform(M.d, d); d.negate(); return *this; } MatXf &MatXf::Invert() { // invert the rotation part R.invert(); // new displacement vector given by: d' = -(R^-1) * d R.xform(d); d.negate(); return *this; } /////////////////////////////////////////////////////////////////////////////// // // class QuatD // /////////////////////////////////////////////////////////////////////////////// QuatD &QuatD::set(double angle, const Vect3d &axis, int normalizeAxis) { double theta = 0.5 * angle; double sine = sin(theta); s_ = cos(theta); if (normalizeAxis) { double n2; if ((n2 = axis.norm2()) < DBL_EPS) { *this = QuatD::ID; return *this; } sine /= sqrt(n2); } x_ = axis.x * sine; y_ = axis.y * sine; z_ = axis.z * sine; return *this; } QuatD &QuatD::set(const Mat3d &R) { double qs2, qx2, qy2, qz2; // squared magniudes of quaternion components double tmp; int i; // first compute squared magnitudes of quaternion components - at least one // will be greater than 0 since quaternion is unit magnitude qs2 = 0.25 * (R.xx + R.yy + R.zz + 1); qx2 = qs2 - 0.5 * (R.yy + R.zz); qy2 = qs2 - 0.5 * (R.zz + R.xx); qz2 = qs2 - 0.5 * (R.xx + R.yy); // find maximum magnitude component i = (qs2 > qx2) ? ((qs2 > qy2) ? ((qs2 > qz2) ? 0 : 3) : ((qy2 > qz2) ? 2 : 3)) : ((qx2 > qy2) ? ((qx2 > qz2) ? 1 : 3) : ((qy2 > qz2) ? 2 : 3)); // compute signed quaternion components using numerically stable method switch (i) { case 0: s_ = sqrt(qs2); tmp = 0.25 / s_; x_ = (R.zy - R.yz) * tmp; y_ = (R.xz - R.zx) * tmp; z_ = (R.yx - R.xy) * tmp; break; case 1: x_ = sqrt(qx2); tmp = 0.25 / x_; s_ = (R.zy - R.yz) * tmp; y_ = (R.xy + R.yx) * tmp; z_ = (R.xz + R.zx) * tmp; break; case 2: y_ = sqrt(qy2); tmp = 0.25 / y_; s_ = (R.xz - R.zx) * tmp; z_ = (R.yz + R.zy) * tmp; x_ = (R.yx + R.xy) * tmp; break; case 3: z_ = sqrt(qz2); tmp = 0.25 / z_; s_ = (R.yx - R.xy) * tmp; x_ = (R.zx + R.xz) * tmp; y_ = (R.zy + R.yz) * tmp; break; } // for consistency, force positive scalar component [ (s; v) = (-s; -v) ] if (s_ < 0) { s_ = -s_; x_ = -x_; y_ = -y_; z_ = -z_; } // normalize, just to be safe tmp = 1.0 / sqrt(s_ * s_ + x_ * x_ + y_ * y_ + z_ * z_); s_ *= tmp; x_ *= tmp; y_ *= tmp; z_ *= tmp; return *this; } QuatD &QuatD::mult(const QuatD &p, const QuatD &q) { s_ = p.s_ * q.s_ - (p.x_ * q.x_ + p.y_ * q.y_ + p.z_ * q.z_); x_ = p.s_ * q.x_ + q.s_ * p.x_ + p.y_ * q.z_ - p.z_ * q.y_; y_ = p.s_ * q.y_ + q.s_ * p.y_ + p.z_ * q.x_ - p.x_ * q.z_; z_ = p.s_ * q.z_ + q.s_ * p.z_ + p.x_ * q.y_ - p.y_ * q.x_; return *this; } QuatD &QuatD::premult(const QuatD &q) { double ox, oy, oz; ox = x_; oy = y_; oz = z_; x_ = q.s_ * ox + s_ * q.x_ + q.y_ * oz - q.z_ * oy; y_ = q.s_ * oy + s_ * q.y_ + q.z_ * ox - q.x_ * oz; z_ = q.s_ * oz + s_ * q.z_ + q.x_ * oy - q.y_ * ox; s_ = q.s_ * s_ - (q.x_ * ox + q.y_ * oy + q.z_ * oz); return *this; } QuatD &QuatD::postmult(const QuatD &q) { double ox, oy, oz; ox = x_; oy = y_; oz = z_; x_ = s_ * q.x_ + ox * q.s_ + oy * q.z_ - oz * q.y_; y_ = s_ * q.y_ + oy * q.s_ + oz * q.x_ - ox * q.z_; z_ = s_ * q.z_ + oz * q.s_ + ox * q.y_ - oy * q.x_; s_ = s_ * q.s_ - (ox * q.x_ + oy * q.y_ + oz * q.z_); return *this; } // The QuatD transformation routines use 19 multiplies and 12 adds // (counting the multiplications by 2.0). See Eqn (20) of "A // Comparison of Transforms and Quaternions in Robotics," Funda and // Paul, Proceedings of International Conference on Robotics and // Automation, 1988, p. 886-991. Vect3d &QuatD::xform(const Vect3d &v, Vect3d &xv) const { const Vect3d *u; Vect3d uv, uuv; u = (const Vect3d *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.0 * s_); uuv.scale(2.0); xv.add(v, uv); xv.add(uuv); return xv; } Vect3d &QuatD::xform(Vect3d &v) const { const Vect3d *u; Vect3d uv, uuv; u = (const Vect3d *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.0 * s_); uuv.scale(2.0); v.add(uv); v.add(uuv); return v; } Vect3d &QuatD::invXform(const Vect3d &v, Vect3d &xv) const { const Vect3d *u; Vect3d uv, uuv; u = (const Vect3d *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.0 * -s_); uuv.scale(2.0); xv.add(v, uv); xv.add(uuv); return xv; } Vect3d &QuatD::invXform(Vect3d &v) const { const Vect3d *u; Vect3d uv, uuv; u = (const Vect3d *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.0 * -s_); uuv.scale(2.0); v.add(uv); v.add(uuv); return v; } /////////////////////////////////////////////////////////////////////////////// // // class QuatF // /////////////////////////////////////////////////////////////////////////////// QuatF &QuatF::set(float angle, const Vect3f &axis, int normalizeAxis) { float theta = 0.5f * angle; float sine = sinf(theta); s_ = cosf(theta); if (normalizeAxis) { float n2; if ((n2 = axis.norm2()) < FLT_EPS) { *this = QuatD::ID; return *this; } sine *= invSqrtFast(n2); } x_ = axis.x * sine; y_ = axis.y * sine; z_ = axis.z * sine; return *this; } QuatF &QuatF::set(const Mat3f &R) { float qs2, qx2, qy2, qz2; // squared magniudes of quaternion components float tmp; int i; // first compute squared magnitudes of quaternion components - at least one // will be greater than 0 since quaternion is unit magnitude qs2 = 0.25f * (R.xx + R.yy + R.zz + 1); qx2 = qs2 - 0.5f * (R.yy + R.zz); qy2 = qs2 - 0.5f * (R.zz + R.xx); qz2 = qs2 - 0.5f * (R.xx + R.yy); // find maximum magnitude component i = (qs2 > qx2) ? ((qs2 > qy2) ? ((qs2 > qz2) ? 0 : 3) : ((qy2 > qz2) ? 2 : 3)) : ((qx2 > qy2) ? ((qx2 > qz2) ? 1 : 3) : ((qy2 > qz2) ? 2 : 3)); // compute signed quaternion components using numerically stable method switch (i) { case 0: s_ = sqrtf(qs2); tmp = 0.25f / s_; x_ = (R.zy - R.yz) * tmp; y_ = (R.xz - R.zx) * tmp; z_ = (R.yx - R.xy) * tmp; break; case 1: x_ = sqrtf(qx2); tmp = 0.25f / x_; s_ = (R.zy - R.yz) * tmp; y_ = (R.xy + R.yx) * tmp; z_ = (R.xz + R.zx) * tmp; break; case 2: y_ = sqrtf(qy2); tmp = 0.25f / y_; s_ = (R.xz - R.zx) * tmp; z_ = (R.yz + R.zy) * tmp; x_ = (R.yx + R.xy) * tmp; break; case 3: z_ = sqrtf(qz2); tmp = 0.25f / z_; s_ = (R.yx - R.xy) * tmp; x_ = (R.zx + R.xz) * tmp; y_ = (R.zy + R.yz) * tmp; break; } // for consistency, force positive scalar component [ (s; v) = (-s; -v) ] if (s_ < 0) { s_ = -s_; x_ = -x_; y_ = -y_; z_ = -z_; } // normalize, just to be safe tmp = invSqrtFast(s_ * s_ + x_ * x_ + y_ * y_ + z_ * z_); s_ *= tmp; x_ *= tmp; y_ *= tmp; z_ *= tmp; return *this; } QuatF &QuatF::mult(const QuatF &p, const QuatF &q) { s_ = p.s_ * q.s_ - (p.x_ * q.x_ + p.y_ * q.y_ + p.z_ * q.z_); x_ = p.s_ * q.x_ + q.s_ * p.x_ + p.y_ * q.z_ - p.z_ * q.y_; y_ = p.s_ * q.y_ + q.s_ * p.y_ + p.z_ * q.x_ - p.x_ * q.z_; z_ = p.s_ * q.z_ + q.s_ * p.z_ + p.x_ * q.y_ - p.y_ * q.x_; return *this; } QuatF &QuatF::premult(const QuatF &q) { float ox, oy, oz; ox = x_; oy = y_; oz = z_; x_ = q.s_ * ox + s_ * q.x_ + q.y_ * oz - q.z_ * oy; y_ = q.s_ * oy + s_ * q.y_ + q.z_ * ox - q.x_ * oz; z_ = q.s_ * oz + s_ * q.z_ + q.x_ * oy - q.y_ * ox; s_ = q.s_ * s_ - (q.x_ * ox + q.y_ * oy + q.z_ * oz); return *this; } QuatF &QuatF::postmult(const QuatF &q) { float ox, oy, oz; ox = x_; oy = y_; oz = z_; x_ = s_ * q.x_ + ox * q.s_ + oy * q.z_ - oz * q.y_; y_ = s_ * q.y_ + oy * q.s_ + oz * q.x_ - ox * q.z_; z_ = s_ * q.z_ + oz * q.s_ + ox * q.y_ - oy * q.x_; s_ = s_ * q.s_ - (ox * q.x_ + oy * q.y_ + oz * q.z_); return *this; } // The QuatF transformation routines use 19 multiplies and 12 adds // (counting the multiplications by 2.0). See Eqn (20) of "A // Comparison of Transforms and Quaternions in Robotics," Funda and // Paul, Proceedings of International Conference on Robotics and // Automation, 1988, p. 886-991. Vect3f &QuatF::xform(const Vect3f &v, Vect3f &xv) const { const Vect3f *u; Vect3f uv, uuv; u = (const Vect3f *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.f * s_); uuv.scale(2.f); xv.add(v, uv); xv.add(uuv); return xv; } Vect3f &QuatF::xform(Vect3f &v) const { const Vect3f *u; Vect3f uv, uuv; u = (const Vect3f *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.f * s_); uuv.scale(2.f); v.add(uv); v.add(uuv); return v; } Vect3f &QuatF::invXform(const Vect3f &v, Vect3f &xv) const { const Vect3f *u; Vect3f uv, uuv; u = (const Vect3f *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.f * -s_); uuv.scale(2.f); xv.add(v, uv); xv.add(uuv); return xv; } Vect3f &QuatF::invXform(Vect3f &v) const { const Vect3f *u; Vect3f uv, uuv; u = (const Vect3f *) &x_; uv.cross(*u, v); uuv.cross(*u, uv); uv.scale(2.f * -s_); uuv.scale(2.f); v.add(uv); v.add(uuv); return v; } ////////////////////////////////////////////////////////////////////////////////// // QuatD definitions ////////////////////////////////////////////////////////////////////////////////// QuatD Slerp(const QuatD &A, const QuatD &B, double t) { double theta = acos(dot(A, B)); double sin_theta = sin(theta); if (fabs(sin_theta) < DBL_EPS) return A; sin_theta = 1 / sin_theta; return A * (sin(theta * (1 - t)) * sin_theta) + B * (sin(theta * t) * sin_theta); } void Mat3f::makeRotationZ() { float cos = 0.0f; float sin; if (yy > FLT_EPS) { float tan = xy / yy; cos = invSqrtFast(tan * tan + 1.0f); sin = cos * tan; } else sin = xy > 0.0f ? 1.0f : -1.0f; xx = cos; xy = -sin; xz = 0.0f; yx = sin; yy = cos; yz = 0.0f; zx = 0.0f; zy = 0.0f; zz = 1.0f; } } // namespace QDEngine