Add gears.matrix for working with cairo matrices

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2015-06-13 16:58:22 +02:00
parent a166f86864
commit 16a1ef0f48
3 changed files with 142 additions and 0 deletions

View File

@ -16,6 +16,7 @@ return
wallpaper = require("gears.wallpaper");
timer = require("gears.timer");
cache = require("gears.cache");
matrix = require("gears.matrix");
}
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

59
lib/gears/matrix.lua Normal file
View File

@ -0,0 +1,59 @@
---------------------------------------------------------------------------
-- @author Uli Schlachter
-- @copyright 2015 Uli Schlachter
-- @release @AWESOME_VERSION@
-- @module gears.matrix
---------------------------------------------------------------------------
local cairo = require("lgi").cairo
local debug = require("gears.debug")
local matrix = {}
--- Copy a cairo matrix
-- @param matrix The matrix to copy.
-- @return A copy of the given cairo matrix.
function matrix.copy(matrix)
debug.assert(cairo.Matrix:is_type_of(matrix), "Argument should be a cairo matrix")
local ret = cairo.Matrix()
ret:init(matrix.xx, matrix.yx, matrix.xy, matrix.yy, matrix.x0, matrix.y0)
return ret
end
--- Check if two cairo matrices are equal
-- @param m1 The first matrix to compare with.
-- @param m2 The second matrix to compare with.
-- @return True if they are equal.
function matrix.equals(m1, m2)
for _, k in pairs{ "xx", "xy", "yx", "yy", "x0", "y0" } do
if m1[k] ~= m2[k] then
return false
end
end
return true
end
--- Calculate a bounding rectangle for transforming a rectangle by a matrix.
-- @param matrix The cairo matrix that describes the transformation.
-- @param x The x coordinate of the rectangle.
-- @param y The y coordinate of the rectangle.
-- @param width The width of the rectangle.
-- @param height The height of the rectangle.
-- @return The x, y, width and height of the bounding rectangle.
function matrix.transform_rectangle(matrix, x, y, width, height)
-- Transform all four corners of the rectangle
local x1, y1 = matrix:transform_point(x, y)
local x2, y2 = matrix:transform_point(x, y + height)
local x3, y3 = matrix:transform_point(x + width, y + height)
local x4, y4 = matrix:transform_point(x + width, y)
-- Find the extremal points of the result
local x = math.min(x1, x2, x3, x4)
local y = math.min(y1, y2, y3, y4)
local width = math.max(x1, x2, x3, x4) - x
local height = math.max(y1, y2, y3, y4) - y
return x, y, width, height
end
return matrix
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80

View File

@ -0,0 +1,82 @@
---------------------------------------------------------------------------
-- @author Uli Schlachter
-- @copyright 2015 Uli Schlachter
---------------------------------------------------------------------------
local matrix = require("gears.matrix")
local cairo = require("lgi").cairo
describe("gears.matrix", function()
describe("copy", function()
it("Test copy", function()
local m1 = cairo.Matrix()
m1:init(1, 2, 3, 4, 5, 6)
local m2 = matrix.copy(m1)
assert.is.equal(m1.xx, m2.xx)
assert.is.equal(m1.xy, m2.xy)
assert.is.equal(m1.yx, m2.yx)
assert.is.equal(m1.yy, m2.yy)
assert.is.equal(m1.x0, m2.x0)
assert.is.equal(m1.y0, m2.y0)
m1.x0 = 42
assert.is_not.equal(m1.x0, m2.x0)
end)
end)
describe("equals", function()
it("Same matrix", function()
local m = cairo.Matrix.create_rotate(1)
assert.is_true(matrix.equals(m, m))
end)
it("Different matrix equals", function()
local m1 = cairo.Matrix.create_rotate(1)
local m2 = cairo.Matrix.create_rotate(1)
assert.is_true(matrix.equals(m1, m2))
end)
it("Different matrix unequal", function()
local m1 = cairo.Matrix()
local m2 = cairo.Matrix()
m1:init(1, 2, 3, 4, 5, 6)
m2:init(1, 2, 3, 4, 5, 0)
assert.is_false(matrix.equals(m1, m2))
end)
end)
describe("transform_rectangle", function()
local function round(n)
return math.floor(n + 0.5)
end
local function test(m, x, y, width, height,
expected_x, expected_y, expected_width, expected_height)
local actual_x, actual_y, actual_width, actual_height =
matrix.transform_rectangle(m, x, y, width, height)
assert.is.equal(round(actual_x), expected_x)
assert.is.equal(round(actual_y), expected_y)
assert.is.equal(round(actual_width), expected_width)
assert.is.equal(round(actual_height), expected_height)
-- Stupid rounding issues...
assert.is_true(math.abs(round(actual_x) - actual_x) < 0.00000001)
assert.is_true(math.abs(round(actual_y) - actual_y) < 0.00000001)
assert.is_true(math.abs(round(actual_width) - actual_width) < 0.00000001)
assert.is_true(math.abs(round(actual_height) - actual_height) < 0.00000001)
end
it("Identity matrix", function()
test(cairo.Matrix.create_identity(), 1, 2, 3, 4, 1, 2, 3, 4)
end)
it("Rotate 180", function()
test(cairo.Matrix.create_rotate(math.pi),
1, 2, 3, 4, -4, -6, 3, 4)
end)
it("Rotate 90", function()
test(cairo.Matrix.create_rotate(math.pi / 2),
1, 2, 3, 4, -6, 1, 4, 3)
end)
end)
end)
-- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80