// Copyright (C) 2012 Rémi Bèges // Jérôme Leclercq // This file is part of the "Nazara Engine". // For conditions of distribution and use, see copyright notice in Config.hpp #include #include #include #include #include #include template NzQuaternion::NzQuaternion() { } template NzQuaternion::NzQuaternion(T W, T X, T Y, T Z) { Set(W, X, Y, Z); } template NzQuaternion::NzQuaternion(T quat[4]) { Set(quat); } template NzQuaternion::NzQuaternion(T angle, const NzVector3& axis) { Set(angle, axis); } template NzQuaternion::NzQuaternion(const NzEulerAngles& angles) { Set(angles); } /* template NzQuaternion::NzQuaternion(const NzMatrix3& mat) { Set(mat); } */ template template NzQuaternion::NzQuaternion(const NzQuaternion& quat) { Set(quat); } template T NzQuaternion::DotProduct(const NzQuaternion& vec) const { return w*vec.w + x*vec.x + y*vec.y + z.vec.z; } template NzQuaternion NzQuaternion::GetConjugate() const { return NzQuaternion(w, -x, -y, -z); } template NzQuaternion NzQuaternion::GetNormalized() const { NzQuaternion quat(*this); quat.Normalize(); return quat; } template T NzQuaternion::Magnitude() const { return std::sqrt(SquaredMagnitude()); } template T NzQuaternion::Normalize() { T squaredLength = SquaredMagnitude(); if (std::fabs(squaredLength) > 0.00001 && std::fabs(squaredLength - 1.0) > 0.00001) { T length = std::sqrt(squaredLength); w /= length; x /= length; y /= length; z /= length; return length; } else return 1.0; // Le quaternion est déjà normalisé } template T NzQuaternion::SquaredMagnitude() const { return w * w + x * x + y * y + z * z; } template void NzQuaternion::Set(T W, T X, T Y, T Z) { w = W; x = X; y = Y; z = Z; } template void NzQuaternion::Set(T quat[4]) { w = quat[0]; x = quat[1]; y = quat[2]; z = quat[3]; } template void NzQuaternion::Set(T angle, const NzVector3& normalizedAxis) { #if !NAZARA_MATH_ANGLE_RADIAN angle = NzDegreeToRadian(angle); #endif angle /= 2; auto sinAngle = std::sin(angle); w = std::cos(angle); x = normalizedAxis.x * sinAngle; y = normalizedAxis.y * sinAngle; z = normalizedAxis.z * sinAngle; } template void NzQuaternion::Set(const NzEulerAngles& angles) { Set(angles.ToQuaternion()); } template template void NzQuaternion::Set(const NzQuaternion& quat) { w = static_cast(quat.w); x = static_cast(quat.x); y = static_cast(quat.y); z = static_cast(quat.z); } template void NzQuaternion::Set(const NzQuaternion& quat) { w = quat.w; x = quat.x; y = quat.y; z = quat.z; } template void NzQuaternion::SetIdentity() { Set(1.0, 0.0, 0.0, 0.0); } template void NzQuaternion::SetZero() { Set(0.0, 0.0, 0.0, 0.0); } template NzQuaternion NzQuaternion::Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp) { if (interp <= 0.0) return quatA; if (interp >= 1.0) return quatB; NzQuaternion q; T cosOmega = quatA.DotProduct(quatB); if (cosOmega < 0.0) { // On inverse tout q.Set(-quatB.w, -quatB.x, -quatB.y, -quatB.z); cosOmega = -cosOmega; } else q.Set(quatB); T k0, k1; if (cosOmega > 0.9999) { // Interpolation linéaire pour éviter une division par zéro k0 = 1.0 - interp; k1 = interp; } else { T sinOmega = std::sqrt(1.0f - (cosOmega * cosOmega)); T omega = std::atan2(sinOmega, cosOmega); // Pour éviter deux divisions sinOmega = 1/sinOmega; k0 = std::sin((1.0 - interp) * omega) * sinOmega; k1 = std::sin(interp * omega) * sinOmega; } NzQuaternion result(k0 * quatA.w, k0 * quatA.x, k0 * quatA.y, k0 * quatA.z); return result += q; } template NzEulerAngles NzQuaternion::ToEulerAngles() const { Normalize(); T test = x*y + z*w; if (test > 0.499) // singularity at north pole return NzEulerAngles(NzDegrees(90.0), NzRadians(2.0 * std::atan2(x, w)), 0.0); if (test < -0.499) return NzEulerAngles(NzDegrees(-90.0), NzRadians(-2.0 * std::atan2(x, w)), 0.0); T xx = x*x; T yy = y*y; T zz = z*z; return NzEulerAngles(NzRadians(std::atan2(2.0*x*w - 2.0*y*z, 1.0 - 2.0*xx - 2.0*zz)), NzRadians(std::atan2(2.0*y*w - 2.0*x*z, 1.f - 2.0*yy - 2.0*zz)), NzRadians(std::asin(2.0*test))); } template NzString NzQuaternion::ToString() const { NzStringStream ss; return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; } template NzQuaternion NzQuaternion::operator+(const NzQuaternion& quat) const { return NzQuaternion(w + quat.w, x + quat.x, y + quat.y, z + quat.z); } template NzQuaternion NzQuaternion::operator*(const NzQuaternion& quat) const { return NzQuaternion(w * quat.w - x * quat.x - y * quat.y - z * quat.z, w * quat.x + x * quat.w + y * quat.z - z * quat.y, w * quat.y + y * quat.w + z * quat.x - x * quat.z, w * quat.z + z * quat.w + x * quat.y - y * quat.x); } template NzVector3 NzQuaternion::operator*(const NzVector3& vec) const { NzVector3 normal(vec); normal.Normalize(); NzQuaternion qvec(0.0, normal.x, normal.y, normal.z); NzQuaternion result = operator*(qvec * GetConjugate()); return NzVector3(result.x, result.y, result.z); } template NzQuaternion NzQuaternion::operator*(T scale) const { return NzQuaternion(w * scale, x * scale, y * scale, z * scale); } template NzQuaternion NzQuaternion::operator/(const NzQuaternion& quat) const { return GetConjugate(quat) * (*this); } template NzQuaternion& NzQuaternion::operator+=(const NzQuaternion& quat) { return operator=(operator+(quat)); } template NzQuaternion& NzQuaternion::operator*=(const NzQuaternion& quat) { return operator=(operator*(quat)); } template NzQuaternion& NzQuaternion::operator*=(T scale) { return operator=(operator*(scale)); } template NzQuaternion& NzQuaternion::operator/=(const NzQuaternion& quat) { return operator=(operator/(quat)); } template bool NzQuaternion::operator==(const NzQuaternion& quat) const { return NzNumberEquals(w, quat.w) && NzNumberEquals(x, quat.x) && NzNumberEquals(y, quat.y) && NzNumberEquals(z, quat.z); } template bool NzQuaternion::operator!=(const NzQuaternion& quat) const { return !operator==(quat); } template bool NzQuaternion::operator<(const NzQuaternion& quat) const { return w < quat.w && x < quat.x && y < quat.y && z < quat.z; } template bool NzQuaternion::operator<=(const NzQuaternion& quat) const { return operator<(quat) || operator==(quat); } template bool NzQuaternion::operator>(const NzQuaternion& quat) const { return !operator<=(quat); } template bool NzQuaternion::operator>=(const NzQuaternion& quat) const { return !operator<(quat); } template std::ostream& operator<<(std::ostream& out, const NzQuaternion& quat) { return out << quat.ToString(); } #include