12#ifndef JAU_MATH_QUATERNION_HPP_
13#define JAU_MATH_QUATERNION_HPP_
49template<std::
floating_po
int Value_type>
82 : m_x(0), m_y(0), m_z(0), m_w(1) {}
85 : m_x(
x), m_y(
y), m_z(
z), m_w(
w) {}
98 return m_w*m_w + m_x*m_x + m_y*m_y + m_z*m_z;
123 return std::sqrt(magnitudeSQ);
146 return m_x *
x + m_y *
y + m_z *
z + m_w *
w;
153 return dot(quat.x(), quat.y(), quat.z(), quat.w());
175 m_x = m_y = m_z =
zero; m_w =
one;
291 return set( m_w * rhs.m_x + m_x * rhs.m_w + m_y * rhs.m_z - m_z * rhs.m_y,
292 m_w * rhs.m_y - m_x * rhs.m_z + m_y * rhs.m_w + m_z * rhs.m_x,
293 m_w * rhs.m_z + m_x * rhs.m_y - m_y * rhs.m_x + m_z * rhs.m_w,
294 m_w * rhs.m_w - m_x * rhs.m_x - m_y * rhs.m_y - m_z * rhs.m_z );
338 return set( m_x * qw + m_y * qz - m_z * qy + m_w * qx,
339 -m_x * qz + m_y * qw + m_z * qx + m_w * qy,
340 m_x * qy - m_y * qx + m_z * qw + m_w * qz,
341 -m_x * qx - m_y * qy - m_z * qz + m_w * qw);
373 return set( m_x * cos + m_w * sin,
374 m_y * cos + m_z * sin,
375 -m_y * sin + m_z * cos,
376 -m_x * sin + m_w * cos);
391 return set( m_x * cos - m_z * sin,
392 m_y * cos + m_w * sin,
393 m_x * sin + m_z * cos,
394 -m_y * sin + m_w * cos);
409 return set( m_x * cos + m_y * sin,
410 -m_x * sin + m_y * cos,
411 m_z * cos + m_w * sin,
412 -m_z * sin + m_w * cos);
466 return rotateByAngleY(headingY).rotateByAngleZ(attitudeZ).rotateByAngleX(bankX).normalize();
506 +
two * ( m_y*m_w*vecZ - m_z*m_w*vecY + m_y*m_x*vecY + m_z*m_x*vecZ );
513 +
two * ( m_x*m_y*vecX + m_z*m_y*vecZ + m_w*m_z*vecX - m_x*m_w*vecZ );
519 +
two * ( m_x*m_z*vecX + m_y*m_z*vecY - m_w*m_y*vecX + m_w*m_x*vecY );
539 if (changeAmnt ==
zero) {
541 }
else if (changeAmnt ==
one) {
550 value_type cosHalfTheta = a.m_x * bx + a.m_y * by + a.m_z * bz + a.m_w * bw;
554 if( cosHalfTheta >= 0.95f ) {
556 scale0 =
one - changeAmnt;
558 }
else if ( cosHalfTheta <= -0.99f ) {
564 if( cosHalfTheta <= -std::numeric_limits<value_type>::epsilon() ) {
570 cosHalfTheta *= -
one;
572 const value_type halfTheta = std::acos(cosHalfTheta);
573 const value_type sinHalfTheta = std::sqrt(
one - cosHalfTheta*cosHalfTheta);
576 if ( std::abs(sinHalfTheta) < 0.001f ){
583 scale0 = std::sin((
one - changeAmnt) * halfTheta) / sinHalfTheta;
584 scale1 = std::sin(changeAmnt * halfTheta) / sinHalfTheta;
588 m_x = a.m_x * scale0 + bx * scale1;
589 m_y = a.m_y * scale0 + by * scale1;
590 m_z = a.m_z * scale0 + bz * scale1;
591 m_w = a.m_w * scale0 + bw * scale1;
617 Vec3& xAxisOut,
Vec3& yAxisOut,
Vec3& zAxisOut)
noexcept {
624 xAxisOut.cross(yAxisOut, zAxisOut).normalize();
628 yAxisOut.cross(zAxisOut, xAxisOut).normalize();
641 return setFromAxes(xAxisOut, yAxisOut, zAxisOut).normalize();
666 const value_type factor = v1.length() * v2.length();
673 Vec3 tmpPivotVec = v1.cross(v2);
681 if (std::abs(v1.x) > std::abs(v1.y)) {
682 if (std::abs(v1.x) > std::abs(v1.z)) {
688 if (std::abs(v1.y) > std::abs(v1.z)) {
694 tmpPivotVec[dominantIndex] = -v1[ (dominantIndex + 1) % 3 ];
695 tmpPivotVec[(dominantIndex + 1) % 3] = v1[ dominantIndex ];
696 tmpPivotVec[(dominantIndex + 2) % 3] =
zero;
720 const value_type factor = v1.length() * v2.length();
727 Vec3 tmpPivotVec = v1.cross(v2);
735 if (std::abs(v1.x) > std::abs(v1.y)) {
736 if (std::abs(v1.x) > std::abs(v1.z)) {
742 if (std::abs(v1.y) > std::abs(v1.z)) {
748 tmpPivotVec[dominantIndex] = -v1[ (dominantIndex + 1) % 3 ];
749 tmpPivotVec[(dominantIndex + 1) % 3] = v1[ dominantIndex ];
750 tmpPivotVec[(dominantIndex + 2) % 3] =
zero;
791 if( vector.is_zero() ) {
796 m_x = vector.x * sin;
797 m_y = vector.y * sin;
798 m_z = vector.z * sin;
799 m_w = std::cos(halfangle);
812 const value_type sqrLength = m_x*m_x + m_y*m_y + m_z*m_z;
818 angle = std::acos(m_w) *
two;
820 axis.set( m_x * invLength,
843 return setFromEuler(angradXYZ.x, angradXYZ.y, angradXYZ.z);
878 const value_type sinHeadingY = std::sin(angle);
879 const value_type cosHeadingY = std::cos(angle);
880 angle = attitudeZ *
half;
881 const value_type sinAttitudeZ = std::sin(angle);
882 const value_type cosAttitudeZ = std::cos(angle);
883 angle = bankX *
half;
888 const value_type cosHeadingXcosAttitude = cosHeadingY * cosAttitudeZ;
889 const value_type sinHeadingXsinAttitude = sinHeadingY * sinAttitudeZ;
890 const value_type cosHeadingXsinAttitude = cosHeadingY * sinAttitudeZ;
891 const value_type sinHeadingXcosAttitude = sinHeadingY * cosAttitudeZ;
893 m_w = cosHeadingXcosAttitude * cosBankX - sinHeadingXsinAttitude * sinBankX;
894 m_x = cosHeadingXcosAttitude * sinBankX + sinHeadingXsinAttitude * cosBankX;
895 m_y = sinHeadingXcosAttitude * cosBankX + cosHeadingXsinAttitude * sinBankX;
896 m_z = cosHeadingXsinAttitude * cosBankX - sinHeadingXcosAttitude * sinBankX;
921 const value_type unit = sqx + sqy + sqz + sqw;
924 if (
test > 0.499f * unit) {
926 two * std::atan2(m_x, m_w),
928 }
else if (
test < -0.499f * unit) {
930 -
two * std::atan2(m_x, m_w),
933 return Vec3( std::atan2(
two * m_x * m_w -
two * m_y * m_z, -sqx + sqy - sqz + sqw),
934 std::atan2(
two * m_y * m_w -
two * m_x * m_z, sqx - sqy - sqz + sqw),
935 std::asin(
two *
test / unit) );
964 m_x = ( m21 - m12 ) * S;
965 m_y = ( m02 - m20 ) * S;
966 m_z = ( m10 - m01 ) * S;
967 }
else if ( m00 > m11 && m00 > m22) {
969 m_w = ( m21 - m12 ) * S;
971 m_y = ( m10 + m01 ) * S;
972 m_z = ( m02 + m20 ) * S;
973 }
else if ( m11 > m22 ) {
975 m_w = ( m02 - m20 ) * S;
976 m_x = ( m20 + m01 ) * S;
978 m_z = ( m21 + m12 ) * S;
981 m_w = ( m10 - m01 ) * S;
982 m_x = ( m02 + m20 ) * S;
983 m_y = ( m21 + m12 ) * S;
1004 return setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, m.m21, m.m22);
1020 xAxis.y, yAxis.y, zAxis.y,
1021 xAxis.z, yAxis.z, zAxis.z);
1065 srecip =
two / norm;
1081 m.m00 =
one - ( yy + zz );
1082 m.m01 = ( xy - zw );
1083 m.m02 = ( xz + yw );
1086 m.m10 = ( xy + zw );
1087 m.m11 =
one - ( xx + zz );
1088 m.m12 = ( yz - xw );
1091 m.m20 = ( xz - yw );
1092 m.m21 = ( yz + xw );
1093 m.m22 =
one - ( xx + yy );
1096 m.m30 = m.m31 = m.m32 =
zero;
1111 tmp.getColumn(2, zAxis);
1112 tmp.getColumn(1, yAxis);
1113 tmp.getColumn(0, xAxis);
1125 toAxes(xAxis, yAxis, zAxis, tmp);
1147 return "Quat[x "+std::to_string(m_x)+
", y "+std::to_string(m_y)+
", z "+std::to_string(m_z)+
", w "+std::to_string(m_w)+
"]";
1151template<std::
floating_po
int T>
1156template<std::
floating_po
int T>
1161template<std::
floating_po
int T>
1166template<std::
floating_po
int T>
1171template<std::
floating_po
int T>
1176template<std::
floating_po
int T>
1178 return out << v.toString();
1182static_assert(
alignof(float) ==
alignof(
Quat4f));
1184template <jau::req::packed_
floating_po
int Value_type>
1196template <jau::req::packed_
floating_po
int Value_type>
1199 return res.setFromMat(m00, m01, m02, m10, m11, m12, m20, m21, m22);
1202template <jau::req::packed_
floating_po
int Value_type>
1206 return mul( quat.toMatrix(tmp) );
Basic 4x4 value_type matrix implementation using fields for intensive use-cases (host operations).
constexpr_cxx26 Matrix4 & rotate(const value_type ang_rad, const value_type x, const value_type y, const value_type z) noexcept
Rotate this matrix about give axis and angle in radians, i.e.
Quaternion< value_type > Quat
constexpr Matrix4() noexcept
Creates a new identity matrix.
Quaternion implementation supporting Gimbal-Lock free rotations.
constexpr Quaternion & operator*=(const Quaternion &rhs) noexcept
Multiply this quaternion: this = this * rhs, returns this.
constexpr Quaternion & setFromMat(const value_type m00, const value_type m01, const value_type m02, const value_type m10, const value_type m11, const value_type m12, const value_type m20, const value_type m21, const value_type m22) noexcept
Compute the quaternion from a 3x3 column rotation matrix.
constexpr void toAxes(Vec3 &xAxis, Vec3 &yAxis, Vec3 &zAxis, Matrix4< value_type > &tmp) const noexcept
Extracts this quaternion's orthogonal rotation axes.
Quaternion & setFromAngleAxis(const value_type angle, const Vec3 &vector) noexcept
constexpr_cxx26 Quaternion & setFromVectors(const Vec3 &v1, const Vec3 &v2) noexcept
Initialize this quaternion from two vectors.
Vec3 rotateVector(const Vec3 &in) noexcept
constexpr value_type x() const noexcept
constexpr value_type magnitudeSquared() const noexcept
constexpr_cxx26 Quaternion & rotateByAngleZ(value_type angle) noexcept
Rotate this quaternion around Z axis with the given angle in radians.
constexpr void setY(value_type y) noexcept
constexpr Quaternion & setIdentity() noexcept
constexpr_cxx26 Quaternion & setFromEuler(const Vec3 &angradXYZ) noexcept
Initializes this quaternion from the given Euler rotation array angradXYZ in radians.
Vector3F< value_type > Vec3
constexpr Quaternion() noexcept
const value_type & const_reference
constexpr Quaternion & operator*=(const value_type rhs) noexcept
Scale this quaternion by a scalar: this = this * rhs, returns this.
constexpr Quaternion & setFromAxes(const Vec3 &xAxis, const Vec3 &yAxis, const Vec3 &zAxis) noexcept
Quaternion & setLookAt(const Vec3 &directionIn, const Vec3 &upIn, Vec3 &xAxisOut, Vec3 &yAxisOut, Vec3 &zAxisOut) noexcept
Set this quaternion to equal the rotation required to point the z-axis at direction and the y-axis to...
constexpr_cxx26 Vec3 toEuler() noexcept
Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ).
constexpr void setZ(value_type z) noexcept
constexpr_cxx26 Quaternion & setSlerp(const Quaternion &a, const Quaternion &b, const value_type changeAmnt) noexcept
Set this quaternion to a spherical linear interpolation between the given start and end quaternions b...
constexpr_cxx26 Quaternion & setFromNormalVectors(const Vec3 &v1, const Vec3 &v2) noexcept
Initialize this quaternion from two normalized vectors.
constexpr_cxx26 Quaternion & rotateByAngleY(value_type angle) noexcept
Rotate this quaternion around Y axis with the given angle in radians.
constexpr Quaternion & set(const value_type x, const value_type y, const value_type z, const value_type w) noexcept
Set all values of this quaternion using the given components.
static constexpr const value_type half
constexpr value_type dot(value_type x, value_type y, value_type z, value_type w) const noexcept
Returns the dot product of this quaternion with the given x,y,z and m_w components.
static constexpr const value_type two
constexpr_cxx26 Quaternion & rotateByEuler(const value_type bankX, const value_type headingY, const value_type attitudeZ) noexcept
Rotates this quaternion from the given Euler rotation angles in radians.
constexpr_cxx26 value_type toAngleAxis(Vec3 &axis) const noexcept
Transform the rotational quaternion to axis based rotation angles.
constexpr Quaternion & operator=(const Quaternion &) noexcept=default
constexpr_cxx26 Quaternion & rotateByAngleNormalAxis(const value_type angle, const value_type axisX, const value_type axisY, const value_type axisZ) noexcept
Rotate this quaternion by the given angle and axis.
std::string toString() const noexcept
constexpr Quaternion & invert() noexcept
Invert the quaternion If rotational, will produce a the inverse rotation.
constexpr Quaternion & operator=(Quaternion &&) noexcept=default
constexpr value_type y() const noexcept
const value_type * const_pointer
constexpr_cxx26 value_type magnitude() const noexcept
Return the magnitude of this quaternion, i.e.
constexpr void setW(value_type w) noexcept
constexpr Quaternion & rotateByAngleX(const value_type sin, const value_type cos) noexcept
Rotate this quaternion around X axis with the given angle's sin + cos values.
constexpr Quaternion & rotateByAngleY(const value_type sin, const value_type cos) noexcept
Rotate this quaternion around Y axis with the given angle's sin + cos values.
constexpr value_type dot(const Quaternion &quat) const noexcept
Returns the dot product of this quaternion with the given quaternion.
constexpr_cxx26 Quaternion & rotateByAngleNormalAxis(const value_type angle, const Vec3 &axis) noexcept
Rotate this quaternion by the given angle and axis.
static constexpr const value_type zero
constexpr value_type w() const noexcept
constexpr Quaternion & rotateByAngleZ(const value_type sin, const value_type cos) noexcept
Rotate this quaternion around Y axis with the given angle's sin + cos values.
constexpr bool isIdentity() const noexcept
Returns true if this quaternion has identity.
constexpr Quaternion(const value_type x, const value_type y, const value_type z, const value_type w) noexcept
constexpr Quaternion & operator-=(const Quaternion &rhs) noexcept
Subtract a quaternion: this = this - rhs, returns this.
constexpr value_type z() const noexcept
constexpr Quaternion & normalize() noexcept
Normalize a quaternion required if to be used as a rotational quaternion.
constexpr_cxx26 Quaternion & setFromEuler(const value_type bankX, const value_type headingY, const value_type attitudeZ) noexcept
Initializes this quaternion from the given Euler rotation angles in radians.
constexpr_cxx26 Quaternion & rotateByAngleX(const value_type angle) noexcept
Rotate this quaternion around X axis with the given angle in radians.
constexpr Quaternion(Quaternion &&o) noexcept=default
static constexpr const value_type allowed_deviation
constexpr Quaternion & setFromMat(const Mat4 &m) noexcept
Compute the quaternion from a 3x3 column rotation matrix from Mat4 instance.
constexpr_cxx26 Quaternion & setFromAngleNormalAxis(const value_type angle, const Vec3 &vector) noexcept
constexpr Mat4 toMatrix() const noexcept
Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
const value_type * const_iterator
constexpr Quaternion & operator+=(const Quaternion &rhs) noexcept
Add a quaternion: this = this + rhs, returns this.
Quaternion & rotateByEuler(const Vec3 &angradXYZ) noexcept
Rotates this quaternion from the given Euler rotation array angradXYZ in radians.
constexpr void toAxes(Vec3 &xAxis, Vec3 &yAxis, Vec3 &zAxis) const noexcept
Extracts this quaternion's orthogonal rotation axes.
static constexpr const value_type one
constexpr Mat4 & toMatrix(Mat4 &m) const noexcept
Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
constexpr Quaternion(const Quaternion &o) noexcept=default
constexpr Quaternion & conjugate() noexcept
Conjugates this quaternion [-x, -y, -z, w].
constexpr void setX(value_type x) noexcept
Matrix4< value_type > Mat4
constexpr bool operator==(const Quaternion &o) const noexcept
Vec3 & rotateVector(const Vec3 &in, Vec3 &out) noexcept
3D vector using three value_type components.
constexpr value_type length() const noexcept
Return the length of a vector, a.k.a the norm or magnitude
constexpr bool is_zero3f(const T &a, const T &b, const T &c, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if all given values a, b and c are less than epsilon, w/ epsilon > 0.
constexpr bool equals(const T &a, const T &b, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if both values are equal, i.e.
constexpr bool is_zero(const T &a, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if the given value is less than epsilon, w/ epsilon > 0.
constexpr Quaternion< T > operator-(const Quaternion< T > &lhs, const Quaternion< T > &rhs) noexcept
constexpr Matrix4< T > operator*(const Matrix4< T > &lhs, const Matrix4< T > &rhs) noexcept
constexpr Quaternion< T > operator+(const Quaternion< T > &lhs, const Quaternion< T > &rhs) noexcept
Matrix4 & setToRotation(const Quat &q)
Set this matrix to rotation using the given Quaternion.
Quaternion< float > Quat4f
Quat & getRotation(Quat &res) const noexcept
Returns the rotation [m00 .
static std::ostream & operator<<(std::ostream &out, const TestDataBF &v)