10000 cleanup · RPellowski/spatialmath-python@b496c82 · GitHub
[go: up one dir, main page]

Skip to content

Commit b496c82

Browse files
committed
cleanup
1 parent a05a9b5 commit b496c82

File tree

2 files changed

+86
-62
lines changed

2 files changed

+86
-62
lines changed

spatialmath/geom3d.py

Lines changed: 75 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections import UserList
77

88
from spatialmath.base import argcheck as arg
9-
from spatialmath import base as sm
9+
import spatialmath.base as base
1010
import matplotlib.pyplot as plt
1111
from mpl_toolkits.mplot3d import Axes3D
1212
from spatialmath import SE3
@@ -227,16 +227,14 @@ def __init__(self, v=None, w=None):
227227
:seealso: Plucker.PQ, Plucker.Planes, Plucker.PointDir
228228
"""
229229
super().__init__() # enable list powers
230+
230231
if w is None:
231-
# single parameter
232-
if isinstance(v, Plucker):
233-
self.data = [v.A]
234-
elif arg.isvector(v, 6):
235-
pl = arg.getvector(v)
236-
self.data = [pl]
237-
else:
238-
raise ValueError('bad argument')
232+
# zero or one arguments passed
233+
if super().arghandler(v, convertfrom=(SE3,)):
234+
return
235+
239236
else:
237+
# additional arguments
240238
assert arg.isvector(v, 3) and arg.isvector(w, 3), 'expecting two 3-vectors'
241239
self.data = [np.r_[v, w]]
242240

@@ -252,8 +250,8 @@ def _identity():
252250
return np.zeros((6,))
253251

254252
@staticmethod
255-
def isvalid(x):
256-
return x.shape == self.shape
253+
def isvalid(x, check=False):
254+
return x.shape == (6,)
257255

258256
@staticmethod
259257
def PQ(P=None, Q=None):
@@ -396,7 +394,7 @@ def uw(self):
396394
397395
``line.uw`` is a unit-vector parallel to the line.
398396
"""
399-
return sm.unitvec(self.w)
397+
return base.unitvec(self.w)
400398

401399
@property
402400
def vec(self):
@@ -430,7 +428,8 @@ def skew(self):
430428
given by :math:`\vee C M C^T` where :math:`C \in \mathbf{R}^{3 \times 4}` is the camera matrix.
431429
"""
432430

433-
v = self.v; w = self.w;
431+
v = self.v
432+
w = self.w
434433

435434
# the following matrix is at odds with H&Z pg. 72
436435
return np.array([
@@ -471,7 +470,7 @@ def ppd(self):
471470
"""
472471
return math.sqrt(np.dot(self.v, self.v) / np.dot(self.w, self.w) )
473472

474-
def point(L, lam):
473+
d B41A ef point(self, lam):
475474
r"""
476475
Generate point on line
477476
@@ -488,7 +487,7 @@ def point(L, lam):
488487
:seealso: Plucker.pp, Plucker.closest, Plucker.uw
489488
"""
490489
lam = arg.getvector(lam, out='row')
491-
return L.pp.reshape((3,1)) + L.uw.reshape((3,1)) * lam
490+
return self.pp.reshape((3,1)) + self.uw.reshape((3,1)) * lam
492491

493492
# ------------------------------------------------------------------------- #
494493
# TESTS ON PLUCKER OBJECTS
@@ -520,7 +519,7 @@ def contains(self, x, tol=50*_eps):
520519
else:
521520
raise ValueError('bad argument')
522521

523-
def __eq__(l1, l2):
522+
def __eq__(l1, l2): # pylint: disable=no-self-argument
524523
"""
525524
Test if two lines are equivalent
526525
@@ -536,9 +535,9 @@ def __eq__(l1, l2):
536535
space. Note that because of the over parameterization, lines can be
537536
equivalent even if their coordinate vectors are different.
538537
"""
539-
return abs( 1 - np.dot(sm.unitvec(l1.vec), sm.unitvec(l2.vec))) < 10*_eps
538+
return abs( 1 - np.dot(base.unitvec(l1.vec), base.unitvec(l2.vec))) < 10*_eps
540539

541-
def __ne__(l1, l2):
540+
def __ne__(l1, l2): # pylint: disable=no-self-argument
542541
"""
543542
Test if two lines are not equivalent
544543
@@ -556,7 +555,7 @@ def __ne__(l1, l2):
556555

557556
return not l1.__eq__(l2)
558557

559-
def isparallel(l1, l2, tol=10*_eps):
558+
def isparallel(l1, l2, tol=10*_eps): # pylint: disable=no-self-argument
560559
"""
561560
Test if lines are parallel
562561
@@ -577,7 +576,7 @@ def isparallel(l1, l2, tol=10*_eps):
577576
return np.linalg.norm(np.cross(l1.w, l2.w) ) < tol
578577

579578

