Transforms and matrices

Transforms and matrices

For basic transformations of the drawing space, use scale(sx, sy), rotate(a), and translate(tx, ty).

translate() shifts the current axes by the specified amounts in x and y. It's relative and cumulative, rather than absolute:

origin()
for i in range(0, step=30, length=6)
    sethue(HSV(i, 1, 1)) # from Colors
    setopacity(0.5)
    circle(0, 0, 40, :fillpreserve)
    setcolor("black")
    strokepath()
    translate(50, 0)
end

translate

scale(x, y) or scale(n) scales the current workspace by the specified amounts. Again, it's relative to the current scale, not to the document's original.

origin()
for i in range(0, step=30, length=6)
    sethue(HSV(i, 1, 1)) # from Colors
    circle(0, 0, 90, :fillpreserve)
    setcolor("black")
    strokepath()
    scale(0.8, 0.8)
end

scale

rotate() rotates the current workspace by the specifed amount about the current 0/0 point. It's relative to the previous rotation, not to the document's original.

origin()
for i in 1:8
    randomhue()
    squircle(Point(40, 0), 20, 30, :fillpreserve)
    sethue("black")
    strokepath()
    rotate(pi/4)
end

rotate

To return home after many changes, you can use setmatrix([1, 0, 0, 1, 0, 0]) to reset the matrix to the default. origin() resets the matrix then moves the origin to the center of the page.

rescale() is a convenient utility function for linear interpolation, also called a "lerp".

Luxor.scaleFunction.
scale(x, y)

Scale workspace by x and y.

Example:

scale(0.2, 0.3)
scale(f)

Scale workspace by f in both x and y.

Luxor.rotateFunction.
rotate(a::Float64)

Rotate workspace by a radians clockwise (from positive x-axis to positive y-axis).

Luxor.translateFunction.
translate(point)
translate(x::Real, y::Real)

Translate the workspace to x and y or to pt.

Matrices and transformations

In Luxor, there's always a current matrix. It's a six element array:

\[\begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ \end{bmatrix}\]

which is usually handled in Julia/Cairo/Luxor as a simple vector/array:

julia> getmatrix()
6-element Array{Float64,1}:
   1.0
   0.0
   0.0
   1.0
   0.0
   0.0

transform(a) transforms the current workspace by 'multiplying' the current matrix with matrix a. For example, transform([1, 0, xskew, 1, 50, 0]) skews the current matrix by xskew radians and moves it 50 in x and 0 in y.

function boxtext(p, t)
    sethue("grey30")
    box(p, 30, 50, :fill)
    sethue("white")
    textcentered(t, p)
end

for i in 0:5
    xskew = tand(i * 5.0)
    transform([1, 0, xskew, 1, 50, 0])
    boxtext(O, string(round(rad2deg(xskew), digits=1), "°"))
end

transform

getmatrix() gets the current matrix, setmatrix(a) sets the matrix to array a.

Luxor.getmatrixFunction.
getmatrix()

Get the current matrix. Returns an array of six float64 numbers:

  • xx component of the affine transformation

  • yx component of the affine transformation

  • xy component of the affine transformation

  • yy component of the affine transformation

  • x0 translation component of the affine transformation

  • y0 translation component of the affine transformation

Some basic matrix transforms:

  • translate

transform([1, 0, 0, 1, dx, dy]) shifts by dx, dy

  • scale

transform([fx 0 0 fy 0 0]) scales by fx and fy

  • rotate

transform([cos(a), -sin(a), sin(a), cos(a), 0, 0]) rotates around to a radians

rotate around O: [c -s s c 0 0]
  • shear

transform([1 0 a 1 0 0]) shears in x direction by a

  • shear in y: [1 B 0 1 0 0]

  • x-skew

transform([1, 0, tan(a), 1, 0, 0]) skews in x by a

  • y-skew

transform([1, tan(a), 0, 1, 0, 0]) skews in y by a

  • flip

transform([fx, 0, 0, fy, centerx * (1 - fx), centery * (fy-1)]) flips with center at centerx/centery

  • reflect

transform([1 0 0 -1 0 0]) reflects in xaxis

transform([-1 0 0 1 0 0]) reflects in yaxis

When a drawing is first created, the matrix looks like this:

getmatrix() = [1.0, 0.0, 0.0, 1.0, 0.0, 0.0]

When the origin is moved to 400/400, it looks like this:

getmatrix() = [1.0, 0.0, 0.0, 1.0, 400.0, 400.0]

To reset the matrix to the original:

setmatrix([1.0, 0.0, 0.0, 1.0, 0.0, 0.0])
Luxor.setmatrixFunction.
setmatrix(m::AbstractArray)

Change the current matrix to matrix m. Use getmatrix() to get the current matrix.

Luxor.transformFunction.
transform(a::AbstractArray)

Modify the current matrix by multiplying it by matrix a.

For example, to skew the current state by 45 degrees in x and move by 20 in y direction:

transform([1, 0, tand(45), 1, 0, 20])

Use getmatrix() to get the current matrix.

Luxor.crossproductFunction.
crossproduct(p1::Point, p2::Point)

This is the perp dot product, really, not the crossproduct proper (which is 3D):

Luxor.blendmatrixFunction.
blendmatrix(b::Blend, m)

Set the matrix of a blend.

To apply a sequence of matrix transforms to a blend:

A = [1 0 0 1 0 0]
Aj = cairotojuliamatrix(A)
Sj = scalingmatrix(2, .2) * Aj
Tj = translationmatrix(10, 0) * Sj
A1 = juliatocairomatrix(Tj)
blendmatrix(b, As)
Luxor.rotationmatrixFunction.
rotationmatrix(a)

Return a 3x3 Julia matrix that will apply a rotation through a radians.

Luxor.scalingmatrixFunction.
scalingmatrix(sx, sy)

Return a 3x3 Julia matrix that will apply a scaling by sx and sy.

translationmatrix(x, y)

Return a 3x3 Julia matrix that will apply a translation in x and y.

Use the getscale(), gettranslation(), and getrotation() functions to find the current values of the current matrix. These can also find the values of arbitrary 3x3 matrices.

Luxor.getscaleFunction.
getscale(R::Matrix)
getscale()

Get the current scale of a Julia 3x3 matrix, or the current Luxor scale.

Returns a tuple of x and y values.

Luxor.gettranslationFunction.
gettranslation(R::Matrix)
gettranslation()

Get the current translation of a Julia 3x3 matrix, or the current Luxor translation.

Returns a tuple of x and y values.

Luxor.getrotationFunction.
getrotation(R::Matrix)
getrotation()

Get the rotation of a Julia 3x3 matrix, or the current Luxor rotation.

\[\begin{bmatrix} a & b & tx \\ c & d & ty \\ 0 & 0 & 1 \\ \end{bmatrix}\]

The rotation angle is atan(-b, a) or atan(c, d).

You can convert between the 6-element and 3x3 versions of a transformation matrix using the functions cairotojuliamatrix() and juliatocairomatrix().

cairotojuliamatrix(c)

Return a 3x3 Julia matrix that's the equivalent of the six-element matrix in c.

juliatocairomatrix(c)

Return a six-element matrix that's the equivalent of the 3x3 Julia matrix in c.