dojox.gfx.matrix¶
Status: | Draft |
---|---|
Version: | 1.3 |
Authors: | Eugene Lazutkin, Kun Xi, Chris Mitchell |
Available: | since 0.4 |
Contents
Coordinates and transformations¶
In order to understand transformations you need to be familiar with fundamentals of matrices (matrix multiplication, multiplication of a vector by a matrix, order of multiplications). dojox.gfx uses a mnemonic way to describe a matrix: xx
scales an X
component of a coordinate, yy
scales a Y
component, xy
, and yx
affect both components, dx
moves an X
component, and dy
moves a Y
component. If you want to refresh your memory, read our Matrix tutorial.
Simple examples:
{xx: 2}
— stretches theX
dimension by 2.{yy: 0.5}
—"stretches"
theY
dimension by 0.5 (shrinks by 2).{dx: 5, dy: 10}
— shifts anX
coordinate by 5, aY
coordinate by 10.{xx: 0.866, xy: 0.5, yx: −0.5, yy: 0.866}
— rotates everything by approximately 30 degrees clockwise (CW) around point(0, 0)
.{xx: 0, xy: 1, yx: −1, yy: 0, dx: 100}
— rotates everything by 90 degrees CW around(0, 0)
, and moves things right by 100.
Don’t worry, in most cases you don’t need to calculate all members of a transformation matrix directly. As you can see not all members of matrix should be specified — all skipped members going to be copied from the identity matrix.
There is a shortcut for scaling — if a number N is used instead of a matrix, it is assumed that it represents a uniform scaling matrix {xx: N, yy: N}
.
There is a shortcut for multiplication (see multiply for details) — is an array is used it is treated as an array of matrices, and all matrices will be multiplied to produce the final matrix.
dojox.gfx.matrix defines Matrix2D
class, as well as numerous helpers (Matrix2D
is propagated to dojox.gfx
namespace for convenience). Most important of them (all in dojox.gfx.matrix
namespace) are listed below.
Matrix2D and normalization¶
As you can see developers can specify matrices in a variety of ways. But for performance reasons internally it is always converted to Matrix2D
, which has all proper attributes defined. You can achieve this normalization by instantiating Matrix2D object or by invoking a creator function called normalize.
Matrix2D¶
Matrix2D is the class for our 2 by 3 matrix. You can always use it to normalize your matrix expression to the canonical representation. It is available in both namespaces: dojox.gfx
and dojox.gfx.matrix
.
Examples:
// identity {xx: 1, xy: 0, dx: 0, yx: 0, yy: 1, dy: 0}
var m1 = new dojox.gfx.Matrix2D();
// shift down {xx: 1, xy: 0, dx: 0, yx: 0, yy: 1, dy: 10}
var m2 = new dojox.gfx.Matrix2D({dy: 10});
// scale by 2 {xx: 2, xy: 0, dx: 0, yx: 0, yy: 2, dy: 0}
var m3 = new dojox.gfx.Matrix2D(2);
// scale by 2 and shift down {xx: 2, xy: 0, dx: 0, yx: 0, yy: 2, dy: 10}
var m3 = new dojox.gfx.Matrix2D([{dy: 10}, 2]);
normalize¶
There is one more useful function: normalize(m)
, which returns Matrix2D:
var m1 = normalize(2); // => {xx: 2, xy: 0, yx: 0, yy: 2, dx: 0, dy: 0}
var m2 = normalize({dy: 10}); // => {xx: 1, xy: 0, yx: 0, yy: 1, dx: 0, dy: 5}
var m3 = normalize([scale(2), translate(100, 200)]);
// => {xx: 2, xy: 0, yx: 0, yy: 2, dx: 200, dy: 400}
The same normalization effect can be achieved with creating a matrix directly.
Matrix creators¶
Matrices can be used to express any linear transformation of coordinates. To simplify the task of creating matrices for common operations numerous matrix creators are provided.
In all signatures a
, b
, c
, and e
are numbers (coordinate components or scaling factors), p
is a 2D coordinate, r
is an angle in radians, d
is an angle in degrees (positive value of an angle is CW), m
is a matrix.
If a function accepts an angle value, there are two versions of this function: with radians, and with degrees. The latter will be denoted with g
suffix. Example: rotate(r)
accepts radians, while rotateg(d)
accepts degrees.
translate¶
Signatures: translate(a, b)
, translate(p)
. Shifts everything:
- by
{dx: a, dy: b}
- by
{dx: p.x, dy: p.y}
scale¶
Signatures: scale(a, b)
, scale(a)
, scale(p)
. Scales a picture:
- by
{xx: a, yy: b}
- by
{xx: a, yy: a}
- by
{xx: p.x, yy: p.y}
rotate¶
Signatures: rotate(r)
, rotateg(d)
. Rotates a picture around (0, 0)
:
- by
r
radians- by
d
degrees
skewX¶
Signatures: skewX(r)
, skewXg(d)
. Skews a picture around (0, 0)
in the X
dimension:
- by
r
radians- by
d
degrees
skewY¶
Signatures: skewY(r)
, skewYg(d)
. Skews a picture around (0, 0)
in the Y
dimension:
- by
r
radians- by
d
degrees
General operations¶
In all signatures a
, b
, c
, and e
are numbers (coordinate components or scaling factors), p
is a 2D coordinate, r
is an angle in radians, d
is an angle in degrees (positive value of an angle is CW), m
is a matrix.
invert¶
Signatures: invert(m)
. Inverts a matrix. This useful function calculates a matrix, which will do the opposite transformation to the m matrix effectively undoing it. For example, scale(2)
produces a matrix to scale uniformly a picture by 2. The opposite matrix is going to be scale(0.5)
. We can produce the same result with invert(scale(2))
. While it seems complicated for this simple case, frequently it is the only way to calculate an inverted matrix for complex transformation, especially when we don’t know how it was produced initially.
multiplyPoint¶
Signatures: multiplyPoint(m, a, b)
, multiplyPoint(m, p)
. Applies a transformation to a coordinate.
multiply¶
Signatures: multiply(m1, m2, ...)
. Multiplies all its parameters to create a single matrix.
This function is extremely useful and there is a shortcut for it: anywhere a matrix is expected, an array of matrices can be specified as well. Examples:
[2, rotateg(45)]
--- rotates everything 45 degrees CW around(0, 0)
and scales everything by 2 after that.[{dy: 10}, scale(2, 1)]
--- scales allX
coordinates by 2, and moves the result down by 10.
More complex example: imagine you have a surface 500 by 500 pixels, and you want everything in it to be magnified around its center by 2, and rotated (around the center as well) by 30 degrees CW. It is easy: [translate(250, 250), rotateg(−30), scale(2), translate(-250, -250)]
. Explanations:
- All scaling, rotating, and skewing operations work around
(0, 0)
point. Let’s move the center of our picture to(0, 0)
:translate(−250, −250)
. - Now we can scale it:
scale(2)
. - Now we can rotate it:
rotateg(−30)
. - Now let’s move our center back:
translate(250, 250)
.
You can see that this kind of transformations follow a "sandwich"
pattern, where the first and the last transformation move an immutable point to/from the origin of coordinates before performing other origin-based operations. The first operation is usually a translation to the origin, and the last is the inverse of the same translation.
"Sandwich" helpers¶
These "around the point" operations are so important that dojox.gfx
provides several helpers for common transformations. Usually they are named like their middle "meaty" part with the suffix At
. Example: scale(a)
=> scaleAt(a, p)
.
In all signatures a
, b
, c
, and e
are numbers (coordinate components or scaling factors), p
is a 2D coordinate, r
is an angle in radians, d
is an angle in degrees (positive value of an angle is CW), m
is a matrix.
If a function accepts an angle value, there are two versions of this function: with radians, and with degrees. The latter will be denoted with g
suffix. Example: rotate(r)
accepts radians, while rotateg(d)
accepts degrees.
scaleAt¶
Applies scale with the center at the given point.
Signatures:
scaleAt(a, p)
scale(a)
around(p.x, p.y)
scaleAt(a, b, c)
scale(a)
around(b, c)
scaleAt(a, b, p)
scale(a, b)
around(p.x, p.y)
scaleAt(a, b, c, e)
scale(a, b)
around(c, e)
rotateAt¶
Applies rotate with the center at the given point.
Signatures:
rotateAt(r, p)
rotate(r)
at(p.x, p.y)
rotateAt(r, a, b)
rotate(r)
at(a, b)
rotategAt(d, p)
rotateg(d)
at(p.x, p.y)
rotategAt(d, a, b)
rotateg(d)
at(a, b)