580-
def __or__(l1, l2):
579+
def __or__(l1, l2): # pylint: disable=no-self-argument
581580
"""
582581
Test if lines are parallel as a binary operator
583582
@@ -595,7 +594,7 @@ def __or__(l1, l2):
595594
return l1.isparallel(l2)
596595

597596

598-
def __xor__(l1, l2):
597+
def __xor__(l1, l2): # pylint: disable=no-self-argument
599598

600599
"""
601600
Test if lines intersect as a binary operator
@@ -623,7 +622,7 @@ def __xor__(l1, l2):
623622
# ------------------------------------------------------------------------- #
624623

625624

626-
def intersects(l1, l2):
625+
def intersects(l1, l2): # pylint: disable=no-self-argument
627626
"""
628627
Intersection point of two lines
629628
@@ -644,12 +643,12 @@ def intersects(l1, l2):
644643
# lines do intersect
645644
return -(np.dot(l1.v, l2.w) * np.eye(3, 3) + \
646645
l1.w.reshape((3,1)) @ l2.v.reshape((1,3)) - \
647-
l2.w.reshape((3,1)) @ l1.v.reshape((1,3))) * sm.unitvec(np.cross(l1.w, l2.w))
646+
l2.w.reshape((3,1)) @ l1.v.reshape((1,3))) * base.unitvec(np.cross(l1.w, l2.w))
648647
else:
649648
# lines don't intersect
650649
return None
651650

652-
def distance(l1, l2):
651+
def distance(l1, l2): # pylint: disable=no-self-argument
653652
"""
654653
Minimum distance between lines
655654
@@ -680,7 +679,7 @@ def distance(l1, l2):
680679
return l
681680

682681

683-
def closest(line, x):
682+
def closest(self, x):
684683
"""
685684
Point on line closest to given point
686685
@@ -709,14 +708,14 @@ def closest(line, x):
709708

710709
x = arg.getvector(x, 3)
711710

712-
lam = np.dot(x - line.pp, line.uw)
713-
p = line.point(lam).flatten() # is the closest point on the line
711+
lam = np.dot(x - self.pp, self.uw)
712+
p = self.point(lam).flatten() # is the closest point on the line
714713
d = np.linalg.norm( x - p)
715714

716715
return namedtuple('closest', 'p d lam')(p, d, lam)
717716

718717

719-
def commonperp(l1, l2):
718+
def commonperp(l1, l2): # pylint: disable=no-self-argument
720719
"""
721720
Common perpendicular to two lines
722721
@@ -740,12 +739,12 @@ def commonperp(l1, l2):
740739
# lines are skew or intersecting
741740
w = np.cross(l1.w, l2.w)
742741
v = np.cross(l1.v, l2.w) - np.cross(l2.v, l1.w) + \
743-
(l1 * l2) * np.dot(l1.w, l2.w) * sm.unitvec(np.cross(l1.w, l2.w))
742+
(l1 * l2) * np.dot(l1.w, l2.w) * base.unitvec(np.cross(l1.w, l2.w))
744743

745744
return Plucker(v, w)
746745

747746

748-
def __mul__(left, right):
747+
def __mul__(left, right): # pylint: disable=no-self-argument
749748
r"""
750749
Reciprocal product
751750
@@ -771,7 +770,7 @@ def __mul__(left, right):
771770
else:
772771
raise ValueError('bad arguments')
773772

774-
def __rmul__(right, left):
773+
def __rmul__(right, left): # pylint: disable=no-self-argument
775774
"""
776775
Line transformation
777776
@@ -788,7 +787,7 @@ def __rmul__(right, left):
788787
:seealso: Plucker.__mul__
789788
"""
790789
if isinstance(left, SE3):
791-
A = np.r_[ np.c_[left.R, sm.skew(-left.t) @ left.R],
790+
A = np.r_[ np.c_[left.R, base.skew(-left.t) @ left.R],
792791
np.c_[np.zeros((3,3)), left.R]
793792
]
794793
return Plucker( A @ right.vec) # premultiply by SE3
@@ -800,7 +799,7 @@ def __rmul__(right, left):
800799
# ------------------------------------------------------------------------- #
801800

802801

803-
def intersect_plane(line, plane):
802+
def intersect_plane(line, plane): # pylint: disable=no-self-argument
804803
r"""
805804
Line intersection with a plane
806805
@@ -851,7 +850,7 @@ def intersect_plane(line, plane):
851850
else:
852851
return None
853852

