Skip to content

Commit bb1f6f7

Browse files
committed
Consistent operation of printline() method for SO2, SE2, SO3, SE3, Quaternion, UnitQuaternion types. In base now have separate functions to convert type to a single line string or to print it. Fixed problem where stdout redirection failed using contextlib.redirect_stdout.
1 parent 8b83c1f commit bb1f6f7

6 files changed

Lines changed: 208 additions & 59 deletions

File tree

spatialmath/base/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
"tr2jac2",
222222
"trinterp2",
223223
"trprint2",
224+
"tr2str2",
224225
"trplot2",
225226
"tranimate2",
226227
"xyt2tr",
@@ -264,6 +265,7 @@
264265
"exp2jac",
265266
"rot2jac",
266267
"trprint",
268+
"tr2str",
267269
"trplot",
268270
"tranimate",
269271
"tr2x",

spatialmath/base/quaternions.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,14 +1152,9 @@ def q2str(
11521152
return template.format(q[0], delim[0], q[1], q[2], q[3], delim[1])
11531153

11541154

1155-
def qprint(
1156-
q: Union[ArrayLike4, ArrayLike4],
1157-
delim: Optional[Tuple[str, str]] = ("<", ">"),
1158-
fmt: Optional[str] = "{: .4f}",
1159-
file: Optional[TextIO] = sys.stdout,
1160-
) -> None:
1155+
def qprint(q: Union[ArrayLike4, ArrayLike4], file=False, **kwargs) -> None:
11611156
"""
1162-
Format a quaternion to a file
1157+
Compact single-line display of a quaternion
11631158
11641159
:arg q: unit-quaternion
11651160
:type q: array_like(4)
@@ -1195,7 +1190,9 @@ def qprint(
11951190
"Usage: qprint(..., file=None) -> str is deprecated, use q2str() instead",
11961191
DeprecationWarning,
11971192
)
1198-
print(q2str(q, delim=delim, fmt=fmt), file=file)
1193+
if file is False:
1194+
file = None # defaults to stdout
1195+
print(q2str(q, **kwargs), file=file)
11991196

12001197

12011198
if __name__ == "__main__": # pragma: no cover

spatialmath/base/transforms2d.py

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import sys
1818
import math
1919
import numpy as np
20+
import warnings
2021

2122
try:
2223
import matplotlib.pyplot as plt
@@ -959,15 +960,15 @@ def trinterp2(start, end, s, shortest: bool = True):
959960
raise ValueError("Argument must be SO(2) or SE(2)")
960961

961962

962-
def trprint2(
963+
def tr2str2(
963964
T: Union[SO2Array, SE2Array],
964965
label: str = "",
965-
file: TextIO = sys.stdout,
966+
file: TextIO = None,
966967
fmt: str = "{:.3g}",
967968
unit: str = "deg",
968969
) -> str:
969970
"""
970-
Compact display of SE(2) or SO(2) matrices
971+
Convert SO(2) or SE(3) matrices to compact single-line string
971972
972973
:param T: matrix to format
973974
:type T: ndarray(3,3) or ndarray(2,2)
@@ -985,12 +986,12 @@ def trprint2(
985986
The matrix is formatted and written to ``file`` and the
986987
string is returned. To suppress writing to a file, set ``file=None``.
987988
988-
- ``trprint2(R)`` displays the SO(2) rotation matrix in a compact
989+
- ``tr2str2(R)`` displays the SO(2) rotation matrix in a compact
989990
single-line format and returns the string::
990991
991992
[LABEL:] θ UNIT
992993
993-
- ``trprint2(T)`` displays the SE(2) homogoneous transform in a compact
994+
- ``tr2str2(T)`` displays the SE(2) homogoneous transform in a compact
994995
single-line format and returns the string::
995996
996997
[LABEL:] [t=X, Y;] θ UNIT
@@ -999,17 +1000,18 @@ def trprint2(
9991000
10001001
>>> from spatialmath.base import *
10011002
>>> T = transl2(1,2) @ trot2(0.3)
1002-
>>> trprint2(T, file=None, label='T')
1003-
>>> trprint2(T, file=None, label='T', fmt='{:8.4g}')
1004-
1003+
>>> tr2str2(T, label='T')
1004+
>>> tr2str2(T, label='T', fmt='{:8.4g}')
10051005
10061006
.. note::
10071007
10081008
- Default formatting is for compact display of data
10091009
- For tabular data set ``fmt`` to a fixed width format such as
10101010
``fmt='{:.3g}'``
10111011
1012-
:seealso: trprint
1012+
.. versionadded:: 1.1.15
1013+
1014+
:seealso: :func:`~tr2str`
10131015
"""
10141016

10151017
s = ""
@@ -1028,8 +1030,6 @@ def trprint2(
10281030
else:
10291031
s += " {} rad".format(_vec2s(fmt, [angle]))
10301032

1031-
if file:
1032-
print(s, file=file)
10331033
return s
10341034

10351035

@@ -1052,6 +1052,70 @@ def _vec2s(fmt: str, v: ArrayLikePure, tol: float = 20) -> str:
10521052
return ", ".join([fmt.format(x) for x in v])
10531053

10541054

1055+
def trprint2(
1056+
T: Union[SO2Array, SE2Array],
1057+
label: str = "",
1058+
file: TextIO = False,
1059+
**kwargs,
1060+
) -> str:
1061+
"""
1062+
Compact single-line display of SE(2) or SO(2) matrices
1063+
1064+
:param T: matrix to format
1065+
:type T: ndarray(3,3) or ndarray(2,2)
1066+
:param label: text label to put at start of line
1067+
:type label: str
1068+
:param file: file to write formatted string to [default is stdout]
1069+
:type file: file object
1070+
:param fmt: conversion format for each number
1071+
:type fmt: str
1072+
:param unit: angular units: 'rad' [default], or 'deg'
1073+
:type unit: str
1074+
:return: formatted string
1075+
:rtype: str
1076+
1077+
The matrix is formatted and written to ``file`` and the
1078+
string is returned. To suppress writing to a file, set ``file=None``.
1079+
1080+
- ``trprint2(R)`` displays the SO(2) rotation matrix in a compact
1081+
single-line format and returns the string::
1082+
1083+
[LABEL:] θ UNIT
1084+
1085+
- ``trprint2(T)`` displays the SE(2) homogoneous transform in a compact
1086+
single-line format and returns the string::
1087+
1088+
[LABEL:] [t=X, Y;] θ UNIT
1089+
1090+
.. runblock:: pycon
1091+
1092+
>>> from spatialmath.base import *
1093+
>>> T = transl2(1,2) @ trot2(0.3)
1094+
>>> trprint2(T, label='T')
1095+
>>> trprint2(T, label='T', fmt='{:8.4g}')
1096+
1097+
1098+
.. note::
1099+
1100+
- Default formatting is for compact display of data
1101+
- For tabular data set ``fmt`` to a fixed width format such as
1102+
``fmt='{:.3g}'``
1103+
1104+
.. versionchanged:: 1.1.15
1105+
To create a string use :func:`~tr2str2` instead of ``trprint2(...file=None)``
1106+
1107+
:seealso: :func:`~tr2str2` :func:`~trprint`
1108+
"""
1109+
if file is None:
1110+
warnings.warn(
1111+
"Usage: trprint2(..., file=None) -> str is deprecated, use tr2str2() instead",
1112+
DeprecationWarning,
1113+
)
1114+
if file is False:
1115+
file = None # defaults to stdout
1116+
print(tr2str2(T, **kwargs), file=file)
1117+
1118+
10551119
def points2tr2(p1: NDArray, p2: NDArray) -> SE2Array:
10561120
"""
10571121
SE(2) transform from corresponding points

spatialmath/base/transforms3d.py

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from collections.abc import Iterable
1919
import math
2020
import numpy as np
21+
import warnings
22+
2123

2224
from spatialmath.base.argcheck import getunit, getvector, isvector, isscalar, ismatrix
2325
from spatialmath.base.vectors import (
@@ -2779,50 +2781,44 @@ def rodrigues(w: ArrayLike3, theta: Optional[float] = None) -> SO3Array:
27792781
)
27802782

27812783

2782-
def trprint(
2784+
def tr2str(
27832785
T: Union[SO3Array, SE3Array],
27842786
orient: str = "rpy/zyx",
27852787
label: str = "",
2786-
file: TextIO = sys.stdout,
2788+
file: TextIO = None,
27872789
fmt: str = "{:.3g}",
27882790
degsym: bool = True,
27892791
unit: str = "deg",
27902792
) -> str:
27912793
"""
2792-
Compact display of SO(3) or SE(3) matrices
2794+
Convert SO(3) or SE(3) matrices to compact single-line string
27932795
2794-
:param T: SE(3) or SO(3) matrix
2795-
:type T: ndarray(4,4) or ndarray(3,3)
2796-
:param label: text label to put at start of line
2797-
:type label: str
2798-
:param orient: 3-angle convention to use
2799-
:type orient: str
2800-
:param file: file to write formatted string to. [default, stdout]
2801-
:type file: file object
2802-
:param fmt: conversion format for each number in the format used with ``format``
2803-
:type fmt: str
2804-
:param unit: angular units: 'rad' [default], or 'deg'
2805-
:type unit: str
2806-
:return: formatted string
2807-
:rtype: str
2808-
:raises ValueError: bad argument
2796+
:param T: SE(3) or SO(3) matrix
2797+
:type T: ndarray(4,4) or ndarray(3,3)
2798+
:param label: text label to put at start of line
2799+
:type label: str
2800+
:param orient: 3-angle convention to use
2801+
:type orient: str
2802+
:param fmt: conversion format for each number in the format used with ``format``
2803+
:type fmt: str
2804+
:param unit: angular units: 'rad' [default], or 'deg'
2805+
:type unit: str
2806+
:return: formatted string
2807+
:rtype: str
2808+
:raises ValueError: bad argument
28092809
2810-
The matrix is formatted and written to ``file`` and the
2811-
string is returned. To suppress writing to a file, set ``file=None``.
2810+
The matrix is formatted and returned as a string.
28122811
2813-
- ``trprint(R)`` prints the SO(3) rotation matrix to stdout in a compact
2814-
single-line format:
2812+
- ``tr2str(R)`` converts the SO(3) rotation matrix to a compact
2813+
single-line string:
28152814
28162815
[LABEL:] ORIENTATION UNIT
28172816
2818-
- ``trprint(T)`` prints the SE(3) homogoneous transform to stdout in a
2819-
compact single-line format:
2817+
- ``tr2str(T)`` prints the SE(3) homogoneous transform to a compact
2818+
single-line string:
28202819
28212820
[LABEL:] [t=X, Y, Z;] ORIENTATION UNIT
28222821
2823-
- ``trprint(X, file=None)`` as above but returns the string rather than
2824-
printing to a file
2825-
28262822
Orientation is expressed in one of several formats:
28272823
28282824
- 'rpy/zyx' roll-pitch-yaw angles in ZYX axis order [default]
@@ -2834,11 +2830,11 @@ def trprint(
28342830
28352831
.. runblock:: pycon
28362832
2837-
>>> from spatialmath.base import transl, rpy2tr, trprint
2833+
>>> from spatialmath.base import *
28382834
>>> T = transl(1,2,3) @ rpy2tr(10, 20, 30, 'deg')
2839-
>>> trprint(T, file=None)
2840-
>>> trprint(T, file=None, label='T', orient='angvec')
2841-
>>> trprint(T, file=None, label='T', orient='angvec', fmt='{:8.4g}')
2835+
>>> tr2str(T)
2836+
>>> tr2str(T, label='T', orient='angvec')
2837+
>>> tr2str(T, label='T', orient='angvec', fmt='{:8.4g}')
28422838
28432839
.. note::
28442840
@@ -2849,7 +2845,9 @@ def trprint(
28492845
- For tabular data set ``fmt`` to a fixed width format such as
28502846
``fmt='{:.3g}'``
28512847
2852-
:seealso: :func:`~spatialmath.base.transforms2d.trprint2` :func:`~tr2eul` :func:`~tr2rpy` :func:`~tr2angvec`
2848+
.. versionadded:: 1.1.15
2849+
2850+
:seealso: :func:`~trprint` :func:`~spatialmath.base.transforms2d.trprint2` :func:`~tr2eul` :func:`~tr2rpy` :func:`~tr2angvec`
28532851
:SymPy: not supported
28542852
"""
28552853

@@ -2898,10 +2896,6 @@ def trprint(
28982896
s += " angvec = ({} | {})".format(theta, _vec2s(fmt, v))
28992897
else:
29002898
raise ValueError("bad orientation format")
2901-
2902-
if file:
2903-
print(s, file=file)
2904-
29052899
return s
29062900

29072901

@@ -2910,6 +2904,80 @@ def _vec2s(fmt, v):
29102904
return ", ".join([fmt.format(x) for x in v])
29112905

29122906

2907+
def trprint(T: Union[SO3Array, SE3Array], file=False, **kwargs) -> str:
2908+
"""
2909+
Compact single-line display of SO(3) or SE(3) matrices
2910+
2911+
:param T: SE(3) or SO(3) matrix
2912+
:type T: ndarray(4,4) or ndarray(3,3)
2913+
:param label: text label to put at start of line
2914+
:type label: str
2915+
:param orient: 3-angle convention to use
2916+
:type orient: str
2917+
:param file: file to write formatted string to. [default, stdout]
2918+
:type file: file object
2919+
:param fmt: conversion format for each number in the format used with ``format``
2920+
:type fmt: str
2921+
:param unit: angular units: 'rad' [default], or 'deg'
2922+
:type unit: str
2923+
:return: formatted string
2924+
:rtype: str
2925+
:raises ValueError: bad argument
2926+
2927+
The matrix is formatted and written to ``file``.
2928+
2929+
- ``trprint(R)`` prints the SO(3) rotation matrix to stdout in a compact
2930+
single-line format:
2931+
2932+
[LABEL:] ORIENTATION UNIT
2933+
2934+
- ``trprint(T)`` prints the SE(3) homogoneous transform to stdout in a
2935+
compact single-line format:
2936+
2937+
[LABEL:] [t=X, Y, Z;] ORIENTATION UNIT
2938+
2939+
Orientation is expressed in one of several formats:
2940+
2941+
- 'rpy/zyx' roll-pitch-yaw angles in ZYX axis order [default]
2942+
- 'rpy/yxz' roll-pitch-yaw angles in YXZ axis order
2943+
- 'rpy/zyx' roll-pitch-yaw angles in ZYX axis order
2944+
- 'eul' Euler angles in ZYZ axis order
2945+
- 'angvec' angle and axis
2946+
2947+
2948+
.. runblock:: pycon
2949+
2950+
>>> from spatialmath.base import *
2951+
>>> T = transl(1,2,3) @ rpy2tr(10, 20, 30, 'deg')
2952+
>>> trprint(T)
2953+
>>> trprint(T, label='T', orient='angvec')
2954+
>>> trprint(T, label='T', orient='angvec', fmt='{:8.4g}')
2955+
2956+
.. note::
2957+
2958+
- If the 'rpy' option is selected, then the particular angle sequence can be
2959+
specified with the options 'xyz' or 'yxz' which are passed through to ``tr2rpy``.
2960+
'zyx' is the default.
2961+
- Default formatting is for compact display of data
2962+
- For tabular data set ``fmt`` to a fixed width format such as
2963+
``fmt='{:.3g}'``
2964+
2965+
.. versionchanged:: 1.1.15
2966+
To create a string use :func:`~tr2str` instead of ``trprint(...file=None)``
2967+
2968+
:seealso: :func:`~tr2str` :func:`~spatialmath.base.transforms2d.trprint2` :func:`~tr2eul` :func:`~tr2rpy` :func:`~tr2angvec`
2969+
:SymPy: not supported
2970+
"""
2971+
if file is None:
2972+
warnings.warn(
2973+
"Usage: trprint(..., file=None) -> str is deprecated, use tr2str() instead",
2974+
DeprecationWarning,
2975+
)
2976+
if file is False:
2977+
file = None # defaults to stdout
2978+
print(tr2str(T, **kwargs), file=file)
2979+
2980+
29132981
try:
29142982
import matplotlib.pyplot as plt
29152983
from mpl_toolkits.mplot3d import Axes3D

0 commit comments

Comments
 (0)