8000 add angdist method to SE3 class, gives rotational difference · krishanrana/spatialmath-python@54061e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 54061e2

Browse files
committed
add angdist method to SE3 class, gives rotational difference
1 parent 1c5f154 commit 54061e2

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

spatialmath/pose3d.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,73 @@ def Rt(cls, R, t, check=True):
14521452

14531453
return cls(base.rt2tr(R, t))
14541454

1455+
def angdist(self, other, metric=6):
1456+
r"""
1457+
Angular distance metric between poses
1458+
1459+
:param other: second rotation
1460+
:type other: SE3 instance
1461+
:param metric: metric, default is 6
1462+
:type metric: int
1463+
:raises TypeError: if other is not an SE3
1464+
:return: angle in radians
1465+
:rtype: float or ndarray
1466+
1467+
``T1.angdist(T2)`` is the geodesic norm, or geodesic distance between the
1468+
rotational parts of the two poses.
1469+
1470+
Several metrics are supported, the first 5 are computed after conversion
1471+
to unit quaternions.
1472+
1473+
====== ===============================================================
1474+
Metric Details
1475+
====== ===============================================================
1476+
0 :math:`1 - | \q_1 \bullet \q_2 | \in [0, 1]`
1477+
1 :math:`\cos^{-1} | \q_1 \bullet \q_2 | \in [0, \pi/2]`
1478+
2 :math:`\cos^{-1} | \q_1 \bullet \q_2 | \in [0, \pi/2]`
1479+
3 :math:`2 \tan^{-1} \| \q_1 - \q_2\| / \|\q_1 + \q_2\| \in [0, \pi/2]`
1480+
4 :math:`\cos^{-1} \left( 2 (\q_1 \bullet \q_2)^2 - 1\right) \in [0, 1]`
1481+
5 :math:`\|I - \mat{R}_1 \mat{R}_2^T\| \in [0, 2]`
1482+
6 :math:`\|\log \mat{R}_1 \mat{R}_2^T\| \in [0, \pi]`
1483+
====== ===============================================================
1484+
1485+
Example:
1486+
1487+
.. runblock:: pycon
1488+
1489+
>>> from spatialmath import UnitQuaternion
1490+
>>> T1 = SE3.Rx(0.3)
1491+
>>> T2 = SE3.Ry(0.3)
1492+
>>> print(T1.angdist(T1))
1493+
>>> print(T1.angdist(T2))
1494+
1495+
.. note::
1496+
- metrics 1, 2, 4 can throw ValueError "math domain error" due to
1497+
numeric errors which push the argument of ``acos()`` marginally
1498+
outside its domain [0, 1].
1499+
- metrics 2 and 3 are equivalent, but 3 is more robust
1500+
1501+
:seealso: :func:`UnitQuaternion.angdist`
1502+
"""
1503+
1504+
if metric < 5:
1505+
from spatialmath.quaternion import UnitQuaternion
1506+
1507+
return UnitQuaternion(self).angdist(UnitQuaternion(other), metric=metric)
1508+
1509+
elif metric == 5:
1510+
op = lambda T1, T2: np.linalg.norm(np.eye(3) - T1[:3,:3] @ T2[:3,:3].T)
1511+
elif metric == 6:
1512+
op = lambda T1, T2: base.norm(base.trlog(T1[:3,:3] @ T2[:3,:3].T, twist=True))
1513+
else:
1514+
raise ValueError('unknown metric')
1515+
1516+
ad = self._op2(other, op)
1517+
if isinstance(ad, list):
1518+
return np.array(ad)
1519+
else:
1520+
return ad
1521+
14551522
# @classmethod
14561523
# def SO3(cls, R, t=None, check=True):
14571524
# if isinstance(R, SO3):

0 commit comments

Comments
 (0)
0