API Reference

Coordinate frames

class coordframe.CoordFrame(m=None, **kwargs)

Coordinate frame defined by an origin and three unit vectors.

Unit vectors are given in world coordinates (origin at zero, matrix is eye(4)). Every transformation in this package is applied within the context of some coordinate frame.

Applying a transformation in this frame:

new_crd = self.m @ tfmat @ inv(self.m) @ crd

Where inv(m) @ crd brings world coordinates into this frame, tfmat @ applies the transformation in this frame, and m @ moves coordinates back into world space.

Convention:

The parent of any CoordFrame is the world frame. The columns of m (this frame’s unit vectors) are defined in the world frame.

Parameters:

m (np.ndarray | None) –

property m: ndarray

4x4 transformation matrix to bring points from this frame to the world.

property origin: ndarray

Origin of the coordinate system.

property i: ndarray

X unit vector represented in world coordinates.

property j: ndarray

Y unit vector represented in world coordinates.

property k: ndarray

Z unit vector represented in world coordinates.

as_points()

Return coordinate frame as a set of four points in world coordinates.

Return type:

PointCloud

transform(tfmat, tf_frame=None)

Transform this coordinate frame in the reference frame tf_frame.

Use this for “change frame, keep point relationships to the frame” transforms.

Parameters:
  • tfmat (ndarray) – 4x4 transformation matrix.

  • tf_frame (CoordFrame | None) – Reference frame in which to apply the transform. Defaults to the world frame.

Returns:

A new CoordFrame (this one is not modified).

Return type:

CoordFrame

from_world(coord_world)

Return point locations in the current frame of reference.

Parameters:

coord_world (ndarray) –

Return type:

ndarray

to_world(coord_local)

Return point locations in the world frame.

Parameters:

coord_local (ndarray) –

Return type:

ndarray

__repr__()

Return repr(self).

Return type:

str

Point clouds

class coordframe.PointCloud(vert, frame=array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]]))

A numpy array of 3D points bound to a reference frame.

Example

v = PointCloud(vert, local_frame)
v.co     # coordinates in local_frame
v.frame  # the reference frame for these coordinates

Remember: a coordinate frame is a point cloud (four points: origin plus the three axis tips).

Parameters:
  • vert (np.ndarray) –

  • frame (np.ndarray | CoordFrame) –

property n: int

Number of points in the cloud.

as_frame()

Return this 4-point cloud as a coordinate frame.

The first point is treated as the origin; the vectors from the origin to the second, third, and fourth points become i, j, k respectively (not normalized).

Return type:

CoordFrame

property center: PointCloud

Center of the point cloud as a new pointcloud object

in_frame(output_coord_system)

Return point cloud in the given frame of reference (output_coord_system).

Parameters:

output_coord_system (ndarray | CoordFrame) –

Return type:

PointCloud

in_world()

Return this point cloud expressed in the world frame.

Notes

When tfmat is the identity, the general formula in coordframe.transform() reduces to inv(out_frame) @ vert_frame; with out_frame also the identity (world), this further reduces to just vert_frame.

Return type:

PointCloud

transform(tfmat, tf_frame=None)

Apply a transform in the reference frame tf_frame.

Use this for “keep frame, change point relationships to the frame” transforms.

Parameters:
  • tfmat (ndarray) – Transformation matrix (3x3 or 4x4).

  • tf_frame (ndarray | CoordFrame | None) – Reference frame for the transform. Defaults to the current frame of reference (self.frame).

Returns:

A new PointCloud with the same frame but transformed coordinates.

Return type:

PointCloud

reframe(new_frame)

Re-frame the points. This maintains point locations in the world frame, but changes the current frame of reference.

Parameters:

new_frame (ndarray | CoordFrame) –

Return type:

PointCloud

reframe_pca(**mapping)

Re-frame the point cloud along its principal-component axes.

Body-axis convention used for the sign of each component:

  • z_dir = +1: up is positive.

  • z_dir = -1: down is positive (e.g. arm bones).

  • Positive x_dir is facing forward.

  • y_dir = z_dir × x_dir (right-hand-rule).

Parameters:

**mapping – Supply two of i, j, k; the third is computed assuming a right-handed frame. {'i': 1, 'j': 2} means the new frame’s i-direction uses PC1 and j-direction uses PC2.

Return type:

PointCloud

__call__()

Return the coordinates in the world frame.

If there is only one point in the cloud, a 1-D array is returned. Convenient for single-point clouds (e.g. origins):

o = PointCloud([a, b, c], frm)
o()  # instead of o.in_world().co[0, :]
Return type:

ndarray

pts_in_box(bbox)

Check if marker coordinates are within a bounding box.

Parameters:

bbox (dict) –

Return type:

ndarray

in_box(bbox)

Returns (bool) True if all the marker’s points are within a bounding box.

Parameters:

bbox (dict) –

Return type:

bool

frac_pts_in_box(bbox)

Returns (float) fraction of marker’s points inside the bounding box

Parameters:

bbox (dict) –

Return type:

float

Quaternions

class coordframe.Quat(vec, theta=None, frame=None, **kwargs)

Unit quaternion for 3D rotation.

Inputs are normalized on construction. q = cos(angle/2) + sin(angle/2) * unit_normal (normal in the world frame by default).

Example

