diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h index 9f0685b6..f09236e1 100644 --- a/src/lol/math/vector.h +++ b/src/lol/math/vector.h @@ -1298,12 +1298,29 @@ extern Quat slerp(Quat const &qa, Quat const &qb, T f); } #define LOL_VEC_3_FUNS(tname, tprefix, type) \ + /* Return the cross product (vector product) of "a" and "b" */ \ tprefix \ inline tname cross(tname const &a, tname const &b) \ { \ return tname((type)(a.y * b.z - a.z * b.y), \ (type)(a.z * b.x - a.x * b.z), \ (type)(a.x * b.y - a.y * b.x)); \ + } \ + \ + /* Return a vector that is orthogonal to "a" */ \ + tprefix \ + inline tname orthogonal(tname const &a) \ + { \ + return lol::abs(a.x) > lol::abs(a.z) \ + ? tname(-a.y, a.x, (type)0) \ + : tname((type)0, -a.z, a.y); \ + } \ + \ + /* Return a vector that is orthonormal to "a" */ \ + tprefix \ + inline tname orthonormal(tname const &a) \ + { \ + return normalize(orthogonal(a)); \ } #define LOL_BINARY_NONVECTOR_OPS(tname, tprefix, type) \ diff --git a/test/unit/vector.cpp b/test/unit/vector.cpp index 7384424d..81ae20ca 100644 --- a/test/unit/vector.cpp +++ b/test/unit/vector.cpp @@ -124,6 +124,32 @@ LOLUNIT_FIXTURE(VectorTest) LOLUNIT_ASSERT_EQUAL(c.w, 0.0f); LOLUNIT_ASSERT_EQUAL(a3, a1); } + + LOLUNIT_TEST(Orthogonal) + { + vec3 a(1.f, 0.f, 0.f); + vec3 b(0.f, 1.f, 0.f); + vec3 c(0.f, 0.f, 1.f); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthogonal(a), a), 0.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthogonal(b), b), 0.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthogonal(c), c), 0.f, 1e-6f); + + /* The length of the orthogonal vector should be at least + * sqrt(2)/2 times the length of the original vector. */ + LOLUNIT_ASSERT_GREATER(length(orthogonal(a)), 0.7f); + LOLUNIT_ASSERT_GREATER(length(orthogonal(b)), 0.7f); + LOLUNIT_ASSERT_GREATER(length(orthogonal(c)), 0.7f); + + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthonormal(a), a), 0.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthonormal(b), b), 0.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(dot(orthonormal(c), c), 0.f, 1e-6f); + + /* The length of the orthonormal vector should be 1. */ + LOLUNIT_ASSERT_DOUBLES_EQUAL(length(orthonormal(a)), 1.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(length(orthonormal(b)), 1.f, 1e-6f); + LOLUNIT_ASSERT_DOUBLES_EQUAL(length(orthonormal(c)), 1.f, 1e-6f); + } }; } /* namespace lol */