18 import math, sys, numpy
as np, trigonometry
as trig, rotation
as rot, general_python
as genpy
20 from math_tools.algebra import vectors_and_matrices
as vm, quaternions
as quat, optimization
as opt
21 from math_tools
import general_math
as gen
25 Changes from version 2:
26 All cgkit functions removed
31 [1] Olivier A. Bauchau et.al, "The Vectorial Parameterization of Rotation", Nonlinear Dynamics, 32, No 1, pp 71 - 92, 2003
35 i_uv = np.array([1.0, 0.0, 0.0])
36 j_uv = np.array([0.0, 1.0, 0.0])
37 k_uv = np.array([0.0, 0.0, 1.0])
39 backward_rotmat = np.append(np.append([j_uv],[-k_uv],axis = 0), [-i_uv], axis = 0).T
40 left_rotmat = np.append(np.append([k_uv],[i_uv],axis = 0), [j_uv], axis = 0).T
41 right_rotmat = np.append(np.append([-k_uv],[i_uv],axis = 0), [-j_uv], axis = 0).T
42 upward_rotmat = np.eye(3)
43 downward_rotmat = np.append(np.append([-i_uv],[j_uv],axis = 0), [-k_uv], axis = 0).T
45 ori_backward = Orientation(backward_rotmat)
48 'pm_unit_quaternion' ,
49 'pm_angular_spherical' ,
50 'pm_vectorial_identity' ,
51 'pm_vectorial_Cayley_Gibbs_Rodrigues' ,
52 'pm_vectorial_Wiener_Milenkovic' ,
53 'pm_vectorial_linear' ,
54 'pm_vectorial_reduced_Euler_Rodrigues' ,
55 'pm_vectorial_normailized_quaternion' ,
56 'pm_angular_Euler_Kardan'
67 def __init__(self, pos, vel = None, acc = None, representation = 'cartesian'):
106 if representation ==
'cartesian':
108 elif representation ==
'cartesian_velocity':
109 return self.cartesian_velocity()
110 elif representation ==
'cartesian_acceleration':
111 return self.cartesian_acceleration()
112 if representation ==
'spherical':
114 elif representation ==
'spherical_velocity':
115 return self.spherical_velocity()
116 elif representation ==
'spherical_acceleration':
117 return self.spherical_acceleration()
118 if representation ==
'cylindrical':
120 elif representation ==
'cylindrical_velocity':
121 return self.cylindrical_velocity()
122 elif representation ==
'cylindrical_acceleration':
123 return self.cylindrical_acceleration()
125 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'__getitem__', representation +
' is not a valid value for representation')
128 return self.
p ==
None
131 return self.
pd ==
None
134 return self.
pdd ==
None
138 if representation ==
'cartesian':
140 elif representation ==
'spherical':
142 elif representation ==
'cylindrical':
145 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'set_velocity', representation +
' is not a valid value for representation')
149 if representation ==
'cartesian':
151 elif representation ==
'spherical':
153 elif representation ==
'cylindrical':
156 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'set_acceleration', representation +
' is not a valid value for representation')
160 if representation ==
'cartesian':
162 elif representation ==
'spherical':
169 elif representation ==
'cylindrical':
177 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'__setitem__', representation +
' is not a valid value for representation')
184 self.
p[0] = self.
s[0]*math.cos(self.
s[1])*math.cos(self.
s[2])
185 self.
p[1] = self.
s[0]*math.sin(self.
s[1])*math.cos(self.
s[2])
186 self.
p[2] = self.
s[0]*math.sin(self.
s[2])
190 self.
p[0] = self.
c[0]*math.cos(self.
c[1])
191 self.
p[1] = self.
c[0]*math.sin(self.
c[1])
192 self.
p[2] = self.
c[2]
201 self.
s[0] = math.sqrt(r*r + z*z)
203 self.
s[2] = math.atan2(z, r)
210 self.
c[0] = math.sqrt(x*x + y*y)
211 self.
c[1] = math.atan2(y, x)
217 p2 = point.cartesian()
218 return np.linalg.norm(p1 - p2)
224 s =
"Point Dimension: " + str(self.
dim) +
'\n'
227 s +=
"Position : " + str(self.
p) +
'\n'
229 s +=
"Velocity : " + str(self.
pd) +
'\n'
231 s +=
"Acceleration : " + str(self.
pdd) +
'\n'
241 def value(self, field_name = 'position', axis = 0):
242 assert (axis <= self.
dim),
"Error from " + __name__ + func_name +
": Argument axis must not esxeed the space dimension"
243 assert (axis >= 0),
"Error from " + __name__ + func_name +
": Argument axis can not have a negative value"
245 if field_name ==
'position':
246 return self.pos[axis]
247 elif field_name ==
'velocity':
248 return self.vel[axis]
249 elif field_name ==
'acceleration':
250 return self.acc[axis]
252 print "Error from " + __name__ + func_name +
": " + field_name +
" is not not a valid value for argument field_name"
255 return Point_3D(pos = p1.cartesian() + p2.cartesian())
258 return Point_3D(pos = p1.cartesian() - p2.cartesian())
261 return Point_3D(pos = - p.cartesian())
330 return (self.
p ==
None)
and (self.
R ==
None)
and (self.
u ==
None)
and (self.
phi ==
None)
and (self.
Q ==
None)
336 return (self.
pd ==
None)
and (self.
Rd ==
None)
and (self.
ud ==
None)
and (self.
phid ==
None)
and (self.
Qd ==
None)
340 return self.
pdd ==
None
353 def __init__(self, ori, representation = 'matrix', ori_velocity = None, ori_acceleration = None, parametrization = 'identity'):
358 if ori_velocity ==
None:
363 if ori_acceleration ==
None:
370 s =
"3D Orientation represented by " + self.
representation +
": \n \n"
377 if gen.equal(self.
angle(), 0.0) :
383 p_nrm = np.linalg.norm(p)
391 self.
H = m*np.eye(3) + 0.5*v2*px + p2_inv*(m - v2_z)*px2
397 elif self.
Rd !=
None:
399 elif self.
omega !=
None:
401 wx = rot.skew(self.
omega)
402 self.
Rd = np.dot(wx, r)
403 elif self.
Qd !=
None:
404 assert False,
"Not Supported !"
405 elif (self.
phid !=
None)
and (self.
ud !=
None):
409 self.
omega = self.
phid*u + np.dot(math.sin(phi)*np.eye(3) + (1.0 - math.cos(phi))*ux, ud)
411 Reference: Olivier A. Bauchau et.al, "The Vectorial Parameterization of Rotation", Nonlinear Dynamics, 32, No 1, pp 71 - 92, 2003 (EQ.10)
413 elif self.
pd !=
None:
416 assert False,
"This should not happen !"
423 elif self.
omega ==
None:
427 self.
omega = rot.axial(np.dot(rd, r.T))
433 elif self.
Qd ==
None:
436 rd = self.matrix_velocity()
437 self.Qd = quaternions.unit_quaternion_velocity(r, rd)
446 ed = 0.5*c*phid*u + s*ud
447 self.
Qd = np.array([wd, ed[0], ed[1], ed[2]])
453 elif self.
phid ==
None:
456 sin_phi = math.sin(phi)
457 self.
phid = np.trace(rd)/(-2*sin_phi)
463 elif self.
ud ==
None:
466 sin_phi = math.sin(phi)
467 cos_phi = math.cos(phi)
472 self.
ud = (axrd - cos_phi*phid*u)/sin_phi
480 self.
R = rot.rotation_matrix(self.
Q)
483 elif (self.
phi !=
None)
and (self.
u !=
None):
484 ux = rot.skew(self.
u)
485 self.
R = np.eye(3) + math.sin(self.
phi)*ux + (1.0 - math.cos(self.
phi))*np.dot(ux,ux)
489 px = rot.skew(self.
p)
491 p = np.linalg.norm(self.
p)
497 self.
R = np.eye(3) + v2_z*px + 0.5*v2*px2
506 self.
p = rot.axial(self.
matrix())
512 self.
p = f*self.
axis()
518 elif self.
pd ==
None:
538 valid_parametrizations = [
'identity',
'linear',
'cayley-gibbs-rodrigues',
'bauchau-trainelli',
'exponential']
539 genpy.check_valid(parametrization, valid_parametrizations, __name__, self.__class__.__name__,sys._getframe().f_code.co_name,
'parametrization')
554 genpy.check_type(phi, [float, np.float64], __name__, self.__class__.__name__,sys._getframe().f_code.co_name,
'phi')
556 return self.
m*math.sin(phi/self.
m)
560 return self.
m*math.tan(phi/self.
m)
566 return math.exp(phi) - 1.0
568 assert False,
"Not Supported!"
572 return self.
m*trig.arcsin(p/self.
m)
576 return self.
m*trig.arctan(p/self.
m)
578 assert False,
"Not Supported!"
580 return math.log(p+1.0)
582 assert False,
"Not Supported!"
586 return math.cos(phi/self.
m)
590 t = math.tan(phi/self.
m)
602 assert False,
"Not Supported!"
604 def noo(self, phi = None):
612 return 2*math.sin(phi/2)*gen.inv(p)
622 return 2*math.tan(phi/2)*gen.inv(p)
624 def moo(self, phi = None):
633 self.
Q = quat.unit_quaternion(r)
638 e = math.sin(phi/2)*u
640 self.Q = np.array([w, e[0], e[1], e[2]])
656 ax = rot.angle_axis(r)
660 self.
phi = trig.arccos(0.5*(np.trace(self.
matrix()) - 1.0))
666 self.
sa = np.zeros((3))
669 self.
sa[2] = math.atan2(ax[2], ax[1])
670 self.
sa[1] = trig.arccos(ax[3])
676 return np.array([self.
angle(), u[0], u[1], u[2]])
681 ax = rot.angle_axis(r)
694 if representation ==
'matrix':
696 elif representation ==
'quaternion':
698 elif representation ==
'angle_axis':
701 elif representation ==
'vector':
704 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'__setitem__', representation +
' is not a valid value for representation')
707 if representation ==
'matrix':
709 elif representation ==
'quaternion':
711 elif representation ==
'angle_axis':
713 elif representation ==
'angle':
715 elif representation ==
'axis':
717 elif representation ==
'vector':
719 elif representation ==
'trace':
720 return np.trace(self.
matrix())
721 elif representation ==
'diag':
722 return np.diag(self.
matrix())
723 elif representation ==
'angular_spherical':
725 elif representation ==
'matrix_velocity':
727 elif representation ==
'quaternion_velocity':
729 elif representation ==
'angle_axis_velocity':
732 elif representation ==
'angle_velocity':
734 elif representation ==
'axis_velocity':
736 elif representation ==
'vector_velocity':
738 elif representation ==
'vector_acceleration':
740 elif representation ==
'trace_velocity':
742 elif representation ==
'diag_velocity':
745 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'__getitem__', representation +
' is not a valid value for representation')
749 if representation ==
'vector':
752 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'__getitem__', representation +
' is not a valid value for representation')
756 if representation ==
None:
758 if representation ==
'quaternion':
760 elif representation ==
'matrix':
762 elif representation ==
'angle_axis':
765 elif representation ==
'vector':
768 assert False,
"Not supported Yet !"
772 if representation ==
None:
774 if representation ==
'vector':
776 elif representation ==
'matrix':
779 assert False, genpy.err_str(__name__ , self.__class__.__name__ ,
'set_acceleration', representation +
' is not a valid value for representation')
782 if representation ==
None:
785 if representation ==
'quaternion':
787 elif representation ==
'matrix':
789 elif representation ==
'angle_axis':
790 return self.angle_axis_velocity()
791 elif representation ==
'angular_spherical':
793 return self.spherical_velocity()
795 assert False,
"Not supported Yet !"
800 r1_dot = o1.matrix_velocity()
801 r2_dot = o2.matrix_velocity()
803 if (r1_dot ==
None)
or (r2_dot ==
None):
806 r_dot = np.dot(r1_dot, r2.T) + np.dot(r1, r2_dot.T)
809 if o1.parametrization == o2.parametrization:
810 o.set_parametrization(o1.parametrization)
812 o.parametrization =
None
813 o.representation = o1.representation
819 r1_dot = o1.matrix_velocity()
820 r2_dot = o2.matrix_velocity()
822 if (r1_dot ==
None)
or (r2_dot ==
None):
825 r_dot = np.dot(r1_dot, r2) + np.dot(r1, r2_dot)
828 if o1.parametrization == o2.parametrization:
829 o.set_parametrization(o1.parametrization)
831 o.parametrization =
None
832 o.representation = o1.representation
845 For example to have a non-rotated ellipsoid centered at the origin with equation:
846 x^2/a^2 + y^2/b^2 + z^2/c^2 = 1
847 Arguments M and center must be selected as:
855 func_name = sys._getframe().f_code.co_name
856 genpy.check_type(M, [np.ndarray], __name__, self.__class__.__name__, func_name,
'M', shape = (3,3))
857 (landa, V) = np.linalg.eig(M)
860 assert vm.positive(landa, non_zero =
True)
and gen.equal(np.linalg.norm(V.imag) , 0.0), genpy.err_str(__name__, self.__class__.__name__, func_name,
'Matrix M must have real and positive eigen values')
864 self.
a = math.sqrt(1.0/landa[0])
865 self.
b = math.sqrt(1.0/landa[1])
866 self.
c = math.sqrt(1.0/landa[2])
870 return (4.0/3.0)*math.pi*self.
a*self.
b*self.
c
873 p0 = np.dot(self.
R, point.cartesian() - self.
center[
'cartesian'])
874 (theta, phi) = opt.distance_from_ellipsoid(a = self.
a, b = self.
b, c = self.
c, x0 = p0[0], y0 = p0[1], z0 = p0[2], silent =
False)
875 px = self.
a*math.cos(theta)*math.cos(phi)
876 py = self.
b*math.sin(theta)*math.cos(phi)
877 pz = self.
c*math.sin(phi)
878 pp = np.array([px, py, pz])
882 p0 = np.dot(self.
R, point.cartesian() - self.
center[
'cartesian'])
883 (theta, phi) = opt.distance_from_ellipsoid(a = self.
a, b = self.
b, c = self.
c, x0 = p0[0], y0 = p0[1], z0 = p0[2], silent =
False, maximum =
True)
884 px = self.
a*math.cos(theta)*math.cos(phi)
885 py = self.
b*math.sin(theta)*math.cos(phi)
886 pz = self.
c*math.sin(phi)
887 pp = np.array([px, py, pz])
891 x_c = point.cartesian() - self.center.cartesian()
892 d = np.dot(np.dot((x_c).T, self.
M), x_c)
893 return gen.equal(d, 1.0)