Skip to content

Commit 61e466e

Browse files
authored
Merge branch 'master' into fix/twist-pitch-clean
2 parents 3b97759 + fff7009 commit 61e466e

22 files changed

Lines changed: 256 additions & 174 deletions

‎.github/CODEOWNERS‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# Global Owners
2-
* @petercorke @jhavl @myeatman-bdai
2+
* @petercorke @jbarry-bdai

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ Similarly when we assign an element or slice of the symbolic matrix to a numeric
452452

453453
On April 28, 2026 this repository moved to the **RAI-Opensource** GitHub organization. If you are still pulling from the previous bdaiinstitute GitHub organization, please update your git remote:
454454
```bash
455-
git remote set-url origin https://github.com/RAI-Opensource/spot_ros2
455+
git remote set-url origin https://github.com/RAI-Opensource/spatialmath-python.git
456456
```
457457

458458
Also update any links of `https://bdaiinstitute.github.io/spatialmath-python` to <https://spatialmath-python.rai-inst.com/>.

‎docs/source/classes-2d.rst‎

Lines changed: 0 additions & 16 deletions
This file was deleted.

‎docs/source/classes-3d.rst‎

Lines changed: 0 additions & 10 deletions
This file was deleted.

‎docs/source/intro.rst‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ The classes ``SE3``, ``SO3``, ``SE2`` and ``SO2`` can provide colorized text out
262262

263263
.. image:: ../figs/colored_output.png
264264
:width: 300
265+
265266
with rotational elements in red, translational elements in blue and constants in grey.
266267

267268
The foreground and background colors can be controlled using the following
@@ -538,8 +539,10 @@ A numpy column vector has shape ``(N,1)`` and a row vector
538539
has shape ``(1,N)`` but functions also accept row ``(1,N)`` and column ``(N,1)``
539540
where a vector argument is required.
540541

541-
.. warning:: For a user transitioning from MATLAB the most significant
542-
differences are:
542+
.. warning::
543+
544+
For a user transitioning from MATLAB the most significant differences are:
545+
543546
- the use of 1D arrays -- all MATLAB arrays have two dimensions,
544547
even if one of them is equal to one.
545548
- Iterating over a 1D NumPy array (N,) returns consecutive elements

‎spatialmath/DualQuaternion.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def SE3(self) -> SE3:
338338
339339
.. runblock:: pycon
340340
341-
>>> from spatialmath import DualQuaternion, SE3
341+
>>> from spatialmath import UnitDualQuaternion, SE3
342342
>>> T = SE3.Rand()
343343
>>> print(T)
344344
>>> d = UnitDualQuaternion(T)

‎spatialmath/base/__init__.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@
210210
"qprint",
211211
"q2str",
212212
# spatialmath.base.transforms2d
213+
"pos2tr2",
213214
"rot2",
214215
"trot2",
215216
"transl2",
@@ -219,6 +220,9 @@
219220
"trexp2",
220221
"trnorm2",
221222
"tr2jac2",
223+
"tr2pos2",
224+
"tr2adjoint2",
225+
"tradjoint2",
222226
"trinterp2",
223227
"trprint2",
224228
"trplot2",

‎spatialmath/base/argcheck.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def isinteger(x: Any) -> bool:
6262
6363
.. runblock:: pycon
6464
65-
>>> from spatialmath.base import isscalar
65+
>>> from spatialmath.base import isinteger
6666
>>> isinteger(1)
6767
>>> isinteger(1.2)
6868

‎spatialmath/base/graphics.py‎