q = Quat([1, 2, 3, 4])  # normalized on construction
q[:]        # 4-element quaternion vector (w, x, y, z)
q.angle     # rotation angle
q.normal    # rotation axis

q2 * q      # compose: apply q, then q2
q * v       # rotate a 3-vector (or nx3 array)
q * frame   # rotate a CoordFrame in world coordinates
q * pcloud  # rotate a PointCloud in its own frame

Typical use inside bpn:

s = new.sphere('sph', u=4, v=3)
s.show_frame()
# rotate around the object center in the world y-direction by 45°
s.frame = cf.Quat([0, 1, 0], np.pi/4, origin=s.loc) * s.frame
# rotate around the object center in the local-frame x-direction
s.frame = cf.Quat([1, 0, 0], np.pi/4, s.frame) * s.frame
Parameters:
  • vec (np.ndarray | list | tuple) –

  • theta (float | None) –

  • frame (CoordFrame | None) –

to_euler()

Convert this quaternion to Euler angles (roll, pitch, yaw).

All three angles are in radians, counterclockwise:

  • roll: rotation around X.

  • pitch: rotation around Y.

  • yaw: rotation around Z.

Returns:

(roll, pitch, yaw).

Return type:

tuple[float, float, float]

Helpers

coordframe.transform(tfmat, vert, vert_frame_mat=array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]]), tf_frame_mat=None, out_frame_mat=None)

Apply a transformation matrix, with explicit input/transform/output frames.

The most general form of a 3D transform in this package. Applies tfmat to vertices that are specified in vert_frame_mat, interprets the transformation in tf_frame_mat, and returns the vertices expressed in out_frame_mat.

Parameters:
  • tfmat (np.ndarray) – 3x3 or 4x4 transformation matrix.

  • vert (np.ndarray) – (nV, 3) vertex coordinates in vert_frame_mat.

  • vert_frame_mat (np.ndarray | CoordFrame) – Reference frame in which vert is given. Defaults to the world frame.

  • tf_frame_mat (np.ndarray | CoordFrame | None) – Frame in which tfmat is applied. Defaults to vert_frame_mat.

  • out_frame_mat (np.ndarray | CoordFrame | None) – Frame in which the result is expressed. Defaults to vert_frame_mat.

Returns:

(nV, 3) transformed vertices in out_frame_mat.

Return type:

np.ndarray

Notes

The five-step expansion is:

  1. Bring vertices to world frame: vert_frame.to_world(vert).

  2. Bring vertices to tf frame: tf_frame.from_world(vert).

  3. Apply tfmat in the tf frame.

  4. Bring vertices back to world: tf_frame.to_world(vert).

  5. Bring vertices to the output frame: out_frame.from_world(vert).

coordframe.m4(m=None, **kwargs)

Construct a 4x4 transformation matrix from a variety of inputs.

Example

m4(m=mat)                      # mat is 3x3 or 4x4
m4(i=i1, j=j1, k=k1, origin=o1)
m4(i=i1, j=j1, k=k1)           # origin defaults to (0, 0, 0)
m4()                           # 4x4 identity (world frame)
m4(..., unit_vectors=True)     # normalize i, j, k
Parameters:
  • m (ndarray | None) – Input matrix (3x3 or 4x4). None produces the identity.

  • **kwargsi, j, k (basis vectors), origin / center, unit_vectors (default False). Per-key assignments override m.

Returns:

A 4x4 numpy array.

Return type:

ndarray

coordframe.v4(vert)

Append a column of ones so (nV, 3) becomes (nV, 4).

Lets a 4x4 transformation matrix be applied to (nV, 3) coordinates.

Parameters:

vert (ndarray) –

Return type:

ndarray

coordframe.apply_matrix(mat, vert)

Apply a transformation matrix to a set of vertices.

Parameters:
  • mat (ndarray) – 3x3 or 4x4 transformation matrix.

  • vert (ndarray) – (nV, 3) array of vertices.

Returns:

(nV, 3) array of transformed vertices.

Return type:

ndarray

coordframe.normal2tfmat(n, out=None)

Compute a rotation matrix taking (0, 0, 1) to the direction n.

The transformation is not unique (there is one free degree of twist). This routine picks the one of two candidates (RxRy vs. RyRx) that displaces x and y the least, so the output is deterministic: a given n always yields the same matrix.

Parameters:
  • n (ndarray) – 3-element direction vector. Normalized internally if not already a unit vector. Treated as the new k_hat.

  • out (str | None) – If 'rxry' or 'ryrx', force that decomposition. Otherwise the smaller-displacement option is chosen.

Returns:

A 3x3 rotation matrix.

Return type:

ndarray

Notes

Intuitively the two candidates minimize twist, but this has not been proven mathematically.

coordframe.twisttf(θ)

Return a 3x3 rotation matrix around the Z axis by θ radians.

Parameters:

θ (float) –

Return type:

ndarray

coordframe.scaletf(s)

Construct a 3x3 scale matrix.

Parameters:

s (float | ndarray | list | tuple) – Either a scalar (uniform scale) or a 3-element vector (per-axis scale).

Return type:

ndarray

coordframe.norm_vec(vec)

Return unit vector, and return zero for zero vector.

Parameters:

vec (ndarray | list | tuple) –

Return type:

ndarray