psychopy.tools.mathtools
¶Assorted math functions for working with vectors, matrices, and quaternions. These functions are intended to provide basic support for common mathematical operations associated with displaying stimuli (e.g. animation, posing, rendering, etc.)
For tools related to view transformations, see viewtools
.
Most functions listed here are very fast, however they are optimized to work on arrays of values (vectorization). Calling functions repeatedly (for instance within a loop), should be avoided as the CPU overhead associated with each function call (not to mention the loop itself) can be considerable.
For example, one may want to normalize a bunch of randomly generated vectors by
calling normalize()
on each row:
v = np.random.uniform(1.0, 1.0, (1000, 4,)) # 1000 length 4 vectors
vn = np.zeros((1000, 4)) # place to write values
# don't do this!
for i in range(1000):
vn[i, :] = normalize(v[i, :])
The same operation is completed in considerably less time by passing the whole array to the function like so:
normalize(v, out=vn) # very fast!
vn = normalize(v) # also fast if `out` is not provided
Specifying an output array to out will improve performance by reducing overhead associated with allocating memory to store the result (functions do this automatically if out is not provided). However, out should only be provided if the output array is reused multiple times. Furthermore, the function still returns a value if out is provided, but the returned value is a reference to out, not a copy of it. If out is not provided, the function will return the result with a freshly allocated array.
Subroutines used by the functions here will perform arithmetic using 64bit floatingpoint precision unless otherwise specified via the dtype argument. This functionality is helpful in certain applications where input and output arrays demand a specific type (eg. when working with data passed to and from OpenGL functions).
If a dtype is specified, input arguments will be coerced to match that type and all floatingpoint arithmetic will use the precision of the type. If input arrays have the same type as dtype, they will automatically passthrough without being recast as a different type. As a performance consideration, all input arguments should have matching types and dtype set accordingly.
Most functions have an out argument, where one can specify an array to write values to. The value of dtype is ignored if out is provided, and all input arrays will be converted to match the dtype of out (if not already). This ensures that the type of the destination array is used for all arithmetic.
length (v[, squared, out, dtype]) 
Get the length of a vector. 
normalize (v[, out, dtype]) 
Normalize a vector or quaternion. 
orthogonalize (v, n[, out, dtype]) 
Orthogonalize a vector relative to a normal vector. 
reflect (v, n[, out, dtype]) 
Reflection of a vector. 
dot (v0, v1[, out, dtype]) 
Dot product of two vectors. 
cross (v0, v1[, out, dtype]) 
Cross product of 3D vectors. 
project (v0, v1[, out, dtype]) 
Project a vector onto another. 
perp (v, n[, norm, out, dtype]) 
Project v to be a perpendicular axis of n. 
lerp (v0, v1, t[, out, dtype]) 
Linear interpolation (LERP) between two vectors/coordinates. 
distance (v0, v1[, out, dtype]) 
Get the distance between vectors/coordinates. 
angleTo (v, point[, degrees, out, dtype]) 
Get the relative angle to a point from a vector. 
bisector (v0, v1[, norm, out, dtype]) 
Get the angle bisector. 
surfaceNormal (tri[, norm, out, dtype]) 
Compute the surface normal of a given triangle. 
surfaceBitangent (tri, uv[, norm, out, dtype]) 
Compute the bitangent vector of a given triangle. 
surfaceTangent (tri, uv[, norm, out, dtype]) 
Compute the tangent vector of a given triangle. 
vertexNormal (faceNorms[, norm, out, dtype]) 
Compute a vertex normal from shared triangles. 
intersectRayPlane (rayOrig, rayDir, …[, dtype]) 
Get the point which a ray intersects a plane. 
intersectRaySphere (rayOrig, rayDir[, …]) 
Calculate the points which a ray/line intersects a sphere (if any). 
intersectRayAABB (rayOrig, rayDir, …[, dtype]) 
Find the point a ray intersects an axisaligned bounding box (AABB). 
intersectRayOBB (rayOrig, rayDir, …[, dtype]) 
Find the point a ray intersects an oriented bounding box (OBB). 
intersectRayTriangle (rayOrig, rayDir, tri[, …]) 
Get the intersection of a ray and signle triangle. 
ortho3Dto2D (p, orig, normal, up[, right, dtype]) 
Get the planar coordinates of an orthogonal projection of a 3D point onto a 2D plane. 
slerp (q0, q1, t[, shortest, out, dtype]) 
Spherical linear interpolation (SLERP) between two quaternions. 
quatToAxisAngle (q[, degrees, dtype]) 
Convert a quaternion to axis and angle representation. 
quatFromAxisAngle (axis, angle[, degrees, dtype]) 
Create a quaternion to represent a rotation about axis vector by angle. 
quatYawPitchRoll (q[, degrees, out, dtype]) 
Get the yaw, pitch, and roll of a quaternion’s orientation relative to the world Z axis. 
alignTo (v, t[, out, dtype]) 
Compute a quaternion which rotates one vector to align with another. 
quatMagnitude (q[, squared, out, dtype]) 
Get the magnitude of a quaternion. 
multQuat (q0, q1[, out, dtype]) 
Multiply quaternion q0 and q1. 
invertQuat (q[, out, dtype]) 
Get tht multiplicative inverse of a quaternion. 
applyQuat (q, points[, out, dtype]) 
Rotate points/coordinates using a quaternion. 
quatToMatrix (q[, out, dtype]) 
Create a 4x4 rotation matrix from a quaternion. 
matrixToQuat (m[, out, dtype]) 
Convert a rotation matrix to a quaternion. 
matrixFromEulerAngles (rx, ry, rz[, degrees, …]) 
Construct a 4x4 rotation matrix from Euler angles. 
scaleMatrix (s[, out, dtype]) 
Create a scaling matrix. 
rotationMatrix (angle[, axis, out, dtype]) 
Create a rotation matrix. 
translationMatrix (t[, out, dtype]) 
Create a translation matrix. 
invertMatrix (m[, homogeneous, out, dtype]) 
Invert a 4x4 matrix. 
isOrthogonal (m) 
Check if a square matrix is orthogonal. 
isAffine (m) 
Check if a 4x4 square matrix describes an affine transformation. 
concatenate (matrices[, out, dtype]) 
Concatenate matrix transformations. 
applyMatrix (m, points[, out, dtype]) 
Apply a matrix over a 2D array of points. 
posOriToMatrix (pos, ori[, out, dtype]) 
Convert a rigid body pose to a 4x4 transformation matrix. 
transform (pos, ori, points[, out, dtype]) 
Transform points using a position and orientation. 
lensCorrection (xys[, coefK, distCenter, …]) 
Lens correction (or distortion) using the division model with even polynomial terms. 
psychopy.tools.mathtools.
length
(v, squared=False, out=None, dtype=None)[source]¶Get the length of a vector.
Parameters: 


