From 19e54cfd87e83d98d16289d4df19acc35cd92a55 Mon Sep 17 00:00:00 2001 From: David Briscoe Date: Fri, 27 May 2022 14:20:40 -0700 Subject: [PATCH] vec3: Rename angle_to -> angle_between In vec2, angle_to is signed and angle_between is unsigned. We only have the unsigned version in vec3, so use the corresponding name. Remove the vec3 implementation from vec2 and use vec2's style implementation. It doesn't allocate new vectors and works even if you somehow call vec3.angle_between(vec2(), vec2()). --- modules/vec2.lua | 8 ++------ modules/vec3.lua | 18 +++++++++++++++--- spec/vec3_spec.lua | 37 ++++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 26 deletions(-) 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)