diff --git a/modules/vec2.lua b/modules/vec2.lua index c392444..6a4f625 100644 --- a/modules/vec2.lua +++ b/modules/vec2.lua @@ -257,18 +257,14 @@ end --- Unsigned angle between two vectors. -- Directionless and thus commutative. +-- Input vectors must be non-zero. -- @tparam vec2 a Vector -- @tparam vec2 b Vector -- @treturn number angle in [0, pi] function vec2.angle_between(a, b) if b then - if vec2.is_vec2(a) then - return acos(a:dot(b) / (a:len() * b:len())) - end - - return acos(vec3.dot(a, b) / (vec3.len(a) * vec3.len(b))) + return acos(a:dot(b) / (a:len() * b:len())) end - return 0 end diff --git a/modules/vec3.lua b/modules/vec3.lua index b653506..2430bd6 100644 --- a/modules/vec3.lua +++ b/modules/vec3.lua @@ -4,6 +4,7 @@ local modules = (...):gsub('%.[^%.]+$', '') .. "." local precond = require(modules .. "_private_precond") local private = require(modules .. "_private_utils") +local acos = math.acos local sqrt = math.sqrt local cos = math.cos local sin = math.sin @@ -330,9 +331,20 @@ function vec3.flip_z(a) return vec3.new(a.x, a.y, -a.z) end -function vec3.angle_to(a, b) - local v = a:normalize():dot(b:normalize()) - return math.acos(v) +-- No angle_to because that requires defining an axis of rotation. Instead you +-- likely want to convert both into vec2 and use vec2.angle_to. + +--- Unsigned angle between two vectors. +-- Directionless and thus commutative. +-- Input vectors must be non-zero. +-- @tparam vec3 a Vector +-- @tparam vec3 b Vector +-- @treturn number angle in [0, pi] +function vec3.angle_between(a, b) + if b then + return acos(a:dot(b) / (a:len() * b:len())) + end + return 0 end --- Return a boolean showing if a table is or is not a vec3. diff --git a/spec/vec3_spec.lua b/spec/vec3_spec.lua index 09fb1d9..a2d4404 100644 --- a/spec/vec3_spec.lua +++ b/spec/vec3_spec.lua @@ -232,30 +232,33 @@ describe("vec3:", function() assert.is.equal(temp, vec3(-1, -2, -3)) end) - it("get two 3-vectors angle", function() - local angle_to = function(a, b) - local deg = math.deg(a:angle_to(b)) + it("gets angle between two 3-vectors", function() + local angle_between = function(a, b) + local deg = math.deg(a:angle_between(b)) return string.format('%.2f', deg) end local a = vec3(1,2,3) - assert.is.equal(angle_to(a, vec3(3, 2, 1)), '44.42') - assert.is.equal(angle_to(a, vec3(0, 10, 0)), '57.69') - assert.is.equal(angle_to(a, vec3(0, -12, -10)), '157.51') + assert.is.equal(angle_between(a, a), '0.00') + assert.is.equal(angle_between(a, vec3(3, 2, 1)), '44.42') + assert.is.equal(angle_between(a, vec3(0, 10, 0)), '57.69') + assert.is.equal(angle_between(a, vec3(0, -12, -10)), '157.51') a = vec3.unit_z - assert.is.equal(angle_to(a, vec3(0, 10, 0)), '90.00') - assert.is.equal(angle_to(a, vec3(-123, 10, 0)), '90.00') - assert.is.equal(angle_to(a, vec3(-10, 0, 10)), '45.00') - assert.is.equal(angle_to(a, vec3(-10, 0, -10)), '135.00') - assert.is.equal(angle_to(a, vec3(0, -10, -10)), '135.00') - assert.is.equal(angle_to(a, vec3(0, 0, -10)), '180.00') - assert.is.equal(angle_to(a, vec3(0, 0, 100)), '0.00') + assert.is.equal(angle_between(a, a), '0.00') + assert.is.equal(angle_between(a, vec3(0, 10, 0)), '90.00') + assert.is.equal(angle_between(a, vec3(-123, 10, 0)), '90.00') + assert.is.equal(angle_between(a, vec3(-10, 0, 10)), '45.00') + assert.is.equal(angle_between(a, vec3(-10, 0, -10)), '135.00') + assert.is.equal(angle_between(a, vec3(0, -10, -10)), '135.00') + assert.is.equal(angle_between(a, vec3(0, 0, -10)), '180.00') + assert.is.equal(angle_between(a, vec3(0, 0, 100)), '0.00') a = vec3(100, 100, 0) - assert.is.equal(angle_to(a, vec3(0, 0, 100)), '90.00') - assert.is.equal(angle_to(a, vec3(0, 0, -100)), '90.00') - assert.is.equal(angle_to(a, vec3(-10, -10, 0)), '180.00') - assert.is.equal(angle_to(a, vec3.unit_z), '90.00') + assert.is.equal(angle_between(a, a), '0.00') + assert.is.equal(angle_between(a, vec3(0, 0, 100)), '90.00') + assert.is.equal(angle_between(a, vec3(0, 0, -100)), '90.00') + assert.is.equal(angle_between(a, vec3(-10, -10, 0)), '180.00') + assert.is.equal(angle_between(a, vec3.unit_z), '90.00') end) end)