Fix angle_to to produce signed angle
angle_to was producing the angle from +x to the difference between a,b which is unexpected. Instead, it should produce the smallest absolute angle between the two vectors and be signed to indicate the direction of rotation. By using the old angle_to implementation and modifying equal() to print out the failures, you can see the numbers that it was producing before didn't make much sense: right:angle_to(down) = 45.0 right:angle_to(left) = 0.0 right:angle_to(up) = -45.0 down:angle_to(right) = -135.0 down:angle_to(left) = -45.0 down:angle_to(up) = -90.0 left:angle_to(down) = 135.0 left:angle_to(up) = -135.0 up:angle_to(right) = 135.0 up:angle_to(down) = 90.0 up:angle_to(left) = 45.0 Now it produces numbers you'd expect: right:angle_to(down) = -90.0 right:angle_to(left) = 180.0 right:angle_to(up) = 90.0 down:angle_to(right) = 90.0 down:angle_to(left) = -90.0 down:angle_to(up) = 180.0 left:angle_to(down) = 90.0 left:angle_to(up) = -90.0 up:angle_to(right) = -90.0 up:angle_to(down) = 180.0 up:angle_to(left) = 90.0 See also https://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors Also added tests for angle_between.
This commit is contained in:
parent
0d8daf0536
commit
39aee9a421
@ -228,22 +228,31 @@ function vec2.perpendicular(a)
|
||||
return new(-a.y, a.x)
|
||||
end
|
||||
|
||||
--- Angle from one vector to another.
|
||||
--- Signed angle from one vector to another.
|
||||
-- Rotations from +x to +y are positive.
|
||||
-- @tparam vec2 a Vector
|
||||
-- @tparam vec2 b Vector
|
||||
-- @treturn number angle
|
||||
-- @treturn number angle in (-pi, pi]
|
||||
function vec2.angle_to(a, b)
|
||||
if b then
|
||||
return atan2(a.y - b.y, a.x - b.x)
|
||||
local angle = atan2(b.y, b.x) - atan2(a.y, a.x)
|
||||
-- convert to (-pi, pi]
|
||||
if angle > math.pi then
|
||||
angle = angle - 2 * math.pi
|
||||
elseif angle <= -math.pi then
|
||||
angle = angle + 2 * math.pi
|
||||
end
|
||||
return angle
|
||||
end
|
||||
|
||||
return atan2(a.y, a.x)
|
||||
end
|
||||
|
||||
--- Angle between two vectors.
|
||||
--- Unsigned angle between two vectors.
|
||||
-- Directionless and thus commutative.
|
||||
-- @tparam vec2 a Vector
|
||||
-- @tparam vec2 b Vector
|
||||
-- @treturn number angle
|
||||
-- @treturn number angle in [0, pi]
|
||||
function vec2.angle_between(a, b)
|
||||
if b then
|
||||
if vec2.is_vec2(a) then
|
||||
|
@ -45,6 +45,4 @@ project_from(out, a, b)
|
||||
mirror_on(out, a, b)
|
||||
reflect(out, i, n)
|
||||
refract(out, i, n, ior)
|
||||
angle_to(a, b)
|
||||
angle_between(a, b)
|
||||
--]]
|
||||
|
@ -203,6 +203,62 @@ describe("vec2:", function()
|
||||
assert.is.equal(temp, vec2(-1, -2))
|
||||
end)
|
||||
|
||||
it("finds angle from one 2-vector to another", function()
|
||||
local d = {
|
||||
right = vec2(1, 0),
|
||||
down = vec2(0, -1),
|
||||
left = vec2(-1, 0),
|
||||
up = vec2(0, 1),
|
||||
}
|
||||
assert.is.equal(math.deg(d.right:angle_to(d.right)), 0.0)
|
||||
assert.is.equal(math.deg(d.right:angle_to(d.down)), -90.0)
|
||||
assert.is.equal(math.deg(d.right:angle_to(d.left)), 180.0)
|
||||
assert.is.equal(math.deg(d.right:angle_to(d.up)), 90.0)
|
||||
|
||||
assert.is.equal(math.deg(d.down:angle_to(d.right)), 90.0)
|
||||
assert.is.equal(math.deg(d.down:angle_to(d.down)), 0.0)
|
||||
assert.is.equal(math.deg(d.down:angle_to(d.left)), -90.0)
|
||||
assert.is.equal(math.deg(d.down:angle_to(d.up)), 180.0)
|
||||
|
||||
assert.is.equal(math.deg(d.left:angle_to(d.right)), 180.0)
|
||||
assert.is.equal(math.deg(d.left:angle_to(d.down)), 90.0)
|
||||
assert.is.equal(math.deg(d.left:angle_to(d.left)), 0.0)
|
||||
assert.is.equal(math.deg(d.left:angle_to(d.up)), -90.0)
|
||||
|
||||
assert.is.equal(math.deg(d.up:angle_to(d.right)), -90.0)
|
||||
assert.is.equal(math.deg(d.up:angle_to(d.down)), 180.0)
|
||||
assert.is.equal(math.deg(d.up:angle_to(d.left)), 90.0)
|
||||
assert.is.equal(math.deg(d.up:angle_to(d.up)), 0.0)
|
||||
end)
|
||||
|
||||
it("finds angle between two 2-vectors", function()
|
||||
local d = {
|
||||
right = vec2(1, 0),
|
||||
down = vec2(0, -1),
|
||||
left = vec2(-1, 0),
|
||||
up = vec2(0, 1),
|
||||
}
|
||||
assert.is.equal(math.deg(d.right:angle_between(d.right)), 0.0)
|
||||
assert.is.equal(math.deg(d.right:angle_between(d.down)), 90.0)
|
||||
assert.is.equal(math.deg(d.right:angle_between(d.left)), 180.0)
|
||||
assert.is.equal(math.deg(d.right:angle_between(d.up)), 90.0)
|
||||
|
||||
assert.is.equal(math.deg(d.down:angle_between(d.right)), 90.0)
|
||||
assert.is.equal(math.deg(d.down:angle_between(d.down)), 0.0)
|
||||
assert.is.equal(math.deg(d.down:angle_between(d.left)), 90.0)
|
||||
assert.is.equal(math.deg(d.down:angle_between(d.up)), 180.0)
|
||||
|
||||
assert.is.equal(math.deg(d.left:angle_between(d.right)), 180.0)
|
||||
assert.is.equal(math.deg(d.left:angle_between(d.down)), 90.0)
|
||||
assert.is.equal(math.deg(d.left:angle_between(d.left)), 0.0)
|
||||
assert.is.equal(math.deg(d.left:angle_between(d.up)), 90.0)
|
||||
|
||||
assert.is.equal(math.deg(d.up:angle_between(d.right)), 90.0)
|
||||
assert.is.equal(math.deg(d.up:angle_between(d.down)), 180.0)
|
||||
assert.is.equal(math.deg(d.up:angle_between(d.left)), 90.0)
|
||||
assert.is.equal(math.deg(d.up:angle_between(d.up)), 0.0)
|
||||
end)
|
||||
|
||||
-- Do this last, to insulate tests from accidental state contamination
|
||||
-- Do vec3 tests last, to insulate tests from accidental state contamination
|
||||
it("converts a 2-vector to a 3-vector", function()
|
||||
|
Loading…
x
Reference in New Issue
Block a user