Returns:  Length of vector v. 
Return type:  float or ndarray 
psychopy.tools.mathtools.
normalize
(v, out=None, dtype=None)[source]¶Normalize a vector or quaternion.
Returns:  Normalized vector v. 

Return type:  ndarray 
Notes
Examples
Normalize a vector:
v = [1., 2., 3., 4.]
vn = normalize(v)
The normalize function is vectorized. It’s considerably faster to normalize large arrays of vectors than to call normalize separately for each one:
v = np.random.uniform(1.0, 1.0, (1000, 4,)) # 1000 length 4 vectors
vn = np.zeros((1000, 4)) # place to write values
normalize(v, out=vn) # very fast!
# don't do this!
for i in range(1000):
vn[i, :] = normalize(v[i, :])
psychopy.tools.mathtools.
orthogonalize
(v, n, out=None, dtype=None)[source]¶Orthogonalize a vector relative to a normal vector.
This function ensures that v is perpendicular (or orthogonal) to n.
Parameters: 


Returns:  Orthogonalized vector v relative to normal vector n. 
Return type:  ndarray 
Warning
If v and n are the same, the direction of the perpendicular vector is indeterminate. The resulting vector is degenerate (all zeros).
psychopy.tools.mathtools.
reflect
(v, n, out=None, dtype=None)[source]¶Reflection of a vector.
Get the reflection of v relative to normal n.
Parameters: 


Returns:  Reflected vector v off normal n. 
Return type:  ndarray 
psychopy.tools.mathtools.
dot
(v0, v1, out=None, dtype=None)[source]¶Dot product of two vectors.
The behaviour of this function depends on the format of the input arguments:
Parameters: 


Returns:  Dot product(s) of v0 and v1. 
Return type:  ndarray 
psychopy.tools.mathtools.
cross
(v0, v1, out=None, dtype=None)[source]¶Cross product of 3D vectors.
The behavior of this function depends on the dimensions of the inputs:
Parameters: 


Returns:  Cross product of v0 and v1. 
Return type:  ndarray 
Notes
Examples
Find the cross product of two vectors:
a = normalize([1, 2, 3])
b = normalize([3, 2, 1])
c = cross(a, b)
If input arguments are 2D, the function returns the cross products of corresponding rows:
# create two 6x3 arrays with random numbers
shape = (6, 3,)
a = normalize(np.random.uniform(1.0, 1.0, shape))
b = normalize(np.random.uniform(1.0, 1.0, shape))
cprod = np.zeros(shape) # output has the same shape as inputs
cross(a, b, out=cprod)
If a 1D and 2D vector are specified, the cross product of each row of the 2D array and the 1D array is returned as a 2D array:
a = normalize([1, 2, 3])
b = normalize(np.random.uniform(1.0, 1.0, (6, 3,)))
cprod = np.zeros(a.shape)
cross(a, b, out=cprod)
psychopy.tools.mathtools.
project
(v0, v1, out=None, dtype=None)[source]¶Project a vector onto another.
Parameters: 


Returns:  Projection of vector v0 on v1. 
Return type:  ndarray or float 
psychopy.tools.mathtools.
perp
(v, n, norm=True, out=None, dtype=None)[source]¶Project v to be a perpendicular axis of n.
Parameters: 


