Source code for attitude.geom.util
from __future__ import division
from functools import reduce
import numpy as N
from numpy.linalg import norm
[docs]def dot(*matrices):
return reduce(N.dot, matrices)
[docs]def augment_tensor(matrix, ndim=None):
"""
Increase the dimensionality of a tensor,
splicing it into an identity matrix of a higher
dimension. Useful for generalizing
transformation matrices.
"""
s = matrix.shape
if ndim is None:
ndim = s[0]+1
arr = N.identity(ndim)
arr[:s[0],:s[1]] = matrix
return arr
[docs]def vector(*args):
"""
A single vector in any coordinate basis,
as a numpy array.
"""
return N.array(args)
def unit_vector(*args):
v = vector(*args)
return v/norm(v)
[docs]def augment(vec):
"""
Augment a vector in any orthonormal basis
with a trailing 1 to form a homogeneous
coordinate vector in that coordinate system.
"""
return N.append(vec,[1])
[docs]def unit_vector(vec):
"""
Return a normalized version of the vector
"""
return vec/N.linalg.norm(vec)
[docs]def column(vec):
"""
Return a vector with a new trailing axis
(of singular dimension) added.
"""
return vec[:,N.newaxis]
[docs]def angle(v1,v2, cos=False):
"""
Find the angle between two vectors.
:param cos: If True, the cosine of the
angle will be returned. False by default.
"""
n = (norm(v1)*norm(v2))
_ = dot(v1,v2)/n
return _ if cos else N.arccos(_)
[docs]class Plane(N.ndarray):
[docs] def hessian_normal(plane):
"""
Return the Hessian Normal form of a plane
(ax + by + cz + d = 0) where [a,b,c] forms
the unit normal vector and d is the distance
to the origin."""
return plane/N.linalg.norm(plane[:-1])
[docs] def offset(plane):
"""
Returns the offset of the plane from the
origin or an arbitrary point.
"""
v = plane.hessian_normal()
return -N.array(v[:-1]*v[-1])
[docs] def normal(plane):
v = plane.hessian_normal()
return v[:-1]
[docs]def plane(normal,offset=0):
# This only works in Hessian-Normal form
return N.append(normal,offset).view(Plane)
[docs]def perpendicular_vector(n):
"""
Get a random vector perpendicular
to the given vector
"""
dim = len(n)
if dim == 2:
return n[::-1]
# More complex in 3d
for ix in range(dim):
_ = N.zeros(dim)
# Try to keep axes near the global projection
# by finding vectors perpendicular to higher-
# index axes first. This may or may not be worth
# doing.
_[dim-ix-1] = 1
v1 = N.cross(n,_)
if N.linalg.norm(v1) != 0:
return v1
raise ValueError("Cannot find perpendicular vector")