Merge branch 'vectorized-orientation-conversion' into no-python-quaternion

This commit is contained in:
Martin Diehl 2020-01-14 09:02:43 +01:00
commit 99684c3e86
1 changed files with 34 additions and 44 deletions

View File

@ -246,9 +246,8 @@ class Rotation:
################################################################################################ ################################################################################################
# static constructors. The input data needs to follow the convention, options allow to # static constructors. The input data needs to follow the convention, options allow to
# relax these convections # relax these convections
@classmethod @staticmethod
def fromQuaternion(cls, def fromQuaternion(quaternion,
quaternion,
acceptHomomorph = False, acceptHomomorph = False,
P = -1): P = -1):
@ -263,11 +262,10 @@ class Rotation:
if not np.isclose(np.linalg.norm(qu), 1.0): if not np.isclose(np.linalg.norm(qu), 1.0):
raise ValueError('Quaternion is not of unit length.\n{} {} {} {}'.format(*qu)) raise ValueError('Quaternion is not of unit length.\n{} {} {} {}'.format(*qu))
return cls(qu) return Rotation(qu)
@classmethod @staticmethod
def fromEulers(cls, def fromEulers(eulers,
eulers,
degrees = False): degrees = False):
eu = eulers if isinstance(eulers, np.ndarray) and eulers.dtype == np.dtype(float) \ eu = eulers if isinstance(eulers, np.ndarray) and eulers.dtype == np.dtype(float) \
@ -276,11 +274,10 @@ class Rotation:
if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or eu[1] > np.pi: if np.any(eu < 0.0) or np.any(eu > 2.0*np.pi) or eu[1] > np.pi:
raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π].\n{} {} {}.'.format(*eu)) raise ValueError('Euler angles outside of [0..2π],[0..π],[0..2π].\n{} {} {}.'.format(*eu))
return cls(eu2qu(eu)) return Rotation(eu2qu(eu))
@classmethod @staticmethod
def fromAxisAngle(cls, def fromAxisAngle(angleAxis,
angleAxis,
degrees = False, degrees = False,
normalise = False, normalise = False,
P = -1): P = -1):
@ -295,11 +292,10 @@ class Rotation:
if not np.isclose(np.linalg.norm(ax[0:3]), 1.0): if not np.isclose(np.linalg.norm(ax[0:3]), 1.0):
raise ValueError('Axis angle rotation axis is not of unit length.\n{} {} {}'.format(*ax[0:3])) raise ValueError('Axis angle rotation axis is not of unit length.\n{} {} {}'.format(*ax[0:3]))
return cls(ax2qu(ax)) return Rotation(ax2qu(ax))
@classmethod @staticmethod
def fromBasis(cls, def fromBasis(basis,
basis,
orthonormal = True, orthonormal = True,
reciprocal = False, reciprocal = False,
): ):
@ -318,18 +314,16 @@ class Rotation:
or not np.isclose(np.dot(om[2],om[0]), 0.0): or not np.isclose(np.dot(om[2],om[0]), 0.0):
raise ValueError('matrix is not orthogonal.\n{}'.format(om)) raise ValueError('matrix is not orthogonal.\n{}'.format(om))
return cls(om2qu(om)) return Rotation(om2qu(om))
@classmethod @staticmethod
def fromMatrix(cls, def fromMatrix(om,
om,
): ):
return cls.fromBasis(om) return Rotation.fromBasis(om)
@classmethod @staticmethod
def fromRodrigues(cls, def fromRodrigues(rodrigues,
rodrigues,
normalise = False, normalise = False,
P = -1): P = -1):
@ -342,22 +336,20 @@ class Rotation:
if ro[3] < 0.0: if ro[3] < 0.0:
raise ValueError('Rodriques rotation angle not positive.\n'.format(ro[3])) raise ValueError('Rodriques rotation angle not positive.\n'.format(ro[3]))
return cls(ro2qu(ro)) return Rotation(ro2qu(ro))
@classmethod @staticmethod
def fromHomochoric(cls, def fromHomochoric(homochoric,
homochoric,
P = -1): P = -1):
ho = homochoric if isinstance(homochoric, np.ndarray) and homochoric.dtype == np.dtype(float) \ ho = homochoric if isinstance(homochoric, np.ndarray) and homochoric.dtype == np.dtype(float) \
else np.array(homochoric,dtype=float) else np.array(homochoric,dtype=float)
if P > 0: ho *= -1 # convert from P=1 to P=-1 if P > 0: ho *= -1 # convert from P=1 to P=-1
return cls(ho2qu(ho)) return Rotation(ho2qu(ho))
@classmethod @staticmethod
def fromCubochoric(cls, def fromCubochoric(cubochoric,
cubochoric,
P = -1): P = -1):
cu = cubochoric if isinstance(cubochoric, np.ndarray) and cubochoric.dtype == np.dtype(float) \ cu = cubochoric if isinstance(cubochoric, np.ndarray) and cubochoric.dtype == np.dtype(float) \
@ -365,12 +357,11 @@ class Rotation:
ho = cu2ho(cu) ho = cu2ho(cu)
if P > 0: ho *= -1 # convert from P=1 to P=-1 if P > 0: ho *= -1 # convert from P=1 to P=-1
return cls(ho2qu(ho)) return Rotation(ho2qu(ho))
@classmethod @staticmethod
def fromAverage(cls, def fromAverage(rotations,
rotations,
weights = []): weights = []):
""" """
Average rotation. Average rotation.
@ -400,11 +391,11 @@ class Rotation:
else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa else M + r.asM() * n # noqa add (multiples) of this rotation to average noqa
eig, vec = np.linalg.eig(M/N) eig, vec = np.linalg.eig(M/N)
return cls.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True) return Rotation.fromQuaternion(np.real(vec.T[eig.argmax()]),acceptHomomorph = True)
@classmethod @staticmethod
def fromRandom(cls): def fromRandom():
r = np.random.random(3) r = np.random.random(3)
A = np.sqrt(r[2]) A = np.sqrt(r[2])
B = np.sqrt(1.0-r[2]) B = np.sqrt(1.0-r[2])
@ -412,7 +403,7 @@ class Rotation:
x = np.sin(2.0*np.pi*r[1])*B x = np.sin(2.0*np.pi*r[1])*B
y = np.cos(2.0*np.pi*r[1])*B y = np.cos(2.0*np.pi*r[1])*B
z = np.sin(2.0*np.pi*r[0])*A z = np.sin(2.0*np.pi*r[0])*A
return cls.fromQuaternion([w,x,y,z],acceptHomomorph=True) return Rotation.fromQuaternion([w,x,y,z],acceptHomomorph=True)
@ -1181,9 +1172,8 @@ class Orientation:
return color return color
@classmethod @staticmethod
def fromAverage(cls, def fromAverage(orientations,
orientations,
weights = []): weights = []):
"""Create orientation from average of list of orientations.""" """Create orientation from average of list of orientations."""
if not all(isinstance(item, Orientation) for item in orientations): if not all(isinstance(item, Orientation) for item in orientations):