diff --git a/qbsp/mathlib.cc b/qbsp/mathlib.cc index d036ace4..12940693 100644 --- a/qbsp/mathlib.cc +++ b/qbsp/mathlib.cc @@ -139,3 +139,26 @@ VectorScale(const vec3_t v, const vec_t scale, vec3_t out) out[1] = v[1] * scale; out[2] = v[2] * scale; } + +/// Returns degrees of clockwise rotation from start to end, assuming `normal` is pointing towards the viewer +float SignedDegreesBetweenUnitVectors(const vec3_t start, const vec3_t end, const vec3_t normal) +{ + const float cosangle = qmax(-1.0, qmin(1.0, DotProduct(start, end))); + const float unsigned_degrees = acos(cosangle) * (360.0 / (2.0 * Q_PI)); + + if (unsigned_degrees < ANGLEEPSILON) + return 0; + + // get a normal for the rotation plane using the right-hand rule + vec3_t rotationNormal; + CrossProduct(start, end, rotationNormal); + VectorNormalize(rotationNormal); + + const float normalsCosAngle = DotProduct(rotationNormal, normal); + if (normalsCosAngle >= 0) { + // counterclockwise rotation + return -unsigned_degrees; + } + // clockwise rotation + return unsigned_degrees; +} diff --git a/qbsp/qbsp.hh b/qbsp/qbsp.hh index 2661783e..9ea947b1 100644 --- a/qbsp/qbsp.hh +++ b/qbsp/qbsp.hh @@ -235,6 +235,8 @@ vec_t VectorNormalize(vec3_t v); void VectorInverse(vec3_t v); void VectorScale(const vec3_t v, const vec_t scale, vec3_t out); +float SignedDegreesBetweenUnitVectors(const vec3_t start, const vec3_t end, const vec3_t normal); + #ifdef __GNUC__ /* min and max macros with type checking */ #define qmax(a,b) ({ \