-
Notifications
You must be signed in to change notification settings - Fork 26
Matrix
Two matrix classes are supplied, Matrix3, a 3x3 matrix for working with 2D affine transformations, and Matrix4, a 4x4 matrix for working with 3D affine transformations.
The default constructor intializes the matrix to the identity:
>>> Matrix3()
Matrix3([ 1.00 0.00 0.00
0.00 1.00 0.00
0.00 0.00 1.00])
>>> Matrix4()
Matrix4([ 1.00 0.00 0.00 0.00
0.00 1.00 0.00 0.00
0.00 0.00 1.00 0.00
0.00 0.00 0.00 1.00])
Internally each matrix is stored as a set of attributes named a to p.
The layout for Matrix3 is:
# a b c # e f g # i j k
and for Matrix4:
# a b c d # e f g h # i j k l # m n o p
If you wish to set or retrieve a number of elements at once, you can do so with a slice:
>>> m = Matrix4()
>>> m[:]
[1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0]
>>> m[12:15] = (5, 5, 5)
>>> m
Matrix4([ 1.00 0.00 0.00 5.00
0.00 1.00 0.00 5.00
0.00 0.00 1.00 5.00
0.00 0.00 0.00 1.00])
Note that slices operate in column-major order, which makes them
suitable for working directly with OpenGL's glLoadMatrix and
glGetFloatv functions.
There are class constructors for the most common types of transform.
new_identity-
Equivalent to the default constructor. Example:
>>> m = Matrix4.new_identity() >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00]) -
new_scale(x, y)andnew_scale(x, y, z) -
The former is defined on Matrix3, the latter on Matrix4. Equivalent to the OpenGL call
glScalef. Example:>>> m = Matrix4.new_scale(2.0, 3.0, 4.0) >>> m Matrix4([ 2.00 0.00 0.00 0.00 0.00 3.00 0.00 0.00 0.00 0.00 4.00 0.00 0.00 0.00 0.00 1.00]) -
new_translate(x, y)andnew_translate(x, y, z) -
The former is defined on Matrix3, the latter on Matrix4. Equivalent to the OpenGL call
glTranslatef. Example:>>> m = Matrix4.new_translate(3.0, 4.0, 5.0) >>> m Matrix4([ 1.00 0.00 0.00 3.00 0.00 1.00 0.00 4.00 0.00 0.00 1.00 5.00 0.00 0.00 0.00 1.00]) new_rotate(angle)-
Create a Matrix3 for a rotation around the origin. angle is specified in radians, anti-clockwise. This is not implemented in Matrix4 (see below for equivalent methods). Example:
>>> import math >>> m = Matrix3.new_rotate(math.pi / 2) >>> m Matrix3([ 0.00 -1.00 0.00 1.00 0.00 0.00 0.00 0.00 1.00])
The following constructors are defined for Matrix4 only.
new- Construct a matrix with 16 values in column-major order.
-
new_rotatex(angle),new_rotatey(angle),new_rotatez(angle) -
Create a Matrix4 for a rotation around the X, Y or Z axis, respectively. angle is specified in radians. Example:
>>> m = Matrix4.new_rotatex(math.pi / 2) >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 0.00 -1.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00]) new_rotate_axis(angle, axis)-
Create a Matrix4 for a rotation around the given axis. angle is specified in radians, and axis must be an instance of Vector3. It is not necessary to normalize the axis. Example:
>>> m = Matrix4.new_rotate_axis(math.pi / 2, Vector3(1.0, 0.0, 0.0)) >>> m Matrix4([ 1.00 0.00 0.00 0.00 0.00 0.00 -1.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00]) new_rotate_euler(heading, attitude, bank)-
Create a Matrix4 for the given Euler rotation. heading is a rotation around the Y axis, attitude around the X axis and bank around the Z axis. All rotations are performed simultaneously, so this method avoids "gimbal lock" and is the usual method for implemented 3D rotations in a game. Example:
>>> m = Matrix4.new_rotate_euler(math.pi / 2, math.pi / 2, 0.0) >>> m Matrix4([ 0.00 -0.00 1.00 0.00 1.00 0.00 -0.00 0.00 -0.00 1.00 0.00 0.00 0.00 0.00 0.00 1.00]) new_perspective(fov_y, aspect, near, far)-
Create a Matrix4 for projection onto the 2D viewing plane. This method is equivalent to the OpenGL call
gluPerspective. fov_y is the view angle in the Y direction, in radians. aspect is the aspect ration width / height of the viewing plane. near and far are the distance to the near and far clipping planes. They must be positive and non-zero. Example:>>> m = Matrix4.new_perspective(math.pi / 2, 1024.0 / 768, 1.0, 100.0) >>> m Matrix4([ 0.75 0.00 0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 -1.02 -2.02 0.00 0.00 -1.00 0.00])
Matrices of the same dimension may be multiplied to give a new matrix. For example, to create a transform which translates and scales:
>>> m1 = Matrix3.new_translate(5.0, 6.0)
>>> m2 = Matrix3.new_scale(1.0, 2.0)
>>> m1 * m2
Matrix3([ 1.00 0.00 5.00
0.00 2.00 6.00
0.00 0.00 1.00])
Note that multiplication is not commutative (the order that you apply transforms matters):
>>> m2 * m1
Matrix3([ 1.00 0.00 5.00
0.00 2.00 12.00
0.00 0.00 1.00])
In-place multiplication is also permitted (and optimised):
>>> m1 *= m2
>>> m1
Matrix3([ 1.00 0.00 5.00
0.00 2.00 6.00
0.00 0.00 1.00])
Multiplying a matrix by a vector returns a vector, and is used to transform a vector:
>>> m1 = Matrix3.new_rotate(math.pi / 2) >>> m1 * Vector2(1.0, 1.0) Vector2(-1.00, 1.00)
Note that translations have no effect on vectors. They do affect points, however:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m1 * Vector2(1.0, 2.0) Vector2(1.00, 2.00) >>> m1 * Point2(1.0, 2.0) Point2(6.00, 8.00)
Multiplication is currently incorrect between matrices and vectors -- the projection component is ignored. Use the Matrix4.transform method instead.
Matrix4 also defines transpose (in-place), transposed (functional), determinant and inverse (functional) methods.
A Matrix3 can be multiplied with a Vector2 or any of the 2D geometry objects (Point2, Line2, Circle, etc).
A Matrix4 can be multiplied with a Vector3 or any of the 3D geometry objects (Point3, Line3, Sphere, etc).
For convenience, each of the matrix constructors are also available as in-place operators. For example, instead of writing:
>>> m1 = Matrix3.new_translate(5.0, 6.0) >>> m2 = Matrix3.new_scale(1.0, 2.0) >>> m1 *= m2
you can apply the scale directly to m1:
>>> m1 = Matrix3.new_translate(5.0, 6.0)
>>> m1.scale(1.0, 2.0)
Matrix3([ 1.00 0.00 5.00
0.00 2.00 6.00
0.00 0.00 1.00])
>>> m1
Matrix3([ 1.00 0.00 5.00
0.00 2.00 6.00
0.00 0.00 1.00])
Note that these methods operate in-place (they modify the original matrix), and they also return themselves as a result. This allows you to chain transforms together directly:
>>> Matrix3().translate(1.0, 2.0).rotate(math.pi / 2).scale(4.0, 4.0)
Matrix3([ 0.00 -4.00 1.00
4.00 0.00 2.00
0.00 0.00 1.00])
All constructors have an equivalent in-place method. For Matrix3, they
are identity, translate, scale and rotate. For Matrix4,
they are identity, translate, scale, rotatex, rotatey,
rotatez, rotate_axis and rotate_euler. Both Matrix3 and
Matrix4 also have an in-place transpose method.
The copy method is also implemented in both matrix classes and
behaves in the obvious way.