Returns:  Perpendicular axis of n from v. 
Return type:  ndarray 
Examples
Determine the local up (yaxis) of a surface or plane given normal:
normal = [0., 0.70710678, 0.70710678]
up = [1., 0., 0.]
yaxis = perp(up, normal)
Do a cross product to get the xaxis perpendicular to both:
xaxis = cross(yaxis, normal)
psychopy.tools.mathtools.
lerp
(v0, v1, t, out=None, dtype=None)[source]¶Linear interpolation (LERP) between two vectors/coordinates.
Parameters: 


Returns:  Vector at t with same shape as v0 and v1. 
Return type:  ndarray 
Examples
Find the coordinate of the midpoint between two vectors:
u = [0., 0., 0.]
v = [0., 0., 1.]
midpoint = lerp(u, v, 0.5) # 0.5 to interpolate halfway between points
psychopy.tools.mathtools.
distance
(v0, v1, out=None, dtype=None)[source]¶Get the distance between vectors/coordinates.
The behaviour of this function depends on the format of the input arguments:
Parameters: 


Returns:  Distance between vectors v0 and v1. 
Return type:  ndarray 
psychopy.tools.mathtools.
angleTo
(v, point, degrees=True, out=None, dtype=None)[source]¶Get the relative angle to a point from a vector.
The behaviour of this function depends on the format of the input arguments:
Parameters: 


Returns:  Distance between vectors v0 and v1. 
Return type:  ndarray 
psychopy.tools.mathtools.
bisector
(v0, v1, norm=False, out=None, dtype=None)[source]¶Get the angle bisector.
Computes a vector which bisects the angle between v0 and v1. Input vectors v0 and v1 must be nonzero.
Parameters: 


Returns:  Bisecting vector [x, y, z]. 
Return type:  ndarray 
psychopy.tools.mathtools.
surfaceNormal
(tri, norm=True, out=None, dtype=None)[source]¶Compute the surface normal of a given triangle.
Parameters: 


Returns:  Surface normal of triangle tri. 
Return type:  ndarray 
Examples
Compute the surface normal of a triangle:
vertices = [[1., 0., 0.], [0., 1., 0.], [1, 0, 0]]
norm = surfaceNormal(vertices)
Find the normals for multiple triangles, and put results in a preallocated array:
vertices = [[[1., 0., 0.], [0., 1., 0.], [1, 0, 0]], # 2x3x3
[[1., 0., 0.], [0., 1., 0.], [1, 0, 0]]]
normals = np.zeros((2, 3)) # normals from two triangles triangles
surfaceNormal(vertices, out=normals)
psychopy.tools.mathtools.
surfaceBitangent
(tri, uv, norm=True, out=None, dtype=None)[source]¶Compute the bitangent vector of a given triangle.
This function can be used to generate bitangent vertex attributes for normal
mapping. After computing bitangents, one may orthogonalize them with vertex
normals using the orthogonalize()
function, or within the fragment
shader. Uses texture coordinates at each triangle vertex to determine the
direction of the vector.
Parameters: 


