implement quaternion functions

This commit is contained in:
2025-03-14 13:13:47 +01:00
parent 07ca986809
commit 51a67bee8f

View File

@@ -1,44 +1,93 @@
#include "../../error.h" #include <math.h>
#include "float3.h" #include "float3.h"
#include "float4.h" #include "float4.h"
// converts a float3 to a quaternion
static inline float4 quat_from_float3(float3 v) {
return (float4){
.w = 0.0F,
.x = v.x,
.y = v.y,
.z = v.z,
};
}
// converts euler angles into quaternion // converts euler angles into quaternion (ordered roll, pitch, yaw) (in radians)
static inline float4 quat_from_euler(float3 euler) { static inline float4 quat_from_euler(float3 euler) {
(void)euler; euler = float3_mul_s(euler, 0.5F); // half the angles due to quaternions using θ/2 in the formula
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function float cx = cosf32(euler.x), sx = sinf32(euler.x);
float cy = cosf32(euler.y), sy = sinf32(euler.y);
float cz = cosf32(euler.z), sz = sinf32(euler.z);
return (float4){
.w = cx * cy * cz - sx * sy * sz,
.x = sx * cy * cz + cx * sy * sz,
.y = cx * sy * cz - sx * cy * sz,
.z = cx * cy * sz + sx * sy * cz,
};
} }
// converts quaternion into euler angles // converts quaternion into euler angles (ordered as roll, pitch, yaw)
static inline float3 quat_to_euler(float4 q) { static inline float3 quat_to_euler(float4 q) {
(void)q; // warn: do not read from these variables until set
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function float3 euler;
} float a, b;
// adds two quaternions // compute the roll (Φ)
static inline float4 quat_add(float4 q1, float4 q2) { a = 2 * (q.w * q.x + q.y * q.z); // sin(r)•cos(p)
(void)q1, (void)q2; b = 1 - 2 * (q.x * q.x + q.y * q.y); // cos(r)•cos(p)
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function euler.x = atan2f(a, b);
}
// subtracts two quaternions // compute the pitch (θ)
static inline float4 quat_sub(float4 q1, float4 q2) { a = 2 * (q.w * q.y - q.z * q.x);
(void)q1, (void)q2; euler.y = fabsf(a) >= 1 ? copysignf(M_PI_2, a) : asinf(a); // if |a| >=1, sgn(a)•(π/2), else asin(a)
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
// compute the yaw (ψ)
a = 2 * (q.w * q.z + q.x * q.y); // sin(y)•cos(y)
b = 1 - 2 * (q.y * q.y + q.z * q.z); // cos(y)•cos(y)
euler.z = atan2f(a, b);
// return the final angles
return euler;
} }
// multiplies two quaternions // multiplies two quaternions
static inline float4 quat_mul(float4 q1, float4 q2) { static inline float4 quat_mul(float4 q1, float4 q2) {
return (float4){ return (float4){
q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, // x .w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, // y .x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x, // z .y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, // w .z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x,
}; };
} }
// multiplies two quaternions // get the conjugate of the quaternion (negates the vector portion)
static inline float4 quat_div(float4 q1, float4 q2) { static inline float4 quat_conj(float4 q) {
(void)q1, (void)q2; return (float4){
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function .w = q.w,
.x = -q.x,
.y = -q.y,
.z = -q.z,
};
}
// get the multiplicative inverse of the quaternion (conj / mag²)
static inline float4 quat_inv(float4 q) {
float mag2 = float4_mag2(q);
if (mag2 == 0.0F) return (float4){0};
mag2 = 1.0F / mag2;
return float4_mul_s(quat_conj(q), mag2);
}
// rotates a vector by the quaternion (q must be a unit quaternion (normalized))
static inline float3 quat_rot(float4 q, float3 v) {
q = quat_mul(quat_mul(q, quat_from_float3(v)), quat_conj(q)); // q•v•q¯¹ (using conjugate for q⁻¹, as for unit quaternions this is the same as the multiplicative inverse)
return (float3){q.x, q.y, q.z};
}
// rotates a vector by the quaternion, q may be non-normalized
static inline float3 quat_rot_s(float4 q, float3 v) {
q = quat_mul(quat_mul(q, quat_from_float3(v)), quat_inv(q)); // q•v•q¯¹
return (float3){q.x, q.y, q.z};
} }