Skip to content

Commit 2fd7f4b

Browse files
committed
first cut at introducing type hints
1 parent 55348c7 commit 2fd7f4b

27 files changed

Lines changed: 5632 additions & 4190 deletions

spatialmath/DualQuaternion.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
from __future__ import annotations
12
import numpy as np
23
from spatialmath import Quaternion, UnitQuaternion, SE3
34
from spatialmath import base
5+
from spatialmath.base.types import *
46

57
# TODO scalar multiplication
68

9+
710
class DualQuaternion:
811
r"""
912
A dual number is an ordered pair :math:`\hat{a} = (a, b)` or written as
10-
:math:`a + \epsilon b` where :math:`\epsilon^2 = 0`.
13+
:math:`a + \epsilon b` where :math:`\epsilon^2 = 0`.
1114
1215
A dual quaternion can be considered as either:
1316
@@ -27,7 +30,7 @@ class DualQuaternion:
2730
:seealso: :func:`UnitDualQuaternion`
2831
"""
2932

30-
def __init__(self, real=None, dual=None):
33+
def __init__(self, real: Quaternion = None, dual: Quaternion = None):
3134
"""
3235
Construct a new dual quaternion
3336
@@ -61,23 +64,23 @@ def __init__(self, real=None, dual=None):
6164
self.dual = Quaternion(real[4:8])
6265
elif real is not None and dual is not None:
6366
if not isinstance(real, Quaternion):
64-
raise ValueError('real part must be a Quaternion subclass')
67+
raise ValueError("real part must be a Quaternion subclass")
6568
if not isinstance(dual, Quaternion):
66-
raise ValueError('real part must be a Quaternion subclass')
69+
raise ValueError("real part must be a Quaternion subclass")
6770
self.real = real # quaternion, real part
6871
self.dual = dual # quaternion, dual part
6972
else:
70-
raise ValueError('expecting zero or two parameters')
73+
raise ValueError("expecting zero or two parameters")
7174

7275
@classmethod
73-
def Pure(cls, x):
76+
def Pure(cls, x: ArrayLike3) -> Self:
7477
x = base.getvector(x, 3)
7578
return cls(UnitQuaternion(), Quaternion.Pure(x))
7679

77-
def __repr__(self):
80+
def __repr__(self) -> str:
7881
return str(self)
7982

80-
def __str__(self):
83+
def __str__(self) -> str:
8184
"""
8285
String representation of dual quaternion
8386
@@ -94,7 +97,7 @@ def __str__(self):
9497
"""
9598
return str(self.real) + " + ε " + str(self.dual)
9699

97-
def norm(self):
100+
def norm(self) -> Tuple[float, float]:
98101
"""
99102
Norm of a dual quaternion
100103
@@ -116,7 +119,7 @@ def norm(self):
116119
b = self.real * self.dual.conj() + self.dual * self.real.conj()
117120
return (base.sqrt(a.s), base.sqrt(b.s))
118121

119-
def conj(self):
122+
def conj(self) -> Self:
120123
r"""
121124
Conjugate of dual quaternion
122125
@@ -137,7 +140,9 @@ def conj(self):
137140
"""
138141
return DualQuaternion(self.real.conj(), self.dual.conj())
139142

140-
def __add__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-argument
143+
def __add__(
144+
left, right: DualQuaternion
145+
) -> Self: # pylint: disable=no-self-argument
141146
"""
142147
Sum of two dual quaternions
143148
@@ -154,7 +159,9 @@ def __add__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-arg
154159
"""
155160
return DualQuaternion(left.real + right.real, left.dual + right.dual)
156161

157-
def __sub__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-argument
162+
def __sub__(
163+
left, right: DualQuaternion
164+
) -> Self: # pylint: disable=no-self-argument
158165
"""
159166
Difference of two dual quaternions
160167
@@ -171,7 +178,7 @@ def __sub__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-arg
171178
"""
172179
return DualQuaternion(left.real - right.real, left.dual - right.dual)
173180