854-
def intersect_volume(line, bounds):
853+
def intersect_volume(self, bounds):
855854
"""
856855
Line intersection with a volume
857856
@@ -890,6 +889,14 @@ def intersect_volume(line, bounds):
890889
for face in range(0, 6):
891890
# for each face of the bounding volume
892891
# x=xmin, x=xmax, y=ymin, y=ymax, z=zmin, z=zmax
892+
893+
# planes are:
894+
# 0 normal in x direction, xmin
895+
# 1 normal in x direction, xmax
896+
# 2 normal in y direction, ymin
897+
# 3 normal in y direction, ymax
898+
# 4 normal in z direction, zmin
899+
# 5 normal in z direction, zmax
893900

894901
i = face // 2 # 0, 1, 2
895902
I = np.eye(3,3)
@@ -899,14 +906,15 @@ def intersect_volume(line, bounds):
899906

900907
# find where line pierces the plane
901908
try:
902-
p, lam = line.intersect_plane(plane)
909+
p, lam = self.intersect_plane(plane)
903910
except TypeError:
904911
continue # no intersection with this plane
905912

906-
# # print('face %d: n=(%f, %f, %f), p=(%f, %f, %f)' % (face, plane.n, plane.p))
907-
# print(' : p=(%f, %f, %f) ' % p)
913+
# print('face %d: n=(%f, %f, %f)' % (face, plane.n[0], plane.n[1], plane.n[2]))
914+
# print(' : p=(%f, %f, %f) ' % (p[0], p[1], p[2]))
908915

909916
# print('face', face, ' point ', p, ' plane ', plane)
917+
# print('lamda', lam, self.point(lam))
910918
# find if intersection point is within the cube face
911919
# test x,y,z simultaneously
912920
k = (p >= bounds23[:,0]) & (p <= bounds23[:,1])
@@ -919,8 +927,7 @@ def intersect_volume(line, bounds):
919927

920928
# put them in ascending order
921929
intersections.sort()
922-
923-
p = line.point(intersections)
930+
p = self.point(intersections)
924931

925932
return namedtuple('intersect_volume', 'p lam')(p, intersections)
926933

@@ -929,7 +936,7 @@ def intersect_volume(line, bounds):
929936
# PLOT AND DISPLAY
930937
# ------------------------------------------------------------------------- #
931938

932-
def plot(line, bounds=None, **kwargs):
939+
def plot(self, *pos, bounds=None, axis=None, **kwargs):
933940
"""
934941
Plot a line
935942
@@ -954,24 +961,32 @@ def plot(line, bounds=None, **kwargs):
954961
955962
:seealso: Plucker.intersect_volume
956963
"""
957-
958-
if bounds is None:
964+
if axis is None:
959965
ax = plt.gca()
966+
else:
967+
ax = axis
968+
969+
if bounds is None:
960970
bounds = np.r_[ax.get_xlim(), ax.get_ylim(), ax.get_zlim()]
961971
else:
972+
bounds = base.getvector(bounds, 6)
962973
ax.set_xlim(bounds[:2])
963974
ax.set_ylim(bounds[2:4])
964975
ax.set_zlim(bounds[4:6])
976+
977+
# print(bounds)
965978

966979
#U = self.Q - self.P;
967980
#line.p = self.P; line.v = unit(U);
968981

969-
P, lam = line.intersect_volume(bounds)
970-
971-
if len(lam) > 0:
972-
return ax.plot(P[0,:], P[1,:], P[2,:], **kwargs)
973-
else:
974-
return None
982+
lines = []
983+
for line in self:
984+
P, lam = line.intersect_volume(bounds)
985+
986+
if len(lam) > 0:
987+
l = ax.plot3D(P[0,:], P[1,:], P[2,:], *pos, **kwargs)
988+
lines.append(l)
989+
return lines
975990

976991
def __str__(self):
977992
"""
@@ -990,7 +1005,7 @@ def __str__(self):
9901005
9911006
"""
9921007

993-
return '\n'.join(['{{ {:.5g} {:.5g} {:.5g}; {:.5g} {:.5g} {:.5g}}}'.format(*list(x.vec)) for x in self])
1008+
return '\n'.join(['{{ {:.5g} {:.5g} {:.5g}; {:.5g} {:.5g} {:.5g}}}'.format(*list(base.removesmall(x.vec))) for x in self])
9941009

9951010
def __repr__(self):
9961011
"""
@@ -1016,7 +1031,7 @@ def __repr__(self):
10161031

10171032
def _repr_pretty_(self, p, cycle):
10181033
"""
1019-
Pretty string for IPython (superclass method)
1034+
Pretty string for IPython
10201035
10211036
:param p: pretty printer handle (ignored)
10221037
:param cycle: pretty printer flag (ignored)
@@ -1029,7 +1044,16 @@ def _repr_pretty_(self, p, cycle):
10291044
In [1]: x
10301045
10311046
"""
1032-
print(self.__str__())
1047+
if len(self) == 1:
1048+
p.begin_group(8, 'Plücker ')
1049+
p.text(str(self))
1050+
p.end_group(8, '')
1051+
else:
1052+
p.begin_group(8, 'Plücker(')
1053+
for i, x in enumerate(self):
1054+
p.break_()
1055+
p.text(str(x))
1056+
p.end_group(8, ')')
10331057

10341058
# function z = side(self1, pl2)
10351059
# Plucker.side Plucker side operator

0 commit comments

Comments
 (0)
0