Returns:  Surface bitangent of triangle tri. 
Return type:  ndarray 
Examples
Computing the bitangents for two triangles from vertex and texture coordinates (UVs):
# array of triangle vertices (2x3x3)
tri = np.asarray([
[(1.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 1.0, 0.0)], # 1
[(1.0, 1.0, 0.0), (1.0, 1.0, 0.0), (1.0, 1.0, 0.0)]]) # 2
# array of triangle texture coordinates (2x3x2)
uv = np.asarray([
[(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)], # 1
[(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]]) # 2
bitangents = surfaceBitangent(tri, uv, norm=True) # bitangets (2x3)
psychopy.tools.mathtools.
surfaceTangent
(tri, uv, norm=True, out=None, dtype=None)[source]¶Compute the tangent vector of a given triangle.
This function can be used to generate tangent vertex attributes for normal
mapping. After computing tangents, one may orthogonalize them with vertex
normals using the orthogonalize()
function, or within the fragment
shader. Uses texture coordinates at each triangle vertex to determine the
direction of the vector.
Parameters: 


Returns:  Surface normal of triangle tri. 
Return type:  ndarray 
Examples
Compute surface normals, tangents, and bitangents for a list of triangles:
# triangle vertices (2x3x3)
vertices = [[[1., 0., 0.], [0., 1., 0.], [1, 0, 0]],
[[1., 0., 0.], [0., 1., 0.], [1, 0, 0]]]
# array of triangle texture coordinates (2x3x2)
uv = np.asarray([
[(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)], # 1
[(0.0, 1.0), (0.0, 0.0), (1.0, 0.0)]]) # 2
normals = surfaceNormal(vertices)
tangents = surfaceTangent(vertices, uv)
bitangents = cross(normals, tangents) # or use `surfaceBitangent`
Orthogonalize a surface tangent with a vertex normal vector to get the vertex tangent and bitangent vectors:
vertexTangent = orthogonalize(faceTangent, vertexNormal)
vertexBitangent = cross(vertexTangent, vertexNormal)
Ensure computed vectors have the same handedness, if not, flip the tangent vector (important for applications like normal mapping):
# tangent, bitangent, and normal are 2D
tangent[dot(cross(normal, tangent), bitangent) < 0.0, :] *= 1.0
psychopy.tools.mathtools.
vertexNormal
(faceNorms, norm=True, out=None, dtype=None)[source]¶Compute a vertex normal from shared triangles.
This function computes a vertex normal by averaging the surface normals of
the triangles it belongs to. If model has no vertex normals, first use
surfaceNormal()
to compute them, then run vertexNormal()
to
compute vertex normal attributes.
While this function is mainly used to compute vertex normals, it can also be supplied triangle tangents and bitangents.
Parameters: 


Returns:  Vertex normal. 
Return type:  ndarray 
Examples
Compute a vertex normal from the face normals of the triangles it belongs to:
normals = [[1., 0., 0.], [0., 1., 0.]] # adjacent face normals
vertexNorm = vertexNormal(normals)
psychopy.tools.mathtools.
intersectRayPlane
(rayOrig, rayDir, planeOrig, planeNormal, dtype=None)[source]¶Get the point which a ray intersects a plane.
Parameters: 


Returns:  Position (ndarray) in space which the line intersects the plane and the distance the intersect occurs from the origin (float). None is returned if the line does not intersect the plane at a single point or at all. 
Return type: 
Examples
Find the point in the scene a ray intersects the plane:
# plane information
planeOrigin = [0, 0, 0]
planeNormal = [0, 0, 1]
planeUpAxis = perp([0, 1, 0], planeNormal)
# ray
rayDir = [0, 0, 1]
rayOrigin = [0, 0, 5]
# get the intersect and distance in 3D world space
pnt, dist = intersectRayPlane(rayOrigin, rayDir, planeOrigin, planeNormal)
psychopy.tools.mathtools.
intersectRaySphere
(rayOrig, rayDir, sphereOrig=(0.0, 0.0, 0.0), sphereRadius=1.0, dtype=None)[source]¶Calculate the points which a ray/line intersects a sphere (if any).
Get the 3D coordinate of the point which the ray intersects the sphere and the distance to the point from orig. The nearest point is returned if the line intersects the sphere at multiple locations. All coordinates should be in world/scene units.
Parameters: 


Returns:  Coordinate in world space of the intersection and distance in scene units from orig. Returns None if there is no intersection. 
Return type: 
psychopy.tools.mathtools.
intersectRayAABB
(rayOrig, rayDir, boundsOffset, boundsExtents, dtype=None)[source]¶Find the point a ray intersects an axisaligned bounding box (AABB).
Parameters: 


Returns:  Coordinate in world space of the intersection and distance in scene units from rayOrig. Returns None if there is no intersection. 
Return type: 
Examples
Get the point on an axisaligned bounding box that the cursor is over and place a 3D stimulus there. The eye location is defined by RigidBodyPose object camera:
# get the mouse position onscreen
mx, my = mouse.getPos()
# find the point which the ray intersects on the box
result = intersectRayAABB(
camera.pos,
camera.transformNormal(win.coordToRay((mx, my))),
myStim.pos,
myStim.thePose.bounds.extents)
# if the ray intersects, set the position of the cursor object to it
if result is not None:
cursorModel.thePose.pos = result[0]
cursorModel.draw() # don't draw anything if there is no intersect
Note that if the model is rotated, the bounding box may not be aligned anymore with the axes. Use intersectRayOBB if your model rotates.
psychopy.tools.mathtools.
intersectRayOBB
(rayOrig, rayDir, modelMatrix, boundsExtents, dtype=None)[source]¶Find the point a ray intersects an oriented bounding box (OBB).
Parameters: 


Returns:  Coordinate in world space of the intersection and distance in scene units from rayOrig. Returns None if there is no intersection. 
Return type: 
Examples
Get the point on an oriented bounding box that the cursor is over and place a 3D stimulus there. The eye location is defined by RigidBodyPose object camera:
# get the mouse position onscreen
mx, my = mouse.getPos()
# find the point which the ray intersects on the box
result = intersectRayOBB(
camera.pos,
camera.transformNormal(win.coordToRay((mx, my))),
myStim.thePose.getModelMatrix(),
myStim.thePose.bounds.extents)
# if the ray intersects, set the position of the cursor object to it
if result is not None:
cursorModel.thePose.pos = result[0]
cursorModel.draw() # don't draw anything if there is no intersect
psychopy.tools.mathtools.
intersectRayTriangle
(rayOrig, rayDir, tri, dtype=None)[source]¶Get the intersection of a ray and signle triangle.
Parameters: 


Returns:  Coordinate in world space of the intersection, distance in scene units from rayOrig, and the barycentric coordinates on the triangle [x, y]. Returns None if there is no intersection. 
Return type: 
psychopy.tools.mathtools.
ortho3Dto2D
(p, orig, normal, up, right=None, dtype=None)[source]¶Get the planar coordinates of an orthogonal projection of a 3D point onto a 2D plane.
This function gets the nearest point on the plane which a 3D point falls on the plane.
Parameters: 


Returns:  Coordinates on the plane [X, Y] where the 3D point projects towards perpendicularly. 
Return type:  ndarray 
Examples
This function can be used with intersectRayPlane()
to find the
location on the plane the ray intersects:
# plane information
planeOrigin = [0, 0, 0]
planeNormal = [0, 0, 1] # must be normalized
planeUpAxis = perp([0, 1, 0], planeNormal) # must also be normalized
# ray
rayDir = [0, 0, 1]
rayOrigin = [0, 0, 5]
# get the intersect in 3D world space
pnt = intersectRayPlane(rayOrigin, rayDir, planeOrigin, planeNormal)
# get the 2D coordinates on the plane the intersect occurred
planeX, planeY = ortho3Dto2D(pnt, planeOrigin, planeNormal, planeUpAxis)
psychopy.tools.mathtools.
slerp
(q0, q1, t, shortest=True, out=None, dtype=None)[source]¶Spherical linear interpolation (SLERP) between two quaternions.
The behaviour of this function depends on the types of arguments:
Parameters: 


Returns:  Quaternion [x, y, z, w] at t. 
Return type:  ndarray 
Examples
Interpolate between two orientations:
q0 = quatFromAxisAngle(90.0, degrees=True)
q1 = quatFromAxisAngle(90.0, degrees=True)
# halfway between 90 and 90 is 0.0 or quaternion [0. 0. 0. 1.]
qr = slerp(q0, q1, 0.5)
Example of smooth rotation of an object with fixed angular velocity:
degPerSec = 10.0 # rotate a stimulus at 10 degrees per second
# initial orientation, axis rotates in the Z direction
qr = quatFromAxisAngle([0., 0., 1.], 0.0, degrees=True)
# amount to rotate every second
qv = quatFromAxisAngle([0., 0., 1.], degPerSec, degrees=True)
#  within main experiment loop 
# `frameTime` is the time elapsed in seconds from last `slerp`.
qr = multQuat(qr, slerp((0., 0., 0., 1.), qv, degPerSec * frameTime))
_, angle = quatToAxisAngle(qr) # discard axis, only need angle
# myStim is a GratingStim or anything with an 'ori' argument which
# accepts angle in degrees
myStim.ori = angle
myStim.draw()
psychopy.tools.mathtools.
quatToAxisAngle
(q, degrees=True, dtype=None)[source]¶Convert a quaternion to axis and angle representation.
This allows you to use quaternions to set the orientation of stimuli that have an ori property.
Parameters: 


Returns:  Axis and angle of quaternion in form ([ax, ay, az], angle). If degrees is True, the angle returned is in degrees, radians if False. 
Return type: 
Examples
Using a quaternion to rotate a stimulus a fixed angle each frame:
# initial orientation, axis rotates in the Z direction
qr = quatFromAxisAngle([0., 0., 1.], 0.0, degrees=True)
# rotation perframe, here it's 0.1 degrees per frame
qf = quatFromAxisAngle([0., 0., 1.], 0.1, degrees=True)
#  within main experiment loop 
# myStim is a GratingStim or anything with an 'ori' argument which
# accepts angle in degrees
qr = multQuat(qr, qf) # cumulative rotation
_, angle = quatToAxisAngle(qr) # discard axis, only need angle
myStim.ori = angle
myStim.draw()
psychopy.tools.mathtools.
quatFromAxisAngle
(axis, angle, degrees=True, dtype=None)[source]¶Create a quaternion to represent a rotation about axis vector by angle.
Parameters: 


Returns:  Quaternion [x, y, z, w]. 
Return type:  ndarray 
Examples
Create a quaternion from specified axis and angle:
axis = [0., 0., 1.] # rotate about Z axis
angle = 90.0 # angle in degrees
ori = quatFromAxisAngle(axis, angle, degrees=True) # using degrees!
psychopy.tools.mathtools.
quatYawPitchRoll
(q, degrees=True, out=None, dtype=None)[source]¶Get the yaw, pitch, and roll of a quaternion’s orientation relative to the world Z axis.
You can multiply the quaternion by the inverse of some other one to make the returned values referenced to a local coordinate system.
Parameters: 


Returns:  Yaw, pitch and roll [yaw, pitch, roll] of quaternion q. 
Return type:  ndarray 
psychopy.tools.mathtools.
alignTo
(v, t, out=None, dtype=None)[source]¶Compute a quaternion which rotates one vector to align with another.
Parameters: 


Returns:  Quaternion which rotates v to t. 
Return type:  ndarray 
Examples
Rotate some vectors to align with other vectors, inputs should be normalized:
vec = [[1, 0, 0], [0, 1, 0], [1, 0, 0]]
targets = [[0, 1, 0], [0, 1, 0], [1, 0, 0]]
qr = alignTo(vec, targets)
vecRotated = applyQuat(qr, vec)
numpy.allclose(vecRotated, targets) # True
Get matrix which orients vertices towards a point:
point = [5, 6, 7]
vec = [0, 0, 1] # initial facing is Z (forward in GL)
targetVec = normalize(point  vec)
qr = alignTo(vec, targetVec) # get rotation to align
M = quatToMatrix(qr) # 4x4 transformation matrix
psychopy.tools.mathtools.
quatMagnitude
(q, squared=False, out=None, dtype=None)[source]¶Get the magnitude of a quaternion.
A quaternion is normalized if its magnitude is 1.
Parameters: 


Returns:  Magnitude of quaternion q. 
Return type:  float or ndarray 
psychopy.tools.mathtools.
multQuat
(q0, q1, out=None, dtype=None)[source]¶Multiply quaternion q0 and q1.
The orientation of the returned quaternion is the combination of the input quaternions.
Parameters: 


Returns:  Combined orientations of q0 amd q1. 
Return type:  ndarray 
Notes
Examples
Combine the orientations of two quaternions:
a = quatFromAxisAngle([0, 0, 1], 45.0, degrees=True)
b = quatFromAxisAngle([0, 0, 1], 90.0, degrees=True)
c = multQuat(a, b) # rotates 135 degrees about Z axis
psychopy.tools.mathtools.
invertQuat
(q, out=None, dtype=None)[source]¶Get tht multiplicative inverse of a quaternion.
This gives a quaternion which rotates in the opposite direction with equal magnitude. Multiplying a quaternion by its inverse returns an identity quaternion as both orientations cancel out.
Parameters: 


Returns:  Inverse of quaternion q. 
Return type:  ndarray 
Examples
Show that multiplying a quaternion by its inverse returns an identity quaternion where [x=0, y=0, z=0, w=1]:
angle = 90.0
axis = [0., 0., 1.]
q = quatFromAxisAngle(axis, angle, degrees=True)
qinv = invertQuat(q)
qr = multQuat(q, qinv)
qi = np.array([0., 0., 0., 1.]) # identity quaternion
print(np.allclose(qi, qr)) # True
Notes
psychopy.tools.mathtools.
applyQuat
(q, points, out=None, dtype=None)[source]¶Rotate points/coordinates using a quaternion.
This is similar to using applyMatrix with a rotation matrix. However, it is computationally less intensive to use applyQuat if one only wishes to rotate points.
Parameters: 


Returns:  Transformed points. 
Return type:  ndarray 
Examples
Rotate points using a quaternion:
points = [[1., 0., 0.], [0., 1., 0.]]
quat = quatFromAxisAngle(90.0, [0., 0., 1.], degrees=True)
pointsRotated = applyQuat(quat, points)
# [[0. 1. 0.]
# [1. 0. 0.]]
Show that you get the same result as a rotation matrix:
axis = [0., 0., 1.]
angle = 90.0
rotMat = rotationMatrix(axis, angle)[:3, :3] # rotation submatrix only
rotQuat = quatFromAxisAngle(axis, angle, degrees=True)
points = [[1., 0., 0.], [0., 1., 0.]]
isClose = np.allclose(applyMatrix(rotMat, points), # True
applyQuat(rotQuat, points))
Specifying an array to q where each row is a quaternion transforms points in corresponding rows of points:
points = [[1., 0., 0.], [0., 1., 0.]]
quats = [quatFromAxisAngle(90.0, [0., 0., 1.], degrees=True),
quatFromAxisAngle(45.0, [0., 0., 1.], degrees=True)]
applyQuat(quats, points)
psychopy.tools.mathtools.
quatToMatrix
(q, out=None, dtype=None)[source]¶Create a 4x4 rotation matrix from a quaternion.
Parameters: 


Returns:  4x4 rotation matrix in rowmajor order. 
Return type:  ndarray or None 
Examples
Convert a quaternion to a rotation matrix:
point = [0., 1., 0., 1.] # 4vector form [x, y, z, 1.0]
ori = [0., 0., 0., 1.]
rotMat = quatToMatrix(ori)
# rotate 'point' using matrix multiplication
newPoint = np.matmul(rotMat.T, point) # returns [1., 0., 0., 1.]
Rotate all points in an array (each row is a coordinate):
points = np.asarray([[0., 0., 0., 1.],
[0., 1., 0., 1.],
[1., 1., 0., 1.]])
newPoints = points.dot(rotMat)
Notes
psychopy.tools.mathtools.
matrixToQuat
(m, out=None, dtype=None)[source]¶Convert a rotation matrix to a quaternion.
Parameters: 


Returns:  Rotation quaternion. 
Return type:  ndarray 
Notes
Examples
Converting a rotation matrix from the OpenGL matrix stack to a quaternion:
glRotatef(45., 1, 0, 0)
m = np.zeros((4, 4), dtype='float32') # store the matrix
GL.glGetFloatv(
GL.GL_MODELVIEW_MATRIX,
m.ctypes.data_as(ctypes.POINTER(ctypes.c_float)))
qr = matrixToQuat(m.T) # must be transposed
Interpolation between two 4x4 transformation matrices:
interpWeight = 0.5
posStart = mStart[:3, 3]
oriStart = matrixToQuat(mStart)
posEnd = mEnd[:3, 3]
oriEnd = matrixToQuat(mEnd)
oriInterp = slerp(qStart, qEnd, interpWeight)
posInterp = lerp(posStart, posEnd, interpWeight)
mInterp = posOriToMatrix(posInterp, oriInterp)
psychopy.tools.mathtools.
matrixFromEulerAngles
(rx, ry, rz, degrees=True, out=None, dtype=None)[source]¶Construct a 4x4 rotation matrix from Euler angles.
Rotations are combined by first rotating about the X axis, then Y, and finally Z.
Parameters: 


Returns:  4x4 rotation matrix. 
Return type:  ndarray 
Examples
Demonstration of how a combination of axisangle rotations is equivalent to a single call of matrixFromEulerAngles:
m1 = matrixFromEulerAngles(90., 45., 135.))
# construct rotation matrix from 3 orthogonal rotations
rx = rotationMatrix(90., (1, 0, 0)) # xaxis
ry = rotationMatrix(45., (0, 1, 0)) # yaxis
rz = rotationMatrix(135., (0, 0, 1)) # zaxis
m2 = concatenate([rz, ry, rx]) # note the order
print(numpy.allclose(m1, m2)) # True
Not only does matrixFromEulerAngles require less code, it also is considerably more efficient than constructing and multiplying multiple matrices.
psychopy.tools.mathtools.
scaleMatrix
(s, out=None, dtype=None)[source]¶Create a scaling matrix.
The resulting matrix is the same as a generated by a glScale call.
Parameters: 


