18
18
from math import sin , cos
19
19
import numpy as np
20
20
from spatialmath import base
21
+ from collections .abc import Iterable
21
22
22
23
_eps = np .finfo (np .float64 ).eps
23
24
@@ -1836,7 +1837,7 @@ def _vec2s(fmt, v):
1836
1837
1837
1838
def trplot (T , axes = None , block = False , dims = None , color = 'blue' , frame = None , # pylint: disable=unused-argument,function-redefined
1838
1839
textcolor = None , labels = ('X' , 'Y' , 'Z' ), length = 1 , style = 'arrow' ,
1839
- origindot = None , projection = 'ortho' , wtl = 0.2 , width = None , d1 = 0.05 ,
1840
+ originsize = 20 , origincolor = None , projection = 'ortho' , wtl = 0.2 , width = None , d1 = 0.05 ,
1840
1841
d2 = 1.15 , anaglyph = None , ** kwargs ):
1841
1842
"""
1842
1843
Plot a 3D coordinate frame
@@ -1851,19 +1852,21 @@ def trplot(T, axes=None, block=False, dims=None, color='blue', frame=None, # p
1851
1852
If dims is [min, max] those limits are applied to the x-, y- and z-axes.
1852
1853
:type dims: array_like(6) or array_like(2)
1853
1854
:param color: color of the lines defining the frame
1854
- :type color: str
1855
- :param textcolor: color of text labels for the frame, default color of lines above
1855
+ :type color: str or list(3) of str
1856
+ :param textcolor: color of text labels for the frame, default `` color``
1856
1857
:type textcolor: str
1857
1858
:param frame: label the frame, name is shown below the frame and as subscripts on the frame axis labels
1858
1859
:type frame: str
1859
1860
:param labels: labels for the axes, defaults to X, Y and Z
1860
1861
:type labels: 3-tuple of strings
1861
1862
:param length: length of coordinate frame axes, default 1
1862
- :type length: float
1863
- :param style: axis style: 'arrow' [default], 'line', 'rgb ' (Rviz style)
1863
+ :type length: float or array_like(3)
1864
+ :param style: axis style: 'arrow' [default], 'line', 'rviz ' (Rviz style)
1864
1865
:type style: str
1865
- :param origindot: size of dot to draw at the origin (default 20)
1866
- :type origindot: int
1866
+ :param originsize: size of dot to draw at the origin, 0 for no dot (default 20)
1867
+ :type originsize: int
1868
+ :param origincolor: color of dot to draw at the origin, default is ``color``
1869
+ :type origincolor: str
1867
1870
:param anaglyph: 3D anaglyph display, left-right lens colors eg. ``'rc'``
1868
1871
for red-cyan glasses. To set the disparity (default 0.1) provide second
1869
1872
argument in a tuple, eg. ``('rc', 0.2)``. Bigger disparity exagerates the
@@ -1906,7 +1909,7 @@ def trplot(T, axes=None, block=False, dims=None, color='blue', frame=None, # p
1906
1909
1907
1910
.. note:: The origin is normally indicated with a marker of the same color
1908
1911
as the frame. The default size is 20. This can be disabled by setting
1909
- its size to zero by ``origindot =0``. For ``'rgb'`` style the default is 0
1912
+ its size to zero by ``originsize =0``. For ``'rgb'`` style the default is 0
1910
1913
but it can be set explicitly, and the color is as per the ``color``
1911
1914
option.
1912
1915
@@ -1973,18 +1976,19 @@ def trplot(T, axes=None, block=False, dims=None, color='blue', frame=None, # p
1973
1976
1974
1977
return
1975
1978
1976
- if style == 'rgb ' :
1977
- if origindot is None :
1978
- origindot = 0
1979
- colors = ( 'red' , 'green' , 'blue' )
1980
- color = 'k'
1981
- width = 8
1979
+ if style == 'rviz ' :
1980
+ if originsize is None :
1981
+ originsize = 0
1982
+ color = 'rgb'
1983
+ if width is None :
1984
+ width = 8
1982
1985
style = 'line'
1983
- else :
1984
- colors = (color ,) * 3
1985
- width = 1
1986
- if origindot is None :
1987
- origindot = 20
1986
+
1987
+ if isinstance (color , str ):
1988
+ if color == 'rgb' :
1989
+ color = ('red' , 'green' , 'blue' )
1990
+ else :
1991
+ color = (color ,) * 3
1988
1992
1989
1993
# check input types
1990
1994
if isrot (T , check = True ):
@@ -1996,7 +2000,7 @@ def trplot(T, axes=None, block=False, dims=None, color='blue', frame=None, # p
1996
2000
for Tk in T :
1997
2001
trplot (Tk , axes = ax , block = block , dims = dims , color = color , frame = frame ,
1998
2002
textcolor = textcolor , labels = labels , length = length , style = style ,
1999
- projection = projection , wtl = wtl , width = width , d1 = d1 ,
2003
+ projection = projection , originsize = originsize , origincolor = origincolor , wtl = wtl , width = width , d1 = d1 ,
2000
2004
d2 = d2 , anaglyph = anaglyph , ** kwargs )
2001
2005
return
2002
2006
@@ -2008,47 +2012,56 @@ def trplot(T, axes=None, block=False, dims=None, color='blue', frame=None, # p
2008
2012
ax .set_zlim (dims [4 :6 ])
2009
2013
2010
2014
# create unit vectors in homogeneous form
2015
+ if not isinstance (length , Iterable ):
2016
+ length = (length ,) * 3
2017
+
2011
2018
o = T @ np .array ([0 , 0 , 0 , 1 ])
2012
- x = T @ np .array ([length , 0 , 0 , 1 ])
2013
- y = T @ np .array ([0 , length , 0 , 1 ])
2014
- z = T @ np .array ([0 , 0 , length , 1 ])
2019
+ x = T @ np .array ([length [ 0 ] , 0 , 0 , 1 ])
2020
+ y = T @ np .array ([0 , length [ 1 ] , 0 , 1 ])
2021
+ z = T @ np .array ([0 , 0 , length [ 2 ] , 1 ])
2015
2022
2016
2023
# draw the axes
2017
2024
2018
2025
if style == 'arrow' :
2019
- ax .quiver (o [0 ], o [1 ], o [2 ], x [0 ] - o [0 ], x [1 ] - o [1 ], x [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color , edgecolor = color )
2020
- ax .quiver (o [0 ], o [1 ], o [2 ], y [0 ] - o [0 ], y [1 ] - o [1 ], y [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color , edgecolor = color )
2021
- ax .quiver (o [0 ], o [1 ], o [2 ], z [0 ] - o [0 ], z [1 ] - o [1 ], z [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color , edgecolor = color )
2026
+ ax .quiver (o [0 ], o [1 ], o [2 ], x [0 ] - o [0 ], x [1 ] - o [1 ], x [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color [ 0 ] , edgecolor = color [ 1 ] )
2027
+ ax .quiver (o [0 ], o [1 ], o [2 ], y [0 ] - o [0 ], y [1 ] - o [1 ], y [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color [ 1 ] , edgecolor = color [ 1 ] )
2028
+ ax .quiver (o [0 ], o [1 ], o [2 ], z [0 ] - o [0 ], z [1 ] - o [1 ], z [2 ] - o [2 ], arrow_length_ratio = wtl , linewidth = width , facecolor = color [ 2 ] , edgecolor = color [ 2 ] )
2022
2029
2023
2030
# plot some points
2024
2031
# invisible point at the end of each arrow to allow auto-scaling to work
2025
2032
ax .scatter (xs = [o [0 ], x [0 ], y [0 ], z [0 ]], ys = [o [1 ], x [1 ], y [1 ], z [1 ]], zs = [o [2 ], x [2 ], y [2 ], z [2 ]],
2026
2033
s = [0 , 0 , 0 , 0 ])
2027
2034
elif style == 'line' :
2028
- ax .plot ([o [0 ], x [0 ]], [o [1 ], x [1 ]], [o [2 ], x [2 ]], color = colors [0 ], linewidth = width )
2029
- ax .plot ([o [0 ], y [0 ]], [o [1 ], y [1 ]], [o [2 ], y [2 ]], color = colors [1 ], linewidth = width )
2030
- ax .plot ([o [0 ], z [0 ]], [o [1 ], z [1 ]], [o [2 ], z [2 ]], color = colors [2 ], linewidth = width )
2031
-
2032
- if origindot > 0 :
2033
- ax .scatter (xs = [o [0 ]], ys = [o [1 ]], zs = [o [2 ]], color = color , s = origindot )
2035
+ ax .plot ([o [0 ], x [0 ]], [o [1 ], x [1 ]], [o [2 ], x [2 ]], color = color [0 ], linewidth = width )
2036
+ ax .plot ([o [0 ], y [0 ]], [o [1 ], y [1 ]], [o [2 ], y [2 ]], color = color [1 ], linewidth = width )
2037
+ ax .plot ([o [0 ], z [0 ]], [o [1 ], z [1 ]], [o [2 ], z [2 ]], color = color [2 ], linewidth = width )
2034
2038
2035
2039
# label the frame
2036
2040
if frame :
2037
- if textcolor is not None :
2038
- color = textcolor
2041
+ if textcolor is None :
2042
+ textcolor = color [0 ]
2043
+ else :
2044
+ textcolor = 'blue'
2045
+ if origincolor is None :
2046
+ origincolor = color [0 ]
2047
+ else :
2048
+ origincolor = 'black'
2039
2049
2040
2050
o1 = T @ np .array ([- d1 , - d1 , - d1 , 1 ])
2041
- ax .text (o1 [0 ], o1 [1 ], o1 [2 ], r'$\{' + frame + r'\}$' , color = color , verticalalignment = 'top' , horizontalalignment = 'center' )
2051
+ ax .text (o1 [0 ], o1 [1 ], o1 [2 ], r'$\{' + frame + r'\}$' , color = textcolor , verticalalignment = 'top' , horizontalalignment = 'center' )
2042
2052
2043
2053
# add the labels to each axis
2044
2054
2045
2055
x = (x - o ) * d2 + o
2046
2056
y = (y - o ) * d2 + o
2047
2057
z = (z - o ) * d2 + o
2048
2058
2049
- ax .text (x [0 ], x [1 ], x [2 ], "$%c_{%s}$" % (labels [0 ], frame ), color = color , horizontalalignment = 'center' , verticalalignment = 'center' )
2050
- ax .text (y [0 ], y [1 ], y [2 ], "$%c_{%s}$" % (labels [1 ], frame ), color = color , horizontalalignment = 'center' , verticalalignment = 'center' )
2051
- ax .text (z [0 ], z [1 ], z [2 ], "$%c_{%s}$" % (labels [2 ], frame ), color = color , horizontalalignment = 'center' , verticalalignment = 'center' )
2059
+ ax .text (x [0 ], x [1 ], x [2 ], "$%c_{%s}$" % (labels [0 ], frame ), color = textcolor , horizontalalignment = 'center' , verticalalignment = 'center' )
2060
+ ax .text (y [0 ], y [1 ], y [2 ], "$%c_{%s}$" % (labels [1 ], frame ), color = textcolor , horizontalalignment = 'center' , verticalalignment = 'center' )
2061
+ ax .text (z [0 ], z [1 ], z [2 ], "$%c_{%s}$" % (labels [2 ], frame ), color = textcolor , horizontalalignment = 'center' , verticalalignment = 'center' )
2062
+
2063
+ if originsize > 0 :
2064
+ ax .scatter (xs = [o [0 ]], ys = [o [1 ]], zs = [o [2 ]], color = origincolor , s = originsize )
2052
2065
2053
2066
if block :
2054
2067
# calling this at all, causes FuncAnimation to fail so when invoked from tranimate skip this bit
@@ -2114,6 +2127,7 @@ def tranimate(T, **kwargs):
2114
2127
plt .show (block = block )
2115
2128
2116
2129
if __name__ == '__main__' : # pragma: no cover
2130
+
2117
2131
import pathlib
2118
2132
2119
2133
exec (open (pathlib .Path (__file__ ).parent .parent .parent .absolute () / "tests" / "base" / "test_transforms3d.py" ).read ()) # pylint: disable=exec-used
0 commit comments