174-
def __mul__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-argument
181+
def __mul__(left, right: Self) -> Self: # pylint: disable=no-self-argument
175182
"""
176183
Product of dual quaternion
177184
@@ -193,7 +200,9 @@ def __mul__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-arg
193200
real = left.real * right.real
194201
dual = left.real * right.dual + left.dual * right.real
195202

196-
if isinstance(left, UnitDualQuaternion) and isinstance(left, UnitDualQuaternion):
203+
if isinstance(left, UnitDualQuaternion) and isinstance(
204+
left, UnitDualQuaternion
205+
):
197206
return UnitDualQuaternion(real, dual)
198207
else:
199208
return DualQuaternion(real, dual)
@@ -202,7 +211,7 @@ def __mul__(left, right): # lgtm[py/not-named-self] pylint: disable=no-self-arg
202211
vp = left * DualQuaternion.Pure(v) * left.conj()
203212
return vp.dual.v
204213

205-
def matrix(self):
214+
def matrix(self) -> R8x8:
206215
"""
207216
Dual quaternion as a matrix
208217
@@ -222,13 +231,12 @@ def matrix(self):
222231
>>> d.matrix() @ d.vec
223232
>>> d * d
224233
"""
225-
return np.block([
226-
[self.real.matrix, np.zeros((4,4))],
227-
[self.dual.matrix, self.real.matrix]
228-
])
234+
return np.block(
235+
[[self.real.matrix, np.zeros((4, 4))], [self.dual.matrix, self.real.matrix]]
236+
)
229237

230238
@property
231-
def vec(self):
239+
def vec(self) -> R8:
232240
"""
233241
Dual quaternion as a vector
234242
@@ -245,10 +253,10 @@ def vec(self):
245253
"""
246254
return np.r_[self.real.vec, self.dual.vec]
247255

248-
249256
# def log(self):
250257
# pass
251-
258+
259+
252260
class UnitDualQuaternion(DualQuaternion):
253261
"""[summary]
254262
@@ -262,6 +270,13 @@ class UnitDualQuaternion(DualQuaternion):
262270
:seealso: :func:`UnitDualQuaternion`
263271
"""
264272

273+
@overload
274+
def __init__(self, T: SE3):
275+
...
276+
277+
def __init__(self, real: Quaternion, dual: Quaternion):
278+
...
279+
265280
def __init__(self, real=None, dual=None):
266281
r"""
267282
Create new unit dual quaternion
@@ -307,13 +322,13 @@ def __init__(self, real=None, dual=None):
307322
T = real
308323
S = UnitQuaternion(T.R)
309324
D = Quaternion.Pure(T.t)
310-
325+
311326
real = S
312327
dual = 0.5 * D * S
313328

314329
super().__init__(real, dual)
315330

316-
def SE3(self):
331+
def SE3(self) -> SE3:
317332
"""
318333
Convert unit dual quaternion to SE(3) matrix
319334
@@ -335,17 +350,18 @@ def SE3(self):
335350
t = 2 * self.dual * self.real.conj()
336351

337352
return SE3(base.rt2tr(R, t.v))
338-
353+
339354
# def exp(self):
340355
# w = self.real.v
341356
# v = self.dual.v
342357
# theta = base.norm(w)
343358

359+
344360
if __name__ == "__main__": # pragma: no cover
345361

346362
from spatialmath import SE3, UnitDualQuaternion
347363

348364
print(UnitDualQuaternion(SE3()))
349365
# import pathlib
350366

351-
# exec(open(pathlib.Path(__file__).parent.parent.absolute() / "tests" / "test_dualquaternion.py").read()) # pylint: disable=exec-used
367+
# exec(open(pathlib.Path(__file__).parent.parent.absolute() / "tests" / "test_dualquaternion.py").read()) # pylint: disable=exec-used

spatialmath/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
print("in spatialmath/__init__")
1+
# print("in spatialmath/__init__")
22

33
from spatialmath.pose2d import SO2, SE2
44
from spatialmath.pose3d import SO3, SE3
55
from spatialmath.baseposematrix import BasePoseMatrix
66
from spatialmath.geom2d import Line2, Polygon2
77
from spatialmath.geom3d import Line3, Plane3
88
from spatialmath.twist import Twist3, Twist2
9-
from spatialmath.spatialvector import SpatialVelocity, SpatialAcceleration, \
10-
SpatialForce, SpatialMomentum, SpatialInertia
9+
from spatialmath.spatialvector import (
10+
SpatialVelocity,
11+
SpatialAcceleration,
12+
SpatialForce,
13+
SpatialMomentum,
14+
SpatialInertia,
15+
)
1116
from spatialmath.quaternion import Quaternion, UnitQuaternion
1217
from spatialmath.DualQuaternion import DualQuaternion, UnitDualQuaternion
13-
#from spatialmath.Plucker import *
18+
19+
# from spatialmath.Plucker import *
1420
# from spatialmath import base as smb
1521

1622
__all__ = [
@@ -39,8 +45,7 @@
3945

4046
try:
4147
import importlib.metadata
48+
4249
__version__ = importlib.metadata.version("spatialmath-python")
4350
except:
4451
pass
45-
46-

spatialmath/base/_types_38.py

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

0 commit comments

Comments
 (0)