Returns:  4x4 scaling matrix in rowmajor order. 
Return type:  ndarray 
psychopy.tools.mathtools.
rotationMatrix
(angle, axis=(0.0, 0.0, 1.0), out=None, dtype=None)[source]¶Create a rotation matrix.
The resulting matrix will rotate points about axis by angle. The resulting matrix is similar to that produced by a glRotate call.
Parameters: 


Returns:  4x4 scaling matrix in rowmajor order. Will be the same array as out if specified, if not, a new array will be allocated. 
Return type:  ndarray 
Notes
psychopy.tools.mathtools.
translationMatrix
(t, out=None, dtype=None)[source]¶Create a translation matrix.
The resulting matrix is the same as generated by a glTranslate call.
Parameters: 


Returns:  4x4 translation matrix in rowmajor order. Will be the same array as out if specified, if not, a new array will be allocated. 
Return type:  ndarray 
psychopy.tools.mathtools.
invertMatrix
(m, homogeneous=False, out=None, dtype=None)[source]¶Invert a 4x4 matrix.
Parameters: 


Returns:  4x4 matrix which is the inverse of m 
Return type:  ndarray 
psychopy.tools.mathtools.
isOrthogonal
(m)[source]¶Check if a square matrix is orthogonal.
If a matrix is orthogonal, its columns form an orthonormal basis and is nonsingular. An orthogonal matrix is invertible by simply taking the transpose of the matrix.
Parameters:  m (array_like) – Square matrix, either 2x2, 3x3 or 4x4. 

