@@ -217,6 +217,9 @@ def Rx(cls, theta, unit='rad'):
217
217
218
218
- ``SE3.Rx(THETA)`` is an SO(3) rotation of THETA radians about the x-axis
219
219
- ``SE3.Rx(THETA, "deg")`` as above but THETA is in degrees
220
+
221
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
222
+ elements.
220
223
"""
221
224
return cls ([tr .rotx (x , unit = unit ) for x in argcheck .getvector (theta )], check = False )
222
225
@@ -234,6 +237,9 @@ def Ry(cls, theta, unit='rad'):
234
237
235
238
- ``SO3.Ry(THETA)`` is an SO(3) rotation of THETA radians about the y-axis
236
239
- ``SO3.Ry(THETA, "deg")`` as above but THETA is in degrees
240
+
241
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
242
+ elements.
237
243
"""
238
244
return cls ([tr .roty (x , unit = unit ) for x in argcheck .getvector (theta )], check = False )
239
245
@@ -248,9 +254,12 @@ def Rz(cls, theta, unit='rad'):
248
254
:type unit: str
249
255
:return: 3x3 rotation matrix
250
256
:rtype: SO3 instance
251
-
257
+
252
258
- ``SO3.Rz(THETA)`` is an SO(3) rotation of THETA radians about the z-axis
253
259
- ``SO3.Rz(THETA, "deg")`` as above but THETA is in degrees
260
+
261
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
262
+ elements.
254
263
"""
255
264
return cls ([tr .rotz (x , unit = unit ) for x in argcheck .getvector (theta )], check = False )
256
265
@@ -265,8 +274,7 @@ def Rand(cls, N=1):
265
274
:rtype: SO3 instance
266
275
267
276
- ``SO3.Rand()`` is a random SO(3) rotation.
268
- - ``SO3.Rand(N)`` is an SO3 object containing a sequence of N random
269
- rotations.
277
+ - ``SO3.Rand(N)`` is a sequence of N random rotations.
270
278
271
279
:seealso: :func:`spatialmath.quaternion.UnitQuaternion.Rand`
272
280
"""
@@ -278,14 +286,17 @@ def Eul(cls, angles, *, unit='rad'):
278
286
Create an SO(3) rotation from Euler angles
279
287
280
288
:param angles: 3-vector of Euler angles
281
- :type angles: array_like
289
+ :type angles: array_like or numpy.ndarray with shape=(N,3)
282
290
:param unit: angular units: 'rad' [default], or 'deg'
283
291
:type unit: str
284
292
:return: 3x3 rotation matrix
285
293
:rtype: SO3 instance
286
294
287
- ``SO3.Eul(ANGLES )`` is an SO(3) rotation defined by a 3-vector of Euler angles :math:`(\phi, \t heta, \psi)` which
295
+ ``SO3.Eul(angles )`` is an SO(3) rotation defined by a 3-vector of Euler angles :math:`(\phi, \t heta, \psi)` which
288
296
correspond to consecutive rotations about the Z, Y, Z axes respectively.
297
+
298
+ If ``angles`` is an Nx3 matrix then the result is a sequence of rotations each defined by Euler angles
299
+ correponding to the rows of angles.
289
300
290
301
:seealso: :func:`~spatialmath.pose3d.SE3.eul`, :func:`~spatialmath.pose3d.SE3.Eul`, :func:`spatialmath.base.transforms3d.eul2r`
291
302
"""
@@ -300,15 +311,15 @@ def RPY(cls, angles, *, order='zyx', unit='rad'):
300
311
Create an SO(3) rotation from roll-pitch-yaw angles
301
312
302
313
:param angles: 3-vector of roll-pitch-yaw angles
303
- :type angles: array_like
314
+ :type angles: array_like or numpy.ndarray with shape=(N,3)
304
315
:param unit: angular units: 'rad' [default], or 'deg'
305
316
:type unit: str
306
317
:param unit: rotation order: 'zyx' [default], 'xyz', or 'yxz'
307
318
:type unit: str
308
319
:return: 3x3 rotation matrix
309
320
:rtype: SO3 instance
310
321
311
- ``SO3.RPY(ANGLES )`` is an SO(3) rotation defined by a 3-vector of roll, pitch, yaw angles :math:`(r, p, y)`
322
+ ``SO3.RPY(angles )`` is an SO(3) rotation defined by a 3-vector of roll, pitch, yaw angles :math:`(r, p, y)`
312
323
which correspond to successive rotations about the axes specified by ``order``:
313
324
314
325
- 'zyx' [default], rotate by yaw about the z-axis, then by pitch about the new y-axis,
@@ -321,6 +332,9 @@ def RPY(cls, angles, *, order='zyx', unit='rad'):
321
332
then by roll about the new z-axis. Convention for a camera with z-axis parallel
322
333
to the optic axis and x-axis parallel to the pixel rows.
323
334
335
+ If ``angles`` is an Nx3 matrix then the result is a sequence of rotations each defined by RPY angles
336
+ correponding to the rows of angles.
337
+
324
338
:seealso: :func:`~spatialmath.pose3d.SE3.rpy`, :func:`~spatialmath.pose3d.SE3.RPY`, :func:`spatialmath.base.transforms3d.rpy2r`
325
339
"""
326
340
if argcheck .isvector (angles , 3 ):
@@ -384,23 +398,32 @@ def AngVec(cls, theta, v, *, unit='rad'):
384
398
return cls (tr .angvec2r (theta , v , unit = unit ), check = False )
385
399
386
400
@classmethod
387
- def Exp (cls ,S ):
401
+ def Exp (cls , S , so3 = False ):
388
402
"""
389
403
Create an SO(3) rotation matrix from so(3)
390
404
391
405
:param S: Lie algebra so(3)
392
406
:type S: numpy ndarray
407
+ :param so3: accept input as an so(3) matrix [default False]
408
+ :type so3: bool
393
409
:return: 3x3 rotation matrix
394
410
:rtype: SO3 instance
395
411
396
412
- ``SO3.Exp(S)`` is an SO(3) rotation defined by its Lie algebra
397
413
which is a 3x3 so(3) matrix (skew symmetric)
398
414
- ``SO3.Exp(t)`` is an SO(3) rotation defined by a 3-element twist
399
415
vector (the unique elements of the so(3) skew-symmetric matrix)
416
+ - ``SO3.Exp(T)`` is a sequence of SO(3) rotations defined by an Nx3 matrix
417
+ of twist vectors, one per row.
418
+
419
+ Note:
420
+
421
+ - an input 3x3 matrix is ambiguous, it could be the first or third case above. In this
422
+ case the parameter `so3` is the decider.
400
423
401
424
:seealso: :func:`spatialmath.base.transforms3d.trexp`, :func:`spatialmath.base.transformsNd.skew`
402
425
"""
403
- if isinstance (S , np . ndarray ) and S . shape [ 1 ] == 3 :
426
+ if argcheck . ismatrix (S , ( - 1 , 3 )) and not so3 :
404
427
return cls ([tr .trexp (s ) for s in S ])
405
428
else :
406
429
return cls (tr .trexp (S ), check = False )
@@ -492,9 +515,9 @@ def inv(self):
492
515
:math:`T = \left[ \begin{array}{cc} R & t \\ 0 & 1 \end{array} \right], T^{-1} = \left[ \begin{array}{cc} R^T & -R^T t \\ 0 & 1 \end{array} \right]`
493
516
"""
494
517
if len (self ) == 1 :
495
- return SE3 (tr .rt2tr (self .R . T , - self . R . T @ self . t ))
518
+ return SE3 (tr .trinv (self .A ))
496
519
else :
497
- return SE3 ([tr .rt2tr ( x . R . T , - x . R . T @ x . t ) for x in self ])
520
+ return SE3 ([tr .trinv ( x ) for x in self . A ])
498
521
499
522
@classmethod
500
523
def isvalid (self , x ):
@@ -525,6 +548,9 @@ def Rx(cls, theta, unit='rad'):
525
548
526
549
- ``SE3.Rx(THETA)`` is an SO(3) rotation of THETA radians about the x-axis
527
550
- ``SE3.Rx(THETA, "deg")`` as above but THETA is in degrees
551
+
552
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
553
+ elements.
528
554
"""
529
555
return cls ([tr .trotx (x , unit ) for x in argcheck .getvector (theta )])
530
556
@@ -542,6 +568,9 @@ def Ry(cls, theta, unit='rad'):
542
568
543
569
- ``SE3.Ry(THETA)`` is an SO(3) rotation of THETA radians about the y-axis
544
570
- ``SE3.Ry(THETA, "deg")`` as above but THETA is in degrees
571
+
572
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
573
+ elements.
545
574
"""
546
575
return cls ([tr .troty (x , unit ) for x in argcheck .getvector (theta )])
547
576
@@ -559,6 +588,9 @@ def Rz(cls, theta, unit='rad'):
559
588
560
589
- ``SE3.Rz(THETA)`` is an SO(3) rotation of THETA radians about the z-axis
561
590
- ``SE3.Rz(THETA, "deg")`` as above but THETA is in degrees
591
+
592
+ If ``theta`` is an array then the result is a sequence of rotations defined by consecutive
593
+ elements.
562
594
"""
563
595
return cls ([tr .trotz (x , unit ) for x in argcheck .getvector (theta )])
564
596
@@ -590,14 +622,17 @@ def Eul(cls, angles, unit='rad'):
590
622
Create an SE(3) pure rotation from Euler angles
591
623
592
624
:param angles: 3-vector of Euler angles
593
- :type angles: array_like
625
+ :type angles: array_like or numpy.ndarray with shape=(N,3)
594
626
:param unit: angular units: 'rad' [default], or 'deg'
595
627
:type unit: str
596
628
:return: 4x4 homogeneous transformation matrix
597
629
:rtype: SE3 instance
598
630
599
631
``SE3.Eul(ANGLES)`` is an SO(3) rotation defined by a 3-vector of Euler angles :math:`(\phi, \t heta, \psi)` which
600
632
correspond to consecutive rotations about the Z, Y, Z axes respectively.
633
+
634
+ If ``angles`` is an Nx3 matrix then the result is a sequence of rotations each defined by Euler angles
635
+ correponding to the rows of angles.
601
636
602
637
:seealso: :func:`~spatialmath.pose3d.SE3.eul`, :func:`~spatialmath.pose3d.SE3.Eul`, :func:`spatialmath.base.transforms3d.eul2r`
603
638
"""
@@ -612,7 +647,7 @@ def RPY(cls, angles, order='zyx', unit='rad'):
612
647
Create an SO(3) pure rotation from roll-pitch-yaw angles
613
648
614
649
:param angles: 3-vector of roll-pitch-yaw angles
615
- :type angles: array_like
650
+ :type angles: array_like or numpy.ndarray with shape=(N,3)
616
651
:param unit: angular units: 'rad' [default], or 'deg'
617
652
:type unit: str
618
653
:param unit: rotation order: 'zyx' [default], 'xyz', or 'yxz'
@@ -632,6 +667,9 @@ def RPY(cls, angles, order='zyx', unit='rad'):
632
667
- 'yxz', rotate by yaw about the y-axis, then by pitch about the new x-axis,
633
668
then by roll about the new z-axis. Convention for a camera with z-axis parallel
634
669
to the optic axis and x-axis parallel to the pixel rows.
670
+
671
+ If ``angles`` is an Nx3 matrix then the result is a sequence of rotations each defined by RPY angles
672
+ correponding to the rows of angles.
635
673
636
674
:seealso: :func:`~spatialmath.pose3d.SE3.rpy`, :func:`~spatialmath.pose3d.SE3.RPY`, :func:`spatialmath.base.transforms3d.rpy2r`
637
675
"""
0 commit comments