Skip to content

Commit 0a7761d

Browse files
Merge pull request #77 from petercorke/xyz-properties
Add properties for x,y,z for SE3 and SE2 classes.
2 parents 90d37a1 + 976998b commit 0a7761d

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

spatialmath/pose2d.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,46 @@ def t(self):
528528
else:
529529
return np.array([x[:2, 2] for x in self.A])
530530

531+
@property
532+
def x(self):
533+
"""
534+
First element of the translational component of SE(2)
535+
536+
:param self: SE(2)
537+
:type self: SE2 instance
538+
:return: translational component
539+
:rtype: float
540+
541+
``v.x`` is the first element of the translational vector component. If ``len(x)`` is:
542+
543+
- 1, return an float
544+
- N>1, return an ndarray with shape=(N,)
545+
"""
546+
if len(self) == 1:
547+
return self.A[0, 2]
548+
else:
549+
return np.array([v[0, 2] for v in self.A])
550+
551+
@property
552+
def y(self):
553+
"""
554+
Second element of the translational component of SE(2)
555+
556+
:param self: SE(2)
557+
:type self: SE2 instance
558+
:return: translational component
559+
:rtype: float
560+
561+
``v.y`` is the second element of the translational vector component. If ``len(x)`` is:
562+
563+
- 1, return an float
564+
- N>1, return an ndarray with shape=(N,)
565+
"""
566+
if len(self) == 1:
567+
return self.A[1, 2]
568+
else:
569+
return np.array([v[1, 2] for v in self.A])
570+
531571
def xyt(self):
532572
r"""
533573
SE(2) as a configuration vector

spatialmath/pose3d.py

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,105 @@ def t(self, v: ArrayLike3):
10361036
v = smb.getvector(v, 3)
10371037
self.A[:3, 3] = v
10381038

1039+
@property
1040+
def x(self) -> float:
1041+
"""
1042+
First element of translational component of SE(3)
1043+
1044+
:return: first element of translational component of SE(3)
1045+
:rtype: float
1046+
1047+
If ``len(v) > 1``, return an array with shape=(N,).
1048+
1049+
Example:
1050+
1051+
.. runblock:: pycon
1052+
1053+
>>> from spatialmath import SE3
1054+
>>> v = SE3(1,2,3)
1055+
>>> v.x
1056+
>>> v = SE3([ SE3(1,2,3), SE3(4,5,6)])
1057+
>>> v.x
1058+
1059+
:SymPy: supported
1060+
"""
1061+
if len(self) == 1:
1062+
return self.A[0, 3]
1063+
else:
1064+
return np.array([v[0, 3] for v in self.A])
1065+
1066+
@x.setter
1067+
def x(self, x: float):
1068+
if len(self) > 1:
1069+
raise ValueError("can only assign elements to length 1 object")
1070+
self.A[0, 3] = x
1071+
1072+
@property
1073+
def y(self) -> float:
1074+
"""
1075+
Second element of translational component of SE(3)
1076+
1077+
:return: second element of translational component of SE(3)
1078+
:rtype: float
1079+
1080+
If ``len(v) > 1``, return an array with shape=(N,).
1081+
1082+
Example:
1083+
1084+
.. runblock:: pycon
1085+
1086+
>>> from spatialmath import SE3
1087+
>>> v = SE3(1,2,3)
1088+
>>> v.y
1089+
>>> v = SE3([ SE3(1,2,3), SE3(4,5,6)])
1090+
>>> v.y
1091+
1092+
:SymPy: supported
1093+
"""
1094+
if len(self) == 1:
1095+
return self.A[1, 3]
1096+
else:
1097+
return np.array([v[1, 3] for v in self.A])
1098+
1099+
@y.setter
1100+
def y(self, y: float):
1101+
if len(self) > 1:
1102+
raise ValueError("can only assign elements to length 1 object")
1103+
self.A[1, 3] = y
1104+
1105+
@property
1106+
def z(self) -> float:
1107+
"""
1108+
Third element of translational component of SE(3)
1109+
1110+
:return: third element of translational component of SE(3)
1111+
:rtype: float
1112+
1113+
If ``len(v) > 1``, return an array with shape=(N,).
1114+
1115+
Example:
1116+
1117+
.. runblock:: pycon
1118+
1119+
>>> from spatialmath import SE3
1120+
>>> v = SE3(1,2,3)
1121+
>>> v.z
1122+
>>> v = SE3([ SE3(1,2,3), SE3(4,5,6)])
1123+
>>> v.z
1124+
1125+
:SymPy: supported
1126+
"""
1127+
if len(self) == 1:
1128+
return self.A[2, 3]
1129+
else:
1130+
return np.array([v[2, 3] for v in self.A])
1131+
1132+
@z.setter
1133+
def z(self, z: float):
1134+
if len(self) > 1:
1135+
raise ValueError("can only assign elements to length 1 object")
1136+
self.A[2, 3] = z
1137+
10391138
# ------------------------------------------------------------------------ #
10401139

10411140
def inv(self) -> SE3:

tests/test_pose2d.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ def test_Rt(self):
390390
array_compare(TT1.A, T1)
391391
array_compare(TT1.R, R1)
392392
array_compare(TT1.t, t1)
393+
self.assertEqual(TT1.x, t1[0])
394+
self.assertEqual(TT1.y, t1[1])
393395

394396
TT = SE2([TT1, TT1, TT1])
395397
array_compare(TT.t, [t1, t1, t1])

tests/test_pose3d.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,20 @@ def test_constructor(self):
789789
nt.assert_equal(T.R, R)
790790
nt.assert_equal(T.t, t)
791791

792+
nt.assert_equal(T.x, t[0])
793+
nt.assert_equal(T.y, t[1])
794+
nt.assert_equal(T.z, t[2])
795+
796+
TT = SE3([T, T, T])
797+
desired_shape = (3,)
798+
nt.assert_equal(TT.x.shape, desired_shape)
799+
nt.assert_equal(TT.y.shape, desired_shape)
800+
nt.assert_equal(TT.z.shape, desired_shape)
801+
802+
ones = np.ones(desired_shape)
803+
nt.assert_equal(TT.x, ones*t[0])
804+
nt.assert_equal(TT.y, ones*t[1])
805+
nt.assert_equal(TT.z, ones*t[2])
792806

793807
# copy constructor
794808
R = SE3.Rx(pi / 2)

0 commit comments

Comments
 (0)