Lines changed: 92 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -115,42 +115,41 @@ def plot_point(
115115
Plot one or more points, with optional text label.
116116
117117
- The color of the marker can be different to the color of the text, the
118-
marker color is specified by a single letter in the marker string.
118+
marker color is specified by a single letter in the marker string.
119119
120120
- A point can have multiple markers, given as a list, which will be
121-
overlaid, for instance ``["rx", "ro"]`` will give a ⨂ symbol.
121+
overlaid, for instance ``["rx", "ro"]`` will give a ⨂ symbol.
122122
123123
- The optional text label is placed to the right of the marker, and
124-
vertically aligned.
124+
vertically aligned.
125125
126126
- Multiple points can be marked if ``pos`` is a 2xn array or a list of
127-
coordinate pairs. In this case:
127+
coordinate pairs. In this case:
128128
129129
- all points have the same ``text`` label
130130
- ``text`` can include the format string {} which is susbstituted for the
131-
point index, starting at zero
131+
point index, starting at zero
132132
- ``text`` can be a tuple containing a format string followed by vectors
133-
of shape(n). For example::
133+
of shape(n). For example::
134134
135-
``("#{0} a={1:.1f}, b={2:.1f}", a, b)``
135+
("#{0} a={1:.1f}, b={2:.1f}", a, b)
136136
137137
will label each point with its index (argument 0) and consecutive
138138
elements of ``a`` and ``b`` which are arguments 1 and 2 respectively.
139139
140140
Example::
141141
142-
>>> from spatialmath.base import plotvol2, plot_text
142+
>>> from spatialmath.base import plotvol2, plot_point
143143
>>> plotvol2(5)
144-
>>> plot_point((0, 0)) # plot default marker at coordinate (1,2)
144+
>>> plot_point((0,0)) # plot default marker at coordinate (1,2)
145145
>>> plot_point((1,1), 'r*') # plot red star at coordinate (1,2)
146-
>>> plot_point((2,2), 'r*', 'foo') # plot red star at coordinate (1,2) and
147-
label it as 'foo'
146+
>>> plot_point((2,2), 'r*', 'foo') # plot red star at coordinate (1,2) and label it as 'foo'
148147
149148
.. plot::
150149
151-
from spatialmath.base import plotvol2, plot_text
150+
from spatialmath.base import plotvol2, plot_point
152151
ax = plotvol2(5)
153-
plot_point((0, 0))
152+
plot_point((0,0))
154153
plot_point((1,1), 'r*')
155154
plot_point((2,2), 'r*', 'foo')
156155
ax.grid()
@@ -327,7 +326,8 @@ def plot_homline(
327326
return handles
328327

329328
def plot_box(
330-
*fmt: Optional[str],
329+
fmt: str | None = None,
330+
*,
331331
lbrt: Optional[ArrayLike4] = None,
332332
lrbt: Optional[ArrayLike4] = None,
333333
lbwh: Optional[ArrayLike4] = None,
@@ -339,6 +339,7 @@ def plot_box(
339339
rt: Optional[ArrayLike2] = None,
340340
wh: Optional[ArrayLike2] = None,
341341
centre: Optional[ArrayLike2] = None,
342+
center: Optional[ArrayLike2] = None,
342343
w: Optional[float] = None,
343344
h: Optional[float] = None,
344345
ax: Optional[plt.Axes] = None,
@@ -358,39 +359,79 @@ def plot_box(
358359
:type rt: array_like(2), optional
359360
:param wh: width and height, if both are the same provide scalar, defaults to None
360361
:type wh: scalar, array_like(2), optional
361-
:param centre: centre of box, defaults to None
362+
:param centre: centre of box, defaults to None (alias: ``center``)
362363
:type centre: array_like(2), optional
363364
:param w: width of box, defaults to None
364365
:type w: float, optional
365366
:param h: height of box, defaults to None
366367
:type h: float, optional
368+
;param lbrt: left-bottom, right-top corners, defaults to None
369+
:type lbrt: array_like(4), optional
370+
:param lrbt: left-right, bottom-top corners, defaults to None
371+
:type lrbt: array_like(4), optional
372+
:param lbwh: left-bottom corner, width and height, defaults to None
373+
:type lbwh: array_like(4), optional
374+
:param ltrb: left-top, right-bottom corners, defaults to None
375+
:type ltrb: array_like(4), optional
367376
:param ax: the axes to draw on, defaults to ``gca()``
368377
:type ax: Axis, optional
369378
:param bbox: bounding box matrix, defaults to None
370379
:type bbox: array_like(4), optional
371-
:param color: box outline color
380+
:param filled: fill the box, defaults to False (alias for Matplotlib ``fill``)
381+
:type filled: bool
382+
:param thickness: line thickness (alias for Matplotlib ``linewidth``)
383+
:type thickness: float, optional
384+
:param kwargs: additional arguments passed to ``pyplot.Rectangle()``
385+
386+
:return: the matplotlib object
387+
:rtype: Patch.Rectangle instance
388+
389+
Appearance is controlled by Matplotlib properties passed as keyword arguments, for example:
390+
391+
:param color: box outline and fill color
372392
:type color: array_like(3) or str
373-
:param fillcolor: box fill color
393+
:param edgecolor: box outline colour (alias: ``ec``)
394+
:type edgecolor: array_like(3) or str
395+
:param fillcolor: box fill colour
374396
:type fillcolor: array_like(3) or str
397+
:param filled: fill the box, defaults to False
398+
:type filled: bool
375399
:param alpha: transparency, defaults to 1
376400
:type alpha: float, optional
377-
:param thickness: line thickness, defaults to None
378-
:type thickness: float, optional
379-
:return: the matplotlib object
380-
:rtype: Patch.Rectangle instance
401+
:param linestyle: box outline line style (alias: ``ls``)
402+
:type linestyle: str, optional
403+
:param linewidth: box outline line thickness (alias: ``lw``)
404+
:type linewidth: float, optional
381405
382-
The box can be specified in many ways:
406+
Additionally, the line style and color can be conveniently set using the pyplot
407+
convention where the first argument is a ``fmt`` string, for example ``"r--"``
408+
for dashed red. The allowable color letters are ``"rgbcmyk"`` and the line style
409+
characters are ``"-", "--", "-.", ":"``.
383410
384-
- bounding box [xmin, xmax, ymin, ymax]
385-
- alternative box [xmin, ymin, xmax, ymax]
386-
- centre and width+height
387-
- left-bottom and right-top corners
388-
- left-bottom corner and width+height
389-
- right-top corner and width+height
390-
- left-top corner and width+height
411+
The box can be specified in many ways. Two corners:
412+
413+
- `lb` = left-bottom corner
414+
- `lt` = left-top corner
415+
- `rb` = right-bottom corner
416+
- `rt` = right-top corner
417+
418+
Alternatively, one corner or `centre` plus the dimensons:
419+
420+
- `wh` = [width, height]
421+
- `w` = width
422+
- `h` = height
423+
424+
Alternatively, the box can be specified by a number of 4-vectors, various
425+
conventions are in use across different packages, so we support them all:
426+
427+
- `lbrt` = [umin, vmin, umax, vmax]
428+
- `lrbt` = [umin, umax, vmin, vmax]
429+
- `lbwh` = [umin, vmin, w, h]
430+
- `bbox` same as `lbwh`
431+
- `ltrb` = [umin, vmin, umax, vmax]`
391432
392433
For plots where the y-axis is inverted (eg. for images) then top is the
393-
smaller vertical coordinate.
434+
smaller vertical coordinate (highest in the window).
394435
395436
Example::
396437
@@ -440,6 +481,8 @@ def plot_box(
440481
elif w is not None and h is not None:
441482
# we have width & height, one corner is enough
442483

484+
if centre is None:
485+
centre = center
443486
if centre is not None:
444487
lb = (centre[0] - w / 2, centre[1] - h / 2)
445488

@@ -464,7 +507,7 @@ def plot_box(
464507
h = lt[1] - rb[1]
465508

466509
else:
467-
raise ValueError("cant compute box")
510+
raise ValueError("insufficient parameters to compute a box")
468511

469512
if w < 0:
470513
raise ValueError("width must be positive")
@@ -479,9 +522,9 @@ def plot_box(
479522
else:
480523
ec = None
481524
ls = ""
482-
if len(fmt) > 0:
525+
if fmt is not None:
483526
colors = "rgbcmywk"
484-
for f in fmt[0]:
527+
for f in fmt:
485528
if f in colors:
486529
ec = f
487530
else:
@@ -490,8 +533,13 @@ def plot_box(
490533
ls = None
491534

492535
if "color" in kwargs:
493-
ec = kwargs["color"]
494-
del kwargs["color"]
536+
ec = kwargs.pop("color")
537+
if "edgecolor" in kwargs:
538+
ec = kwargs.pop("edgecolor")
539+
if "linestyle" in kwargs:
540+
ls = kwargs.pop("linestyle")
541+
elif "ls" in kwargs:
542+
ls = kwargs.pop("ls")
495543
r = plt.Rectangle(
496544
lb, w, h, clip_on=True, linestyle=ls, edgecolor=ec, fill=False, **kwargs
497545
)
@@ -558,7 +606,7 @@ def plot_arrow(
558606
ax = plotvol2(5)
559607
ax.grid()
560608
plot_arrow(
561-
(-2, -2), (2, 4), label="$\mathit{p}_3$", color="r", width=0.1
609+
(-2, -2), (2, 4), label=r"$\mathit{p}_3$", color="r", width=0.1
562610
)
563611
plt.show(block=True)
564612
@@ -846,13 +894,15 @@ def plot_ellipse(
846894
The ellipse is defined by :math:`x^T \mat{E} x = s^2` where :math:`x \in
847895
\mathbb{R}^2` and :math:`s` is the scale factor.
848896
849-
.. note:: For some common cases we require :math:`\mat{E}^{-1}`, for example
897+
.. note::
898+
For some common cases we require :math:`\mat{E}^{-1}`, for example:
899+
850900
- for robot manipulability
851-
:math:`\nu (\mat{J} \mat{J}^T)^{-1} \nu` i
901+
:math:`\nu (\mat{J} \mat{J}^T)^{-1} \nu` i
852902
- a covariance matrix
853-
:math:`(x - \mu)^T \mat{P}^{-1} (x - \mu)`
854-
so to avoid inverting ``E`` twice to compute the ellipse, we flag that
855-
the inverse is provided using ``inverted``.
903+
:math:`(x - \mu)^T \mat{P}^{-1} (x - \mu)`
904+
so to avoid inverting ``E`` twice to compute the ellipse, we flag that
905+
the inverse is provided using ``inverted``.
856906
857907
Returns a set of ``resolution`` that lie on the circumference of a circle
858908
of given ``center`` and ``radius``.
@@ -1101,7 +1151,7 @@ def plot_ellipsoid(
11011151
.. note::
11021152
11031153
- If a confidence interval is given then ``E`` is interpretted as a covariance
1104-
matrix and the ellipse size is computed using an inverse chi-squared function.
1154+
matrix and the ellipse size is computed using an inverse chi-squared function.
11051155
11061156
:seealso: :func:`~matplotlib.pyplot.plot_surface`, :func:`~matplotlib.pyplot.plot_wireframe`
11071157
"""

‎spatialmath/base/quaternions.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,8 @@ def q2str(
11191119
fmt: Optional[str] = "{: .4f}",
11201120
) -> str:
11211121
"""
1122-
Format a quaternion as a string
1122+
Convert quaternion to compact single-line string
1123+
11231124
11241125
:arg q: unit-quaternion
11251126
:type q: array_like(4)

0 commit comments

Comments
 (0)