/////////////////////////////////////////////////////////////////////////////// // // ## ###### // ###### ### Based on: // ## ############### // ########## # # # Shark 3D Engine (www.shark3d.com) // ######## // ######### # # # Copyright (c) 1996-2001 Spinor GmbH. // ## ########## // ## // /////////////////////////////////////////////////////////////////////////////// // // G A M E.O.N.E - LOW LEVEL LIB V1.0 // Copyright (C) 2001 LEVEL ONE ENTERTAINMENT, // Licensed under the terms of LGPL. //:--------------------------------------------------------------------------- //:Description // // LOW LEVEL 3D VEC3 UTIL HEADERFILE // //:--------------------------------------------------------------------------- #ifndef _LL3D_VEC3_H #define _LL3D_VEC3_H #include "ll3d_math.h" namespace ll3d { template struct CVec3; template struct CMat3x3; template struct CQuat; typedef CVec3 CVec3f; typedef const CVec3f CVec3f_c; typedef CVec3f &CVec3f_r; typedef const CVec3f &CVec3f_cr; typedef CVec3 CVec3d; typedef const CVec3d CVec3d_c; typedef CVec3d &CVec3d_r; typedef const CVec3d &CVec3d_cr; typedef CMat3x3 CMat3x3f; typedef const CMat3x3f CMat3x3f_c; typedef CMat3x3f &CMat3x3f_r; typedef const CMat3x3f &CMat3x3f_cr; typedef CMat3x3 CMat3x3d; typedef const CMat3x3d CMat3x3d_c; typedef CMat3x3d &CMat3x3d_r; typedef const CMat3x3d &CMat3x3d_cr; typedef CQuat CQuatf; typedef const CQuatf CQuatf_c; typedef CQuatf &CQuatf_r; typedef const CQuatf &CQuatf_cr; typedef CQuat CQuatd; typedef const CQuatd CQuatd_c; typedef CQuatd &CQuatd_r; typedef const CQuatd &CQuatd_cr; /* * 3D Vector */ template struct CVec3 { T m_x, m_y, m_z; CVec3(); // Default constructor. Note that the components are not initialized. CVec3(T s); // Set each component to the same value. CVec3(T x, T y, T z); // Constructor CVec3(const CVec3 &v); // Copy constructor CVec3 &operator=(const CVec3 &v); // Assignment operator. CVec3 operator+() const; CVec3 operator-() const; // Negation operator. CVec3 &operator+=(const CVec3 &v); CVec3 &operator-=(const CVec3 &v); CVec3 &operator*=(T s); CVec3 &operator/=(T s); T GetSqLen() const; // Square of the vector. T GetLen() const; // Square of the vector. CVec3 GetNormalized() const; // Normalized to unit length. CVec3 GetNormalizedTo(T Len) const; // Normalized to length bool IsNull() const; // Are all components null? bool IsFinite() const; // Are all components finit values? // Linear interpolation between two vectors. // Returns (*this) + (v - (*this)) * Frac. CVec3 InterpLinear(const CVec3 &v, T Frac) const; // Project v onto Dir. It is // v.GetProjAlong() = Dir * (Vec.GetSqLen() / (Vec * Dir)). // It is except for rounding errors // v = v.GetProjOrtho() + v.GetProjAlong(). CVec3 GetProjAlong(const CVec3 &Dir) const; // Project v onto the plane orthogonal to Dir. // It is v.GetProjOrtho() = v - v.GetProjAlong(). // It is except for rounding errors // v = v.GetProjOrtho() + v.GetProjAlong(). CVec3 GetProjOrtho(const CVec3 &Dir) const; // Get constraint vector of v onto Dir. It is // v.GetConstrAlong(Dir) = Dir * (v.GetSqLen() / (Vec * Dir)). CVec3 GetConstrAlong(const CVec3 &Dir) const; // Get constraint vector v onto the plane // orthogonal to Dir. CVec3 GetConstrOrtho(const CVec3 &Dir) const; // Vector divided by its squared length. // v.GetReziproc() = v / v.GetSqLen(). CVec3 GetReziproc() const; CVec3 GetAbsComp() const; // Return for each component the absolute value. CVec3 GetSignComp() const; // Return the sign of each component. T GetMinComp() const; // Return the smallest component. T GetMaxComp() const; // Return the largest component. T GetSumAbsComp() const; // Return the sum of the absolute value of all components. T GetMaxAbsComp() const; // Return the maximum of the absolute value of all components. CVec3 &SetCompToMin(const CVec3 &v); // Set to the minimum component wise. CVec3 &SetCompToMax(const CVec3 &v); // Set to the maximum component wise. CVec3 CompMin(const CVec3 &v) const; CVec3 CompMax(const CVec3 &v) const; CVec3 CompMin(const CVec3 &v2, const CVec3 &v3) const; CVec3 CompMax(const CVec3 &v2, const CVec3 &v3) const; CVec3 operator+(const CVec3 &v) const; CVec3 operator-(const CVec3 &v) const; CVec3 operator*(T s) const; // Scalar multiplication. CVec3 operator/(T s) const; // Scalar division. T operator*(const CVec3 &v) const; // Scalar product. CVec3 operator^(const CVec3 &v) const; // Cross product of two vectors. CVec3 operator*(const CMat3x3 &m) const; bool operator==(const CVec3 &v) const; // Equality. bool operator!=(const CVec3 &v) const; // Inequality. int CompareComp(const CVec3 &v) const; // Defines an order on vectors. T Area(const CVec3 &v) const ;// Area spanned by v1 AND v2. // Volume spanned by v1, v2 and v3. // Guaranteed to be null if two vectors are equal. T Volume(const CVec3 &v2, const CVec3 &v3) const; CVec3 CompProd(const CVec3 &v) const; // Component wise product. CVec3 CompQuot(const CVec3 &v) const; // Component wise division. CVec3 CompReziproc() const; // Reziproc of each component. bool IsCosAngleAbove(const CVec3 &v, T c) const; // Returns true if cos(angle_between(v1, v2)) > c bool IsEachCompNe(const CVec3 &v) const; bool IsEachCompLt(const CVec3 &v) const; bool IsEachCompLe(const CVec3 &v) const; bool IsEachCompGt(const CVec3 &v) const; bool IsEachCompGe(const CVec3 &v) const; bool IsAnyCompEq(const CVec3 &v) const; bool IsAnyCompLt(const CVec3 &v) const; bool IsAnyCompLe(const CVec3 &v) const; bool IsAnyCompGt(const CVec3 &v) const; bool IsAnyCompGe(const CVec3 &v) const; // Scalar multiplication with t, cross product from left with x,y,z. // Return [v * q.t, v ^ q.v]. // Warning! This operator does not rotate and scale the vector // by the scaled rotation representated by the quaternion. // To perform this, you must use the matrix // returned by CQuat::GetMat. CVec3 operator*(const CQuat &q) const; }; /* * 3x3 Matrix */ template struct CMat3x3 { T m_xx, m_xy, m_xz, m_yx, m_yy, m_yz, m_zx, m_zy, m_zz; CMat3x3(); // Default constructor. Note that the components are not initialized. // Initializating with multiple of unity matrix. // Also allows to use 0 as null matrix and 1 as unity matrix. CMat3x3(T s); // Constructor. CMat3x3( T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz); CMat3x3(const CMat3x3 &m); // Copy constructor. CMat3x3 &operator=(const CMat3x3 &m); // Assignment operator. CMat3x3 operator+() const; CMat3x3 operator-() const; // Negation operator. CMat3x3 &operator+=(const CMat3x3 &m); CMat3x3 &operator-=(const CMat3x3 &m); CMat3x3 &operator*=(const CMat3x3 &m); CMat3x3 &operator*=(T s); CMat3x3 &operator/=(T s); CMat3x3 GetTransposed() const; // Returns the transposed matrix. // Return the transposed inverse matrix // times the determinant of the matrix. CMat3x3 GetSubDet() const; CMat3x3 GetInv() const; // Return the inverse matrix. T GetSqLen() const; // Returns the sum of the square if all components. T GetLen() const; // Returns the root of the sum of the square of all components. // Returns the determinant. // Guaranteed to be null if two rows or colums are equal. T GetDet() const; T GetTrace() const; // Returns the sum of the diagonal elements. // Returns the dual vector of the matrix. // The dual vector is the contraction of the levicita tensor // with the matrix interpretated as tensor of second rank. // v_a = e_abc M^bc. CVec3 GetDual() const; bool IsNull() const; // Are all components null? bool IsFinite() const; // Are all components finite? CVec3 GetRowX() const; // Return the vector build of m_xx, m_xy, m_xz. CVec3 GetRowY() const; // Return the vector build of m_yx, m_yy, m_yz. CVec3 GetRowZ() const; // Return the vector build of m_zx, m_zy, m_zz. CVec3 GetColX() const; // Return the vector build of m_xx, m_yx, m_zx. CVec3 GetColY() const; // Return the vector build of m_xy, m_yy, m_zy. CVec3 GetColZ() const; // Return the vector build of m_xz, m_yz, m_zz. void SetRowX(const CVec3 &v); void SetRowY(const CVec3 &v); void SetRowZ(const CVec3 &v); void SetColX(const CVec3 &v); void SetColY(const CVec3 &v); void SetColZ(const CVec3 &v); CMat3x3 GetAbsComp() const;// Builds the absolute value of each component. T GetSumAbsComp() const;// Returns the sum of the absolute values of each component. T GetMaxAbsComp() const;// Returns the maximal absolute value of all components. CVec3 GetSumAbsRows() const;// Returns per the sum of the absolute values of the components of each row. CVec3 GetSumAbsCols() const;// Returns per the sum of the absolute values of the components of each column. CVec3 GetMaxAbsRows() const;// Returns per the maximum of the absolute values of the components of each row. CVec3 GetMaxAbsCols() const;// Returns per the maximum of the absolute values of the components of each column. CVec3 GetLenRows() const;// Returns the length of the row vectors. CVec3 GetLenCols() const;// Returns the length of the column vectors. CMat3x3 GetScaledRows(const CVec3 &v) const;// Returns the length of the column vectors. CMat3x3 GetScaledCols(const CVec3 &v) const;// Multiplies each column the the corresponding component of v. // Tensor product of two vectors. // This is no global function to explicitely exclude type conversions // for the first argument. static CMat3x3 ByTensorProd(const CVec3 &v1, const CVec3 &v2); // The dual matrix of a vector is the contraction of the levicita tensor // with the vector. // M_ab = e_abc v^c. static CMat3x3 ByDual(const CVec3 &v); static CMat3x3 ByDiag(const CVec3 &v);// Create a diagonal matrix. static CMat3x3 ByDiag(T x, T y, T z);// Create a diagonal matrix. static CMat3x3 ByRows( const CVec3 &vx, const CVec3 &vy, const CVec3 &vz); // Create a matrix by its row vectors. static CMat3x3 ByCols( const CVec3 &vx, const CVec3 &vy, const CVec3 &vz);// Create a matrix by its column vectors. CMat3x3 operator+(const CMat3x3 &m) const; CMat3x3 operator-(const CMat3x3 &m) const; CMat3x3 operator*(T s) const;// Scalar multiplication. CMat3x3 operator/(T s) const; CMat3x3 operator*(const CMat3x3 &m) const;// Matrix multiplication. CVec3 operator*(const CVec3 &v) const; // Multiply the vector x,y,z with the matrix from left. // Return [q.t, m * q.v] CQuat operator*(const CQuat &q); bool operator==(const CMat3x3 &m) const; bool operator!=(const CMat3x3 &m) const; // Defines an order on vectors. int CompareComp(const CMat3x3 &m) const; }; /* * Quaternion * * A quaternion has four components (t, x, y, z). * It represents a concatication of a rotation and a scaling * in the following way. * The direction of the vector (x, y, z) is the rotation axis. * The length of the vector (x, y, z) is sqrt(scale) * sin(angle/2) * and t is sqrt(scale) * cos(angle/2), * where angle is the rotation angle, and scale is the scaling factor. * */ template struct CQuat { T m_t, m_x, m_y, m_z; // Default constructor. Note that the components are not initialized. CQuat(); // Initialize with a multiple of the unity quaternion. // Also allows to use 0 as null quaternion. CQuat(T s); CQuat(T t, T x, T y, T z); CQuat(T t, const CVec3 &v); CQuat(const CQuat &q);// Copy constructor. CQuat &operator=(const CQuat &q);// Assign operator. CVec3 GetVec() const;// Return the components x,y,z as vector. void SetVec(const CVec3 &v);// Set the x,y,z components and let t unchanged. CQuat operator+() const; CQuat operator-() const; // Negation. CQuat &operator+=(const CQuat &q); CQuat &operator-=(const CQuat &q); CQuat &operator*=(const CQuat &q); // Quaternion multiplication. CQuat &operator*=(T s); CQuat &operator/=(T s); CQuat GetAbs() const;// If t < 0, negate. // Negate x,y,z. // Geometrically this means to reverse the rotation // but keep the scaling. // Mathematically, this is the star operator. // See also @ident{CQuat::GetRevMat}. CQuat GetRev() const; // Get the inverse quaternion. CQuat GetInv() const; // The sum of the square of each component. // This is the scaling factor. T GetSqLen() const; // The root of the sum of the square of each component. // This is the square root of the scaling factor. T GetLen() const; // The half angle of the rotation. // See also @ident{CQuat::GetRotAngle}. T GetQuatAngle() const; T GetRotAngle() const;// The angle of the rotation. CQuat GetNormalized() const;// Normalize to length one. CQuat GetNormalizedTo(T Len) const;// Normalize to length // Square root of the quaternion. // Has same axis, half angle, and root of length. CQuat GetSqRoot() const; // Power of a quaternion, where the result is normalized to one. // Has same axis, the angle multiplied by the exponent, // and the length always one. // If *this is zero, the result is 1. // This function is faster than the full CQuat::PowerTo CQuat NormalizedPowerTo(T Exponent) const; // Power of a quaternion. // Has same axis, the angle multiplied by the exponent, // and the length raised to the power of the exponent. // This function is slower than CQuat::NormalizedPowerTo. CQuat PowerTo(T Exponent) const; bool IsNull() const;// Are all components null? bool IsFinite() const;// Are all components finite? CMat3x3 GetMat() const;// Builds the corresponding scaled rotation matrix. // Builds the reverse of the corresponding scaled rotation matrix. // See also CQuat::GetRev. CMat3x3 GetRevMat() const; // Builds the inverse of the corresponding scaled rotation matrix. // See also CQuat::GetInv. CMat3x3 GetInvMat() const; // Return rotation around Axis by angle Angle radians. static CQuat ByRot( const CVec3 &Axis, T Angle); // Return scaled rotation around Axis // by angle Angle radians and scaled by SqLen. static CQuat ByScaledRot( const CVec3 &Axis, T Angle, T Scale); // Returns the shortest scaled rotation mapping // From into To. // Also see CQuat::ByPathAxis // and CQuat::ByPathAlso. static CQuat ByPathShortest( const CVec3 &From, const CVec3 &To); // Returns the rotation around Axis // mapping the plane spanned by Axis and From // into the plane spanned by Axis and To. // The resulting quaternion has no scale, so it has always length one. static CQuat ByPathAxis( const CVec3 &Axis, const CVec3 &AlsoFrom, const CVec3 &AlsoTo); // Returns the scaled rotation mapping From into To // but also mapping the plane spanned by From and AlsoFrom // into the plane spanned by To and AlsoTo. // Roughly speaking, it mappes From into To, // but also tries to map AlsoFrom into AlsoTo // as far as possible. static CQuat ByPathAlso(const CVec3 &From, const CVec3 &To, const CVec3 &AlsoFrom, const CVec3 &AlsoTo); // Some kind of inverse of CQuat::GetMat. // For a quaternion q with must have t not near 0 // is CQuat::ByBestOfMat(q.GetMat()) = q.GetAbs(). // Returns a rotation-invariant result for matrices // which are no scaled rotation. // It uses the formulars // SqRoot(0.5 * (m.GetTrace() - s), v = - 0.5 * m.GetDual()) // Warning! Degenerates for 180 degree rotations (hence t -> 0). static CQuat ByBestOfMat(const CMat3x3 &m); // Some kind of inverse of @ident{CQuat::GetMat}. // For a quaternion q // is CQuat::ByRotMat(q.GetMat()) = q.GetAbs(). // This function has no degeneration point for scaledrotation matrices. // Warning! Generates crazy, non-rotation-invariant results // for non-scaledrotation matrices. static CQuat ByRotMat(const CMat3x3 &m); // Returns the total quaternion when concatenating // the following rotations: // // Pan radians around the x-axis. // Tilt radians around the y-axis. // Roll radians around the z-axis. // This is equivalent to // // { // CQuat::ByRotXYZ(Pan, Tilt, Roll) // = CQuat::ByRot(CVec3(1, 0, 0), Pan) // * CQuat::ByRot(CVec3(0, 1, 0), Tilt) // * CQuat::ByRot(CVec3(0, 0, 1), Roll) // } // Assuming that a vector is rotated by multiplying the rotation matrix // from left as in // { // v -> CQuat::ByRotXYZ(Pan, Tilt, Roll) * v; // } // pan, tilt and roll // have the usual geometrical interpretation. // The inverse operation is CQuat::GetRotAngleXYZ. // If the rotations around the axis should be performed // around the axes in different order, you can still use this function, // but have to permutate the x,y and z component // of the resulting quaternion. // For example, to rotate // { By Pan around y-axis (instead of x-axis). } // { By Tilt around the x-axis (instead of y-axis). } // { By Roll around the z-axis. } // calculate CQuat::ByRotXYZ(Pan, Tilt, Roll), // and swap the x and y component of the resulting quaternion. static CQuat ByRotXYZ(T Pan, T Tilt, T Roll); // Calculates three rotation angles pan, tilt roll. // This is the inverse to CQuat::ByRotXYZ. void GetRotAngleXYZ(T &Pan, T &Tilt, T &Roll); CQuat operator+(const CQuat &q) const; CQuat operator-(const CQuat &q) const; CQuat operator*(T s) const; // Scalar multiplication. CQuat operator/(T s) const; // Scalar division. CQuat operator*(const CQuat &q) const; // Quaternion multiplication. // Multiply the vector x,y,z with the matrix from right. // Return [q.t, q.v * m] CQuat operator*(const CMat3x3 &m) const; // Scalar multiplication with t, cross product from right with x,y,z. // Return [v * q.t, v ^ q.v]. // Warning! This operator does not rotate and scale the vector // by the scaled rotation representated by the quaternion. // To perform this, you must use the matrix // returned by CQuat::GetMat. CVec3 operator*(const CVec3 &v) const; bool operator==(const CQuat &q) const; bool operator!=(const CQuat &q) const; // Defines an order on vectors. int CompareComp(const CQuat &q) const; // Scalar product: // Sum of the product of each corresponding component. // This is a rotation invariant quantity. // The scalar product is negative if the quotient of the quaternions // is negative. T ScalarProd(const CQuat &q) const; T GetQuatAngleBetween(const CQuat &q) const;// Rotation angle between two quaternions: T GetRotAngleBetween(const CQuat &q) const;// Rotation angle between two quaternions: // interpolation // Interpolates linear between two quaternions. // Returns (*this) + (q - (*this)) * Frac. // Linear interpolation means linear in the quaternion // considered as vector. // Frac == 0 returns *this, // Frac == 1 returns q. // Note that the corresponding matrix CQuat::GetMat // is interpolated quadratically. // If *this is near to q relative to their length, // linear interpolation is aproximately equivalent // to the exponential and geometric interpolations // CQuat::InterpStrictExp, // CQuat::InterpShortestExp, // to CQuat::InterpStrictGeo, and // CQuat::InterpShortestGeo CQuat InterpLinear(const CQuat &q, T Frac) const; // interpolation // Interpolate exponential between two quaternions. // Exponential interpolation means angle-linear interpolation // of the rotation, and exponential interpolation of the scale, // analogous to exponential interpolation of complex numbers. // Frac == 0 returns q1. // Frac == 1 returns q2. // In contrast to CQuat::InterpShortestExp, // interpolation pathes can be rotations up to 360 degrees // due to the two-way representation of the same rotation // by two quaternions. // In contrast to CQuat::InterpStrictGeo, // the scale is interpolated exponential. // Both *this and q must not be zero or near zero, // since the function degenerates at these points. // If *this is near to q relative to their length, // the interpolation is aproximately equivalent // to linear interpolation CQuat::InterpLinear. CQuat InterpStrictExp(const CQuat &q, T Frac) const; // interpolation // Interpolate exponential between two scaled rotations. // Exponential interpolation means angle-linear interpolation // of the rotation, and exponential interpolation of the scale, // analogous to exponential interpolation of complex numbers. // Frac == 0 returns +/- q1. // Frac == 1 returns +/- q2. // In contrast to CQuat::InterpStrictExp, // this interpolation identifies the two quaternions representing // the same scaled rotation, so that the interpolation path // always is not more than 180 degree. // In contrast to CQuat::InterpShortestExp. // the scale is interpolated exponential. // Both *this and q must not be zero or near zero, // since the function degenerates at these points. // If *this is near to q relative to their length, // the interpolation is aproximately equivalent // to linear interpolation CQuat::InterpLinear. CQuat InterpShortestExp(const CQuat &q, T Frac) const; // interpolation // Interpolate geometrical between two quaternions. // Geometrical interpolation means angle-linear interpolation // of the rotation, and linear interpolation of the scale. // Frac == 0} returns q1. // Frac == 1} returns q2. // In contrast to CQuat::InterpShortestGeo, // interpolation pathes can be rotations up to 360 degrees // due to the two-way representation of the same rotation // by two quaternions. // In contrast to CQuat::InterpStrictExp, // the scale is interpolated linear. // If *this or q is zero, the angle is kept constant, // and only the scale is interpolated. // If *this or q are not zero, they should be not near zero // to avoid degeneration artifacts. // If *this is near to q relative to their length, // the interpolation is aproximately equivalent // to linear interpolation CQuat::InterpLinear. CQuat InterpStrictGeo(const CQuat &q, T Frac) const; // interpolation // Interpolate geometrical between two scaled rotations. // Geometrical interpolation means angle-linear interpolation // of the rotation, and linear interpolation of the scale. // Frac == 0 returns +/- q1. // Frac == 1 returns +/- q2. // In contrast to CQuat::InterpStrictGeo, // this interpolation identifies the two quaternions representing // the same scaled rotation, so that the interpolation path // always is not more than 180 degree. // In contrast to CQuat::InterpShortestExp. // the scale is interpolated linear. // If *this or q is zero, the angle is kept constant, // and only the scale is interpolated. // If *this or q are not zero, they should be not near zero // to avoid degeneration artifacts. // If *this is near to q relative to their length, // the interpolation is aproximately equivalent // to linear interpolation CQuat::InterpLinear. CQuat InterpShortestGeo(const CQuat &q, T Frac) const; // Extract the rotation around the axis Dir. // The rotation axis CQuat::GetVec is projected // onto Dir. It is v.GetProjAlong(Dir) // = CQuat(v.t, v.GetVec().GetProjAlong(Dir)). // It is except for rounding errors // v.GetProjAlong().GetVec() parallel to Dir. // The function does not conserve the norm of the quaternion. // See also CQuat::GetProjOrthoLeft // and CQuat::GetProjOrthoRight. CQuat GetProjAlong(const CVec3 &Dir) const; // Eliminate rotation around the axis Dir. // It is except for rounding errors // v = v.GetProjOrthoLeft() * v.GetProjAlong() // and v.GetProjOrthoLeft().GetVec() * Ortho = 0. // The function does not conserve the norm of the quaternion. // See also CQuat::GetProjAlong // and CQuat::GetProjOrthoRight. CQuat GetProjOrthoLeft(const CVec3 &Dir) const; // Eliminate rotation around the axis Dir. // It is except for rounding errors // v = v.GetProjAlong() * v.GetProjOrthoRight() // and v.GetProjOrthoRight().GetVec() * Ortho = 0. // The function does not conserve the norm of the quaternion. // See also CQuat::GetProjAlong // and CQuat::GetProjOrthoLeft. CQuat GetProjOrthoRight(const CVec3 &Dir) const; }; /* * CVector Implementation */ template inline CVec3::CVec3() { } template inline CVec3::CVec3(T s) { m_x = m_y = m_z = s; } template inline CVec3::CVec3(T x, T y, T z) { m_x = x; m_y = y; m_z = z; } template inline CVec3::CVec3(const CVec3 &v) { m_x = v.m_x; m_y = v.m_y; m_z = v.m_z; } template inline CVec3 &CVec3::operator=(const CVec3 &v) { m_x = v.m_x; m_y = v.m_y; m_z = v.m_z; return (*this); } template inline CVec3 CVec3::operator+() const { return (*this); } template inline CVec3 CVec3::operator-() const { return CVec3(- m_x, - m_y, - m_z); } template inline CVec3 &CVec3::operator+=(const CVec3 &v) { return (*this) = (*this) + v; } template inline CVec3 &CVec3::operator-=(const CVec3 &v) { return (*this) = (*this) - v; } template inline CVec3 &CVec3::operator*=(T s) { return (*this) = (*this) * s; } template inline CVec3 &CVec3::operator/=(T s) { return (*this) = (*this) / s; } template inline T CVec3::GetSqLen() const { return m_x * m_x + m_y * m_y + m_z * m_z; } template T CVec3::GetLen() const { return Sqrt(m_x * m_x + m_y * m_y + m_z * m_z); } template CVec3 CVec3::GetNormalized() const { T f = 1 / Sqrt(m_x * m_x + m_y * m_y + m_z * m_z); return CVec3(f * m_x, f * m_y, f * m_z); } template CVec3 CVec3::GetNormalizedTo(T Len) const { T f = Len / Sqrt(m_x * m_x + m_y * m_y + m_z * m_z); return CVec3(f * m_x, f * m_y, f * m_z); } template inline bool CVec3::IsNull() const { return m_x == 0 && m_y == 0 && m_z == 0; } template bool CVec3::IsFinite() const { return IsFinite(m_x) && ll3d::IsFinite(m_y) && ll3d::IsFinite(m_z); } template CVec3 CVec3::InterpLinear(const CVec3 &v, T Frac) const { return (*this) + (v - (*this)) * Frac; } template CVec3 CVec3::GetProjAlong(const CVec3 &Dir) const { const CVec3 &Vec = (*this); return Dir * ((Vec * Dir) / Dir.GetSqLen()); } template CVec3 CVec3::GetProjOrtho(const CVec3 &Dir) const { const CVec3 &Vec = (*this); return Vec - Dir * ((Vec * Dir) / Dir.GetSqLen()); } template CVec3 CVec3::GetConstrAlong(const CVec3 &Dir) const { const CVec3 &Vec = (*this); return Dir * (Vec.GetSqLen() / (Vec * Dir)); } template CVec3 CVec3::GetConstrOrtho(const CVec3 &Dir) const { const CVec3 &Vec = (*this); T Frac = Vec.GetSqLen() / (Dir ^ Vec).GetSqLen(); return Vec * (Frac * Dir.GetSqLen()) - Dir * (Frac * (Dir * Vec)); } template CVec3 CVec3::GetReziproc() const { T f = 1 / (m_x * m_x + m_y * m_y + m_z * m_z); return CVec3(f * m_x, f * m_y, f * m_z); } template inline CVec3 CVec3::GetAbsComp() const { return CVec3(Abs(m_x), Abs(m_y), Abs(m_z)); } template CVec3 CVec3::GetSignComp() const { return CVec3(Sign(m_x), Sign(m_y), Sign(m_z)); } template T CVec3::GetMinComp() const { return Min(m_x, m_y, m_z); } template T CVec3::GetMaxComp() const { return Max(m_x, m_y, m_z); } template T CVec3::GetSumAbsComp() const { return Abs(m_x) + Abs(m_y) + Abs(m_z); } template T CVec3::GetMaxAbsComp() const { return Max(Abs(m_x), Abs(m_y), Abs(m_z)); } template CVec3 CVec3::CompMin(const CVec3 &v) const { return CVec3( Min(m_x, v.m_x), Min(m_y, v.m_y), Min(m_z, v.m_z)); } template CVec3 CVec3::CompMax(const CVec3 &v) const { return CVec3( Max(m_x, v.m_x), Max(m_y, v.m_y), Max(m_z, v.m_z)); } template CVec3 CVec3::CompMin(const CVec3 &v2, const CVec3 &v3) const { return CVec3( Min(m_x, v2.m_x, v3.m_x), Min(m_y, v2.m_y, v3.m_y), Min(m_z, v2.m_z, v3.m_z)); } template CVec3 CVec3::CompMax(const CVec3 &v2, const CVec3 &v3) const { return CVec3( Max(m_x, v2.m_x, v3.m_x), Max(m_y, v2.m_y, v3.m_y), Max(m_z, v2.m_z, v3.m_z)); } template CVec3 &CVec3::SetCompToMin(const CVec3 &v) { if(v.m_x < m_x) m_x = v.m_x; if(v.m_y < m_y) m_y = v.m_y; if(v.m_z < m_z) m_z = v.m_z; return (*this); } template CVec3 &CVec3::SetCompToMax(const CVec3 &v) { if(v.m_x > m_x) m_x = v.m_x; if(v.m_y > m_y) m_y = v.m_y; if(v.m_z > m_z) m_z = v.m_z; return (*this); } /////////////////////////////////////////////////////////////////////////////// template inline CVec3 CVec3::operator+(const CVec3 &v) const { return CVec3(m_x + v.m_x, m_y + v.m_y, m_z + v.m_z); } template inline CVec3 CVec3::operator-(const CVec3 &v) const { return CVec3(m_x - v.m_x, m_y - v.m_y, m_z - v.m_z); } template inline CVec3 CVec3::operator*(T s) const { return CVec3(m_x * s, m_y * s, m_z * s); } template inline CVec3 CVec3::operator/(T s) const { return CVec3(m_x / s, m_y / s, m_z / s); } template inline T CVec3::operator*(const CVec3 &v) const { return m_x * v.m_x + m_y * v.m_y + m_z * v.m_z; } template inline CVec3 CVec3::operator^(const CVec3 &v) const { return CVec3( m_y * v.m_z - m_z * v.m_y, m_z * v.m_x - m_x * v.m_z, m_x * v.m_y - m_y * v.m_x); } template inline CVec3 CVec3::operator*(const CMat3x3 &m) const { return CVec3( m_x * m.m_xx + m_y * m.m_yx + m_z * m.m_zx, m_x * m.m_xy + m_y * m.m_yy + m_z * m.m_zy, m_x * m.m_xz + m_y * m.m_yz + m_z * m.m_zz); } template inline bool CVec3::operator==(const CVec3 &v) const { return m_x == v.m_x && m_y == v.m_y && m_z == v.m_z; } template inline bool CVec3::operator!=(const CVec3 &v) const { return m_x != v.m_x || m_y != v.m_y || m_z != v.m_z; } template int CVec3::CompareComp(const CVec3 &v) const { if(m_x < v.m_x) return -1; else if(m_x > v.m_x) return 1; else if(m_y < v.m_y) return -1; else if(m_y > v.m_y) return 1; else if(m_z < v.m_z) return -1; else if(m_z > v.m_z) return 1; else return 0; } template T CVec3::Area(const CVec3 &v) const { T x = m_y * v.m_z - m_z * v.m_y; T y = m_z * v.m_x - m_x * v.m_z; T z = m_x * v.m_y - m_y * v.m_x; return Sqrt(x * x + y * y + z * z); } template T CVec3::Volume(const CVec3 &v2, const CVec3 &v3) const { // Not using subdeterminant expansion to guarantee // that the result is exact null if two vectors are equal. return m_x * v2.m_y * v3.m_z - m_x * v2.m_z * v3.m_y + m_y * v2.m_z * v3.m_x - m_y * v2.m_x * v3.m_z + m_z * v2.m_x * v3.m_y - m_z * v2.m_y * v3.m_x; } template inline CVec3 CVec3::CompProd(const CVec3 &v) const { return CVec3(m_x * v.m_x, m_y * v.m_y, m_z * v.m_z); } template inline CVec3 CVec3::CompQuot(const CVec3 &v) const { return CVec3(m_x / v.m_x, m_y / v.m_y, m_z / v.m_z); } template inline CVec3 CVec3::CompReziproc() const { return CVec3(1 / m_x, 1 / m_y, 1 / m_z); } template bool CVec3::IsCosAngleAbove(const CVec3 &v, T c) const { const CVec3 &This = (*this); T Scal = This * v; T Sq1 = GetSqLen(); T Sq2 = v.GetSqLen(); return Scal * Abs(Scal) > c * Sq1 * Sq2; } template bool CVec3::IsEachCompNe(const CVec3 &v) const { return m_x != v.m_x && m_y != v.m_y && m_z != v.m_z; } template bool CVec3::IsEachCompLt(const CVec3 &v) const { return m_x < v.m_x && m_y < v.m_y && m_z < v.m_z; } template bool CVec3::IsEachCompLe(const CVec3 &v) const { return m_x <= v.m_x && m_y <= v.m_y && m_z <= v.m_z; } template bool CVec3::IsEachCompGt(const CVec3 &v) const { return m_x > v.m_x && m_y > v.m_y && m_z > v.m_z; } template bool CVec3::IsEachCompGe(const CVec3 &v) const { return m_x >= v.m_x && m_y >= v.m_y && m_z >= v.m_z; } template bool CVec3::IsAnyCompEq(const CVec3 &v) const { return m_x == v.m_x || m_y == v.m_y || m_z == v.m_z; } template bool CVec3::IsAnyCompLt(const CVec3 &v) const { return m_x < v.m_x || m_y < v.m_y || m_z < v.m_z; } template bool CVec3::IsAnyCompLe(const CVec3 &v) const { return m_x <= v.m_x || m_y <= v.m_y || m_z <= v.m_z; } template bool CVec3::IsAnyCompGt(const CVec3 &v) const { return m_x > v.m_x || m_y > v.m_y || m_z > v.m_z; } template bool CVec3::IsAnyCompGe(const CVec3 &v) const { return m_x >= v.m_x || m_y >= v.m_y || m_z >= v.m_z; } /* * CMat3x3 Implementation */ template inline CMat3x3::CMat3x3() { } template inline CMat3x3::CMat3x3(T s) { m_xx = s; m_xy = 0; m_xz = 0; m_yx = 0; m_yy = s; m_yz = 0; m_zx = 0, m_zy = 0; m_zz = s; } template inline CMat3x3::CMat3x3(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) { m_xx = xx; m_xy = xy; m_xz = xz; m_yx = yx; m_yy = yy; m_yz = yz; m_zx = zx; m_zy = zy; m_zz = zz; } template inline CMat3x3::CMat3x3(const CMat3x3 &m) { m_xx = m.m_xx; m_xy = m.m_xy; m_xz = m.m_xz; m_yx = m.m_yx; m_yy = m.m_yy; m_yz = m.m_yz; m_zx = m.m_zx; m_zy = m.m_zy; m_zz = m.m_zz; } template inline CMat3x3 &CMat3x3::operator=(const CMat3x3 &m) { m_xx = m.m_xx; m_xy = m.m_xy; m_xz = m.m_xz; m_yx = m.m_yx; m_yy = m.m_yy; m_yz = m.m_yz; m_zx = m.m_zx; m_zy = m.m_zy; m_zz = m.m_zz; return (*this); } template inline CMat3x3 CMat3x3::operator+() const { return (*this); } template inline CMat3x3 CMat3x3::operator-() const { return CMat3x3( - m_xx, - m_xy, - m_xz, - m_yx, - m_yy, - m_yz, - m_zx, - m_zy, - m_zz); } template inline CMat3x3 &CMat3x3::operator+=(const CMat3x3 &m) { return (*this) = (*this) + m; } template inline CMat3x3 &CMat3x3::operator-=(const CMat3x3 &m) { return (*this) = (*this) - m; } template inline CMat3x3 &CMat3x3::operator*=(const CMat3x3 &m) { return (*this) = (*this) * m; } template inline CMat3x3 &CMat3x3::operator*=(T s) { return (*this) = (*this) * s; } template inline CMat3x3 &CMat3x3::operator/=(T s) { return (*this) = (*this) / s; } template inline CMat3x3 CMat3x3::GetTransposed() const { return CMat3x3( m_xx, m_yx, m_zx, m_xy, m_yy, m_zy, m_xz, m_yz, m_zz); } template CMat3x3 CMat3x3::GetSubDet() const { return CMat3x3( m_yy * m_zz - m_yz * m_zy, m_yz * m_zx - m_yx * m_zz, m_yx * m_zy - m_yy * m_zx, m_zy * m_xz - m_zz * m_xy, m_zz * m_xx - m_zx * m_xz, m_zx * m_xy - m_zy * m_xx, m_xy * m_yz - m_xz * m_yy, m_xz * m_yx - m_xx * m_yz, m_xx * m_yy - m_xy * m_yx); } template CMat3x3 CMat3x3::GetInv() const { T sxx = m_yy * m_zz - m_yz * m_zy; T sxy = m_yz * m_zx - m_yx * m_zz; T sxz = m_yx * m_zy - m_yy * m_zx; T syx = m_zy * m_xz - m_zz * m_xy; T syy = m_zz * m_xx - m_zx * m_xz; T syz = m_zx * m_xy - m_zy * m_xx; T szx = m_xy * m_yz - m_xz * m_yy; T szy = m_xz * m_yx - m_xx * m_yz; T szz = m_xx * m_yy - m_xy * m_yx; T d = m_xx * sxx + m_xy * sxy + m_xz * sxz; T f = 1 / d; return CMat3x3( f * sxx, f * syx, f * szx, f * sxy, f * syy, f * szy, f * sxz, f * syz, f * szz); } template T CMat3x3::GetSqLen() const { return (m_xx * m_xx + m_xy * m_xy + m_xz * m_xz) + (m_yx * m_yx + m_yy * m_yy + m_yz * m_yz) + (m_zx * m_zx + m_zy * m_zy + m_zz * m_zz); } template T CMat3x3::GetLen() const { return Sqrt(GetSqLen()); } template T CMat3x3::GetDet() const { // Not using subdeterminant expansion to guarantee // that the result is exact null if two vectors are equal. return m_xx * m_yy * m_zz - m_xx * m_yz * m_zy + m_xy * m_yz * m_zx - m_xy * m_yx * m_zz + m_xz * m_yx * m_zy - m_xz * m_yy * m_zx; } template inline T CMat3x3::GetTrace() const { return m_xx + m_yy + m_zz; } template inline CVec3 CMat3x3::GetDual() const { return CVec3(m_yz - m_zy, m_zx - m_xz, m_xy - m_yx); } template bool CMat3x3::IsNull() const { return m_xx == 0 && m_xy == 0 && m_xz == 0 && m_yx == 0 && m_yy == 0 && m_yz == 0 && m_zx == 0 && m_zy == 0 && m_zz == 0; }; template bool CMat3x3::IsFinite() const { return IsFinite(m_xx) && IsFinite(m_xy) && IsFinite(m_xz) && IsFinite(m_yx) && IsFinite(m_yy) && IsFinite(m_yz) && IsFinite(m_zx) && IsFinite(m_zy) && IsFinite(m_zz); }; template CVec3 CMat3x3::GetRowX() const { return CVec3(m_xx, m_xy, m_xz); } template CVec3 CMat3x3::GetRowY() const { return CVec3(m_yx, m_yy, m_yz); } template CVec3 CMat3x3::GetRowZ() const { return CVec3(m_zx, m_zy, m_zz); } template CVec3 CMat3x3::GetColX() const { return CVec3(m_xx, m_yx, m_zx); } template CVec3 CMat3x3::GetColY() const { return CVec3(m_xy, m_yy, m_zy); } template CVec3 CMat3x3::GetColZ() const { return CVec3(m_xz, m_yz, m_zz); } template void CMat3x3::SetRowX(const CVec3 &v) { m_xx = v.m_x; m_xy = v.m_y; m_xz = v.m_z; } template void CMat3x3::SetRowY(const CVec3 &v) { m_yx = v.m_x; m_yy = v.m_y; m_yz = v.m_z; } template void CMat3x3::SetRowZ(const CVec3 &v) { m_zx = v.m_x; m_zy = v.m_y; m_zz = v.m_z; } template void CMat3x3::SetColX(const CVec3 &v) { m_xx = v.m_x; m_yx = v.m_y; m_zx = v.m_z; } template void CMat3x3::SetColY(const CVec3 &v) { m_xy = v.m_x; m_yy = v.m_y; m_zy = v.m_z; } template void CMat3x3::SetColZ(const CVec3 &v) { m_xz = v.m_x; m_yz = v.m_y; m_zz = v.m_z; } template inline CMat3x3 CMat3x3::GetAbsComp() const { return CMat3x3( Abs(m_xx), Abs(m_xy), Abs(m_xz), Abs(m_yx), Abs(m_yy), Abs(m_yz), Abs(m_zx), Abs(m_zy), Abs(m_zz)); } template inline T CMat3x3::GetSumAbsComp() const { return Abs(m_xx) + Abs(m_xy) + Abs(m_xz) + Abs(m_yx) + Abs(m_yy) + Abs(m_yz) + Abs(m_zx) + Abs(m_zy) + Abs(m_zz); } template inline T CMat3x3::GetMaxAbsComp() const { return Max( Max(Abs(m_xx), Abs(m_xy), Abs(m_xz)), Max(Abs(m_yx), Abs(m_yy), Abs(m_yz)), Max(Abs(m_zx), Abs(m_zy), Abs(m_zz))); } template CVec3 CMat3x3::GetSumAbsRows() const { return CVec3( Abs(m_xx) + Abs(m_xy) + Abs(m_xz), Abs(m_yx) + Abs(m_yy) + Abs(m_yz), Abs(m_zx) + Abs(m_zy) + Abs(m_zz)); } template CVec3 CMat3x3::GetSumAbsCols() const { return CVec3( Abs(m_xx) + Abs(m_yx) + Abs(m_zx), Abs(m_xy) + Abs(m_yy) + Abs(m_zy), Abs(m_xz) + Abs(m_yz) + Abs(m_zz)); } template CVec3 CMat3x3::GetMaxAbsRows() const { return CVec3( Max(Abs(m_xx), Abs(m_xy), Abs(m_xz)), Max(Abs(m_yx), Abs(m_yy), Abs(m_yz)), Max(Abs(m_zx), Abs(m_zy), Abs(m_zz))); } template CVec3 CMat3x3::GetMaxAbsCols() const { return CVec3( Max(Abs(m_xx), Abs(m_yx), Abs(m_zx)), Max(Abs(m_xy), Abs(m_yy), Abs(m_zy)), Max(Abs(m_xz), Abs(m_yz), Abs(m_zz))); } template CVec3 CMat3x3::GetLenRows() const { return CVec3( Sqrt(m_xx * m_xx + m_xy * m_xy + m_xz * m_xz), Sqrt(m_yx * m_yx + m_yy * m_yy + m_yz * m_yz), Sqrt(m_zx * m_zx + m_zy * m_zy + m_zz * m_zz)); } template CVec3 CMat3x3::GetLenCols() const { return CVec3( Sqrt(m_xx * m_xx + m_yx * m_yx + m_zx * m_zx), Sqrt(m_xy * m_xy + m_yy * m_yy + m_zy * m_zy), Sqrt(m_xz * m_xz + m_yz * m_yz + m_zz * m_zz)); } template CMat3x3 CMat3x3::GetScaledRows( const CVec3 &v) const { return CMat3x3( v.m_x * m_xx, v.m_x * m_xy, v.m_x * m_xz, v.m_y * m_yx, v.m_y * m_yy, v.m_y * m_yz, v.m_z * m_zx, v.m_z * m_zy, v.m_z * m_zz); } template CMat3x3 CMat3x3::GetScaledCols( const CVec3 &v) const { return CMat3x3( v.m_x * m_xx, v.m_y * m_xy, v.m_z * m_xz, v.m_x * m_yx, v.m_y * m_yy, v.m_z * m_yz, v.m_x * m_zx, v.m_y * m_zy, v.m_z * m_zz); } /////////////////////////////////////////////////////////////////////////////// template CMat3x3 CMat3x3::ByTensorProd( const CVec3 &v1, const CVec3 &v2) { return CMat3x3( v1.m_x * v2.m_x, v1.m_x * v2.m_y, v1.m_x * v2.m_z, v1.m_y * v2.m_x, v1.m_y * v2.m_y, v1.m_y * v2.m_z, v1.m_z * v2.m_x, v1.m_z * v2.m_y, v1.m_z * v2.m_z); } template inline CMat3x3 CMat3x3::ByDual(const CVec3 &v) { return CMat3x3( 0, v.m_z, - v.m_y, - v.m_z, 0, v.m_x, v.m_y, - v.m_x, 0); } template inline CMat3x3 CMat3x3::ByDiag(const CVec3 &v) { return CMat3x3(v.m_x, 0, 0, 0, v.m_y, 0, 0, 0, v.m_z); } template inline CMat3x3 CMat3x3::ByDiag(T x, T y, T z) { return CMat3x3(x, 0, 0, 0, y, 0, 0, 0, z); } template inline CMat3x3 CMat3x3::ByRows( const CVec3 &vx, const CVec3 &vy, const CVec3 &vz) { return CMat3x3( vx.m_x, vx.m_y, vx.m_z, vy.m_x, vy.m_y, vy.m_z, vz.m_x, vz.m_y, vz.m_z); } template inline CMat3x3 CMat3x3::ByCols( const CVec3 &vx, const CVec3 &vy, const CVec3 &vz) { return CMat3x3( vx.m_x, vy.m_x, vz.m_x, vx.m_y, vy.m_y, vz.m_y, vx.m_z, vy.m_z, vz.m_z); } /////////////////////////////////////////////////////////////////////////////// template inline bool CMat3x3::operator==(const CMat3x3 &m) const { return m_xx == m.m_xx && m_xy == m.m_xy && m_xz == m.m_xz && m_yx == m.m_yx && m_yy == m.m_yy && m_yz == m.m_yz && m_zx == m.m_zx && m_zy == m.m_zy && m_zz == m.m_zz; } template inline bool CMat3x3::operator!=(const CMat3x3 &m) const { return m_xx != m.m_xx || m_xy != m.m_xy || m_xz != m.m_xz || m_yx != m.m_yx || m_yy != m.m_yy || m_yz != m.m_yz || m_zx != m.m_zx || m_zy != m.m_zy || m_zz != m.m_zz; } template int CMat3x3::CompareComp(const CMat3x3 &m) const { if(m_xx < m.m_xx) return -1; else if(m_xx > m.m_xx) return 1; else if(m_xy < m.m_xy) return -1; else if(m_xy > m.m_xy) return 1; else if(m_xz < m.m_xz) return -1; else if(m_xz > m.m_xz) return 1; else if(m_yx < m.m_yx) return -1; else if(m_yx > m.m_yx) return 1; else if(m_yy < m.m_yy) return -1; else if(m_yy > m.m_yy) return 1; else if(m_yz < m.m_yy) return -1; else if(m_yz > m.m_yz) return 1; else if(m_zx < m.m_zx) return -1; else if(m_zx > m.m_zx) return 1; else if(m_zy < m.m_zy) return -1; else if(m_zy > m.m_zy) return 1; else if(m_zz < m.m_zy) return -1; else if(m_zz > m.m_zz) return 1; else return 0; } /////////////////////////////////////////////////////////////////////////////// template inline CMat3x3 CMat3x3::operator+(const CMat3x3 &m) const { return CMat3x3( m_xx + m.m_xx, m_xy + m.m_xy, m_xz + m.m_xz, m_yx + m.m_yx, m_yy + m.m_yy, m_yz + m.m_yz, m_zx + m.m_zx, m_zy + m.m_zy, m_zz + m.m_zz); } template inline CMat3x3 CMat3x3::operator-(const CMat3x3 &m) const { return CMat3x3( m_xx - m.m_xx, m_xy - m.m_xy, m_xz - m.m_xz, m_yx - m.m_yx, m_yy - m.m_yy, m_yz - m.m_yz, m_zx - m.m_zx, m_zy - m.m_zy, m_zz - m.m_zz); } template inline CMat3x3 CMat3x3::operator*(T s) const { return CMat3x3( m_xx * s, m_xy * s, m_xz * s, m_yx * s, m_yy * s, m_yz * s, m_zx * s, m_zy * s, m_zz * s); } template inline CMat3x3 CMat3x3::operator/(T s) const { return CMat3x3( m_xx / s, m_xy / s, m_xz / s, m_yx / s, m_yy / s, m_yz / s, m_zx / s, m_zy / s, m_zz / s); } template CMat3x3 CMat3x3::operator*(const CMat3x3 &m) const { return CMat3x3( m_xx * m.m_xx + m_xy * m.m_yx + m_xz * m.m_zx, m_xx * m.m_xy + m_xy * m.m_yy + m_xz * m.m_zy, m_xx * m.m_xz + m_xy * m.m_yz + m_xz * m.m_zz, m_yx * m.m_xx + m_yy * m.m_yx + m_yz * m.m_zx, m_yx * m.m_xy + m_yy * m.m_yy + m_yz * m.m_zy, m_yx * m.m_xz + m_yy * m.m_yz + m_yz * m.m_zz, m_zx * m.m_xx + m_zy * m.m_yx + m_zz * m.m_zx, m_zx * m.m_xy + m_zy * m.m_yy + m_zz * m.m_zy, m_zx * m.m_xz + m_zy * m.m_yz + m_zz * m.m_zz); } template CVec3 CMat3x3::operator*(const CVec3 &v) const { return CVec3( m_xx * v.m_x + m_xy * v.m_y + m_xz * v.m_z, m_yx * v.m_x + m_yy * v.m_y + m_yz * v.m_z, m_zx * v.m_x + m_zy * v.m_y + m_zz * v.m_z); } /* * CQuat Implementation */ template inline CQuat::CQuat() { } template inline CQuat::CQuat(T s) { m_t = s; m_x = m_y = m_z = 0; } template inline CQuat::CQuat(T t, T x, T y, T z) { m_t = t; m_x = x; m_y = y; m_z = z; } template inline CQuat::CQuat(T t, const CVec3 &v) { m_t = t; m_x = v.m_x; m_y = v.m_y; m_z = v.m_z; } template inline CQuat::CQuat(const CQuat &q) { m_t = q.m_t; m_x = q.m_x; m_y = q.m_y; m_z = q.m_z; } template inline CVec3 CQuat::GetVec() const { return CVec3(m_x, m_y, m_z); } template inline void CQuat::SetVec(const CVec3 &v) { m_x = v.m_x; m_y = v.m_y; m_z = v.m_z; } template inline CQuat &CQuat::operator=(const CQuat &q) { m_t = q.m_t; m_x = q.m_x; m_y = q.m_y; m_z = q.m_z; return (*this); } template inline CQuat CQuat::operator+() const { return (*this); } template inline CQuat CQuat::operator-() const { return CQuat(- m_t, - m_x, - m_y, - m_z); } template inline CQuat &CQuat::operator+=(const CQuat &q) { return (*this) = (*this) + q; } template inline CQuat &CQuat::operator-=(const CQuat &q) { return (*this) = (*this) - q; } template inline CQuat &CQuat::operator*=(const CQuat &q) { return (*this) = (*this) * q; } template inline CQuat &CQuat::operator*=(T s) { return (*this) = (*this) * s; } template inline CQuat &CQuat::operator/=(T s) { return (*this) = (*this) / s; } template CQuat operator*(const CMat3x3 &m, const CQuat &q) { // = [q.t, m * q.v] return CQuat( q.m_t, m.m_xx * q.m_x + m.m_xy * q.m_y + m.m_xz * q.m_z, m.m_yx * q.m_x + m.m_yy * q.m_y + m.m_yz * q.m_z, m.m_zx * q.m_x + m.m_zy * q.m_y + m.m_zz * q.m_z); } template CQuat operator*(const CQuat &q, const CMat3x3 &m) { // = [q.t, q.v * m] return CQuat( q.m_t, q.m_x * m.m_xx + q.m_y * m.m_yx + q.m_z * m.m_zx, q.m_x * m.m_xy + q.m_y * m.m_yy + q.m_z * m.m_zy, q.m_x * m.m_xz + q.m_y * m.m_yz + q.m_z * m.m_zz); } template CVec3 operator*(const CVec3 &v, const CQuat &q) { // = [v * q.t, v ^ q.v] return CVec3( v.m_x * q.m_t + v.m_y * q.m_z - v.m_z * q.m_y, v.m_y * q.m_t + v.m_z * q.m_x - v.m_x * q.m_z, v.m_z * q.m_t + v.m_x * q.m_y - v.m_y * q.m_x); } template CVec3 operator*(const CQuat &q, const CVec3 &v) { // = [q.t * v, q.v ^ v] return CVec3( q.m_t * v.m_x + q.m_y * v.m_z - q.m_z * v.m_y, q.m_t * v.m_y + q.m_z * v.m_x - q.m_x * v.m_z, q.m_t * v.m_z + q.m_x * v.m_y - q.m_y * v.m_x); } template CQuat CQuat::GetAbs() const { if(m_t >= 0) return CQuat(m_t, m_x, m_y, m_z); else return CQuat(- m_t, - m_x, - m_y, - m_z); } template inline CQuat CQuat::GetRev() const { return CQuat(m_t, - m_x, - m_y, - m_z); } template CQuat CQuat::GetInv() const { T f = 1 / (m_t * m_t + m_x * m_x + m_y * m_y + m_z * m_z); return CQuat(f * m_t, - f * m_x, - f * m_y, - f * m_z); } template T CQuat::GetSqLen() const { return m_t * m_t + m_x * m_x + m_y * m_y + m_z * m_z; } template T CQuat::GetLen() const { return Sqrt(GetSqLen()); } template inline T CQuat::GetQuatAngle() const { return 0.5 * GetRotAngle(); } template T CQuat::GetRotAngle() const { T cc = m_t * m_t; T ss = m_x * m_x + m_y * m_y + m_z * m_z; return Acos((cc - ss) / (cc + ss)); } template CQuat CQuat::GetNormalized() const { T f = 1 / Sqrt(m_t * m_t + m_x * m_x + m_y * m_y + m_z * m_z); return CQuat(f * m_t, f * m_x, f * m_y, f * m_z); } template CQuat CQuat::GetNormalizedTo(T Len) const { T f = Len / Sqrt(m_t * m_t + m_x * m_x + m_y * m_y + m_z * m_z); return CQuat(f * m_t, f * m_x, f * m_y, f * m_z); } template CQuat CQuat::GetSqRoot() const { T Len = Sqrt(m_t * m_t + m_x * m_x + m_y * m_y + m_z * m_z); T RootArg = 2 * (Len + m_t); if(RootArg < 0) // Maybe caused by precision errors. RootArg = 0; T Root = Sqrt(RootArg); T f = 1 / Root; if(!IsFinite(f)) f = 0; return CQuat(0.5 * Root, f * m_x, f * m_y, f * m_z); } template CQuat CQuat::NormalizedPowerTo(T Exponent) const { T cc = m_t * m_t; T ss = m_x * m_x + m_y * m_y + m_z * m_z; T dc = (cc - ss) / (cc + ss); if(!IsFinite(dc)) { // *this is near zero. return CQuat(1); } else { T Angle = 0.5 * Acos(dc); T NewAngle = Exponent * Angle; T hs = Sin(NewAngle); T hc = Cos(NewAngle); T f = hs / Sqrt(ss); if(!IsFinite(f)) { // *this is near to 1. return CQuat(1); } else return CQuat(hc, f * m_x, f * m_y, f * m_z); } } template CQuat CQuat::PowerTo(T Exponent) const { T SqLen = m_t * m_t + + m_x * m_x + m_y * m_y + m_z * m_z; T LogSqLen = Log(SqLen); if(!IsFinite(LogSqLen)) return CQuat(0); // *this was 0. else { T NewLen = Exp(Exponent * 0.5f * LogSqLen); return NormalizedPowerTo(Exponent) * NewLen; } } template inline bool CQuat::IsNull() const { return m_t == 0 && m_x == 0 && m_y == 0 && m_z == 0; } template bool CQuat::IsFinite() const { return IsFinite(m_t) && IsFinite(m_x) && IsFinite(m_y) && IsFinite(m_z); } template CMat3x3 CQuat::GetMat() const { // M w = (t^2 - v^2) w + 2 v (v w) + 2 t (v ^ w) T tt = m_t * m_t; T xx = m_x * m_x; T yy = m_y * m_y; T zz = m_z * m_z; T tx2 = 2 * m_t * m_x; T ty2 = 2 * m_t * m_y; T tz2 = 2 * m_t * m_z; T xy2 = 2 * m_x * m_y; T yz2 = 2 * m_y * m_z; T zx2 = 2 * m_z * m_x; return CMat3x3( tt + xx - yy - zz, xy2 - tz2, zx2 + ty2, xy2 + tz2, tt + yy - zz - xx, yz2 - tx2, zx2 - ty2, yz2 + tx2, tt + zz - xx - yy); } template inline CMat3x3 CQuat::GetRevMat() const { return GetRev().GetMat(); } template inline CMat3x3 CQuat::GetInvMat() const { return GetInv().GetMat(); } /////////////////////////////////////////////////////////////////////////////// template T CQuat::ScalarProd(const CQuat &q) const { return m_t * q.m_t + m_x * q.m_x + m_y * q.m_y + m_z * q.m_z; } template T CQuat::GetQuatAngleBetween(const CQuat &q) const { //CQuat Quot = (GetInv() * q2); CQuat Quot = (GetInv() * q); return Quot.GetQuatAngle(); } template T CQuat::GetRotAngleBetween(const CQuat &q) const { //CQuat Quot = (GetInv() * q2); CQuat Quot = (GetInv() * q); return Quot.GetRotAngle(); } template CQuat CQuat::InterpLinear(const CQuat &q, T Frac) const { const CQuat &This = (*this); return This + (q - This) * Frac; } template CQuat CQuat::InterpStrictExp(const CQuat &q, T Frac) const { const CQuat qBase = (*this); CQuat Quot = (qBase.GetInv() * q); CQuat Delta = Quot.PowerTo(Frac); return qBase * Delta; } template CQuat CQuat::InterpShortestExp(const CQuat &q, T Frac) const { const CQuat &qBase = (*this); CQuat Quot = (qBase.GetInv() * q); CQuat Delta = Quot.GetAbs().PowerTo(Frac); return qBase * Delta; } template CQuat CQuat::InterpStrictGeo(const CQuat &q, T Frac) const { const CQuat qBase = (*this); float Scale1 = qBase.GetSqLen(); float Scale2 = q.GetSqLen(); float Scale = Scale1 + (Scale2 - Scale1) * Frac; float Fac = Sqrt(Scale / Scale1); if(!IsFinite(Fac)) { // *this is near zero. return q * Fac; } else { CQuat Diff = (qBase.GetRev() * q); CQuat Delta = Diff.NormalizedPowerTo(Frac); // If q is near zero, Delta is 1. return (qBase * Delta) * Fac; } } template CQuat CQuat::InterpShortestGeo(const CQuat &q, T Frac) const { const CQuat qBase = (*this); float Scale1 = qBase.GetSqLen(); float Scale2 = q.GetSqLen(); float Scale = Scale1 + (Scale2 - Scale1) * Frac; float Fac = Sqrt(Scale / Scale1); if(!IsFinite(Fac)) { // *this is near zero. return q * Fac; } else { CQuat Diff = (qBase.GetRev() * q); CQuat Delta = Diff.GetAbs().NormalizedPowerTo(Frac); // If q is near zero, Delta is 1. return (qBase * Delta) * Fac; } } template CQuat CQuat::GetProjAlong( const CVec3 &Dir) const { return CQuat(m_t, GetVec().GetProjAlong(Dir)); } template CQuat CQuat::GetProjOrthoLeft( const CVec3 &Dir) const { return (*this) * GetProjAlong(Dir).GetInv(); } template CQuat CQuat::GetProjOrthoRight( const CVec3 &Dir) const { return GetProjAlong(Dir).GetInv() * (*this); } /////////////////////////////////////////////////////////////////////////////// template CQuat CQuat::ByRot( const CVec3 &Axis, T Angle) { T HalfAngle = 0.5 * Angle; T hs = Sin(HalfAngle); T hc = Cos(HalfAngle); T AxisLen = Axis.GetLen(); T f = hs / AxisLen; if(ll3d::IsFinite(f)) return CQuat(hc, f * Axis.m_x, f * Axis.m_y, f * Axis.m_z); else return CQuat(1); } template CQuat CQuat::ByScaledRot( const CVec3 &Axis, T Angle, T Scale) { T HalfAngle = 0.5 * Angle; T hs = Sin(HalfAngle); T hc = Cos(HalfAngle); T AxisLen = Axis.GetLen(); T f = hs / AxisLen; if(IsFinite(f)) return CQuat(hc, f * Axis.m_x, f * Axis.m_y, f * Axis.m_z); else return CQuat(AxisLen); } template CQuat CQuat::ByPathShortest( const CVec3 &From, const CVec3 &To) { CVec3 RezFrom = From.GetReziproc(); CQuat Base(RezFrom * To, RezFrom ^ To); return Base.GetSqRoot(); } template CQuat CQuat::ByPathAxis( const CVec3 &Axis, const CVec3 &AlsoFrom, const CVec3 &AlsoTo) { // Not using PathShortest(From x Axis, To x Axis) // to avoid singularity at From = - To // Technique: // OrthoFrom := AlsoFrom.GetProjOrtho(Axis) // OrthoTo := AlsoFrom.GetProjOrtho(Axis) // sBase = sin(rotation_angle) = (OrthoFrom ^ OrthoTo) * UnitAxis // cBase = cos(rotation_angle) = OrthoFrom * OrthoTo // sHalf = sin(rotation_angle/2) // cHalf = cos(rotation_angle/2) CVec3 UnitAxis = Axis.GetNormalized(); T AxisFrom = UnitAxis * AlsoFrom; T AxisTo = UnitAxis * AlsoTo; T sBase = UnitAxis.Volume(AlsoFrom, AlsoTo); T cBase = (AlsoFrom * AlsoTo) - AxisFrom * AxisTo; T BaseLen = Sqrt(cBase * cBase + sBase * sBase); T cUnit = cBase / BaseLen; T sHalf = Sqrt(0.5f * Abs(1 - cUnit)); // Abs for protection T cHalf = Sqrt(0.5f * Abs(1 + cUnit)); if(sBase < 0) sHalf = - sHalf; return CQuat(cHalf, UnitAxis * sHalf); } template CQuat CQuat::ByPathAlso( const CVec3 &From, const CVec3 &To, const CVec3 &AlsoFrom, const CVec3 &AlsoTo) { // First calculate shortest rotation: CQuat Shortest = CQuat::ByPathShortest(From, To); CVec3 EffAlsoFrom = Shortest.GetMat() * AlsoFrom; // Second, add extra rotation around To axis. CQuat Extra = CQuat::ByPathAxis(To, EffAlsoFrom, AlsoTo); return Extra * Shortest; } template CQuat CQuat::ByBestOfMat( const CMat3x3 &m) { // It uses the formulars // SqRoot(0.5 * (m.GetTrace() - s), v = - 0.5 * m.GetDual()) T s = Sqrt(m.GetSqLen() / 3); T qt = 0.5 * (m.m_xx + m.m_yy + m.m_zz - s); T qx = 0.5 * (m.m_zy - m.m_yz); T qy = 0.5 * (m.m_xz - m.m_zx); T qz = 0.5 * (m.m_yx - m.m_xy); return CQuat(qt, qx, qy, qz).GetSqRoot(); } template CQuat CQuat::ByRotMat( const CMat3x3 &m) { T s = Sqrt(m.GetSqLen() / 3); T tt4 = s + m.m_xx + m.m_yy + m.m_zz; T xx4 = (s + m.m_xx) - (m.m_yy + m.m_zz); T yy4 = (s + m.m_yy) - (m.m_zz + m.m_xx); T zz4 = (s + m.m_zz) - (m.m_xx + m.m_yy); T t = tt4 > 0 ? 0.5 * Sqrt(tt4) : 0; T x = xx4 > 0 ? (m.m_yz <= m.m_zy ? 0.5 : -0.5) * Sqrt(xx4) : 0; T y = yy4 > 0 ? (m.m_zx <= m.m_xz ? 0.5 : -0.5) * Sqrt(yy4) : 0; T z = zz4 > 0 ? (m.m_xy <= m.m_yx ? 0.5 : -0.5) * Sqrt(zz4) : 0; return CQuat(t, x, y, z); } template CQuat CQuat::ByRotXYZ(T Pan, T Tilt, T Roll) { T HalfPan = 0.5 * Pan; T HalfTilt = 0.5 * Tilt; T HalfRoll = 0.5 * Roll; T SinX = Sin(HalfPan); T CosX = Cos(HalfPan); T SinY = Sin(HalfTilt); T CosY = Cos(HalfTilt); T SinZ = Sin(HalfRoll); T CosZ = Cos(HalfRoll); T SinXCosZ = SinX * CosZ; T SinXSinZ = SinX * SinZ; T CosXCosZ = CosX * CosZ; T CosXSinZ = CosX * SinZ; return CQuat( CosXCosZ * CosY - SinXSinZ * SinY, SinXCosZ * CosY + CosXSinZ * SinY, CosXCosZ * SinY - SinXSinZ * CosY, CosXSinZ * CosY + SinXCosZ * SinY); } template void CQuat::GetRotAngleXYZ(T &Pan, T &Tilt, T &Roll) { T SinX = 2 * (m_t * m_x - m_y * m_z); T SinZ = 2 * (m_t * m_z - m_x * m_y); T SinY = 2 * (m_t * m_y + m_z * m_x); T CosU = m_t * m_t - m_y * m_y; T CosV = m_z * m_z - m_x * m_x; T CosX = CosU + CosV; T CosZ = CosU - CosV; T CosY = Sqrt(SinX * SinX + CosX * CosX); Pan = Atan2(SinX, CosX); Roll = Atan2(SinZ, CosZ); Tilt = Atan2(SinY, CosY); } /////////////////////////////////////////////////////////////////////////////// template inline CQuat CQuat::operator+(const CQuat &q) const { return CQuat(m_t + q.m_t, m_x + q.m_x, m_y + q.m_y, m_z + q.m_z); } template inline CQuat CQuat::operator-(const CQuat &q) const { return CQuat(m_t - q.m_t, m_x - q.m_x, m_y - q.m_y, m_z - q.m_z); } template inline CQuat CQuat::operator*(T s) const { return CQuat(m_t * s, m_x * s, m_y * s, m_z * s); } template inline CQuat CQuat::operator/(T s) const { return CQuat(m_t / s, m_x / s, m_y / s, m_z / s); } template CQuat CQuat::operator*(const CQuat &q) const { // == CQuat(t1 * t2 - v1 * v2, t1 * v2 + v1 * t2 + v1 ^ v2); return CQuat( m_t * q.m_t - m_x * q.m_x - m_y * q.m_y - m_z * q.m_z, m_t * q.m_x + m_x * q.m_t + m_y * q.m_z - m_z * q.m_y, m_t * q.m_y + m_y * q.m_t + m_z * q.m_x - m_x * q.m_z, m_t * q.m_z + m_z * q.m_t + m_x * q.m_y - m_y * q.m_x); } template inline bool CQuat::operator==(const CQuat &q) const { return m_t == q.m_t && m_x == q.m_x && m_y == q.m_y && m_z == q.m_z; } template inline bool CQuat::operator!=(const CQuat &q) const { return m_t != q.m_t || m_x != q.m_x || m_y != q.m_y || m_z != q.m_z; } template int CQuat::CompareComp(const CQuat &q) const { if(m_t < q.m_t) return -1; else if(m_t > q.m_t) return 1; else if(m_x < q.m_x) return -1; else if(m_x > q.m_x) return 1; else if(m_y < q.m_y) return -1; else if(m_y > q.m_y) return 1; else if(m_z < q.m_z) return -1; else if(m_z > q.m_z) return 1; else return 0; } }//namespace ll3d #endif //_LL3D_VEC3_H