@@ -20,15 +20,15 @@ class Quaternion(UserList):
20
20
21
21
def __init__ (self , s = None , v = None , check = True , norm = True ):
22
22
"""
23
- A unit quaternion is one for which M{s^2+vx^2+vy^2+vz^2 = 1}.
23
+ A zero quaternion is one for which M{s^2+vx^2+vy^2+vz^2 = 1}.
24
24
A quaternion can be considered as a rotation about a vector in space where
25
25
q = cos (theta/2) sin(theta/2) <vx vy vz>
26
26
where <vx vy vz> is a unit vector.
27
27
:param s: scalar
28
28
:param v: vector
29
29
"""
30
30
if s is None and v is None :
31
- self .data = [ quat . qone ( ) ]
31
+ self .data = [ np . array ([ 0 , 0 , 0 , 0 ] ) ]
32
32
33
33
elif argcheck .isscalar (s ) and argcheck .isvector (v ,3 ):
34
34
self .data = [ np .r_ [s , argcheck .getvector (v )] ]
@@ -37,13 +37,23 @@ def __init__(self, s=None, v=None, check=True, norm=True):
37
37
self .data = [ argcheck .getvector (s ) ]
38
38
39
39
elif type (s ) is list :
40
- if check :
41
- assert argcheck .isvectorlist (s ,4 ), 'list must comprise 4-vectors'
42
- self .data = s
40
+ if isinstance (s [0 ], np .ndarray ):
41
+ if check :
42
+ assert argcheck .isvectorlist (s ,4 ), 'list must comprise 4-vectors'
43
+ self .data = s
44
+ elif isinstance (s [0 ], self .__class__ ):
45
+ # possibly a list of objects of same type
46
+ assert all ( map ( lambda x : isinstance (x , self .__class__ ), s ) ), 'all elements of list must have same type'
47
+ self .data = [x ._A for x in s ]
48
+ else :
49
+ raise ValueError ('incorrect list' )
43
50
44
51
elif isinstance (s , np .ndarray ) and s .shape [1 ] == 4 :
45
52
self .data = [x for x in s ]
46
53
54
+ elif isinstance (s , Quaternion ):
55
+ self .data = s .data
56
+
47
57
else :
48
58
raise ValueError ('bad argument to Quaternion constructor' )
49
59
@@ -64,7 +74,7 @@ def _A(self):
64
74
return self .data
65
75
66
76
def __getitem__ (self , i ):
67
- print ('getitem' , i )
77
+ # print('getitem', i)
68
78
#return self.__class__(self.data[i])
69
79
return self .__class__ (self .data [i ])
70
80
@@ -122,15 +132,13 @@ def vec(self):
122
132
def pure (cls , v ):
123
133
return cls (s = 0 , v = argcheck .getvector (v ,3 ), norm = True )
124
134
135
+ @property
125
136
def conj (self ):
126
- if instance (v , np .ndarray ) and len (shape ) > 1 and v .shape [1 ] == 3 :
127
- return self .__class__ ( [quat .conj (q ._A ) for q in self ] )
128
- else :
129
- return self .__class__ (quat .conj (self ._A ))
137
+ return Quaternion ( [quat .conj (q ._A ) for q in self ], norm = False )
138
+
130
139
131
- def conj (self ):
132
- return self .__class__ ( [quat .conj (q ._A ) for q in self ] )
133
140
141
+ @property
134
142
def norm (self ):
135
143
"""Return the norm of this quaternion.
136
144
Code retrieved from: https://github.com/petercorke/robotics-toolbox-python/blob/master/robot/Quaternion.py
@@ -139,10 +147,11 @@ def norm(self):
139
147
@return: the norm
140
148
"""
141
149
if len (self ) == 1 :
142
- return np . linalg . norm (self .double () )
150
+ return quat . qnorm (self ._A )
143
151
else :
144
- return np .array ([quat .norm (q ._A ) for q in self ])
152
+ return np .array ([quat .qnorm (q ._A ) for q in self ])
145
153
154
+ @property
146
155
def unit (self ):
147
156
"""Return an equivalent unit quaternion
148
157
Code retrieved from: https://github.com/petercorke/robotics-toolbox-python/blob/master/robot/Quaternion.py
@@ -153,11 +162,25 @@ def unit(self):
153
162
return UnitQuaternion ( [quat .unit (q ._A ) for q in self ], norm = False )
154
163
155
164
165
+ @property
156
166
def matrix (self ):
157
- return qmatrix (self ._A )
167
+ return quat . matrix (self ._A )
158
168
159
169
#-------------------------------------------- arithmetic
160
170
171
+ def inner (self , other ):
172
+ assert isinstance (other , Quaternion ), 'operands to inner must be Quaternion subclass'
173
+ return self ._op2 (other , lambda x , y : quat .inner (x , y ), list1 = False )
174
+
175
+ def __eq__ (self , other ):
176
+ assert type (self ) == type (other ), 'operands to == are of different types'
177
+ return self ._op2 (other , lambda x , y : quat .isequal (x , y ), list1 = False )
178
+
179
+ def __ne__ (self , other ):
180
+ assert type (self ) == type (other ), 'operands to == are of different types'
181
+ return self ._op2 (other , lambda x , y : not quat .isequal (x , y ), list1 = False )
182
+
183
+
161
184
def __mul__ (left , right ):
162
185
"""
163
186
multiply quaternion
@@ -204,7 +227,7 @@ def __mul__(left, right):
204
227
if type (left ) == type (right ):
205
228
# quaternion * quaternion case (same class)
206
229
return left .__class__ ( left ._op2 (right , lambda x , y : quat .qqmul (x , y ) ) )
207
- elif isinstance (other , Quaternion ):
230
+ elif isinstance (right , Quaternion ):
208
231
# quaternion * quaternion case (different class)
209
232
return Quaternion ( left ._op2 (right , lambda x , y : quat .qqmul (x , y ) ) )
210
233
elif argcheck .isscalar (right ):
@@ -258,7 +281,7 @@ def __rmul__(right, left):
258
281
A 3-vector of length N is a 3xN numpy array, where each column is a 3-vector.
259
282
"""
260
283
# scalar * quaternion case
261
- return Quaternion ([other * q ._A for q in self ])
284
+ return Quaternion ([left * q ._A for q in right ])
262
285
263
286
def __imul__ (left , right ):
264
287
"""
@@ -409,13 +432,6 @@ def __sub__(left, right):
409
432
assert type (left ) == type (right ), 'operands to - are of different types'
410
433
return Quaternion ( left ._op2 (right , lambda x , y : x - y ) )
411
434
412
-
413
- def __eq__ (self , other ):
414
- assert type (self ) == type (other ), 'operands to == are of different types'
415
- return self ._op2 (other , lambda x , y : quat .isequal (x , y ), list1 = False )
416
-
417
- def __ne__ (self , other ):
418
- return not self .__eq__ (other )
419
435
420
436
def _op2 (self , other , op , list1 = True ):
421
437
@@ -430,10 +446,10 @@ def _op2(self, other, op, list1=True):
430
446
return [op (self ._A , x ._A ) for x in other ]
431
447
else :
432
448
if len (other ) == 1 :
433
- print ('== Nx1' )
449
+ # print('== Nx1')
434
450
return [op (x ._A , other ._A ) for x in self ]
435
451
elif len (self ) == len (other ):
436
- print ('== NxN' )
452
+ # print('== NxN')
437
453
return [op (x ._A , y ._A ) for (x ,y ) in zip (self , other )]
438
454
else :
439
455
raise ValueError ('length of lists to == must be same length' )
@@ -472,7 +488,7 @@ def _op2(self, other, op, list1=True):
472
488
def __repr__ (self ):
473
489
s = ''
474
490
for q in self :
475
- s += quat .print (q ._A , file = None ) + '\n '
491
+ s += quat .qprint (q ._A , file = None ) + '\n '
476
492
s .rstrip ('\n ' )
477
493
return s
478
494
@@ -536,19 +552,24 @@ def __init__(self, s=None, v=None, norm=True, check=True):
536
552
self .data = [q ]
537
553
538
554
elif argcheck .isvector (s ,4 ):
539
- print ('uq constructor 4vec' )
555
+ # print('uq constructor 4vec')
540
556
q = argcheck .getvector (s )
541
557
# if norm:
542
558
# q = quat.unit(q)
543
559
print (q )
544
560
self .data = [q ]
545
561
546
562
elif type (s ) is list :
547
- if check :
548
- assert argcheck .isvectorlist (s ,4 ), 'list must comprise 4-vectors'
549
- if norm :
550
- s = [quat .unit (q ) for q in s ]
551
- self .data = s
563
+ if isinstance (s [0 ], np .ndarray ):
564
+ if check :
565
+ assert argcheck .isvectorlist (s ,4 ), 'list must comprise 4-vectors'
566
+ self .data = s
567
+ elif type (s [0 ]) == type (self ):
568
+ # possibly a list of objects of same type
569
+ assert all ( map ( lambda x : type (x ) == type (self ), s ) ), 'all elements of list must have same type'
570
+ self .data = [x ._A for x in s ]
571
+ else :
572
+ raise ValueError ('incorrect list' )
552
573
553
574
elif isinstance (s , np .ndarray ) and s .shape [1 ] == 4 :
554
575
if norm :
@@ -769,14 +790,16 @@ def to_se3(self):
769
790
from .pose import SO3
770
791
return SE3 (so3 = SO3 .np (self .r ()))
771
792
793
+
772
794
773
795
def __repr__ (self ):
774
796
s = ''
775
797
for q in self :
776
- s += quat .print (q ._A , delim = ('<<' , '>>' ), file = None ) + '\n '
798
+ s += quat .qprint (q ._A , delim = ('<<' , '>>' ), file = None ) + '\n '
777
799
s .rstrip ('\n ' )
778
800
return s
779
801
802
+
780
803
def __str__ (self ):
781
804
return self .__repr__ ()
782
805
@@ -808,6 +831,10 @@ def to_se3(self):
808
831
809
832
810
833
if __name__ == '__main__' : # pragma: no cover
834
+
835
+ import pathlib
836
+ import os .path
837
+
811
838
q = Quaternion ([1 ,2 ,3 ,4 ])
812
839
print (q )
813
840
q .append (q )
@@ -826,4 +853,4 @@ def to_se3(self):
826
853
# import pathlib
827
854
# import os.path
828
855
829
- # runfile( os.path.join(pathlib.Path(__file__).parent.absolute(), "test_quaternion.py") )
856
+ exec ( open ( os .path .join (pathlib .Path (__file__ ).parent .absolute (), "test_quaternion.py" )). read ( ) )
0 commit comments