8000 Factor out userlist wrappers in class agnostic way · flyinger/spatialmath-python@881582e · GitHub
[go: up one dir, main page]

Skip to content

Commit 881582e

Browse files
committed
Factor out userlist wrappers in class agnostic way
test it on quaternions first
1 parent 739bccd commit 881582e

File tree

2 files changed

+176
-179
lines changed

2 files changed

+176
-179
lines changed

spatialmath/quaternion.py

Lines changed: 2 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22
Provide quaternion and unit-quaternion abstractions as classes
33
"""
44

5-
from collections import UserList
65
import math
76
import numpy as np
87
from typing import Any
98
from spatialmath import base as tr
109
from spatialmath.base import quaternions as quat
1110
from spatialmath.base import argcheck
1211
from spatialmath import pose3d as p3d
12+
from spatialmath.smuserlist import SMUserList
1313

14-
15-
class Quaternion(UserList):
14+
class Quaternion(SMUserList):
1615
r"""
1716
A quaternion is a compact method of representing a 3D rotation that has
1817
computational advantages including speed and numerical robustness.
@@ -98,182 +97,6 @@ def __init__(self, s: Any =None, v=None, check=True):
9897
else:
9998
raise ValueError('bad argument to Quaternion constructor')
10099

101-
@classmethod
102-
def Empty(cls):
103-
"""
104-
Construct an empty quaternion object
105-
106-
:return: a quaternion instance with zero values
107-
:rtype: Quaternion
108-
109-
Example::
110-
111-
>>> q = Quaternion.Empty()
112-
>>> len(q)
113-
0
114-
"""
115-
q = cls()
116-
q.data = []
117-
return q
118-
119-
@property
120-
def _A(self):
121-
# get the underlying numpy array
122-
if len(self.data) == 1:
123-
return self.data[0]
124-
else:
125-
return self.data
126-
127-
# ------------------------------------------------------------------------ #
128-
129-
def __getitem__(self, i):
130-
"""
131-
Access value of a quaternion instance
132-
133-
:param i: index of element to return
134-
:type i: int
135-
:return: the specific element of the pose
136-
:rtype: Quaternion or UnitQuaternion instance
137-
:raises IndexError: if the element is out of bounds
138-
139-
Note that only a single index is supported, slices are not.
140-
141-
Example::
142-
143-
>>> q = UnitQuaternion.Rx([0, 0.3, 0.6])
144-
>>> len(q)
145-
3
146-
>>> q[1]
147-
0.988771 << 0.149438, 0.000000, 0.000000 >>
148-
"""
149-
150-
if isinstance(i, slice):
151-
return self.__class__([self.data[k] for k in range(i.start or 0, i.stop or len(self), i.step or 1)])
152-
else:
153-
return self.__class__(self.data[i])
154-
155-
def __setitem__(self, i, value):
156-
"""
157-
Assign a value to a quaternion instance
158-
159-
:param i: index of element to assign to
160-
:type i: int
161-
:param value: the value to insert
162-
:type value: Quaternion or UnitQuaternion instance
163-
:raises ValueError: incorrect type of assigned value
164-
165-
Assign the argument to an element of the object's internal list of values.
166-
This supports the assignement operator, for example::
167-
168-
>>> q = Quaternion([Quaternion() for i in range(10)]) # sequence of ten identity values
169-
>>> len(q)
170-
10
171-
>>> q[3] = Quaternion([1,2,3,4]) # assign to position 3 in the list
172-
"""
173-
if not type(self) == type(value):
174-
raise ValueError("can't insert different type of object")
175-
if len(value) > 1:
176-
raise ValueError("can't insert a multivalued element - must have len() == 1")
177-
self.data[i] = value.A
178-
179-
def append(self, q):
180-
"""
181-
Append a value to a quaternion instance
182-
183-
:param x: the value to append
184-
:type x: Quaternion or UnitQuaternion instance
185-
:raises ValueError: incorrect type of appended object
186-
187-
Appends the argument to the object's internal list of values.
188-
189-
Examples::
190-
191-
>>> q = Quaternion()
192-
>>> len(q)
193-
1
194-
>>> q.append(Quaternion([1,2,3,4]))
195-
>>> len(q)
196-
2
197-
"""
198-
#print('in append method')
199-
if not type(self) == type(q):
200-
raise ValueError("can't append different type of object")
201-
if len(q) > 1:
202-
raise ValueError("can't append a multivalued instance - use extend")
203-
super().append(q.A)
204-
205-
206-
def extend(self, q):
207-
"""
208-
Extend sequence of values of a quaternion instance
209-
210-
:param x: the value to extend
211-
:type x: Quaternion or UnitQuaternion instance
212-
:raises ValueError: incorrect type of appended object
213-
214-
Appends the argument to the object's internal list of values.
215-
216-
Examples::
217-
218-
>>> q = UnitQuaternion()
219-
>>> len(q)
220-
1
221-
>>> q.extend(UnitQuaternion.Rx([0.1, 0.2]))
222-
>>> len(3)
223-
3
224-
"""
225-
#print('in extend method')
226-
if not type(self) == type(q):
227-
raise ValueError("can't append different type of object")
228-
super().extend(q._A)
229-
230-
def insert(self, i, value):
231-
"""
232-
Insert a value to a quaternion instance
233-
234-
:param i: element to insert value before
235-
:type i: int
236-
:param value: the value to insert
237-
:type value: Quaternion or UnitQuaternion instance
238-
:raises ValueError: incorrect type of inserted value
239-
240-
Inserts the argument into the object's internal list of values.
241-
242-
Examples::
243-
244-
>>> q = UnitQuaternion()
245-
>>> q.insert(0, UnitQuaternion.Rx(0.1)) # insert at position 0 in the list
246-
>>> len(q)
247-
2
248-
"""
249-
if not type(self) == type(value):
250-
raise ValueError("can't insert different type of object")
251-
if len(value) > 1:
252-
raise ValueError("can't insert a multivalued instance - must have len() == 1")
253-
super().insert(i, value._A)
254-
255-
def pop(self):
256-
"""
257-
Pop value of a quaternion instance
258-
259-
:return: the first quaternion value
260-
:rtype: Quaternion or UnitQuaternion instance
261-
:raises IndexError: if there are no values to pop
262-
263-
Removes the first quaternion value from the instancet.
264-
265-
Example::
266-
267-
>>> q = UnitQuaternion.Rx([0, 0.3, 0.6])
268-
>>> len(q)
269-
3
270-
>>> q.pop()
271-
1.000000 << 0.000000, 0.000000, 0.000000 >>
272-
>>> len(q)
273-
2
274-
"""
275-
return self.__class__(super().pop())
276-
277100
@property
278101
def s(self):
279102
"""

spatialmath/smuserlist.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
Provide list super powers for spatial math objects.
3+
"""
4+
5+
from collections import UserList
6+
7+
class SMUserList(UserList):
8+
9+
@classmethod
10+
def Empty(cls):
11+
"""
12+
Construct an empty instance (superclass method)
13+
14+
:return: a quaternion instance with zero values
15+
:rtype: Quaternion
16+
17+
Example::
18+
19+
>>> q = Quaternion.Empty()
20+
>>> len(q)
21+
0
22+
"""
23+
q = cls()
24+
q.data = []
25+
return q
26+
27+
@property
28+
def _A(self):
29+
# get the underlying numpy array
30+
if len(self.data) == 1:
31+
return self.data[0]
32+
else:
33+
return self.data
34+
35+
@property
36+
def _A(self):
37+
# get the underlying numpy array
38+
if len(self.data) == 1:
39+
return self.data[0]
40+
else:
41+
return self.data
42+
43+
# ------------------------------------------------------------------------ #
44+
45+
def __getitem__(self, i):
46+
"""
47+
Access value of an instance (superclass method)
48+
49+
:param i: index of element to return
50+
:type i: int
51+
:return: the specific element of the pose
52+
:rtype: Quaternion or UnitQuaternion instance
53+
:raises IndexError: if the element is out of bounds
54+
55+
Note that only a single index is supported, slices are not.
56+
57+
Example::
58+
59+
>>> q = UnitQuaternion.Rx([0, 0.3, 0.6])
60+
>>> len(q)
61+
3
62+
>>> q[1]
63+
0.988771 << 0.149438, 0.000000, 0.000000 >>
64+
"""
65+
66+
if isinstance(i, slice):
67+
return self.__class__([self.data[k] for k in range(i.start or 0, i.stop or len(self), i.step or 1)])
68+
else:
69+
return self.__class__(self.data[i])
70+
71+
def __setitem__(self, i, value):
72+
"""
73+
Assign a value to an instance (superclass method)
74+
75+
:param i: index of element to assign to
76+
:type i: int
77+
:param value: the value to insert
78+
:type value: Quaternion or UnitQuaternion instance
79+
:raises ValueError: incorrect type of assigned value
80+
81+
Assign the argument to an elemen 10000 t of the object's internal list of values.
82+
This supports the assignement operator, for example::
83+
84+
>>> q = Quaternion([Quaternion() for i in range(10)]) # sequence of ten identity values
85+
>>> len(q)
86+
10
87+
>>> q[3] = Quaternion([1,2,3,4]) # assign to position 3 in the list
88+
"""
89+
if not type(self) == type(value):
90+
raise ValueError("can't insert different type of object")
91+
if len(value) > 1:
92+
raise ValueError("can't insert a multivalued element - must have len() == 1")
93+
self.data[i] = value.A
94+
95+
def append(self, value):
96+
"""
97+
Append a value to an instance (superclass method)
98+
99+
:param x: the value to append
100+
:type x: Quaternion or UnitQuaternion instance
101+
:raises ValueError: incorrect type of appended object
102+
103+
Appends the argument to the object's internal list of values.
104+
105+
"""
106+
#print('in append method')
107+
if not type(self) == type(value):
108+
raise ValueError("can't append different type of object")
109+
if len(value) > 1:
110+
raise ValueError("can't append a multivalued instance - use extend")
111+
super().append(value.A)
112+
113+
114+
def extend(self, value):
115+
"""
116+
Extend sequence of values in an instance (superclass method)
117+
118+
:param x: the value to extend
119+
:type x: instance of same type
120+
:raises ValueError: incorrect type of appended object
121+
122+
Appends the argument's values to the object's internal list of values.
123+
"""
124+
#print('in extend method')
125+
if not type(self) == type(value):
126+
raise ValueError("can't append different type of object")
127+
super().extend(value._A)
128+
129+
def insert(self, i, value):
130+
"""
131+
Insert a value to an instance (superclass method)
132+
133+
:param i: element to insert value before
134+
:type i: int
135+
:param value: the value to insert
136+
:type value: instance of same type
137+
:raises ValueError: incorrect type of inserted value
138+
139+
Inserts the argument into the object's internal list of values.
140+
141+
Examples::
142+
143+
>>> q = UnitQuaternion()
144+
>>> q.insert(0, UnitQuaternion.Rx(0.1)) # insert at position 0 in the list
145+
>>> len(q)
146+
2
147+
"""
148+
if not type(self) == type(value):
149+
raise ValueError("can't insert different type of object")
150+
if len(value) > 1:
151+
raise ValueError("can't insert a multivalued instance - must have len() == 1")
152+
super().insert(i, value._A)
153+
154+
def pop(self):
155+
"""
156+
Pop value from an instance (superclass method)
157+
158+
:return: the first value
159+
:rtype: instance of same type
160+
:raises IndexError: if there are no values to pop
161+
162+
Removes the first quaternion value from the instancet.
163+
164+
Example::
165+
166+
>>> q = UnitQuaternion.Rx([0, 0.3, 0.6])
167+
>>> len(q)
168+
3
169+
>>> q.pop()
170+
1.000000 << 0.000000, 0.000000, 0.000000 >>
171+
>>> len(q)
172+
2
173+
"""
174+
return self.__class__(super().pop())

0 commit comments

Comments
 (0)
0