Returns:  True if the matrix is orthogonal. 
Return type:  bool 
psychopy.tools.mathtools.
isAffine
(m)[source]¶Check if a 4x4 square matrix describes an affine transformation.
Parameters:  m (array_like) – 4x4 transformation matrix. 

Returns:  True if the matrix is affine. 
Return type:  bool 
psychopy.tools.mathtools.
concatenate
(matrices, out=None, dtype=None)[source]¶Concatenate matrix transformations.
Combine 4x4 transformation matrices into a single matrix. This is similar to what occurs when building a matrix stack in OpenGL using glRotate, glTranslate, and glScale calls. Matrices are multiplied together from righttoleft, or the last item to first. Note that changing the order of the input matrices changes the final result.
The data types of input matrices are coerced to match that of out or dtype if out is None. For performance reasons, it is best that all arrays passed to this function have matching data types.
Parameters: 


Returns:  Concatenation of input matrices as a 4x4 matrix in rowmajor order. 
Return type:  ndarray 
Examples
Create an SRT (scale, rotate, and translate) matrix to convert modelspace coordinates to worldspace:
S = scaleMatrix([2.0, 2.0, 2.0]) # scale model 2x
R = rotationMatrix(90., [0., 0., 1]) # rotate 90 about Z axis
T = translationMatrix([0., 0., 5.]) # translate point 5 units away
SRT = concatenate([S, R, T])
# transform a point in modelspace coordinates to worldspace
pointModel = np.array([0., 1., 0., 1.])
pointWorld = np.matmul(SRT, pointModel.T) # point in WCS
# ... or ...
pointWorld = matrixApply(SRT, pointModel)
Create a modelview matrix from a worldspace pose represented by an orientation (quaternion) and position (vector). The resulting matrix will transform modelspace coordinates to eyespace:
# eye pose as quaternion and vector
stimOri = quatFromAxisAngle([0., 0., 1.], 45.0)
stimPos = [0., 1.5, 5.]
# create model matrix
R = quatToMatrix(stimOri)
T = translationMatrix(stimPos)
M = concatenate(R, T) # model matrix
# create a view matrix, can also be represented as 'pos' and 'ori'
eyePos = [0., 1.5, 0.]
eyeFwd = [0., 0., 1.]
eyeUp = [0., 1., 0.]
V = lookAt(eyePos, eyeFwd, eyeUp) # from viewtools
# modelview matrix
MV = concatenate([M, V])
You can put the created matrix in the OpenGL matrix stack as shown below. Note that the matrix must have a 32bit floatingpoint data type and needs to be loaded transposed since OpenGL takes matrices in columnmajor order:
GL.glMatrixMode(GL.GL_MODELVIEW)
# pyglet
MV = np.asarray(MV, dtype='float32') # must be 32bit float!
ptrMV = MV.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
GL.glLoadTransposeMatrixf(ptrMV)
# PyOpenGL
MV = np.asarray(MV, dtype='float32')
GL.glLoadTransposeMatrixf(MV)
Furthermore, you can convert a point from modelspace to homogeneous clipspace by concatenating the projection, view, and model matrices:
# compute projection matrix, functions here are from 'viewtools'
screenWidth = 0.52
screenAspect = w / h
scrDistance = 0.55
frustum = computeFrustum(screenWidth, screenAspect, scrDistance)
P = perspectiveProjectionMatrix(*frustum)
# multiply modelspace points by MVP to convert them to clipspace
MVP = concatenate([M, V, P])
pointModel = np.array([0., 1., 0., 1.])
pointClipSpace = np.matmul(MVP, pointModel.T)
psychopy.tools.mathtools.
applyMatrix
(m, points, out=None, dtype=None)[source]¶Apply a matrix over a 2D array of points.
This function behaves similarly to the following Numpy statement:
points[:, :] = points.dot(m.T)
Transformation matrices specified to m must have dimensions 4x4, 3x4, 3x3 or 2x2. With the exception of 4x4 matrices, input points must have the same number of columns as the matrix has rows. 4x4 matrices can be used to transform both Nx4 and Nx3 arrays.
Parameters: 


Returns:  Transformed coordinates. 
Return type:  ndarray 
Notes
Examples
Construct a matrix and transform a point:
# identity 3x3 matrix for this example
M = [[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]]
pnt = [1.0, 0.0, 0.0]
pntNew = applyMatrix(M, pnt)
Construct an SRT matrix (scale, rotate, transform) and transform an array of points:
S = scaleMatrix([5.0, 5.0, 5.0]) # scale 5x
R = rotationMatrix(180., [0., 0., 1]) # rotate 180 degrees
T = translationMatrix([0., 1.5, 3.]) # translate point up and away
M = concatenate([S, R, T]) # create transform matrix
# points to transform
points = np.array([[0., 1., 0., 1.], [1., 0., 0., 1.]]) # [x, y, z, w]
newPoints = applyMatrix(M, points) # apply the transformation
Convert CIEXYZ colors to sRGB:
sRGBMatrix = [[3.2404542, 1.5371385, 0.4985314],
[0.969266, 1.8760108, 0.041556 ],
[0.0556434, 0.2040259, 1.0572252]]
colorsRGB = applyMatrix(sRGBMatrix, colorsXYZ)
psychopy.tools.mathtools.
posOriToMatrix
(pos, ori, out=None, dtype=None)[source]¶Convert a rigid body pose to a 4x4 transformation matrix.
A pose is represented by a position coordinate pos and orientation quaternion ori.
Parameters: 


Returns:  4x4 transformation matrix. 
Return type:  ndarray 
psychopy.tools.mathtools.
transform
(pos, ori, points, out=None, dtype=None)[source]¶Transform points using a position and orientation. Points are rotated then translated.
Parameters: 


Returns:  Transformed points. 
Return type:  ndarray 
Examples
Transform points by a position coordinate and orientation quaternion:
# rigid body pose
ori = quatFromAxisAngle([0., 0., 1.], 90.0, degrees=True)
pos = [0., 1.5, 3.]
# points to transform
points = np.array([[0., 1., 0., 1.], [1., 0., 0., 1.]]) # [x, y, z, 1]
outPoints = np.zeros_like(points) # output array
transform(pos, ori, points, out=outPoints) # do the transformation
You can get the same results as the previous example using a matrix by doing the following:
R = rotationMatrix(90., [0., 0., 1])
T = translationMatrix([0., 1.5, 3.])
M = concatenate([R, T])
applyMatrix(M, points, out=outPoints)
If you are defining transformations with quaternions and coordinates, you can skip the costly matrix creation process by using transform.
Notes
psychopy.tools.mathtools.
lensCorrection
(xys, coefK=(1.0, ), distCenter=(0.0, 0.0), out=None, dtype=None)[source]¶Lens correction (or distortion) using the division model with even polynomial terms.
Calculate new vertex positions or texture coordinates to apply radial warping, such as ‘pincushion’ and ‘barrel’ distortion. This is to compensate for optical distortion introduced by lenses placed in the optical path of the viewer and the display (such as in an HMD).
Parameters: 


Returns:  Array of distorted vertices. 
Return type:  ndarray 
Notes
References
[1]  Fitzgibbon, W. (2001). Simultaneous linear estimation of multiple view geometry and lens distortion. Proceedings of the 2001 IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR). IEEE. 
Examples
Creating a lens correction mesh with barrel distortion (eg. for HMDs):
vertices, textureCoords, normals, faces = gltools.createMeshGrid(
subdiv=11, tessMode='center')
# recompute vertex positions
vertices[:, :2] = mt.lensCorrection(vertices[:, :2], coefK=(5., 5.))